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

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

Description

取出 eductf-lab.exe 中的 next stage payload (embedded PE file),並計算其 MD5 hash。 Flag format: FLAG{462fe0000…} (hex character must be lowercase)

Background

  • DOS Header
  • NT Headers - Optional Header

Source code

  • sub_140001870 :::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
      __int64 __fastcall sub_140001870(char **pe_file, _QWORD *pe_file_size)
      {
        *pe_file = byte_140005040;
        *pe_file_size = 72770i64;                     // 這是個是怎麼判斷成PE size我也不知道
        if ( **pe_file == 'ZM' )
        {
          if ( *(sub_1400013D0(*pe_file) + 0x18) == 0x20B )
          {
            return 1i64;
          }
          else
          {
            sub_140001260("remote dll optional header magic check failed\n");
            return 0i64;
          }
        }
        else
        {
          sub_140001260("remote dll magic check failed\n");
          return 0i64;
        }
      }
    

    :::

Recon

  1. 進到sub_140001BF0之後可以先觀察sub_140001870,前面有source code可以看到他正在比對byte_140005040的前面兩個字元是不是等於MZ,也就是一支PE file的magic header,並且又比對了後面0x18的位置是不是等於0x20B,也就是另外一個magic header(用來判斷該程式是否可於64-bits運行),由以上操作幾乎可以確定駭客把真正的程式(可能是惡意的)塞在正常的PE file中 :::info 如果只是要解題的話,到這邊就可以了,只要利用前一題學到的把byte_140005040改變他的type,變成char[72770],再用Shift+E,把raw data export出來,丟到online md5 checksum,就可以得到這支檔案的hash(462fe0007f86957f59824e113f78947c) :::
  2. sub_1400013D0仔細看他的操作,其實就是把byte_140005040的地址,加上0x3C,再取值,就是e_lfanew,也就是NT Headers的file offset,這個offset加上原本的原本的140005040就是NT header,所以可以把sub_1400013D0 rename成getNtHdr
    1
    2
    3
    4
     __int64 __fastcall getNtHdr(__int64 a1)
     {
       return *(a1 + 0x3C) + a1;
     }
    
  3. 接下來可以改變這個function的type,按Y,改IMAGE_NT_HEADERS *__fastcall getNtHdr(_QWORD),就變得非常簡潔好看,另外,要把pe_file的type從_int64改成_QWORD的原因是pe_file存的是byte_140005040的地址,不是數字,雖然代表的byte數一樣,但意義不相同,所以IDA可能會解析不出來
  4. 最後就把目前的這個sub function rename成getEmbeddedPE_File就可以了

:::info ::: :::spoiler 解析後

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;
    }
  }
}

::: Flag: FLAG{462fe0007f86957f59824e113f78947c}