概述
在本文中,我们将使用miasm动态分析研究一个shellcode。该分析包含了对Miasm内部结构的描述,并阐述了miasm的优势。shellcode位于存档dyn_sc_shellcodes.zip中,使用密码infected进行了加密。最终的脚本在这里:dyn_sc_run.py。
(译者注:文章底部会附上下载链接)
概要:
- 第一次尝试
- 符号执行
- 沙盒模拟
- 深入shellcode
- 艰难的部分
- 结束语
此分析基于Miasm修订版 2cf6970
第一次尝试
这是shellcode的原始dump:
我们可以看到这个shellcode是纯粹的ascii。让我们反汇编它的第一个基本块:
运行后,我们得到了下边的图(文件graph_execflow.dot)
注意:PUSH EAX POP ECX是模仿MOV ECX, EAX,以保持纯粹的 ascii编码。我们可以看到,shellcode是从一些计算开始的,然后xor一个内存单元:
我们可以手动或动态分析它。不过作为练习,我们将尝试确定哪个地方在操作这个指针。现在的问题是:ECX + 0x30指向的值在哪里?在Miasm中,至少有两种方法可以回答这个问题:
1、从头开始使用符号执行来检索地址0x19处的ECX等式
2、使用DependencyGraph(依赖图),其目标是跟踪参与所选变量值的所有行。我们不会在这里介绍这个模块,以后会有专门的文章来讲解这个模块。
符号执行
以下是符号执行的基本步骤:
1、反汇编基本块
2、将反汇编结果翻译为miasm中间语言(IR)
3、创建一个初始状态
4、启动符号执行
以下代码将shellcode从地址0x0反汇编到0x1C (在XOR之后)。然后我们将在IR中翻译它,最后运行符号执行到地址0x1C处。脚本如下:
运行输出结果如下:
由于ECX = (EAX_init+0xFFFFFFF0),xor操作的内存位于[ECX + 0x30],替换ECX可得(EAX_init + 0xFFFFFFF0) + 0x30 = EAX_init + 0x20。顺便说一下,EAX_init是初始符号执行状态下EAX的值。
实际上,shellcode包含有关应用程序运行时EAX值的信息。我没有说的是这个shellcode是在一个漏洞利用之后被执行的,这会导致虚表(vtable)损坏进而执行CALL EAX。因此shellcode肯定知道在执行第一条指令时, EAX指向它。
如果您不想仅仅为了运行符号执行而编写Python代码,那么脚本miasm/example/ida/symbol_exec.py就可以解决问题。在IDA下,按Alt-F7并运行脚本。然后选择要执行的代码并按F3。
您应该得到以下结果:
沙盒模拟
为了继续分析,我们将在沙盒中模拟运行shellcode。为此,Miasm提供多种解决方案。
示例miasm/example/jitter/x86_32.py中有一个简单的沙盒演示 。以下是脚本的核心:
在这个脚本中,我们从一个空的沙盒开始。如果不为堆栈创建空间,则第一个PUSH将触发错误,会提示代码正在尝试访问未映射的内存页面。这解释了myjit.init_stack()。0x1337BEEF被压入堆栈以强制潜在的 RET跳转到指定地址。然后,我们在此地址添加断点以发现此类行为。
跟踪结果如下:
在上边的日志中,脚本在地址0x40000019处出错,结合前边对XOR的分析。我们可以看到错误是shellcode尝试访问地址0x20处的未映射内存区域。实际上,沙盒初始化状态时默认是将EAX设置为0x0。由于shellcode被映射到了地址0x40000000,因此会导致找不到内存地址区域。要修复这个错误,我们需要将EAX设置为0x40000000,调整为如下:
现在,执行能够在自修改代码之后继续运行。由于日志过于详细,所以从现在开始,我们将仅激活块跟踪(block trace) (有关更多详细信息,请参阅上一篇文章)。
我们将如下代码
替换为:
运行后显示的第一个基本块:
有意思的信息出现在下一个基本块:
请注意,这个新的基本块其实是第1个基本块中的片段。此处主要发生了如下的事情:
1、Miasm翻译第一个基本块并开始执行。
2、执行到自动修改代码处,修改第1个基本块指向的内存数据,这会扰乱第1个基本块。
3、执行完毕后,此块将从缓存中删除。
4、引擎恢复执行,修改后的基本块作为新基本块处理,反汇编并显示
【译者注:第2点翻译可能理解有偏差,大家可以对照下英文原文以确认翻译】
请注意,这个新的基本块与第1个基本块的末尾略有不同。
修改前:
修改后:
深入Shellcode
该基本块(loc_000000004000001C)解密下一个阶段。我们可以在0x40000033处停止执行并将内存转储到磁盘以观察下一阶段同时进行进一步分析。可是等等!还有更多:
上面的代码是另一个解密循环。此时,我们将在地址0x4000004b处添加一个断点来转储shellcode,此断点将触发回调,该回调会将解密代码从内存转储到硬盘。
在这个阶段,可以对解密代码进行静态分析。不过我们将使用miasm沙盒进行动态分析。
这是下一个基本块:
剧透:对于有经验的人来说,我们有一个代码模式,就是我们可以在内存中堆叠一个特殊的字符串:
日志在执行期间(再次)引发另一个Miasm错误:
在执行这个基本块期间,地址0x30处的代码在尝试访问沙盒内存之外的地址。请注意,在这种情况下,我们不知道错误指令的确切地址,不过我们可以通过脚本的交互模式来检索它:
错误的指令是:
这里,EAX是0x0,因此内存查找位于地址0x30,未映射到内存中。有一个技巧:我们可以使用段选择器FS查找真正的内存。默认情况下,Miasm不会模拟分段,这解释了之前的结果。
由于我们在Windows上,我们知道此代码是查找PEB(进程环境块),因此我们有两个选择:
1、我们可以在地址0x30处映射一个内存页,其中插入假的PEB结构数据。
2、另一种解决方案是为段选择器FS和具有自定义基址的相应段描述符分配值。该基址位于一个新的内存区域,并且填充了假的PEB结构数据。以此同时,您还必须在Miasm中启用分段支持。
很痛苦不是吗?不过幸运的是,Miasm实现了简易的Windows结构模拟(miasm2.os_dep.win_api_x86_32_seh.py)。
该PEB包含了一些有趣的信息,比如通过加载器映射到内存的模块链表信息等。默认情况下,如果启用Windows结构仿真,Miasm将创建一个PEB,其中包含与其加载器相关的虚拟信息。当然,你还可以强制Miasm加载特定模块,并使用它们来创建一致的加载模块链表(参见下文)。
要自动加载所有这些信息,你可以使用类miasm2.analysis.sandbox::Sandbox_Win_x86_32,它以二进制文件的路径作为输入,并设置一个像前面描述的简易环境。一个例子是miasm/example/jitter/sandbox_pe_x86_32.py。
沙盒里运行的PE二进制文件是iexplorer.exe(漏洞攻击的目标),这个二进制文件将作为宿主,Miasm将使用它来构建加载器结构。模块依赖项也将被加载(它们必须存在于./win_dll目录中)。
由于shellcode不与此二进制文件交互,我们还可以加载虚拟二进制文件(如calc.exe)。最后但并非最不重要的是,如果您没有calc.exe,则可以使用elfesteem从shellcode构建有效的可执行文件:
在下一部分中,我们将使用脚本 miasm/example/jitter/sandbox_pe_x86_32.py。此脚本用于加载二进制文件并创建工作环境。以下是默认选项:
在这里,我们感兴趣的选项是:
-s (--usesegm) 启用分段
-y (--use-seh) 启用windows结构仿真(译者注:指仿真PEB结构) (是的,很遗憾选中了这个名字)
-l (--loadbasedll) 可加载任意模块(后面会有详细介绍)
-b (--dumpblocs) 显示块跟踪
如前所述,我们可以强制从默认列表加载库:
我们将修改脚本以加载相关模块,并在shellcode地址处开始执行:
以下是运行此脚本的命令行(此处我们使用box_upx.exe作为宿主):
请注意,你需要新建一个名为win_dll的目录,其中包含所需DLL(例如,Windows XP的目录)。执行输出结果如下:
在这里,Miasm尝试加载所需的模块(ntdll.dll...等)。其中一些存在于win_dll目录下并且已加载,有些则不是。对于那些不存在的,Miasm将创建一个虚拟基地址和虚拟导出地址(0x7111XXXX附近)。接下来,Miasm加载宿主二进制文件(box_upx.exe)。以下是块跟踪的摘录:
下边是从PEB结构中提取导入的部分。shellcode使用函数和DLL哈希值(0xEC0E4E8E 和0x6E2BCA17)查找其依赖项。对于有经验的人来说下边是典型的代码:
此段代码遍历InLoadOrderModuleList链表,并查找名称哈希与提供的哈希匹配的模块。在这种情况下,它将是 kernel32.dll。然后它以相同的方式遍历此模块的导出目录以找到预期的导出。目前,我们无法知道搜索到的函数,但是如果我们查看下一个日志:
我们从jitter得到了一个信息,那就是代码从kernel32模块中调用了LoadKibraryA,这是个解析函数。但是Miasm怎么知道这个?
事实上,每次在内存中加载库时,Miasm都会在每个导出的地址上添加断点,并记住地址和导出名称之间的关系。当模拟程序计数器到达其中一个断点时,模拟将暂停。Miasm随后尝试找到一个Python函数,其名称的格式为:模块名称_模块函数,并调用它。
在这里,我们实现了一组简单的Windows函数,一旦调用,它们将与沙盒里的寄存器/内存上的真实函数具有与相同的效果。例如,如果二进制文件调用rand,我们可以强制其返回值使其更少随机:
这些默认函数在模块miasm2.os_dep.win_api_x86_32中定义 。这是LoadLibraryA的代码:
然后,jitter将恢复执行到新的程序计数器处,并且继续执行,就好像已调用Windows函数一样。这个机制允许我们在Python中编写或模拟任何函数!
顺便说一下,如果为ARM实现前两个辅助程序,则可以使用相同的Python代码在Windows上为此体系结构模拟LoadLibraryA。
请注意,如果要获取模块名称,可以修改脚本以将其记录,或者将断点设置为0x40000076以停止执行并手动检索模块名称。可以这样修改:
现场测试下:
艰难的部分
来看看接下来是什么?报错如下,显然是程序的另一次崩溃!
这里发生了什么?地址0x400002ca处的函数是通过hash解析目标函数的函数。所以代码解析了另一个函数并尝试调用它。顺便说一句,如果你觉得日志输出不是很人性化,您可以添加一些符号来加以改善。
举个例子:
最终输出结果:
这样就比较清晰明朗了。
那现在的问题是什么?Miasm断点断在了函数ole32_CoInitializeEx的内部。不幸的是,此功能未在默认库中实现。但我们真的被困在这里吗?并不是的。如果你阅读了MSDN文档,就会知道此函数用于初始化COM对象,如果一切正常,则返回0x1。那么,让我们在脚本中实现一个简单的功能,是不是感觉这是在使用与架构无关的代码重新实现Windows API?
注意:函数声明位置很重要,必须在沙盒(sandbox)实例化之前调用。这样声明属于globals()。
日志现在是这样的:
OK,现在我们已经成功模拟了这个功能。但还有更多:
shellcode已经解析并调用函数kernel32_VirtualAlloc,该函数已在Miasm库中实现。然后调用另一个函数:
嘿,shellcode似乎根据Windows版本有不同的行为。值得注意的是,使用自定义kernel32_GetVersion将会覆盖Miasm库中定义的函数,因此你可以通过其行为来查看对shellcode的影响。
接下来,又出现了错误:
该脚本尝试解析并执行ntdll_swprintf,这个会有点困难。第一步,让我们只转储格式字符串:
输出结果:
由于格式字符串非常简单,让我们实现swprintf的简化版本:
我们来看看新的输出:
注意:我们故意更改脚本的输出以避免被标记为无效宿主。
这是URLDownloadToCacheFileW函数的简单实现:
这会通知shellcode我们已正确下载二进制文件并将其存储在名为toto的文件中。
这是最后的日志:
看看第一个参数:
shellcode尝试执行刚下载的二进制文件。
结束语
首先,祝贺看到这里的读者:这是一篇很长的文章。我们在不断的尝试中完成了对shellcode的动态分析。同时,你也更加了解了Miasm的内部结构。我承认这对于Miasm新手,学习'成本'有点高,我在写这些台词时再次意识到了这一点,但你最终可能会有一个灵活的工具来进行这样的分析。顺便提一下,你可以尝试修改kernel32_myCreateProcess以使其失败,你会发现shellcode的行为会被改变。这种方法虽然不能作为所有问题解决方案,但它可以帮助进行具体分析。当然已完成的脚本也可用于相同或类似行为的其他shellcode。
作为奖励,在链接存档中有第二个shellcode:试一试!
作者:serpilliere
2016年2月12日
=================================================
译者注:由于本人英文水平及逆向理论知识有限,如果遇到不确定地方,大家可以访问作者原文链接自行推敲:
----> http://www.miasm.re/blog/2016/02/12/dynamic_shellcode_analysis.html <-----
另外,我已经打包了上边链接为mhtml到百度云,参见下边的相关资源。
翻译:flydream
2018年12月10日
文中相关资源:
shellcode:http://www.miasm.re/blog/_downloads/dyn_sc_shellcodes.zip
最终python脚本:http://www.miasm.re/blog/_downloads/dyn_sc_run.py
miasm:https://github.com/cea-sec/miasm
上边的链接如果打不开,访问以下链接:
https://pan.baidu.com/s/1Pq2wZAxfk8u_wVHC0yFVpQ 提取码:ukwg
最后
以上就是完美香氛为你收集整理的使用Miasm动态分析shellcode(翻译)第一次尝试符号执行沙盒模拟深入Shellcode 艰难的部分 结束语文中相关资源:的全部内容,希望文章能够帮你解决使用Miasm动态分析shellcode(翻译)第一次尝试符号执行沙盒模拟深入Shellcode 艰难的部分 结束语文中相关资源:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复