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

非管理员权限下GetTokenInformation返回ERROR_NOACCESS问题排查

问题分析与修复

核心错误点

  1. 未分配内存给TOKEN_USER结构体
    你声明了PTOKEN_USER user = NULL;但从未为其分配内存,第二次调用GetTokenInformation时传入NULL指针,导致写入操作触发内存访问错误(ERROR_NOACCESS)。第一次调用GetTokenInformation仅用于获取所需缓冲区大小,必须根据返回的returnLength分配内存后再执行第二次调用。

  2. 进程句柄有效性判断逻辑错误
    代码中if (OGHandle != NULL || OGHandle != INVALID_HANDLE_VALUE)的逻辑永远为真(一个句柄不可能同时等于NULL和INVALID_HANDLE_VALUE),应改为&&:if (OGHandle != NULL && OGHandle != INVALID_HANDLE_VALUE),否则会对无效句柄执行后续操作。

  3. 进程打开权限不匹配
    使用PROCESS_QUERY_LIMITED_INFORMATION打开进程时,该权限仅能获取受限进程信息,无法满足打开进程令牌的需求。应使用PROCESS_QUERY_INFORMATION权限(非管理员对同权限进程可正常获取)。

修复后的代码

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <malloc.h>

int main() {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        printf("Could not open handle via CreateToolhelp32Snapshot()\n");
        return 1;
    }

    PROCESSENTRY32 pe = { sizeof(pe) };
    if (!Process32First(hSnapshot, &pe)) {
        printf("Process32First failed\n");
        CloseHandle(hSnapshot);
        return 1;
    }

    do {
        // 使用PROCESS_QUERY_INFORMATION确保能打开进程令牌
        HANDLE OGHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe.th32ProcessID);
        HANDLE tokenHandle = NULL;
        DWORD returnLength = 0;
        PTOKEN_USER user = NULL;

        if (OGHandle != NULL && OGHandle != INVALID_HANDLE_VALUE) {
            // 打开令牌只需TOKEN_QUERY权限
            if (OpenProcessToken(OGHandle, TOKEN_QUERY, &tokenHandle)) {
                // 第一次调用获取缓冲区大小
                if (!GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &returnLength)) {
                    if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
                        // 分配对应大小的内存
                        user = (PTOKEN_USER)LocalAlloc(LPTR, returnLength);
                        if (user != NULL) {
                            // 第二次调用获取令牌信息
                            if (GetTokenInformation(tokenHandle, TokenUser, user, returnLength, &returnLength)) {
                                // 可选:将SID转换为字符串打印
                                WCHAR sidStr[256];
                                if (ConvertSidToStringSidW(user->User.Sid, &sidStr)) {
                                    printf("Process ID: %d, SID: %ws\n", pe.th32ProcessID, sidStr);
                                    LocalFree(sidStr);
                                }
                            } else {
                                printf("GetTokenInfo() failed with error code %d\n", GetLastError());
                            }
                            LocalFree(user);
                        } else {
                            printf("Failed to allocate memory for TOKEN_USER\n");
                        }
                    } else {
                        printf("First GetTokenInfo() failed with error code %d\n", GetLastError());
                    }
                }
            } else {
                printf("OpenProcessToken failed with error code %d\n", GetLastError());
            }
        }

        printf("Process ID: %d  , PPID: %d  , Path: %ws \n", pe.th32ProcessID, pe.th32ParentProcessID, pe.szExeFile );
        if (OGHandle != NULL) CloseHandle(OGHandle);
        if (tokenHandle != NULL) CloseHandle(tokenHandle);
    } while (Process32Next(hSnapshot, &pe));

    CloseHandle(hSnapshot);
    return 0;
}

额外说明

  • 内存分配使用LocalAlloc+LocalFree是Windows API标准做法,也可使用malloc但需确保内存对齐。
  • 非管理员权限下,仅能获取与当前进程权限层级相同或更低的进程SID,系统核心进程(如system、csrss等)无法访问,属于正常权限限制。
  • OpenProcessToken只需TOKEN_QUERY权限,无需额外添加TOKEN_QUERY_SOURCE,除非需要查询令牌来源信息。

内容的提问来源于stack exchange,提问作者user2494337

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 12:35:02