C++ 删除每个API调用都失败的文件夹,错误为\u访问\u拒绝

C++ 删除每个API调用都失败的文件夹,错误为\u访问\u拒绝,c++,winapi,windows-10,delete-file,access-denied,C++,Winapi,Windows 10,Delete File,Access Denied,我已创建了一个无法访问的文件夹。我使用了nullptr作为安全描述符,但出于某种原因,它没有复制父文件夹的ACL,而是使文件夹无法访问 我无法查看或更改所有者,所有来自提升进程或命令提示的操作都会失败,并出现错误\u访问被拒绝 在尝试希望不关心ACL的Linux live CD之前,我是否有机会在Windows(Shell或C++)中删除此文件夹?假设该文件未打开,并且没有不兼容的删除共享标志,也没有文件节 为了删除文件,我们在父文件夹中设置了文件\u删除子文件夹。并且文件不是只读的。在这种情况

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

我无法查看或更改所有者,所有来自提升进程或命令提示的操作都会失败,并出现
错误\u访问被拒绝


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

假设该文件未打开,并且没有不兼容的删除共享标志,也没有文件节

为了删除文件,我们在父文件夹中设置了
文件\u删除子文件夹
。并且文件不是只读的。在这种情况下,调用(但不是或-如果文件具有空DACL,则这两个api都将失败)就足够了。如果文件具有只读属性-失败,代码
状态\u无法\u删除
。在这种情况下,我们需要首先删除只读。为此,需要使用
file\u WRITE\u属性
access打开文件。如果我们有
SE_RESTORE_PRIVILEGE
并在调用中设置
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;
}
NTSTATUS DeleteEx(POBJECT\u属性poa)
{
NTSTATUS状态=ZwDeleteFile(poa);
如果(状态==状态\u无法\u删除)
{
布尔b;
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,TRUE、FALSE和b);
处理文件;
IO_状态_块iosb;

如果(0您只需要启用备份(或还原)权限:

#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;
}
#包括
#包括
内部wmain(内部argc,wchar\u t**argv)
{
//argv[1]必须包含要删除的目录
拉赫托肯;
结构
{    
德沃德特权伯爵;
LUID_和_属性特权[1];
}tkp;
如果(OpenProcessToken)(GetCurrentProcess(),
令牌(调整(特权|令牌(查询和删除))
{
LookupPrivilegeValue(NULL,SE_BACKUP_NAME,&tkp.Privileges[0].Luid);
tkp.privilegecont=1;
tkp.Privileges[0]。属性=SE_PRIVILEGE_ENABLED;
如果(!AdjustTokenPrivileges)(hToken,FALSE,
(PTOKEN_特权)和tkp,0,(PTOKEN_特权)NULL,0)
{
printf(“AdjustTokenPrivileges:%u\n”,GetLastError());
返回1;
}
如果(GetLastError()!=错误\u成功)
{
//如果你没有特权,就会发生这种情况
printf(“AdjustTokenPrivileges:%u\n”,GetLastError());
返回1;
}
闭合手柄(hToken);
}
如果(!RemoveDirectory(argv[1]))
{
printf(“RemoveDirectory:%u\n”,GetLastError());
返回1;
}
printf(“OK\n”);
返回0;
}
注意,为了简洁起见,省略了一些错误处理即使调用成功,也有意义;它将返回
ERROR\u SUCCESS
ERROR\u NOT\u ALL\u ASSIGNED
,具体取决于您是否实际拥有尝试启用的所有特权


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

将在您的情况下使用,并查看您是否可以删除它om在那里。问题已标记。您的任何调用都不是Windows API的一部分。虽然这可能会解决问题,但它没有解决所问的问题。@IInspectable-我使用的也是winapi-从某些用户模式dll(具体情况下为ntdll.dll)导出函数。其他用户模式DLL之间没有区别。所有这些api都有很好的文档记录。如果文件最初没有只读属性-只需调用
ZwDeleteFile
do task。或者您有更好的解决方案?发布的Windows api文档是契约性的。发布的本机api文档仅供参考。请参阅以获取参考。当您必须为您的软件提供支持时,这会产生很大的不同。专业软件开发人员通常必须为他们的软件提供支持。@IInspectable-发布的本机API文档仅供参考。-这是为什么?在具体文档中的何处-例如-声明了?这是众所周知的API。所有文档d至少20年。并且在用户和内核模式下都受支持。这也是有文档记录的。在什么问题上?ZwDeleteFile
是最好的解决方案。而且这个api没有内核32外壳。所以这里没有choice@IInspectable通过这个逻辑,我的标记也会阻止某人在普通的ISC++中回答。我应该删除<代码> WiAPI吗?如果问题是欢迎答案,而不必担心确切的API,IMHO。这个问题更有用。(我的,可能是错误的假设是,仅仅标记“C++”可以理解为答案被限制为ISO C++,这不是我想要的。)而且还是一次调用
ZwDeleteFile
执行相同的任务,因为
DELETE
FILE\u READ\u ATTRIBUTES
这是对文件的特殊访问。如果我们在父级上有
FILE\u DELETE\u CHILD
FILE\u LIST\u DIRECTORY
在父级上,对于
FILE\u READ\u ATTRIBUTES
在子级上,文件系统授予
DELETE
)。并且,如果文件夹具有只读属性,则仍需要首先更改文件属性。