C语言中WinAPI特权启用函数的for循环卡在第二次迭代的原因及解决
问题原因与修复方案
问题根源
你的代码出现无限循环的核心原因是**TOKEN_PRIVILEGES结构体默认内存不足以容纳多个特权项**。根据WinAPI定义,TOKEN_PRIVILEGES的Privileges成员是一个大小为ANYSIZE_ARRAY(即1)的数组。当你传入dwCount > 1时,循环中访问tp.Privileges[i](i≥1)会触发栈内存越界,破坏栈上的其他变量(比如循环计数器i),导致i被意外重置为初始值,进而引发无限循环。
修复方案
有两种可靠的修复方式,核心思路都是确保TOKEN_PRIVILEGES结构体有足够内存存储所有特权项:
方法一:动态分配内存(通用兼容方案)
根据特权数量计算所需内存,动态分配结构体空间,确保Privileges数组能容纳所有项:
void EnablePrivileges(LPCWSTR awszPrivileges[], DWORD dwCount){ HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { printf("Failed to open process token. Error: %lu\n", GetLastError()); return; } // 计算总内存:结构体头部 + 额外的特权项内存 DWORD totalSize = sizeof(TOKEN_PRIVILEGES) + (dwCount - 1) * sizeof(LUID_AND_ATTRIBUTES); PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)malloc(totalSize); if (!tp) { printf("Failed to allocate memory. Error: %lu\n", GetLastError()); CloseHandle(hToken); return; } tp->PrivilegeCount = dwCount; for (DWORD i = 0; i < dwCount; ++i) { wprintf(TEXT("Privilege constant: %ls | Iterator value: %lu\n"), awszPrivileges[i], i); if(!LookupPrivilegeValueW(NULL, awszPrivileges[i], &tp->Privileges[i].Luid)) { printf("Failed to lookup privilege value. Error: %lu\n", GetLastError()); free(tp); CloseHandle(hToken); return; } tp->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; } if (!AdjustTokenPrivileges(hToken, FALSE, tp, totalSize, NULL, NULL)) { printf("Failed to adjust token privileges. Error: %lu\n", GetLastError()); } else { printf("Token privileges adjusted successfully.\n"); } free(tp); CloseHandle(hToken); }
方法二:使用自定义变长结构体(灵活实现)
通过自定义结构体,明确指定Privileges数组的长度,再动态分配内存:
void EnablePrivileges(LPCWSTR awszPrivileges[], DWORD dwCount){ HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { printf("Failed to open process token. Error: %lu\n", GetLastError()); return; } // 定义支持变长特权数组的结构体 typedef struct { DWORD PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[]; } DynamicTokenPrivileges; // 分配对应大小的内存 DynamicTokenPrivileges* tp = (DynamicTokenPrivileges*)malloc(sizeof(DWORD) + dwCount * sizeof(LUID_AND_ATTRIBUTES)); if (!tp) { printf("Failed to allocate memory. Error: %lu\n", GetLastError()); CloseHandle(hToken); return; } tp->PrivilegeCount = dwCount; for (DWORD i = 0; i < dwCount; ++i) { wprintf(TEXT("Privilege constant: %ls | Iterator value: %lu\n"), awszPrivileges[i], i); if(!LookupPrivilegeValueW(NULL, awszPrivileges[i], &tp->Privileges[i].Luid)) { printf("Failed to lookup privilege value. Error: %lu\n", GetLastError()); free(tp); CloseHandle(hToken); return; } tp->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; } if (!AdjustTokenPrivileges(hToken, FALSE, (PTOKEN_PRIVILEGES)tp, sizeof(DWORD) + dwCount * sizeof(LUID_AND_ATTRIBUTES), NULL, NULL)) { printf("Failed to adjust token privileges. Error: %lu\n", GetLastError()); } else { printf("Token privileges adjusted successfully.\n"); } free(tp); CloseHandle(hToken); }
额外注意事项
- 打印
DWORD类型的循环计数器i时,要用%lu格式符,避免格式不匹配导致的输出错误。 - 动态分配的内存必须在函数结束前释放,防止内存泄漏。
- 调用
AdjustTokenPrivileges时,第四个参数要传入结构体的实际总大小,而非固定的sizeof(TOKEN_PRIVILEGES),确保API能正确处理所有特权项。
内容的提问来源于stack exchange,提问作者Hantalyte
相关产品推荐
相关产品推荐

