You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++删除需管理员权限的Windows Defender历史目录?

解决方案

错误码0x5对应ERROR_ACCESS_DENIED,即使以管理员身份运行,也可能因为文件被Windows Defender进程锁定、权限继承限制或系统对象保护导致删除失败。以下是不依赖system()/ShellExecute()的纯C++/Windows API实现方案:

1. 启用管理员特权并修改对象权限

Windows Defender的目录/文件带有严格的ACL权限,需要先获取所有权并授予当前用户完全控制权限,再执行删除:

步骤说明

  • 启用进程的SE_TAKE_OWNERSHIP_NAME、SE_RESTORE_NAME和SE_BACKUP_NAME特权,这是修改系统对象权限的前提。
  • 递归遍历目标目录,为每个文件/目录设置当前用户为所有者,并添加完全控制权限。
  • 使用Windows API递归删除文件和目录,替代std::filesystem(避免其未处理权限的问题)。

代码示例

#include <windows.h>
#include <aclapi.h>
#include <vector>
#include <string>

#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "user32.lib")

// 启用指定特权
bool EnablePrivilege(LPCWSTR privilegeName) {
    HANDLE hToken;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return false;
    }

    TOKEN_PRIVILEGES tp{};
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!LookupPrivilegeValueW(nullptr, privilegeName, &tp.Privileges[0].Luid)) {
        CloseHandle(hToken);
        return false;
    }

    bool result = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, nullptr) != FALSE;
    CloseHandle(hToken);
    return result;
}

// 设置文件/目录的所有者为当前用户,并添加完全控制权限
bool SetFullControlPermission(LPCWSTR path) {
    DWORD dwError;
    PSID pCurrentUserSid = nullptr;
    SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;

    // 获取当前管理员组SID
    if (!AllocateAndInitializeSid(&ntAuthority, 1, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pCurrentUserSid)) {
        return false;
    }

    // 设置所有者
    dwError = SetNamedSecurityInfoW((LPWSTR)path, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, pCurrentUserSid, nullptr, nullptr, nullptr);
    if (dwError != ERROR_SUCCESS) {
        FreeSid(pCurrentUserSid);
        return false;
    }

    // 添加完全控制权限
    EXPLICIT_ACCESSW ea{};
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESSW));
    ea.grfAccessPermissions = GENERIC_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    ea.Trustee.ptstrName = (LPWSTR)pCurrentUserSid;

    PACL pNewAcl = nullptr;
    dwError = SetEntriesInAclW(1, &ea, nullptr, &pNewAcl);
    if (dwError != ERROR_SUCCESS) {
        FreeSid(pCurrentUserSid);
        return false;
    }

    dwError = SetNamedSecurityInfoW((LPWSTR)path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, pNewAcl, nullptr);
    LocalFree(pNewAcl);
    FreeSid(pCurrentUserSid);
    return dwError == ERROR_SUCCESS;
}

// 递归删除目录
bool DeleteDirectoryRecursive(LPCWSTR dirPath) {
    WIN32_FIND_DATAW findData{};
    HANDLE hFind = FindFirstFileW((std::wstring(dirPath) + L"\\*").c_str(), &findData);
    if (hFind == INVALID_HANDLE_VALUE) {
        return false;
    }

    bool success = true;
    do {
        const std::wstring fileName = findData.cFileName;
        if (fileName == L"." || fileName == L"..") continue;

        const std::wstring fullPath = std::wstring(dirPath) + L"\\" + fileName;
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // 递归删除子目录
            if (!DeleteDirectoryRecursive(fullPath.c_str())) {
                success = false;
            }
        } else {
            // 删除文件,若被锁定则标记为重启后删除
            if (!DeleteFileW(fullPath.c_str())) {
                if (GetLastError() == ERROR_ACCESS_DENIED) {
                    if (!MoveFileExW(fullPath.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
                        success = false;
                    }
                } else {
                    success = false;
                }
            }
        }
    } while (FindNextFileW(hFind, &findData) && success);

    FindClose(hFind);

    // 删除当前目录
    if (success) {
        success = RemoveDirectoryW(dirPath);
        // 若目录仍无法删除,标记为重启后删除
        if (!success && GetLastError() == ERROR_ACCESS_DENIED) {
            success = MoveFileExW(dirPath, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT);
        }
    }

    return success;
}

int main() {
    // 启用必要特权
    if (!EnablePrivilege(SE_TAKE_OWNERSHIP_NAME) || 
        !EnablePrivilege(SE_RESTORE_NAME) || 
        !EnablePrivilege(SE_BACKUP_NAME)) {
        MessageBoxW(nullptr, L"无法启用管理员特权", L"错误", MB_ICONERROR);
        return 1;
    }

    const std::vector<std::wstring> targetPaths = {
        L"C:\\ProgramData\\Microsoft\\Windows Defender\\Scans\\History",
        L"C:\\ProgramData\\Microsoft\\Windows Defender\\Scans\\BackupStore"
    };

    for (const auto& path : targetPaths) {
        // 设置权限
        if (!SetFullControlPermission(path.c_str())) {
            MessageBoxW(nullptr, (L"无法设置权限: " + path).c_str(), L"警告", MB_ICONWARNING);
        }
        // 递归删除
        if (DeleteDirectoryRecursive(path.c_str())) {
            MessageBoxW(nullptr, (L"成功删除: " + path).c_str(), L"提示", MB_ICONINFORMATION);
        } else {
            MessageBoxW(nullptr, (L"删除失败,将在重启后删除: " + path).c_str(), L"提示", MB_ICONINFORMATION);
        }
    }

    return 0;
}

2. 使用Restart Manager关闭占用进程

如果文件被Windows Defender的服务(如WinDefend)锁定,可以用Restart Manager API停止相关进程,删除后再恢复:

核心步骤

  • 调用RmStartSession创建重启会话。
  • 调用RmRegisterResources注册目标目录。
  • 调用RmGetList获取占用资源的进程列表。
  • 调用RmShutdown关闭这些进程,执行删除后再用RmRestart恢复。

注意事项

  • 该方法需要管理员权限,且可能影响Windows Defender的实时保护功能,操作后建议重启Defender服务。

关键说明

  • std::filesystem::remove_all失败的原因通常是未处理权限或文件锁定,上述方案直接操作Windows API,能更精细地处理这些场景。
  • 若最终仍无法删除,MOVEFILE_DELAY_UNTIL_REBOOT会将目录标记为系统重启后删除,这是处理顽固系统文件的最后手段。

内容的提问来源于stack exchange,提问作者mcs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 10:25:20