---
# System prepended metadata

title: Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)
tags: [Reverse, eductf, CTF]

---

# Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)
## Background
* [CreateToolhelp32Snapshot](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot)
* [Process32FirstW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw)
* [GetCurrentProcess](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess)
* [OpenProcess](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess)
* [EqualSid](https://learn.microsoft.com/zh-tw/windows/win32/api/securitybaseapi/nf-securitybaseapi-equalsid)
* [Process32NextW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32nextw)
* [OpenProcessToken](https://learn.microsoft.com/zh-tw/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken)
* [GetTokenInformation](https://learn.microsoft.com/zh-tw/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation)
## Source code
* sub_1400016B0
    :::spoiler IDA Source Code解析前
    ```cpp
    __int64 returnTargetPid()
    {
      DWORD LastError; // eax
      DWORD v2; // eax
      WCHAR *szExeFile; // rax
      signed __int64 v4; // rcx
      WCHAR v5; // dx
      int v6; // eax
      DWORD th32ProcessID; // [rsp+20h] [rbp-288h]
      HANDLE hSnapshot; // [rsp+28h] [rbp-280h]
      HANDLE hObject; // [rsp+30h] [rbp-278h]
      HANDLE CurrentProcess; // [rsp+38h] [rbp-270h]
      PSID pSid1; // [rsp+40h] [rbp-268h] BYREF
      PSID pSid2; // [rsp+48h] [rbp-260h] BYREF
      PROCESSENTRY32W pe; // [rsp+50h] [rbp-258h] BYREF

      hSnapshot = CreateToolhelp32Snapshot(2u, 0);
      if ( hSnapshot == (HANDLE)-1i64 )
      {
        LastError = GetLastError();
        sub_140001260("CreateToolhelp32Snapshot failed with error %lu\n", LastError);
        return 0i64;
      }
      else
      {
        pe.dwSize = 568;
        if ( Process32FirstW(hSnapshot, &pe) )
        {
          pSid2 = malloc(0x44ui64);
          CurrentProcess = GetCurrentProcess();
          sub_140001500(CurrentProcess, &pSid2);
          th32ProcessID = 0;
          do
          {
            pSid1 = malloc(0x44ui64);
            hObject = OpenProcess(0x400u, 0, pe.th32ProcessID);
            if ( hObject )
            {
              if ( (unsigned int)sub_140001500(hObject, &pSid1) )
              {
                if ( EqualSid(pSid1, pSid2) )
                {
                  szExeFile = pe.szExeFile;
                  v4 = (char *)L"msedge.exe" - (char *)pe.szExeFile;
                  while ( 1 )
                  {
                    v5 = *szExeFile;
                    if ( *szExeFile != *(WCHAR *)((char *)szExeFile + v4) )
                      break;
                    ++szExeFile;
                    if ( !v5 )
                    {
                      v6 = 0;
                      goto LABEL_14;
                    }
                  }
                  v6 = v5 < *(WCHAR *)((char *)szExeFile + v4) ? -1 : 1;
    LABEL_14:
                  if ( !v6 )
                    th32ProcessID = pe.th32ProcessID;
                }
                free(pSid1);
              }
              CloseHandle(hObject);
            }
          }
          while ( !th32ProcessID && Process32NextW(hSnapshot, &pe) );
          free(pSid2);
          CloseHandle(hSnapshot);
          return th32ProcessID;
        }
        else
        {
          v2 = GetLastError();
          sub_140001260("Process32First failed with error %lu\n", v2);
          CloseHandle(hSnapshot);
          return 0i64;
        }
      }
    }    
    ```
    :::
## Recon
1. 首先，他先利用`CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)`把當前系統中所有的process都snapshot，並回傳指定快照集的開啟控制碼(handle)
2. 在[MSDN](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot#parameters)中有提到
    > 若要列舉process，請參閱 [Process32FirstW](https://learn.microsoft.com/zh-tw/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw)

    所以的確，該function底下就有使用到這個API(#27)，主要目的是擷取系統snapshot中所遇到的第一個process相關資訊
3. 接著進到`sub_140001500`中看一下，如果不看其他exception handler的話其實蠻簡單的
    1. 也就是他會先取得`currentProcess`的token handle(暫時不需要知道handle是啥)，然後再取得儲存資料所需要的buffer size，這邊很tricky的地方是，在#14的地方原本是設定`TokenInformationLength = 0`，而後面呼叫的`GetTokenInformation`就一定會報錯，但他只是想知道TokenInformation的length為多少，所以當他執行完#15行之後，`&TokenInformationLength`會儲存Length，而我可以利用報錯error code(也就是0x7A, `ERROR_INSUFFICIENT_BUFFER`)，進到if statement中，然後利用得到的length再malloc一個空間，做後續的操作
        ![](https://hackmd.io/_uploads/ByZ4tHpMp.png)
    2. 再次呼叫GetTokenInformation 取得資料，此時因為我們已經明確知道需要多大的空間了，所以就不會再報錯了，此時才能真正的取得資料
        ![](https://hackmd.io/_uploads/SJoEKSpfT.png)
    3. 將User SID 複製到a2這個變數
    :::spoiler
    ```cpp
    __int64 __fastcall sub_140001500(void *a1, PSID *a2)
    {
      DWORD v2; // eax
      DWORD v4; // eax
      DWORD v5; // eax
      DWORD LastError; // eax
      PSID *TokenInformation; // [rsp+30h] [rbp-28h]
      DWORD TokenInformationLength; // [rsp+38h] [rbp-20h] BYREF
      HANDLE TokenHandle; // [rsp+40h] [rbp-18h] BYREF

      TokenHandle = 0i64;
      if ( OpenProcessToken(a1, 0x20008u, &TokenHandle) )
      {
        TokenInformationLength = 0;
        GetTokenInformation(TokenHandle, TokenUser, 0i64, 0, &TokenInformationLength);
        if ( GetLastError() == 122 )
        {
          TokenInformation = (PSID *)malloc(TokenInformationLength);
          if ( TokenInformation )
          {
            if ( GetTokenInformation(
                   TokenHandle,
                   TokenUser,
                   TokenInformation,
                   TokenInformationLength,
                   &TokenInformationLength) )
            {
              if ( CopySid(0x44u, *a2, *TokenInformation) )
              {
                if ( !IsValidSid(*a2) )
                  sub_140001260("Sid is invalid\n");
                free(TokenInformation);
                CloseHandle(TokenHandle);
                return 1i64;
              }
              else
              {
                LastError = GetLastError();
                sub_140001260("CopySid failed, %d\n", LastError);
                return 0i64;
              }
            }
            else
            {
              v5 = GetLastError();
              sub_140001260("GetTokenInformatoin failed, %d\n", v5);
              CloseHandle(TokenHandle);
              return 0i64;
            }
          }
          else
          {
            CloseHandle(TokenHandle);
            return 0i64;
          }
        }
        else
        {
          v4 = GetLastError();
          sub_140001260("GetTokenInformatoin 1 failed, %d\n", v4);
          CloseHandle(TokenHandle);
          return 0i64;
        }
      }
      else
      {
        v2 = GetLastError();
        sub_140001260("OpenProcessToken failed, %d\n", v2);
        return 0i64;
      }
    }
    ```
    :::
4. 回到`sub_1400016B0`，可以看到#33~#67是一個do_while loop，該loop就是把現在存取的process再打開(利用PID指定)，並取得他的handle，然後找到該process的User SID，再去比對前一個步驟取得的User SID和現在取得的User SID有沒有一樣，如果一樣就做==#43~#57==(其實就是`memcmp("msedge.exe", process’s executable file name)`)，他會去比對目前的這一支程式的filename是不是`msedge.exe`，如果這個Edge Process的User SID和目前的current User SID一樣且`memcmp`也回傳是，就return PID

:::info
簡略流程如下:
1. snapshot目前所有的process
2. 取得目前執行這支程式(A)的User SID
3. 遍歷snapshot中所有的process，如果遍歷的process(B)的User SID和剛剛取得的一樣就再memcmp，看目前的這支程式(B)是不是msedge.exe，如果是就回傳PID，若否就再遍歷下一個process(B')
:::