如何用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
相关产品推荐
相关产品推荐

