7.4 透過API列舉程式許可權

lyshark發表於2023-09-23

GetTokenInformation 用於檢索程式或執行緒的令牌(Token)資訊。Token是一個資料結構,其包含有關程式或執行緒的安全上下文,代表當前使用者或服務的安全識別符號和許可權資訊。GetTokenInformation函式也可以用來獲取這些安全資訊,通常用於在執行時檢查某個程式或執行緒的許可權或安全資訊。

該函式原型如下:

BOOL GetTokenInformation(
  HANDLE TokenHandle,
  TOKEN_INFORMATION_CLASS TokenInformationClass,
  LPVOID TokenInformation,
  DWORD TokenInformationLength,
  PDWORD ReturnLength
);

引數說明:

  • TokenHandle:當前程式或執行緒令牌的控制程式碼。
  • TokenInformationClass:表示要檢索的Token資訊類別,是TOKEN_INFORMATION_CLASS列舉型別的值之一。這個引數的值確定TokenInformation引數的方案,以及返回的資訊型別。
  • TokenInformation:指向要接收資訊的緩衝區的指標。
  • TokenInformationLength:要接收的緩衝區的大小(以位元組為單位)。
  • ReturnLength:實際緩衝區的大小(以位元組為單位)。

常見的TokenInformationClass值包括:

  • TokenUser:使用者標識資訊;
  • TokenGroups:組資訊;
  • TokenOwner:所有者資訊;
  • TokenPrimaryGroup:主組資訊;
  • TokenPrivileges:特權資訊;
  • TokenSessionId:會話ID資訊。

該函式的返回值為BOOL型別。如果函式執行成功,則返回非零值,否則返回零。如果函式返回零,則可以呼叫 GetLastError() 函式獲取錯誤程式碼。

#include <stdio.h>
#include <ShlObj.h>
#include <Windows.h>

void ShowPrviliges(HANDLE process)
{
  // 透過程式控制程式碼獲取到程式令牌
  HANDLE hToken;
  OpenProcessToken(process, TOKEN_QUERY, &hToken);

  // 獲取查詢到的令牌資訊
  DWORD dwSize;
  GetTokenInformation(hToken, TokenPrivileges, NULL, NULL, &dwSize);

  // 根據令牌中的大小分配空間
  char* pBuf = new char[dwSize] {};
  GetTokenInformation(hToken, TokenPrivileges, pBuf, dwSize, &dwSize);

  // 將記憶體中的內容用要查詢資料結構體解析
  TOKEN_PRIVILEGES* pTp = (TOKEN_PRIVILEGES*)pBuf;
  DWORD dwCount = pTp->PrivilegeCount;               // 解析出許可權個數
  LUID_AND_ATTRIBUTES* pluid = pTp->Privileges;      // 具備的許可權型別

  for (int i = 0; i < dwCount; i++, pluid++)
  {
    char szName[100] = {};
    DWORD dwLen = sizeof(szName);
    LookupPrivilegeNameA(0, &pluid->Luid, szName, &dwLen);
    switch (pluid->Attributes)
    {
    case 0:
      printf("ID => %3d \t 狀態 => 關閉 \t\t 型別 => %s \n", i, szName); break;
    case 1:
      printf("ID => %3d \t 狀態 => 預設 \t\t 型別 => %s \n", i, szName); break;
    case 2:
      printf("ID => %3d \t 狀態 => 開啟 \t\t 型別 => %s \n", i, szName); break;
    case 3:
      printf("ID => %3d \t 狀態 => 預設開啟 \t\t 型別 => %s \n", i, szName); break;
    }
  }
  delete pBuf;
}

int main(int argc, char* argv[])
{
  // 拿到自身程式的控制程式碼
  HANDLE LocalProcess = GetCurrentProcess();
  ShowPrviliges(LocalProcess);

  system("pause");
  return 0;
}

如下所示程式碼同樣是一段許可權檢索的實現,函式EnumOwner()接受一個指向程式令牌的控制程式碼,並使用它來檢索有關令牌使用者的資訊。使用GetTokenInformation()獲取一個包含令牌使用者的安全識別符號(SID)指標的TOKEN_USER結構。然後,它使用LocalAlloc()SID分配記憶體,並使用CopySid()SID複製到該記憶體中。最後使用LookupAccountSid()檢索與SID相關聯的使用者賬戶的名稱。函式返回指向包含賬戶名稱的字元字串的指標。

main()函式中使用OpenProcess()PROCESS_QUERY_INFORMATION標誌檢索當前程式的控制程式碼。然後,它使用OpenProcessToken()TOKEN_QUERY標誌檢索程式令牌的控制程式碼。將該控制程式碼傳遞給EnumOwner()以檢索與令牌相關聯的使用者賬戶名稱。最後使用printf()列印賬戶名稱,使用CloseHandle()關閉令牌控制程式碼,使用CloseHandle()關閉程式控制程式碼。

#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>

// 透過程式Token獲取程式許可權型別
char * __stdcall EnumOwner(HANDLE htoken)
{
  DWORD dwLen;
  PSID pSid = 0;
  TOKEN_USER* pWork;
  SID_NAME_USE use;
  TCHAR User[256], Domain[256];

  GetTokenInformation(htoken, TokenUser, NULL, 0, &dwLen);
  pWork = (TOKEN_USER*)LocalAlloc(LMEM_ZEROINIT, dwLen);
  if (GetTokenInformation(htoken, TokenUser, pWork, dwLen, &dwLen))
  {
    dwLen = GetLengthSid(pWork->User.Sid);
    pSid = (PSID)LocalAlloc(LMEM_ZEROINIT, dwLen);
    CopySid(dwLen, pSid, pWork->User.Sid);
    dwLen = 256;
    LookupAccountSid(NULL, pSid, &User[0], &dwLen, &Domain[0], &dwLen, &use);
    // printf("\t 主機 => %s \t 許可權使用者 => %s ", Domain, User);
    return User;
  }
  return NULL;
}

int main(int argc, char* argv[])
{
  HANDLE ProcessHandle, hToken;

  ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE,GetCurrentProcessId());
  if (ProcessHandle != NULL)
  {
    if (OpenProcessToken(ProcessHandle, TOKEN_QUERY, &hToken))
    {
      char *token = EnumOwner(hToken);
      printf("[+] 當前程式身份: %s \n", token);
      CloseHandle(hToken);
      CloseHandle(ProcessHandle);
    }
  }

  system("pause");
  return 0;
}

本文作者: 王瑞
本文連結: https://www.lyshark.com/post/136e2c9d.html
版權宣告: 本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!

相關文章