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

解决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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:21:37