在恶意软件分析过程中,恶意软件经常会在内存中注入一些恶意代码。这些恶意代码或shellcode有可能不是常规的PE文件,无法直接使用xdbg或ida进行分析。这种时候可以使用speakeasy来模拟确认shellcode的功能,但是在学习过程中“自动化”并不是一个很好的办法,实际上,“自动化”的结果并不是很理想。这篇文章,深入学习一下如何对shellcode进行手动分析。
Malware bazaar 链接:https://bazaar.abuse.ch/sample/26f9955137d96222533b01d3985c0b1943a7586c167eceeaa4be808373f7dd30/?ref=embeeresearch.io
相比于正常的PE文件,shellocde需要我们自己选择架构。
一般的Windows程序,编译器通常选择Visual Studio。但是对于shellcode,只需要确保是x86、32位和little就行了,编译器都可以。
这是载入shellcode后的ghidra:
由于shellcode没有文件头,Ghidra默认不会反汇编它,我们需要手动进行反汇编。
对第一个字节按D
或者鼠标右键:
反汇编之后右侧可能还是空白的,这个时候继续在第一个字节上按 f
即定义一个函数:
在shellcode中,是没有函数名称的,因为函数调用都是通过API哈希进行的。
API哈希
进入分析第一个 FUN_0000008f
:
有俩个通过API哈希进行的函数调用。这里验证一下,复制下来到google 搜索:
0x726774c 对应的是kernel32.dll
中的LoadLibraryA
函数
回到Ghidra,查看左侧的汇编代码:
发现了 PUSH + CALL 的组合。通过PUSH将哈希值压入栈中,然后CALL 的EBP负责解析刚刚的hash,从内存中查找与之对应的API函数地址。
这是一个标准的API哈希解析模式,也是Cobalt Strike 和 Metasploit 生成的 shellcode 常用的方法,因为它们需要尽可能的保证小而简洁的代码在受害者系统中实现复杂功能。
在API哈希调用的上方还有俩个类似哈希的十六进制数值得留意一下:
将其复制下来,使用cyberchef解码:
可以发现它是要加载的库 wininet
对另一个API哈希也进行搜索
这样,我们就知道了如何通过Ghidra手动解析API哈希了,可以在Ghidra中添加注释方便调试。
但是,我们不可能一直用Google搜索的方法来辨别API哈希,有点太蠢了。同时,面对一些定制的恶意软件以及哈希的特点,只需要略微的改动就可以使得Hash发生变化。因此我们应该通过定位寄存器的方式来解析API哈希。
API解析之后自然是要执行的。那么就定位到API解析最后的返回值:
该shellcode的第一个函数FUN_00000000
前面大致内容都是解析API哈希的操作,解析的函数在最后执行。
通过图形视图,也可以发现该 JMP EAX是整个函数的结尾:
工具地址:https://github.com/OALabs/BlobRunner
BlobRunner 是一款简单的工具,可用于快速调试在恶意软件分析过程中提取的 shellcode。BlobRunner 会为目标文件分配内存,并跳转到分配内存的基址(或偏移量)。
下载下来解压后,放到同一工作台内,打开cmd :blobrunner.exe shellcode.bin
可以看到shellcode已经被加载到基地址 0x00500000
接着再将该blobrunner.exe附加到xdbg上就可以了。
附加到blobrunner,添加一个断点 00500000
之后可以回到blobrunner并按任何按键来执行代码:
如上图,在Ghidra中可以知道地址。所以可以bp 0x00500000+0x86
在xdbg中连续按俩次F7进入我们刚刚分析的第一个函数内:
在俩个call ebp上设置断点,运行到此处。查看右侧堆栈情况:
可以发现刚刚call ebp的哈希值。
这里继续F9,直接断在了JMP EAX上,查看右侧窗口,发现eax的值被解析出来了:
(这里因为乱码换了个xdbg,blobrunner重新启动了,所以地址会有所不同)
继续F9,解析下一个API哈希。
InternetConnectA
函数为给定站点打开文件传输协议 (FTP) 或 HTTP 会话,因此它需要传入一个参数。再次F9,可以看到程序传入的参数,即C2:
继续F9,可以解析到其它的API哈希,以及其传入的参数:
定位到解密API哈希函数的末尾,即执行函数调用的地方,就可以发现被解析的值。
在本例中基地址是 0x00ff0000;
这里CALL ebp可以跟进一下,发现解析API的函数地址就是 0x00ff0006
往下走可以发现包含散列API函数名称的确切位置;至于解析后的函数位置即之前的JMP EAX。
现在我们已知:
需要设置俩个条件断点:
如下图所示:
关于条件断点的编写,可以自行查阅。
之后F9运行,查看日志文件,可以发现如下图所示:
Hash:
API:
在Ghidra中,图形界面我们可以发现一处圆圈,这说明这里循环了很多次。
这可以用作散列发生位置的指示器,并识别所涉及的散列算法的类型。
在这块有个指令 ROR edi,0xd
。 0xD 的十进制是 13。这对应于 Cobalt Strike 和 Metasploit 使用的 ROR 13 哈希逻辑。
关于API哈希这个技术具体是如何实现的,这涉及到了Windows数据结构的问题-PEB结构和Ldr链的关系,留待后续。
16 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!