# 0x0A Shellcode Extraction - ShadowPad shellcode inside xShell [TOC] ## 前言 完整分析可以看這,本篇會介紹如何做shellcode的拆解 http://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2017/08/07172148/ShadowPad_technical_description_PDF.pdf 大意是2017年時,NetSarang產品中其中一個DLL - `NSSOCK2.DLL`被發現了後門程式`ShadowPad` 被竄改的DLL隱藏了惡意shellcode在裡面 同時此DLL會被多樣產品使用,包含下列 - Xmanager Enterprise 5.0 Build 1232 - Xmanager 5.0 Build 1045 - Xshell 5.0 Build 1322 - Xftp 5.0 Build 1218 - Xlpd 5.0 Build 1220 nssock2.dll MD5: `97363d50a279492fda14cbab53429e75` <br> ## IDA 後門的地方在`sub_1000C6C0`處,程式用了xor等手法進行解密 ![](https://i.imgur.com/2Umfq2r.png) <br> 由於整包xshell.exe無法找到,同時手邊只有藏有後門的DLL檔案,無法透過動態分析獲取shellcode 只能手動拆除 首先使用IDA Script儲存加密的shellcode ``` fname = <FILEPATH> address = 0x1000F718 size = 0xFb48 file = fopen(fname, "wb"); enc_shellcode = get_bytes(0x1000F718,size) file.write(enc_shellcode) file.close() ``` <br> ## Extration 有了shellcode檔案,只要寫一隻小程式來解密就可以了 ``` dec_array = bytearray() f = bytearray(open("shadowpad.bin", 'rb').read()) v5 = 0xcf56f204 # little endian for index in range(0,0xFB44): dec_array.append((v5 ^ f[index + 4]) & 0xff) # & 0xff 確保長度為byte v5_1 = (v5 << 0x10) v5_2 = (v5 >> 0x10) v5 = ((0xc9bed351 * (v5_1 + v5_2)) - 0x57a25e37) & 0xffffffff new_f = open("decrypt.bin", 'wb') new_f.write(dec_array) new_f.close() ``` <br> 最後把得到的檔案用IDA載入,就可以進行下一階段的分析啦 ![](https://i.imgur.com/uGXmRTt.png) <br> ## Shellcode Analysis - scdbg.exe ### 靜態分析 - scdbg.exe 進入REMnux,可以利用scbdg.exe來開始接下來的分析,觀察樣本所使用的API ``` remnux@remnux:~$ wine /opt/scdbg/scdbg.exe -s 10000000 -f ~/Downloads/dump_xshell Loaded fb48 bytes from file /home/remnux/Downloads/dump_xshell Initialization Complete.. Max Steps: 10000000 Using base offset: 0x401000 4106bc VirtualAlloc(base=0 , sz=17000) = 600000 410954 LoadLibraryA(KERNEL32.dll) 410a2a GetProcAddress(Sleep) 410a2a GetProcAddress(lstrcpyA) 410a2a GetProcAddress(lstrcpynA) 410a2a GetProcAddress(GetSystemDirectoryA) 410a2a GetProcAddress(GetVolumeInformationA) 410a2a GetProcAddress(WideCharToMultiByte) 410a2a GetProcAddress(MultiByteToWideChar) 410a2a GetProcAddress(lstrlenW) 410a2a GetProcAddress(lstrcpyW) 410a2a GetProcAddress(lstrcatW) 410a2a GetProcAddress(GetProcAddress) 410a2a GetProcAddress(LoadLibraryA) 410a2a GetProcAddress(SystemTimeToFileTime) 410a2a GetProcAddress(GetSystemTime) 410a2a GetProcAddress(VirtualAlloc) 410a2a GetProcAddress(QueryPerformanceCounter) 410a2a GetProcAddress(lstrlenA) 410954 LoadLibraryA(USER32.dll) 410a2a GetProcAddress(wsprintfA) 410954 LoadLibraryA(ADVAPI32.dll) 410a2a GetProcAddress(RegQueryValueExA) 410a2a GetProcAddress(GetUserNameA) 410a2a GetProcAddress(RegCloseKey) 410a2a GetProcAddress(RegFlushKey) 410a2a GetProcAddress(RegSetValueExA) 410a2a GetProcAddress(RegCreateKeyExA) 410954 LoadLibraryA(ole32.dll) Unknown Dll - Not implemented by libemu 0 emu_parse no memory found at 0x0 0 ???? No memory At Address step: 1229304 foffset: 0 eax=a ecx=b302a344 edx=600000 ebx=0 esp=12fe08 ebp=12fff0 esi=0 edi=0 EFL 44 P Z Stepcount 1229304 ``` <br> ### 靜態分析 - speakeasy 另一個選擇,是用 [speakeasy.py](https://www.fireeye.com/blog/threat-research/2020/08/emulation-of-malicious-shellcode-with-speakeasy.html) 來模擬 ``` remnux@remnux:~/Downloads/speakeasy$ python3 run_speakeasy.py -r -a x86 -t ~/Downloads/dump_xshell -o report.json 0x106bc: 'kernel32.VirtualAlloc(0x0, 0x17000, 0x1000, "PAGE_EXECUTE_READWRITE")' -> 0x50000 0x10954: 'kernel32.LoadLibraryA("KERNEL32.dll")' -> 0x77000000 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "Sleep")' -> 0xfeee0000 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrcpyA")' -> 0xfeee0001 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrcpynA")' -> 0xfeee0002 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "GetSystemDirectoryA")' -> 0xfeee0003 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "GetVolumeInformationA")' -> 0xfeee0004 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "WideCharToMultiByte")' -> 0xfeee0005 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "MultiByteToWideChar")' -> 0xfeee0006 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrlenW")' -> 0xfeee0007 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrcpyW")' -> 0xfeee0008 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrcatW")' -> 0xfeee0009 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "GetProcAddress")' -> 0xfeee000a 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "LoadLibraryA")' -> 0xfeee000b 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "SystemTimeToFileTime")' -> 0xfeee000c 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "GetSystemTime")' -> 0xfeee000d 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "VirtualAlloc")' -> 0xfeee000e 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "QueryPerformanceCounter")' -> 0xfeee000f 0x10a2a: 'kernel32.GetProcAddress(0x77000000, "lstrlenA")' -> 0xfeee0010 0x10954: 'kernel32.LoadLibraryA("USER32.dll")' -> 0x77d10000 0x10a2a: 'kernel32.GetProcAddress(0x77d10000, "wsprintfA")' -> 0xfeee0011 0x10954: 'kernel32.LoadLibraryA("ADVAPI32.dll")' -> 0x78000000 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "RegQueryValueExA")' -> 0xfeee0012 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "GetUserNameA")' -> 0xfeee0013 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "RegCloseKey")' -> 0xfeee0014 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "RegFlushKey")' -> 0xfeee0015 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "RegSetValueExA")' -> 0xfeee0016 0x10a2a: 'kernel32.GetProcAddress(0x78000000, "RegCreateKeyExA")' -> 0xfeee0017 0x10954: 'kernel32.LoadLibraryA("ole32.dll")' -> 0x65500000 0x10a2a: 'kernel32.GetProcAddress(0x65500000, "CoCreateGuid")' -> 0xfeee0018 0x10954: 'kernel32.LoadLibraryA("WS2_32.dll")' -> 0x78c00000 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x17)' -> 0xfeee0019 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x6f)' -> 0xfeee001a 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x15)' -> 0xfeee001b 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x16)' -> 0xfeee001c 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x3)' -> 0xfeee001d 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x11)' -> 0xfeee001e 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x14)' -> 0xfeee001f 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0xf)' -> 0xfeee0020 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x73)' -> 0xfeee0021 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0xb)' -> 0xfeee0022 0x10a2a: 'kernel32.GetProcAddress(0x78c00000, 0x9)' -> 0xfeee0023 0x10954: 'kernel32.LoadLibraryA("IPHLPAPI.DLL")' -> 0x0 * Finished emulating * Saving emulation report to report.json ``` 兩個工具的結果差不多,大多API都能抓出來 比較有趣的地方是一開始就調用了VirtualAlloc,接下來的動態分析可以看一下發生什麼事 <br> ### 動態分析 - jmp2it 可以利用jmp2it進行shellcode動態分析 ``` jmp2it.exe dump_xshell 0x0 pause ``` 在x32dbg中Attach,依照jmp2it的指示,就可以動態分析了 ![](https://i.imgur.com/8esyTG2.png) <br> Shellcode做了動態API載入並且調用了剛剛提到的VirtualAlloc (此處可以針對VirtualAlloc回傳memory區塊下write breakpoint) ![](https://i.imgur.com/SLv7aUK.png) <br> shellcode會在`0xF6D2`的地方將下一階段的shellcode解密並且跳轉過去, 暫命名為shellcode_2 ![](https://i.imgur.com/Yks5rYL.png =70%x) (解密處) ![](https://i.imgur.com/shgdkcS.png) 對該Memory區域下Execute breakpoint shellcode_2會呼叫`CreateThread`並且從參數得知startAddress為`1911` 可以設定breakpoint ![](https://i.imgur.com/BAvj90T.png) 並且成功跳轉到shellcode_2 ![](https://i.imgur.com/Y3SWN63.png) <br> shellcode_2的詳細分析建議參考本篇一開始的link <br> [-0xbc](https://hackmd.io/@0xbc000) ###### tags: `Malware Analysis` `Reverse Engineering` `tutorials`