如何使用Windows API C++更改已创建的文件夹/目录安全权限

How to change already created folder/directory security permission using Windows API C++

本文关键字:文件夹 权限 安全 创建 Windows 何使用 API C++      更新时间:2023-10-16

我必须更改已创建目录的目录权限。如果目录不存在,我可以使用给定安全访问属性的CreateDirectoryEx创建新目录,但是当目录已经存在时,我必须更改目录的安全访问属性 例如:管理员 - 完全访问权限 用户=读取访问权限

首先检查目录是否存在,如果目录存在,则更改安全属性

我能够使用本文更改目录permisison https://learn.microsoft.com/en-us/windows/win32/secauthz/modifying-the-acls-of-an-object-in-c--

对于内核对象的设置安全性,需要使用NtSetSecurityObjectSetKernelObjectSecurity(这在NtSetSecurityObject上是非常薄的外壳(,特别是如果您已经拥有带有WRITE_DAC的对象句柄,并且如果您还想LABEL_SECURITY_INFORMATIONsetWRITE_OWNER

需要了解,没有任何其他方法可以在对象上设置安全性 - 任何其他 API 如SetSecurityInfoSetNamedSecurityInfoW无论如何都会内部调用SetKernelObjectSecurityNtSetSecurityObject

如果我们需要open_if逻辑 - 创建新文件夹(如果它不存在(或打开(如果它已经存在(- 需要使用或NtCreateFileFILE_OPEN_IF处置。 然后需要查找IO_STATUS_BLOCK的信息成员 - 它是FILE_OPENED还是FILE_CREATED. 如果FILE_OPENED调用NtSetSecurityObject因为在这种情况下,安全描述符将在调用NtCreateFile中被忽略。 否则,我们已经在NtCreateFile中设置了安全描述符。 代码可以是下一个:

NTSTATUS CreateFolderWithSD(PCWSTR lpNewDirectory, PSECURITY_ATTRIBUTES psa)
{
UNICODE_STRING ObjectName;
NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(lpNewDirectory, &ObjectName, 0, 0);
if (0 <= status)
{
IO_STATUS_BLOCK iosb;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, 0, psa->lpSecurityDescriptor };
status = NtCreateFile(&oa.RootDirectory, WRITE_DAC|WRITE_OWNER, &oa, &iosb, 0,
FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF, 
FILE_DIRECTORY_FILE, 0, 0);
RtlFreeUnicodeString(&ObjectName);
if (0 <= status)
{
switch (iosb.Information)
{
case FILE_OPENED:
status = NtSetSecurityObject(oa.RootDirectory, 
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION, oa.SecurityDescriptor);
case FILE_CREATED:
break;
default: __debugbreak();
}
NtClose(oa.RootDirectory);
}
}
return status;
}
void TestNF(PCWSTR lpNewDirectory)
{
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
if (ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FRFX;;;BU)S:(ML;;NWNX;;;HI)",
SDDL_REVISION_1, &sa.lpSecurityDescriptor, 0))
{
CreateFolderWithSD(lpNewDirectory, &sa);
LocalFree(sa.lpSecurityDescriptor);
}
}

在 msdn 页面的 SetKernelObjectSecurity 函数存在下一个注释

注意在文件系统对象上设置安全描述符时,不应使用此函数。相反,请使用 SetSecurityInfo 或SetNamedSecurityInfo函数。

现在我对这个笔记的注释 - 为什么不应该使用?(这不是说不能使用 - 当然可以(。我没有看到任何理由或解释这一点。在任何情况下,当我们在文件上设置安全性时,都将使用此API - 直接或间接。所以认为需要忽略这个注释,它没有任何解释。


另请注意本机API的使用 - 这既是内核又是用户模式API(不仅是许多人认为的内核(,并且像任何其他API一样轻松(或困难(使用它。 没有任何不同(只需使用ntdllp.lib或ntdll.lib(。 我使用NtCreateFile因为任何 Win 32 API 不提供这样的功能 - 文件夹和返回结果上的open_if逻辑 - 是实际打开或创建的文件。CreateFileW不能创建文件夹,即使是文件也是如此 - 尽管存在选项OPEN_ALWAYS(equ 表示FILE_OPEN_IF(,但 API 不返回信息是FILE_OPENEDFILE_CREATED- 它只是删除它。CreateDirectory根本没有open_if逻辑 - 如果指定的目录已经存在,它会失败并ERROR_ALREADY_EXISTS。所以真的NtCreateFile在这里拥有最好的和没有模拟功能,因为它和使用过。使用但不SetKernelObjectSecurityNtSetSecurityObject给出相同的错误类型(NTSTATUS(喜欢和NtCreateFile