Win2K 部分註冊表鍵(如 HKLM\SYSTEM\ControlSet001\Enum\Root)默認拒絕寫入,提權也難繞過。需編程修改 DACL(自主訪問控制列表)賦予權限,操作完成後恢復原狀。
GetNamedSecurityInfo 獲取目標鍵現有安全描述符與 Old DACL。BuildExplicitAccessWithName 構建 EXPLICIT_ACCESS 結構,指定 Everyone 擁有 GENERIC_ALL 並可繼承 (SUB_CONTAINERS_AND_OBJECTS_INHERIT)。SetEntriesInAcl 合併新舊 ACE 生成 New DACL。SetNamedSecurityInfo 寫入新 DACL,獲得完全控制權。LocalFree 釋放所有分配的安全描述符與 ACL 緩衝區。
LPTSTR lpObjectName = "MACHINE\\SYSTEM\\ControlSet001\\Enum\\Root";
SE_OBJECT_TYPE ObjectType = SE_REGISTRY_KEY;
PACL OldDACL = NULL, NewDACL = NULL;
PSECURITY_DESCRIPTOR SD = NULL;
EXPLICIT_ACCESS ea;
// 初始化空 ACL
SetEntriesInAcl(0, NULL, NULL, &OldDACL);
SetEntriesInAcl(0, NULL, NULL, &NewDACL);
// 獲取現有 DACL
if (GetNamedSecurityInfo(lpObjectName, ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, &OldDACL, NULL, &SD) != ERROR_SUCCESS) return;
// 構建完全控制 ACE
ZeroMemory(&ea, sizeof(ea));
BuildExplicitAccessWithName(&ea, "Everyone", GENERIC_ALL, SET_ACCESS,
SUB_CONTAINERS_AND_OBJECTS_INHERIT);
// 合併生成新 DACL
if (SetEntriesInAcl(1, &ea, OldDACL, &NewDACL) == ERROR_SUCCESS) {
SetNamedSecurityInfo(lpObjectName, ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, NewDACL, NULL);
}
// ... 此處執行註冊表操作 ...
// 恢復原權限:構建只讀 ACE 覆蓋回 OldDACL
BuildExplicitAccessWithName(&ea, "Everyone", GENERIC_READ, SET_ACCESS, NO_INHERITANCE);
SetEntriesInAcl(1, &ea, NULL, &OldDACL);
SetNamedSecurityInfo(lpObjectName, ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, OldDACL, NULL);
// 清理資源
if (SD) LocalFree((HLOCAL)SD);
if (NewDACL) LocalFree((HLOCAL)NewDACL);
if (OldDACL) LocalFree((HLOCAL)OldDACL);
<aclapi.h> 並鏈接 Advapi32.lib。finally 或 goto Cleanup 確保權限回滾與資源釋放,避免留下安全隱患。