標準 `whoami.exe` 僅顯示當前進程令牌信息。本工具 `TokenInfor` 支持指定 PID 查看**任意進程**的訪問令牌完整信息:用戶 SID、群組成員、特權列表、令牌類型、模擬級別、令牌源。適用於權限審計、提權分析、服務帳號排查。
// 令牌用戶
typedef struct _TOKEN_USER { SID_AND_ATTRIBUTES User; } TOKEN_USER;
// 群組
typedef struct _TOKEN_GROUPS { DWORD GroupCount; SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; } TOKEN_GROUPS;
// 特權
typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; } TOKEN_PRIVILEGES;
// 統計信息 (類型/模擬級別/ID)
typedef struct _TOKEN_STATISTICS {
LUID TokenId; LUID AuthenticationId; LARGE_INTEGER ExpirationTime;
TOKEN_TYPE TokenType; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
DWORD DynamicCharged, DynamicAvailable, GroupCount, PrivilegeCount;
LUID ModifiedId;
} TOKEN_STATISTICS;
// 令牌源
typedef struct _TOKEN_SOURCE { CHAR SourceName[8]; LUID SourceIdentifier; } TOKEN_SOURCE;
int main(int argc, char* argv[]) {
DWORD dwPid = (argc > 1) ? atoi(argv[1]) : GetCurrentProcessId();
// 啟用 SeDebugPrivilege 以訪問系統進程 (如 csrss.exe)
EnableDebugPriv(TRUE);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid);
if (!hProcess) { PrintError("OpenProcess"); return 1; }
// 獲取進程映像路徑 (需 Psapi.dll)
HMODULE hPsapi = LoadLibrary("psapi.dll");
if (hPsapi) {
auto pGetModName = (GetModuleFileNameExType*)GetProcAddress(hPsapi, "GetModuleFileNameExA");
if (pGetModName) { char path[MAX_PATH]; pGetModName(hProcess, NULL, path, MAX_PATH); printf("Path: %s\n", path); }
FreeLibrary(hPsapi);
}
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
PrintUserName(hToken);
PrintGroups(hToken);
PrintPrivileges(hToken);
PrintTokenType(hToken);
PrintTokenSource(hProcess); // 需 TOKEN_QUERY_SOURCE
CloseHandle(hToken);
}
CloseHandle(hProcess);
EnableDebugPriv(FALSE);
return 0;
}
void PrintUserName(HANDLE hToken) {
BYTE buf[1024]; DWORD len;
if (GetTokenInformation(hToken, TokenUser, buf, sizeof(buf), &len)) {
TOKEN_USER* ptu = (TOKEN_USER*)buf;
char name[256], domain[256]; DWORD n=256, d=256; SID_NAME_USE snu;
if (LookupAccountSid(NULL, ptu->User.Sid, name, &n, domain, &d, &snu))
printf("User: %s\\%s (SID: %s)\n", domain, name, SidToString(ptu->User.Sid));
}
}
void PrintGroups(HANDLE hToken) {
BYTE buf[4096]; DWORD len;
if (GetTokenInformation(hToken, TokenGroups, buf, sizeof(buf), &len)) {
TOKEN_GROUPS* ptg = (TOKEN_GROUPS*)buf;
printf("Groups (%d):\n", ptg->GroupCount);
for (DWORD i=0; iGroupCount; i++) {
char name[256], domain[256]; DWORD n=256, d=256; SID_NAME_USE snu;
if (LookupAccountSid(NULL, ptg->Groups[i].Sid, name, &n, domain, &d, &snu))
printf(" [%d] %s\\%s (Attr: 0x%X)\n", i, domain, name, ptg->Groups[i].Attributes);
}
}
}
void PrintPrivileges(HANDLE hToken) {
BYTE buf[4096]; DWORD len;
if (GetTokenInformation(hToken, TokenPrivileges, buf, sizeof(buf), &len)) {
TOKEN_PRIVILEGES* ptp = (TOKEN_PRIVILEGES*)buf;
printf("Privileges (%d):\n", ptp->PrivilegeCount);
for (DWORD i=0; iPrivilegeCount; i++) {
LUID luid = ptp->Privileges[i].Luid;
char pname[256], dname[512]; DWORD pn=256, dn=512;
if (LookupPrivilegeName(NULL, &luid, pname, &pn)) {
if (LookupPrivilegeDisplayName(NULL, pname, dname, &dn, NULL))
printf(" [%d] %s - %s %s\n", i, pname, dname, (ptp->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) ? "(Enabled)" : "");
}
}
}
}
void PrintTokenType(HANDLE hToken) {
BYTE buf[1024]; DWORD len;
if (GetTokenInformation(hToken, TokenStatistics, buf, sizeof(buf), &len)) {
TOKEN_STATISTICS* pts = (TOKEN_STATISTICS*)buf;
printf("Token Type: %s\n", pts->TokenType == TokenPrimary ? "Primary" : "Impersonation");
if (pts->TokenType == TokenImpersonation) {
static const char* levels[] = {
"Anonymous", "Identification", "Impersonation", "Delegation"
};
if (pts->ImpersonationLevel <= SecurityDelegation)
printf("Impersonation Level: %s\n", levels[pts->ImpersonationLevel]);
}
}
}
BOOL EnableDebugPriv(BOOL fEnable) {
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
TOKEN_PRIVILEGES tp = {1};
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
BOOL ok = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
CloseHandle(hToken);
return ok && GetLastError() != ERROR_NOT_ALL_ASSIGNED;
}
D:\> TokenInfor.exe 160
Token Information of Process ID = 160.
Execute File Path = \??\D:\WINNT\system32\csrss.exe.
User Name : NT AUTHORITY\SYSTEM (S-1-5-18)
Belong to 3 groups
[0] BUILTIN\Administrators (S-1-5-32-544) Attr: 0x7
[1] \Everyone (S-1-1-0) Attr: 0x7
[2] NT AUTHORITY\Authenticated Users (S-1-5-11) Attr: 0x7
Have 21 Privileges
[0] SeTcbPrivilege - Act as part of the operating system (Enabled)
[1] SeCreateTokenPrivilege - Create a token object (Enabled)
[2] SeTakeOwnershipPrivilege - Take ownership of files or other objects (Enabled)
...
[20] SeUndockPrivilege - Undock computer (Enabled)
Token Type : Primary Token
OpenProcessToken QUERY_SOURCE error : 5 (Access Denied)
`TokenInfor` 以精簡的 C 代碼展示了 Windows 訪問令牌核心數據結構的枚舉與解析全流程。掌握 `TOKEN_QUERY` 信息類、`LookupAccountSid/Name/DisplayName` 解析鏈、`SeDebugPrivilege` 提權模式,是 Windows 安全開發、權限模型研究、滲透測試後利用階段的必備基本功。