You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:34:57