Ghidra and ShadowHammer

2024-07-10

繼續補坑…
ref: https://www.youtube.com/watch?v=gI0nZR4z7_M

ubuntu 可以直接用 snap 裝 ghidra

sudo snap install ghidra

照著影片說,第一步要先修長度

僅需打勾 PE Header Annotation

照教學說,惡意程式是把 shellcode append 在 .text 區段後面,所以這一段就是要把 .text 區段做 patch,

在這一步要做的就是把 physical address 與 virtual address 跟 size of raw data 對齊

記得要 enable editing of bytes
全選後選 extract and import

analysis options 多選 Decompiler Parameter IDWindowsPE x86 Propagate External Parameters
前者是為了獲得較正確的變數名稱,後者是可以會將 function 的參數資訊以註解方式顯示
如果有看到 FUN_0051B908 那就代表 patch 成功了

Dump payload

根據動態分析(process monitor)可以得知他會寫一個 idx.ini

ok,先從 write 開始追

像這種 Library function 不看,要看的是在 User 寫的程式有 call 的

最後只有FUN_00401810 符合要求

照著教學把 function name 改成 write_somthing 這個名稱
然後透過 CreateFileW 得知 param_2 是 file_name

然後找到是誰 call write_somthing 的

然後一樣改參數名稱

也順便把能識別的 function 做命名

至於那個 0x88 到底是什麼呢? 回頭去看 write_somthing 怎麼使用這個變數的

找msdn
https://learn.microsoft.com/zh-tw/windows/win32/api/libloaderapi/nf-libloaderapi-findresourcew

從這邊可以知道 0x88 是 exe 的 Resource ID

嘗試把他解出看


但沒什麼好看的,有可能 shellcode 是動態寫入的,用靜態來看只會看到一堆 gadget

於是透過 offset 來找看看有沒有其他東西,將 Resource Address 扣除 ImageBaseAddress
0x0056ec78 - 0x400000 = 0x16ec78 (ImageBaseAddress直接看程式最上面的address就有了)

第一個不看,二三個都在同一個 funtcion

首先第14行感覺是拿 module base address,所以改一下變數名稱 pHVar3 變成 module_addr_400000
然後看一下到底是誰會用他,發現到它是被包含在 __crtExitProcess 內,有可能是一個被 Modify 過的 standard lib

再回去 function 內,要如何推出其他 offset 的 function 呢?
看一下這一行,這個是透過 0x16ec78 找到的,而這個 0x16ec78 是使用 ImageBaseAddress 加上 offset 得到的

所以可以透過一樣的方法,看 asm 去推導其他的 function
pcVar1,他是使過 0x11c27c 跟 ImageBaseAddress 相加得到的,把這兩個相加後去看會得到什麼
0x11c27c+0x400000=0x51c27c

基本上看到查到這邊後,就直接把 FUN_0051B908 改成 shellcode
然後 pcVar1 也改成 VirtualAlloc,順道連 DataType 一起改 (右鍵->Retype Variable)
0x40 的部分改成 PAGE_EXECUTE_READWRITE0x1000 的部分改成 MEM_COMMIT (右鍵-> Set Equate..)
需要的話可以再加註解 (右鍵->Comments)
全部大概長這樣

繼續追下去,這次要看,程式拿這個 VirtualAlloc 的 Buffer 要幹什麼事情
進去 FUN_0051B802,看到這個感覺就很像是 decode function

看完 decode function 之後回來 shellcode,需要知道 decode 之後他的 entry point 在哪

首先第42行,將 Resource Buffer 的內容複製進 VirtualAlloc buffer 內,後面就是做 count,在47行對 VirtualAlloc Buffer 做 decode 之後,48行就是 shellcode 的 entry point,0xfab 是 entry 的 offset
照教學的做法是直接將 asm 轉 C 然後編譯程式後直接利用他 decode,但…這一塊要處理很多 exception 很麻煩,我覺得更快的方法還是直接做動態分析把 shellcode 拉出來(我們已經知道 shellcode會存放在哪了)

首先因為系統會有 ASLR,所以要先知道 Ghidra 與 Windbg 的 ImageBaseAddress 的 offset 多少

透過 u $exentry 取得 entry point address,透過圖中方法可以找到 MZ header,其實透過 !peb 也可以

然後把 Windbg 的 base address 扣掉 ghidra 的 0x400000 就取得 offset 了
0x10f0000-0x400000=0xcf0000
然後下斷點在 0x51b9b8+0xcf0000=0x120b9b8,然後看一下 register

就可以知道解完的 shellcode 在 0xcb00000xcb0fab 是 entry point

然後順勢使用 .writemem [file path] 0xcb0000 L?[mem range],這邊我直接碰到底端,就直接全 dump

Analysis Payload

接著來看 decode 後的 shellcode 長怎樣

首先在 0xfb6 看到針對 FS:0x18 做事情


這邊改一下 DATA TYPE
相關需要的可以在這下載
https://github.com/0x6d696368/ghidra-data/tree/master/typeinfo
http://terminus.rewolf.pl/terminus/
Change unaff_FS_OFFSET to NT_TIB*


Change Self to TEB*

Change p_Var2 to LDR_DATA_ENTRY

Create a new structure LDR_DATA_TABLE_ENTRY_0x10
首先複製要更改的 struct 其他地方




Change local_64 to LDR_DATA_TABLE_ENTRY*


從 22 跟 23 行可以看出他針對 Kernel32.dll 做 dllname 的遍例尋找

Import Table Hash

接下來看 FUN_00000010,但這邊不曉得是不是因為我是直接動態 leak 出來的,怎麼樣都解不出教學的樣子,索性直接貼成果

下一步,嘗試 leak function hash list
FUN_00000010 拿來改一下

改完後的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv)
{
char cVar1;
char *name;
int iVar2;
char *pcVar3;
int local_c;
int local_8;

local_8 = 0;
local_c = 0;
pcVar3 = name = argv[1];
cVar1 = *pcVar3;
while (cVar1 != '\0') {
local_c = local_c * 0x21 + (int)cVar1;
pcVar3 = pcVar3 + 1;
cVar1 = *pcVar3;
}
printf("%s: %x\n", name, local_c);
//} while (local_8 < *(int *)(iVar2 + 0x18));
return 0;
}

然後 clone https://github.com/0x6d696368/ghidra-data.git

cat * | grep -Eo NAME=.+\" | awk -F \" {'print $2'} | grep -v .dll > functionNames


這樣就有 function hash list 了

然後看一下 shellcode 找的 function 是那些

然後繼續修 function type …
先創一個 structure







照著 hash table 一個一個壓上去

接著回到 entry 看最後一個 function,FUN_00000950

發現他有用到 EAX 的 register,看一下 EAX 誰會用到

編輯一下 FUN_00000950,幫他加個參數



接著看 FUN_000002e1



idx.txt

c2



conclusion

  1. 透過 GetAdaptersInfo 取得 MAC 資訊
  2. 透過 MD5Init, MD5Update 和 MD5Final 計算 MAC 的 MD5 值
  3. 當 Match 到 MD5 的值時,從 asushotfix[.]com 下載 shellcode 並執行
  4. 如果沒 Match 的話, write something to idx.txt