【问题标题】:Delete folder for which every API call fails with ERROR_ACCESS_DENIED删除每个 API 调用都失败并显示 ERROR_ACCESS_DENIED 的文件夹
【发布时间】:2017-09-29 06:30:58
【问题描述】:

我用CreateDirectoryW 创建了一个我无权访问的文件夹。我使用nullptr 作为安全描述符,但由于某种原因它没有复制父文件夹的 ACL,而是使文件夹无法访问。

我无法查看或更改所有者。 takeownicaclsSetNamedSecurityInfoW,全部来自提升的进程或命令提示符,以 ERROR_ACCESS_DENIED 失败。

在尝试不关心 ACL 的 Linux live CD 之前,我是否有机会在 Windows(Shell 或 C++)中删除此文件夹?

【问题讨论】:

标签: c++ winapi windows-10 delete-file access-denied


【解决方案1】:

您只需要启用备份(或恢复)权限:

#include <Windows.h>

#include <stdio.h>

int wmain(int argc, wchar_t ** argv)
{
    // argv[1] must contain the directory to remove

    HANDLE hToken;
    struct 
    {    
        DWORD PrivilegeCount;
        LUID_AND_ATTRIBUTES Privileges[1];    
    } tkp;

    if (OpenProcessToken(GetCurrentProcess(), 
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
    {
        LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tkp.Privileges[0].Luid);

        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

        if (!AdjustTokenPrivileges(hToken, FALSE, 
            (PTOKEN_PRIVILEGES)&tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
        {
            printf("AdjustTokenPrivileges: %u\n", GetLastError());
            return 1;
        }

        if (GetLastError() != ERROR_SUCCESS)
        {
            // This happens if you don't have the privilege
            printf("AdjustTokenPrivileges: %u\n", GetLastError());
            return 1;
        }

        CloseHandle(hToken);
    }

    if (!RemoveDirectory(argv[1]))
    {
        printf("RemoveDirectory: %u\n", GetLastError());
        return 1;
    }

    printf("OK\n");
    return 0;
}

请注意,为了简洁起见,省略了一些错误处理。另请注意,AdjustTokenPrivileges() 是少数几个特殊情况之一,即使调用成功,调用 GetLastError() 也是有意义的;它将返回ERROR_SUCCESSERROR_NOT_ALL_ASSIGNED,具体取决于您是否真的拥有您尝试启用的所有权限。

这是绕过文件安全权限的相当通用的解决方案。它适用于大多数 API 调用,但在某些情况下(尤其是 CreateFile),您必须提供一个特殊标志才能使用备份权限。除了删除您没有权限的文件或删除目录之外,您还可以更改属性、更改权限,甚至将所有权分配给其他人,这是不允许的。

【讨论】:

  • 并且仍然单独调用ZwDeleteFile 执行相同的任务,因为DELETEFILE_READ_ATTRIBUTES 这是对文件的特殊访问。如果父级上有FILE_DELETE_CHILD,文件系统将授予DELETE。 (FILE_LIST_DIRECTORY 父母为FILE_READ_ATTRIBUTES 孩子)。如果文件夹具有只读属性 - 我们需要首先更改文件属性。
【解决方案2】:

假设该文件未打开且不兼容删除共享标志且文件中没有部分。

删除文件足够的两件事 - 我们在 parent 文件夹中有FILE_DELETE_CHILD。并且文件不是只读的。在这种情况下,调用ZwDeleteFile(但不是DeleteFileRemoveDirectory - 如果文件有空DACL,这两个API 都会失败)就足够了。如果文件具有只读属性 - ZwDeleteFile 失败,代码为 STATUS_CANNOT_DELETE。在这种情况下,我们需要首先删除只读。为此需要以FILE_WRITE_ATTRIBUTES 访问权限打开文件。如果我们有SE_RESTORE_PRIVILEGE 并在调用ZwOpenFile 时设置FILE_OPEN_FOR_BACKUP_INTENT 选项,我们可以这样做。所以删除文件的代码可以是下一个:

NTSTATUS DeleteEx(POBJECT_ATTRIBUTES poa)
{
    NTSTATUS status = ZwDeleteFile(poa);

    if (status == STATUS_CANNOT_DELETE)
    {
        BOOLEAN b;
        RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &b);
        HANDLE hFile;

        IO_STATUS_BLOCK iosb;
        if (0 <= (status = NtOpenFile(&hFile, FILE_WRITE_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT)))
        {
            static FILE_BASIC_INFORMATION fbi = {{},{},{},{}, FILE_ATTRIBUTE_NORMAL};
            status = ZwSetInformationFile(hFile, &iosb, &fbi, sizeof(fbi), FileBasicInformation);
            NtClose(hFile);

            if (0 <= status)
            {
                status = ZwDeleteFile(poa);
            }
        }
    }

    return status;
}

【讨论】:

  • 问题被标记为winapi。您的所有调用都不是 Windows API 的一部分。虽然这可能会解决问题,但它并不能解决所提出的问题。
  • @IInspectable - 我也使用 winapi - 从某些用户模式 ​​dll 导出的函数(具体情况下为 ntdll.dll)。另一个用户模式 ​​dll 之间没有什么不同。并且所有这些 api 都有据可查。如果文件最初没有只读属性 - 单次调用ZwDeleteFile 执行任务。或者你有更好的解决方案?
  • 已发布的 Windows API 文档是合同性的。已发布的本机 API 文档仅供参考。请参阅Calling Internal APIs 以供参考。当您必须为您的软件提供支持时,这会产生很大的不同。专业软件开发人员通常必须为其软件提供支持。
  • @IInspectable - 已发布的原生 API 文档仅供参考。 - 这就是为什么?在具体的文档中 - 比如说 - msdn.microsoft.com/en-us/library/windows/hardware/… 这说明了什么?这是众所周知的api。所有记录至少约 20 年。并在用户模式和内核模式下均受支持。这也被记录在案。在什么问题? ZwDeleteFile 是最好的解决方案。而且这个api没有kernel32 shell。所以这里别无选择
  • @IInspectable 按照这个逻辑,我的标签也会阻止某人用普通的 ISO C++ 回答。我应该删除winapi 标签吗?如果它欢迎完成工作的答案而不用担心确切的 api,恕我直言,这个问题会更有用。 (我的假设可能是错误的,只是标记“C++”可以理解为意味着答案仅限于 ISO C++,这不是我想要的。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多