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;
}
posted @ 2024-07-08 15:26  倚剑问天  阅读(19)  评论(0编辑  收藏  举报