使用Windows API和C++获取进程完整性令牌的异常问题
问题分析与修正
核心问题是你没有为TOKEN_MANDATORY_LABEL结构分配有效内存,直接将GetTokenInformation的输出写入了指针变量本身的内存空间,导致后续读取的SID结构完全损坏,进而引发GetSidSubAuthorityCount返回异常指针。
具体错误点拆解
步骤4中,你使用&dwIntegrity作为GetTokenInformation的输出参数,但dwIntegrity是TOKEN_MANDATORY_LABEL*类型——这意味着你把完整的令牌数据写到了指针变量的内存里(通常仅8字节/4字节),而不是指针指向的、足够容纳TOKEN_MANDATORY_LABEL+SID数据的内存区域。这种情况下,dwIntegrity->Label.Sid指向的是无效内存,调用GetSidSubAuthorityCount自然会读取到错误数据。
修正后的完整流程
#include <windows.h> #include <iostream> int main() { DWORD dwPID = 6084; // 1. 获取进程句柄,必须检查返回值 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); if (!hProc) { std::cout << "[+] Error: OpenProcess " << GetLastError() << std::endl; return 1; } // 2. 获取令牌句柄,TOKEN_QUERY权限足够 HANDLE hTok; if (!OpenProcessToken(hProc, TOKEN_QUERY, &hTok)) { std::cout << "[+] Error: OpenProcessToken " << GetLastError() << std::endl; CloseHandle(hProc); return 1; } // 3. 获取所需内存大小 DWORD dwRetLen = 0; if (!GetTokenInformation(hTok, TokenIntegrityLevel, NULL, 0, &dwRetLen)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { std::cout << "[+] Error: GetTokenInformation (get size) " << GetLastError() << std::endl; CloseHandle(hTok); CloseHandle(hProc); return 1; } } // 4. 分配足够内存存储TOKEN_MANDATORY_LABEL结构 TOKEN_MANDATORY_LABEL* pIntegrityLabel = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(LocalAlloc(LPTR, dwRetLen)); if (!pIntegrityLabel) { std::cout << "[+] Error: LocalAlloc failed" << std::endl; CloseHandle(hTok); CloseHandle(hProc); return 1; } // 5. 获取实际的完整性令牌数据 if (!GetTokenInformation(hTok, TokenIntegrityLevel, pIntegrityLabel, dwRetLen, &dwRetLen)) { std::cout << "[+] Error: GetTokenInformation " << GetLastError() << std::endl; LocalFree(pIntegrityLabel); CloseHandle(hTok); CloseHandle(hProc); return 1; } // 6. 正确读取完整性级别 DWORD subAuthCount = *GetSidSubAuthorityCount(pIntegrityLabel->Label.Sid); DWORD integrityLevel = *GetSidSubAuthority(pIntegrityLabel->Label.Sid, subAuthCount - 1); std::cout << "[+] Integrity Level: 0x" << std::hex << integrityLevel << std::endl; // 7. 清理资源 LocalFree(pIntegrityLabel); CloseHandle(hTok); CloseHandle(hProc); return 0; }
额外注意事项
- 必须检查所有API的返回值,尤其是内存分配和句柄获取操作,避免后续无效操作。
- 用完句柄和内存后要及时释放,防止资源泄漏。
TOKEN_QUERY权限足以获取完整性令牌,不需要额外的TOKEN_QUERY_SOURCE。
内容的提问来源于stack exchange,提问作者Teodor Cristian
相关产品推荐
相关产品推荐

