解决TOKEN_PRIVILEGES的Privileges数组越界及内存分配问题
解决AdjustTokenPrivileges多权限调整时的数组越界警告
问题根源在于TOKEN_PRIVILEGES结构体的Privileges成员是变长数组(声明为LUID_AND_ATTRIBUTES Privileges[1];),编译器静态检查时会默认认为该数组仅包含1个元素,因此访问Privileges[1]会触发越界警告。你尝试的union写法虽然实际分配了足够内存,但编译器的静态分析未识别到union的存储大小,依然按结构体本身的定义进行检查。
下面提供三种可行的解决方法:
方法1:直接声明包含足够权限的扩展结构体
手动定义一个包含目标权限数量的结构体,绕过编译器对原结构体的静态检查:
#include <Windows.h> int main() { HANDLE hToken = NULL; // 声明带2个权限的扩展TOKEN_PRIVILEGES结构 struct { DWORD PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[2]; } tp = {0}; LUID luid1, luid2; HANDLE hProcess = GetCurrentProcess(); // 补充缺失的进程句柄定义 if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) goto cleanup; LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &luid1); LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &luid2); tp.PrivilegeCount = 2; tp.Privileges[0].Luid = luid1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tp.Privileges[1].Luid = luid2; tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; // 传入结构体实际大小,而非sizeof(TOKEN_PRIVILEGES) AdjustTokenPrivileges(hToken, FALSE, (PTOKEN_PRIVILEGES)&tp, sizeof(tp), NULL, NULL); cleanup: if (hToken) CloseHandle(hToken); return 0; }
方法2:动态分配内存(适合权限数量不确定的场景)
通过计算所需内存大小动态分配,灵活适配任意数量的权限:
#include <Windows.h> #include <malloc.h> int main() { HANDLE hToken = NULL; PTOKEN_PRIVILEGES tp = NULL; LUID luid1, luid2; HANDLE hProcess = GetCurrentProcess(); const int privilegeCount = 2; // 计算总内存:结构体头部 + 权限数组占用空间 DWORD totalSize = offsetof(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * privilegeCount; tp = (PTOKEN_PRIVILEGES)malloc(totalSize); if (!tp) goto cleanup; if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) goto cleanup; LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &luid1); LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &luid2); tp->PrivilegeCount = privilegeCount; tp->Privileges[0].Luid = luid1; tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tp->Privileges[1].Luid = luid2; tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE, tp, totalSize, NULL, NULL); cleanup: if (tp) free(tp); if (hToken) CloseHandle(hToken); return 0; }
方法3:修正union的使用方式
通过类型转换让编译器识别实际的数组长度,同时注意传入正确的内存大小:
#include <Windows.h> int main() { HANDLE hToken = NULL; LUID luid1, luid2; HANDLE hProcess = GetCurrentProcess(); union { TOKEN_PRIVILEGES tp; unsigned char storage[offsetof(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 2]; } u = {0}; if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) goto cleanup; LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &luid1); LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &luid2); u.tp.PrivilegeCount = 2; // 强制类型转换告知编译器数组长度足够 ((LUID_AND_ATTRIBUTES*)u.tp.Privileges)[0].Luid = luid1; ((LUID_AND_ATTRIBUTES*)u.tp.Privileges)[0].Attributes = SE_PRIVILEGE_ENABLED; ((LUID_AND_ATTRIBUTES*)u.tp.Privileges)[1].Luid = luid2; ((LUID_AND_ATTRIBUTES*)u.tp.Privileges)[1].Attributes = SE_PRIVILEGE_ENABLED; // 传入union的实际大小,而非原结构体大小 AdjustTokenPrivileges(hToken, FALSE, &u.tp, sizeof(u), NULL, NULL); cleanup: if (hToken) CloseHandle(hToken); return 0; }
关键注意点
- 调用
AdjustTokenPrivileges时,第四个参数BufferLength必须传入结构体的实际总大小,不能用sizeof(TOKEN_PRIVILEGES),否则系统无法正确识别所有权限。 - 补充了
hProcess的初始化(使用GetCurrentProcess()),避免原代码中未初始化句柄导致的错误。 - 所有方法都添加了资源清理逻辑,防止句柄或内存泄漏。
内容的提问来源于stack exchange,提问作者user19739379
相关产品推荐
相关产品推荐

