---
# System prepended metadata

title: 0x0A Shellcode Extraction - ShadowPad shellcode inside xShell
tags: [Malware Analysis, Reverse Engineering, tutorials]

---

# 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`