Windows进程令牌相关信息的获取
代码样例
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <conio.h>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <Windows.h>
#include <WinDef.h>
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR;
PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;
#define InitializeObjectAttributes(p, n, a, r, s) { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID;
typedef CLIENT_ID* PCLIENT_ID;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
typedef NTSTATUS(NTAPI* typedef_RtlGetVersion)(OUT PRTL_OSVERSIONINFOW lpVersionInformation);
typedef NTSTATUS(NTAPI* typedef_NtOpenProcess)(__out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId);
typedef NTSTATUS(NTAPI* typedef_NtClose)(__in HANDLE Handle);
typedef NTSTATUS(NTAPI* typedef_NtQueryInformationToken)(
IN HANDLE TokenHandle,
IN TOKEN_INFORMATION_CLASS TokenInformationClass,
OUT PVOID TokenInformation,
IN ULONG TokenInformationLength,
OUT PULONG ReturnLength
);
typedef NTSTATUS(NTAPI* typedef_NtOpenProcessToken)(
IN HANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE TokenHandle
);
#define SE_PRIVILEGE_DISABLED (0x00000000L)
#ifdef UNICODE
typedef std::wstring String;
#define __T(x) L ## x
#else
typedef std::string String;
#define __T(x) x
#endif
typedef String CString;
#include <ntlsa.h>
typedef_NtOpenProcess g_NtOpenProcess;
typedef_NtQueryInformationToken g_NtQueryInformationToken;
typedef_NtOpenProcessToken g_NtOpenProcessToken;
typedef_NtClose g_NtClose;
void initFunc()
{
g_NtOpenProcess = (typedef_NtOpenProcess)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtOpenProcess");
g_NtQueryInformationToken = (typedef_NtQueryInformationToken)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationToken");
g_NtOpenProcessToken = (typedef_NtOpenProcessToken)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtOpenProcessToken");
g_NtClose = (typedef_NtClose)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtClose");
}
bool getProcessTokenPrivilege(DWORD dwPid, std::map<std::string, DWORD>& result)
{
// Open a handle to the target process with read access
HANDLE hProcess = INVALID_HANDLE_VALUE;
CLIENT_ID client{};
OBJECT_ATTRIBUTES oa{};
client.UniqueProcess = ULongToHandle(dwPid);
oa.Length = sizeof(OBJECT_ATTRIBUTES);
NTSTATUS status = g_NtOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION, &oa, &client);
if (!NT_SUCCESS(status))
{
return false;
}
// Open a handle to the process token with query access
HANDLE hToken = INVALID_HANDLE_VALUE;
status = g_NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (!NT_SUCCESS(status))
{
g_NtClose(hToken);
return false;
}
// Get the required size for privilege information
DWORD tokenInfoLength = 0;
status = g_NtQueryInformationToken(hToken, TokenPrivileges, NULL, 0, &tokenInfoLength);
if (STATUS_BUFFER_TOO_SMALL == status && !tokenInfoLength)
{
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
// Allocate memory for the privilege information
LPVOID tokenInformation = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, tokenInfoLength);
if (tokenInformation == NULL)
{
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
// Get the token privileges
status = g_NtQueryInformationToken(hToken, TokenPrivileges, tokenInformation, tokenInfoLength, &tokenInfoLength);
if (!NT_SUCCESS(status))
{
HeapFree(GetProcessHeap(), 0, tokenInformation);
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
// Cast the retrieved data to TOKEN_PRIVILEGES structure
const auto privileges = static_cast<TOKEN_PRIVILEGES*>(tokenInformation);
static constexpr auto fnLuidToString = [](LUID Luid) -> std::string {
char buffer[_countof("00000000-00000000") + 1] = { '\0' };
sprintf_s(buffer, sizeof(buffer), "%08x-%08x", Luid.HighPart, Luid.LowPart);
return std::string(buffer);
};
// Loop through each privilege
for (DWORD i = 0; i < privileges->PrivilegeCount; ++i)
{
// Lookup privilege name for better readability (optional)
std::string privilegeName;
DWORD dwReturn = 0;
if (!LookupPrivilegeNameA(NULL, &privileges->Privileges[i].Luid, NULL, &dwReturn) && dwReturn)
{
privilegeName.resize(dwReturn);
if (LookupPrivilegeNameA(NULL, &privileges->Privileges[i].Luid, privilegeName.data(), &dwReturn))
{
/**
* Attributes:
*
* #define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L)
* #define SE_PRIVILEGE_ENABLED (0x00000002L)
* #define SE_PRIVILEGE_REMOVED (0X00000004L)
* #define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L)
*/
result.insert_or_assign(privilegeName.c_str(), privileges->Privileges[i].Attributes);
}
else
{
result.insert_or_assign(std::move(fnLuidToString(privileges->Privileges[i].Luid)), privileges->Privileges[i].Attributes);
}
}
}
// Clean up resources
HeapFree(GetProcessHeap(), 0, tokenInformation);
g_NtClose(hToken);
g_NtClose(hProcess);
return true;
}
LSA_HANDLE getLookupPolicyHandle()
{
static LSA_HANDLE cachedLookupPolicyHandle = NULL;
LSA_HANDLE lookupPolicyHandle;
LSA_HANDLE newLookupPolicyHandle;
// Use the cached value if possible.
lookupPolicyHandle = InterlockedCompareExchangePointer(&cachedLookupPolicyHandle, NULL, NULL);
// If there is no cached handle, open one.
if (!lookupPolicyHandle)
{
if (NT_SUCCESS([](_Out_ PLSA_HANDLE PolicyHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ PUNICODE_STRING SystemName) -> NTSTATUS {
OBJECT_ATTRIBUTES objectAttributes{};
InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
return LsaOpenPolicy((PLSA_UNICODE_STRING)SystemName, (PLSA_OBJECT_ATTRIBUTES)&objectAttributes, DesiredAccess, PolicyHandle);
}(&newLookupPolicyHandle, POLICY_LOOKUP_NAMES, NULL)))
{
// We succeeded in opening a policy handle, and since we did not have a cached handle
// before, we will now store it.
lookupPolicyHandle = InterlockedCompareExchangePointer(&cachedLookupPolicyHandle, newLookupPolicyHandle, NULL);
if (!lookupPolicyHandle)
{
// Success. Use our handle.
lookupPolicyHandle = newLookupPolicyHandle;
}
else
{
// Someone already placed a handle in the cache. Close our handle and use their
// handle.
LsaClose(newLookupPolicyHandle);
}
}
}
return lookupPolicyHandle;
}
std::wstring getSidFullName(PSID Sid, BOOLEAN IncludeDomain, PSID_NAME_USE NameUse)
{
NTSTATUS status;
LSA_HANDLE policyHandle;
std::wstring fullName;
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
PLSA_TRANSLATED_NAME names;
policyHandle = getLookupPolicyHandle();
referencedDomains = NULL;
names = NULL;
if (NT_SUCCESS(status = LsaLookupSids(
policyHandle,
1,
&Sid,
&referencedDomains,
&names
)))
{
if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
{
PWSTR domainNameBuffer = NULL;
ULONG domainNameLength = 0;
if (IncludeDomain && names[0].DomainIndex >= 0)
{
PLSA_TRUST_INFORMATION trustInfo;
trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
domainNameBuffer = trustInfo->Name.Buffer;
domainNameLength = trustInfo->Name.Length;
}
else
{
domainNameBuffer = NULL;
domainNameLength = 0;
}
if (domainNameBuffer && domainNameLength != 0)
{
fullName.resize(domainNameLength / sizeof(WCHAR) + names[0].Name.Length / sizeof(WCHAR) + sizeof('\\'));
memcpy(&fullName[0], domainNameBuffer, domainNameLength);
fullName[domainNameLength / sizeof(WCHAR)] = '\\';
memcpy(&fullName[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);
}
else
{
fullName.resize(names[0].Name.Length / sizeof(WCHAR));
memcpy(&fullName[0], names[0].Name.Buffer, names[0].Name.Length);
}
if (NameUse)
{
*NameUse = names[0].Use;
}
}
}
if (referencedDomains) LsaFreeMemory(referencedDomains);
if (names) LsaFreeMemory(names);
return fullName;
}
bool getProcessTokenGroup(DWORD dwPid, std::map<std::wstring, DWORD>& result)
{
HANDLE hProcess = INVALID_HANDLE_VALUE;
CLIENT_ID client{};
OBJECT_ATTRIBUTES oa{};
client.UniqueProcess = ULongToHandle(dwPid);
oa.Length = sizeof(OBJECT_ATTRIBUTES);
NTSTATUS status = g_NtOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION, &oa, &client);
if (!NT_SUCCESS(status))
{
return false;
}
HANDLE hToken = INVALID_HANDLE_VALUE;
status = g_NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (!NT_SUCCESS(status))
{
g_NtClose(hToken);
return false;
}
// Get the required size for privilege information
DWORD tokenInfoLength = 0;
status = g_NtQueryInformationToken(hToken, TokenGroups, NULL, 0, &tokenInfoLength);
if (STATUS_BUFFER_TOO_SMALL == status && !tokenInfoLength)
{
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
// Allocate memory for the privilege information
PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, tokenInfoLength);
if (Groups == NULL)
{
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
status = g_NtQueryInformationToken(hToken, TokenGroups, Groups, tokenInfoLength, &tokenInfoLength);
if (!NT_SUCCESS(status))
{
HeapFree(GetProcessHeap(), 0, Groups);
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
for (ULONG i = 0; i < Groups->GroupCount; i++)
{
const auto FullName = getSidFullName(Groups->Groups[i].Sid, TRUE, NULL);
if (!FullName.empty())
{
/**
* Attributes:
*
* #define SE_GROUP_MANDATORY (0x00000001L)
* #define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L)
* #define SE_GROUP_ENABLED (0x00000004L)
* #define SE_GROUP_OWNER (0x00000008L)
* #define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L)
* #define SE_GROUP_INTEGRITY (0x00000020L)
* #define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
* #define SE_GROUP_LOGON_ID (0xC0000000L)
* #define SE_GROUP_RESOURCE (0x20000000L)
*/
result.insert_or_assign(FullName, Groups->Groups[i].Attributes);
}
}
HeapFree(GetProcessHeap(), 0, Groups);
g_NtClose(hToken);
g_NtClose(hProcess);
return true;
}
bool isProcessElevated(DWORD dwPid, BOOL& bElevated)
{
HANDLE hProcess = INVALID_HANDLE_VALUE;
CLIENT_ID client{};
OBJECT_ATTRIBUTES oa{};
client.UniqueProcess = ULongToHandle(dwPid);
oa.Length = sizeof(OBJECT_ATTRIBUTES);
NTSTATUS status = g_NtOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION, &oa, &client);
if (!NT_SUCCESS(status))
{
return false;
}
HANDLE hToken = INVALID_HANDLE_VALUE;
status = g_NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (!NT_SUCCESS(status))
{
g_NtClose(hToken);
return false;
}
TOKEN_ELEVATION_TYPE elevationType;
DWORD size = 0;
status = g_NtQueryInformationToken(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &size);
if (!NT_SUCCESS(status))
{
g_NtClose(hToken);
g_NtClose(hProcess);
return false;
}
bElevated = (elevationType == TokenElevationTypeFull);
g_NtClose(hToken);
g_NtClose(hProcess);
return true;
}
int main(int argc, char** argv) {
// Replace with the target process ID
DWORD processId = GetCurrentProcessId(); // Example process ID
printf("Process Id: %d \n\n", processId);
initFunc();
BOOL bElevated = FALSE;
isProcessElevated(processId, bElevated);
printf("Is Process Elevated: %d \n", bElevated);
std::map<std::string, DWORD> result;
getProcessTokenPrivilege(processId, result);
for (const auto& item : result)
{
printf("Token Privilege [%s]: 0x%X \n", item.first.c_str(), item.second);
}
printf("\n");
std::map<std::wstring, DWORD> result2;
getProcessTokenGroup(processId, result2);
for (const auto& item : result2)
{
printf("Token Group [%ws]: 0x%X \n", item.first.c_str(), item.second);
}
printf("\n");
system("pause");
return 0;
}
本文为博主总结文章,欢迎转载,请注明出处。