实验链接
通过本实验理解ESP原理的操作机理,并掌握使用ESP原理进行脱壳的流程。
链接:http://www.hetianlab.com/expc.do?ce=ec372be3-7a24-4309-838d-92dc0e83869b
实验简介
实验所属系列: CTF竞赛
实验对象: 本科/专科信息安全专业
相关课程及专业: Windows编程,C语言,汇编语言
实验类别: 实践实验类
预备知识
基础的汇编语言命令以及对汇编程序的基本审计能力。
-
壳的概念
加壳的全称应该是可执行程序资源压缩,是保护文件的常用手段。加壳过的程序可以直接运行,但是不能查看源代码。要经过脱壳才可以查看源代码。
加壳是利用特殊的算法,对EXE、DLL文件里的资源进行压缩、加密。类似WINZIP 的效果,只不过这个压缩之后的文件,可以独立运行,解压过程完全隐蔽,都在内存中完成。它们附加在原程序上通过Windows加载器载入内存后,先于原始程序执行,得到控制权,执行过程中对原始程序进行解密、还原,还原完成后再把控制权交还给原始程序,执行原来的代码部分。加上外壳后,原始程序代码在磁盘文件中一般是以加密后的形式存在的,只在执行时在内存中还原,这样就可以比较有效地防止破解者对程序文件的非法修改,同时也可以防止程序被静态反编译。
壳的类型通常分为压缩壳和加密壳两类。压缩壳的特点是减小软件体积大小,加密保护不是重点。加密壳种类比较多,不同的壳侧重点不同,一些壳单纯保护程序,另一些壳提供额外的功能,如提供注册机制、使用次数、时间限制等。 -
Upx
UPX (the Ultimate Packer foreXecutables)是一款先进的可执行程序文件压缩器(压缩壳),压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间、网络上传下载的时间和其它分布以及存储费用。 通过 UPX 压缩过的程序和程序库完全没有功能损失和压缩之前一样可正常地运行,对于支持的大多数格式没有运行时间或内存的不利后果。 UPX 支持许多不同的可执行文件格式 包含 Windows 95/98/ME/NT/2000/XP/CE 程序和动态链接库、DOS 程序、 Linux 可执行文件和核心。–百度百科
-
PEiD
PEiD(PE Identifier)是一款著名的查壳工具,其功能强大,几乎可以侦测出所有的壳,其数量已超过470 种PE 文档 的加壳类型和签名。
-
OllyDbg
OllyDbg(简称“OD”)是由Oleh Yuschuk编写的一款具有可视化界面的用户模式调试器,可以在当前各种版本的Windows上运行,但NT系统架构更能发挥OllyDbg的强大功能。OllyDbg结合了动态调试和静态分析,具有GUI界面,非常容易上手,对于异常的跟踪处理相当灵活。这些特性使OllyDbg成为调试Ring3级程序的首选工具。他的反汇编引擎很强大,可识别数千个被C和Windows频繁使用的函数,并能将其参数注释出来。它会自动分析函数过程,循环语句,代码中的字符串等。此外,开放式的设计给了这个软件很强的生命力。通过爱好者们的不断修改和扩充,OllyDbg的脚本执行能力和开放插件接口使其变得越来越强大。
实验目的
-
理解ESP原理的操作机理。
-
掌握使用ESP原理进行脱壳的流程。
实验环境
服务器:Windows7,IP地址:随机分配
辅助工具:PEiD,OllyDbg
文件及工具下载:http://tools.hetianlab.com/tools/T009.zip
实验步骤
步骤一
黑阔给你发了一份秘密文件,你需要通过逆向分析来获取其中隐藏的信息。你发现通过IDA或者OllyDbg等工具去进行调试总是会存在错误。经过再三的分析你猜测,可能是黑阔给这份软件加了‘壳’。所以,应该怎么去脱去这个讨厌的壳呢。
任务分为3个部分:
-
对加壳和未加壳的文件进行对比分析。
-
在OllyDbg中对文件进行进一步的分析。
-
详细说明两次ESP原理,并且通过ESP原理去进行脱壳。
任务描述:通过各种不同的方式,来对两个加壳和未加壳的文件进行对比,体会两者的差异性。
对加壳软件和不加壳软件进行对比:
左边是没有加壳的,右边是加壳的,明显的发现体积缩小了一大半。
打开PEiD,对两个文件进行进一步的分析:
使用PEiD软件进行查壳仅仅是我们判断一个软件是否带“壳”的第一步。现在,一些商用的软件为了通过加密来保护知识产权,已不满足于ASProtect、ACProtect等这些有名的强壳,这些壳虽加密强度高,对新手来说遥不可及,但因为很多人研究,已经很容易进行手动脱壳。所以这些商家就想到了自行加壳和修改程序入口的特征,这样查壳工具就会显示无壳,但其实还是加了壳的,有时还不止一层壳。具体如何进行软件是否加壳的判断,我们会在后续的实验中不断地进行深入探究。
本次实验以最基础的upx压缩壳来进行示例,目的在于初步普及壳的概念以及如何进行脱壳的思路。经过PEID对比,可以得到加壳前和加壳后的EP段信息以及一些有用的信息(壳的类别等)。
步骤二
任务描述:使用OllyDbg去具体的分析
首先配置Ollydbg程序。
将原版文件下的中文或英文版文件粘贴至该文件目录下,作者使用的汉化版:
点击 选项->界面,选择目录,分别修改源位置和保存文件位置:
重启程序,完成配置。
并不是所有的带壳文件都会报出这样的提示,这里我们为了方便接下来的操作,统一选择否。
载入后的OD界面:
步骤三
任务描述:对ESP原理进行详细的说明,并且通过ESP原理去对目标文件进行脱壳
ESP定律原理:在开始学习ESP定律之前,先了解一些简单的汇编知识。
-
call
这个命令是访问子程序的一个汇编基本指令,从底层原理来看可以这样来理解:
以以下汇编程序为例:
-
向堆栈中压入下一行程序的地址;
-
JMP到call的子程序地址处。
例如:00401029.E8 DA240A00 call 004A3508
0040102E.5A pop edx
在执行了00401029以后,程序会将0040102E压入堆栈,然后JMP到004A3508地址处!
-
-
RETN
与call对应的就是RETN了。对于RETN可以这样来理解:- 将当前的ESP中指向的地址出栈;
- JMP到这个地址。
这个就完成了一次调用子程序的过程。在这里关键的地方是:如果要返回父程序,则当在堆栈中进行堆栈的操作的时候,一定要保证在RETN这条指令之前,ESP指向的是压入栈中的地址。这也就是著名的“堆栈平衡”原理!
-
狭义ESP定律
ESP定律的原理就是“堆栈平衡”原理。
来到程序的入口处看看吧。- 这个是加了ASPACK壳的入口时各个寄存器的值!
EAX 00000000
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 0040D000 ASPACK. - 这个是ASPACK壳JMP到OEP后的寄存器的值!
EAX 004010CC ASPACK.004010CC
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 004010CC ASPACK.004010CC
是不是除了EIP不同以外,eax保存当前OEP值,其他都一模一样啊!
造成这样的结果原因如下:
0040D000 A> 60 pushad //注意这里ESP=0012FFC4
0040D001 E8 00000000 callASPACK.0040D006 //ESP=0012FFA4
PUSHAD就是把所有寄存器压栈!再到壳的最后看看:
0040D558 61 popad //ESP=0012FFA4
0040D559 75 08 jnz short ASPACK.0040D563 //注意这里ESP=0012FFC4
也就是说当我们对ESP的0012FFA4下硬件访问断点之后。当程序要通过堆栈访问这些值,从而恢复原来寄存器的值,准备跳向苦苦寻觅的OEP的时候,OD中断下来。
小结:可以把壳假设为一个子程序,当壳把代码解压前和解压后,他必须要做的是遵循堆栈平衡的原理。
因为大家对ESP理解各有异同,但是,大同小异!一般理解可以为:- 在命令行下断hresp-4(此时的ESP就是OD载入后当前显示的值)
- hr ESP(关键标志下一行代码所指示的ESP值(单步通过))
- 这个是加了ASPACK壳的入口时各个寄存器的值!
总结:
-
ESP定律的原理是堆栈平衡
-
ESP定律的适用范围:几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用。但是在何时下断点避开校验,何时下断OD才能断下来,这还需要多多总结和多多积累。
如果知道壳在什么地方对code段解压完毕,就可以使用内存断点,找到OEP。如果不知道,那么就依靠2次内存断点去找,如果还不行就用多次内存断点。总之明白了原理在多次的内存断点其实都一样。从这个过程中了解的是壳在对区段解码的顺序!
基于ESP原理,可以通过F8步进,注意右面寄存器FPU的显示,当有且只有ESP和EIP为红色时,就可以用ESP定律了:
具体如下,可以右键ESP后面那个地址,然后选择在数据窗口中跟随:
也可以直接在下面的Command窗口中输入dd 0018FF6C 后回车:
这两种方法最终的效果都会在数据窗口中跟随到0018FF6C 这个地址,然后可以右键那一段地址任意HEX设置断点→硬件访问:
这个操作也可以在command窗口输入 HR 0018FF6C 回车后完成,然后按F9运行程序,此时程序会暂停在设置的断点位置:
然后F8单步走,到了jnz位置后不要再按F8了(这是向上跳转的):
用鼠标点击它的下一行然后按F4,后继续F8,让程序强制转到跳转下面继续运行,到达jmp后必须跳过去,此时再次执行F8,因为接下来就有可能是程序的OEP领空。
OEP:程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP)。
一般情况下,跳转之后,在Hexdump列显示55,即为程序的OEP。
找到OEP!
然后就可以脱壳了,脱壳前先把断点清理掉,以免出错【调试→硬件断点→删除】:
然后右击程序当前位置第一行代码,选择OllyDump脱壳调试进程:
然后在弹出的窗口中选择 “脱壳”,然后输入要另存为的文件名:
至此,已经脱壳结束,检查下程序能否正常运行:
比对脱壳后的文件与之前的两个文件的差别与联系:
EP段提示UPX0是因为没有优化区段:
可以点扩展信息来详细看下对比。
脱壳后:
注意:要点下后后面的 “-” 号才能看到具体信息,否则不显示。
未脱壳:
答题
感想
之前学习汇编都是使用debug,纯命令行的一个汇编程序。今天接触了ollydbg,觉得这是一个神仙汇编软件,多窗口,可视化界面非常友好,同样可以单步执行、过程执行,进行命令行跳转等,还可以同时进行数据追踪。多窗口可观察到地址列、汇编语言列、反汇编语言类,以及标志位、寄存器等以及他们的值。
非常良心推荐汇编入门教学,比debug容易上手的多!