五一期间,分析那个木马的过程中(见上一篇,它其中的是InInitializationOrderModuleList,见下图)就碰到了通过PEB_LDR_DATA链的InMemoryOrderModuleList找Kernel32.dll最终获取函数的地址。本文介绍得浅显易懂,都是实用的方法,感觉还不错,推荐给你们。
依赖项
Shellcode 有一些依赖关系,这可能会使编写它们变得有点困难。
-
长度——因为 shellcode 利用内存中的特定漏洞,序列需要尽可能高效。这意味着攻击者必须使其长度适合缓冲区的大小,因此所有指令都将在内存空间中运行。
如果 shellcode 的长度将大于缓冲区的大小,则可能会出现某些结果,例如程序崩溃甚至被利用(例如缓冲区溢出)。 -
不允许的字符——当shellcode 中出现
‘r’
,‘n’
,0x00
等字符时,应该运行的代码将终止而不是完成。# 为什么?
例如,当0x00
读取“空字节”(类似值)时,CPU 将其识别为字符串的结尾(空终止符)。
Unix Shellcodes
Unix 操作系统提供直接访问以通信和管理内核 - 使用指令int 0x80
。因此,当系统调用跟随该指令设置时,shellcode 将被赋予以高权限执行的能力。
Windows Shell 代码
在基于 Windows 的操作系统中,由于 ASLR(地址空间布局随机化)等内存保护机制,创建 shellcode 可能会有点困难。
在内存中查找 API 函数的地址
大多数时候,shellcode 被注入到正在运行的进程中,因此它没有任何关于内存状态的先验知识,以及 API 函数的地址。
结论:不能基于静态地址。
因此,shellcode 无法使用Call CreateProcessA
or指令jmp sub_40100000
,必须独立于其位置运行才能找到所需的 API 函数并手动解析地址。换句话说,要找到它想要使用的DLL,而不考虑地址,而是基于内存中对象的结构。这也是它被称为位置无关代码(PIC)的原因。
例如,要调用GetProcAddress
,shellcode 需要找到Kernel32.dll
DLL 的地址。
那么怎么做呢?
PEB - 过程环境块
由于 PEB 对象总是被加载到内存的同一个地址FS:[0x30]
,所以 shellcode 可以使用它!
它需要做什么:
-
转到 PEB 对象。
-
传递
PEB_LDR_DATA
对象,直到它到达InMemoryOrderModuleList
链表,其中包含有关进程加载的模块的信息。在此之后,shellcode 将保存想要的模块(通常Kernel32.dll
是第三个对象)。 -
DllBase
使用该字段查找所需 DLL 的基地址。 -
找到它的导出表。
-
找到想要的功能(如
GetProcAddress
)。 -
使用函数获取函数的地址
GetProcAddress
。 -
最终,使用合适的参数运行想要的功能。
使用 SEH——结构化异常处理
该技术是关于访问 SEH 链的底部,通过输入 TIB(线程信息块)中的第一个属性,该属性具有一个常量地址 - FS:[0x0]
. 它包含Kernel32.dll
模块的默认异常处理程序。要定位所需模块的地址,可以返回内存地址,直到找到模块的入口点(使用MZ
签名或0x5A4D
例如)。
使用 TEB——线程环境块
与 SEH 技术一样,可以访问 TEB 对象,该对象在内存中具有恒定的位置 — FS:[0x18]
. 穿过这个对象可能会导致你进入 SEH 链,如上所述。
顶栈
这种方法不是很常见,因为它依赖于在堆栈中具有所需 API 函数的所需 DLL 的地址。
通过哈希查找 API 函数
这种技术也称为 SFHA(Stephen Fewer 的哈希 API)。它使用 4 个字节来表示寄存器DLL!WinAPI
内部函数的 Hash 值。EAX
然后,JMP
正在对该地址进行调用以调用该函数。注意从哪个函数调用EAX
以及它获取的参数(您可以在 MSDN 中查看它们)。然后,与内存中的实际值进行比较。例如,如果一个 shellcode 调用该Win_Exec
函数,它将通过每个DLL!WinApi
使用其他技术之一,并带有其他参数(我们可以PUSH
在寄存器调用之前通过指令识别它们)。当我们输入参数的内存地址时,我们可能知道里面有什么(可能是PS1
脚本或编码命令..)。
检测
在我们对什么是 shellcode 有所了解之后,让我们看看如何检测它们。
注意去混淆,解密一个混淆或加密的脚本以暴露shellcode!
使用行为模式
如上所述,shellcode 是表示指令的 Opcodes 序列。因此,我们可以找到这个序列并对其进行检查。
如果我们有恶意程序的源代码运行 shellcode(如 PowerShell 或 JavaScript),我们可以寻找可以代表操作码的值/变量/字符串,这可能会导致我们找到 shellcode 本身。
让我们看一下指令:mov ebp, esp
. shellcode 将使用的字符序列可以有多种格式:
-
十六进制值:
8B EC
-
反斜杠十六进制值:
x8BEC
-
Unicode 百分比:
%u8B%EC
-
反斜杠 Unicode:
u8BuEC
-
大批:
[0x8B, 0xEC]
在确定这些字符的序列可以代表 CPU 指令之后——我们将重点关注它。
转储 shellcode
在检测到潜在的 shellcode 后,将其转储到二进制文件是实现我们目标的第一步。
-
base64dump.py
工具 — 允许查找可能包含 shellcode 的部分并将其转储到二进制文件 (.bin
) 中,以便对其进行分析。参数: 1. — 允许搜索用于百分比 Unicode 编码 ( ) 的字符串。2. — 允许搜索用于反斜杠 Unicode 编码 ( ) 的字符串。3. — 允许搜索用作十六进制值的字符串。4. — 允许使用 Base64 编码搜索字符串。允许通过 ID 定位想要的部分,并将其转储到二进制文件中。大多数情况下,将选择最大的部分。显示所选部分的十六进制视图。base64dump.py -e {param} {file}
pu
%u
bu
u
hex
base64
base64dump.py -e {param} {file} -s {sectionID} -d > {outFile.bin}
base64dump.py -e {param} {file} -s {sectionID} -a
-
objdump.py
tool — 允许在提取 shellcode 时转储它。 -
使用 Hex-Editor — Hex-Editor 可用于删除不相关的部分。因此,只剩下 shellcode 并且可以保存到
.bin
文件中。
如何分析shellcode?
可以通过两种主要方式执行 shellcode 分析:静态分析和动态分析。
静态分析——代码分析
这样,包含 shellcode 的二进制文件将被转换为可执行文件,并被加载到反汇编程序(如 IDA PRO)中。然后,它将被分析为可执行文件。
用法:
-
shellcode2exe.py {file.bin}
-
shellcode2exe.bat {3264} {file.bin} {file.exe}
动态分析
scdbg
工具——允许模拟 shellcode 的执行,以便找到它使用的 API 函数,这可以表明它的很多行为。
-
scdbg -s {steps} -f {file.bin}
-
运行 GUI
scdbg
工具并向其启动二进制文件。 -
使用
FindSC
将在加载的二进制文件中找到 shellcode 的开头。
jmp2it
工具——允许在专用进程下执行 shellcode,该进程用作可执行文件的“shell”。因此,将调试器附加到正在运行的进程,使您能够调试 shellcode。
-
jmp2it {file.bin} {offset}
—offset
表示 shellcode 从二进制入口点的偏移量(0x0
用于开始)。
shellcode_launcher.exe
— 与之前的工具类似。
结论
在这篇文章中,我们了解了如何使用多种工具来识别和分析 shellcode,希望你能从这篇文章中学到一二。
原文始发于微信公众号(MicroPest):识别和分析 shellcode的一些方法
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论