Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)

Simple Reverse - 0x20(2023 Lab - WinMalware - Extract Next Stage Payload - 2)

Background

Source code

  • sub_1400016B0 :::spoiler IDA Source Code解析前
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
      __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中有提到

    若要列舉process,請參閱 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一個空間,做後續的操作
    2. 再次呼叫GetTokenInformation 取得資料,此時因為我們已經明確知道需要多大的空間了,所以就不會再報錯了,此時才能真正的取得資料
    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’) :::