Windows注册表BAM键权限异常:含写入权限时无法匹配输出及删除值问题
问题分析与解决方案
核心问题
你遇到的情况本质是BAM注册表键的系统权限限制,以及代码中缺失错误排查逻辑:
SYSTEM\CurrentControlSet\Services\bam\State\UserSettings属于Windows核心服务的受保护键,默认即便是管理员权限,直接用KEY_WRITE/KEY_ALL_ACCESS打开也会失败,但你的代码没有输出打开键失败的错误信息,导致误以为是枚举匹配的问题,实际上是键根本没打开成功,后续逻辑完全没执行。- 另外,你用
RegSetValueExW设置空数据的方式并不是真正删除注册表值,正确操作应该用RegDeleteValueW。
解决步骤
1. 先添加错误排查逻辑
在所有RegOpenKeyExW失败的分支里,输出具体错误码,确认问题根源:
// 外层键打开失败时 else { DWORD err = GetLastError(); std::cerr << "Failed to open root key. Error code: " << err << std::endl; return false; } // 内层子键打开失败时 else { DWORD err = GetLastError(); std::wcerr << L"Failed to open subkey: " << subkeyName << L". Error code: " << err << std::endl; }
常见错误码比如5(拒绝访问),就说明权限不足。
2. 针对受保护注册表键的权限获取流程
要修改BAM这类键,必须先获取键的所有权,再调整ACL权限,最后才能打开写入权限:
- 使用
RegOpenKeyExW以KEY_READ | WRITE_OWNER权限打开键 - 获取当前的安全描述符,修改所有者为当前进程的管理员组
- 设置新的安全描述符给键,添加写入权限
- 重新以
KEY_READ | KEY_WRITE权限打开键
3. 修正后的完整代码示例
#include <windows.h> #include <iostream> #include <vector> #include <aclapi.h> #include <sddl.h> #pragma comment(lib, "advapi32.lib") bool containsKeywords(const std::wstring& valueName, const std::vector<std::wstring>& keywords) { for (const auto& kw : keywords) { if (valueName.find(kw) != std::wstring::npos) { return true; } } return false; } bool adjustRegistryKeyPermissions(HKEY hKey) { DWORD err; PSECURITY_DESCRIPTOR pSD = nullptr; PACL pOldDacl = nullptr; PACL pNewDacl = nullptr; EXPLICIT_ACCESS ea; // 获取当前安全描述符 err = GetSecurityInfo(hKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, nullptr, nullptr, &pOldDacl, nullptr, &pSD); if (err != ERROR_SUCCESS) { std::cerr << "GetSecurityInfo failed. Error: " << err << std::endl; return false; } // 设置当前用户的写入权限 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = KEY_WRITE | KEY_READ; ea.grfAccessMode = SET_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = TRUSTEE_IS_USER; ea.Trustee.ptstrName = (LPTSTR)L"CURRENT_USER"; // 创建新的DACL err = SetEntriesInAcl(1, &ea, pOldDacl, &pNewDacl); if (err != ERROR_SUCCESS) { std::cerr << "SetEntriesInAcl failed. Error: " << err << std::endl; LocalFree(pSD); return false; } // 设置新的安全描述符到键 err = SetSecurityInfo(hKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, nullptr, nullptr, pNewDacl, nullptr); if (err != ERROR_SUCCESS) { std::cerr << "SetSecurityInfo failed. Error: " << err << std::endl; LocalFree(pNewDacl); LocalFree(pSD); return false; } LocalFree(pNewDacl); LocalFree(pSD); return true; } bool modifyBamRegistry() { HKEY hKey; LPCWSTR subkeyPath = L"SYSTEM\\CurrentControlSet\\Services\\bam\\State\\UserSettings"; // 先以可修改所有者的权限打开键 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, subkeyPath, 0, KEY_READ | WRITE_OWNER, &hKey) != ERROR_SUCCESS) { DWORD err = GetLastError(); std::cerr << "Failed to open root key. Error code: " << err << std::endl; return false; } // 调整键的权限 if (!adjustRegistryKeyPermissions(hKey)) { RegCloseKey(hKey); return false; } // 关闭后重新以读写权限打开 RegCloseKey(hKey); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, subkeyPath, 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS) { DWORD err = GetLastError(); std::cerr << "Failed to reopen root key with write access. Error code: " << err << std::endl; return false; } DWORD index = 0; WCHAR subkeyName[MAX_PATH]; DWORD subkeyNameSize = MAX_PATH; std::vector<std::wstring> keywords = { L"test1", L"test2", L"test3" }; while (RegEnumKeyExW(hKey, index, subkeyName, &subkeyNameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { HKEY subkey; // 内层子键同样需要先调整权限,或者直接用读写权限打开(如果父键权限已调整) if (RegOpenKeyExW(hKey, subkeyName, 0, KEY_READ | KEY_WRITE, &subkey) == ERROR_SUCCESS) { DWORD valueIndex = 0; WCHAR valueName[MAX_PATH]; DWORD valueNameSize = MAX_PATH; while (RegEnumValueW(subkey, valueIndex, valueName, &valueNameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { DWORD valueType; DWORD dataSize; if (RegQueryValueExW(subkey, valueName, NULL, &valueType, NULL, &dataSize) == ERROR_SUCCESS && valueType == REG_BINARY && containsKeywords(valueName, keywords)) { std::wcout << L"Subkey: " << subkeyName << L", Value Name: " << valueName << L", Value Type: REG_BINARY" << std::endl; // 真正删除注册表值 if (RegDeleteValueW(subkey, valueName) == ERROR_SUCCESS) { std::wcout << L"Deleted value: " << valueName << L" from subkey: " << subkeyName << L" from subkey: " << subkeyName << L". Error code: " << err << std::endl; } } valueIndex++; valueNameSize = MAX_PATH; } RegCloseKey(subkey); } else { DWORD err = GetLastError(); std::wcerr << L"Failed to open subkey: " << subkeyName << L". Error code: " << err << std::endl; } index++; subkeyNameSize = MAX_PATH; } RegCloseKey(hKey); return true; } int main() { // 必须以管理员权限运行程序 modifyBamRegistry(); return 0; }
关键注意事项
- 程序必须以管理员权限运行,否则所有权限调整操作都会失败。
- 调整注册表权限是敏感操作,测试时务必谨慎,避免破坏系统键。
- BAM键记录的是进程活动信息,修改可能影响系统的某些行为,操作前请备份相关注册表分支。
内容的提问来源于stack exchange,提问作者VIGGO420
相关产品推荐
相关产品推荐

