加壳脱壳笔记
脱壳存根(stub)
脱壳存根执行了以下三个步骤:
(1)将原始程序脱壳到内存中
(2)解析原始可执行文件的所有导入函数
(3)将可执行程序转移到原始的程序入口点(OEP)
手动查找OEP
查找尾部跳转指令
-
最简单的手动查找策略就是查找尾部跳转指令,当脱壳存根开始运行时,尾部跳转指令跳转的地址不包含有效指令,但是一旦原程序运行就肯定包含有效的指令。
-
另一种查找尾部跳转的方法是在栈上设置读断点。要设置读断点,必须使用硬件断点,或一个OllyDbg内存断点来实现。
这种方法应用在ESP定律法中:
(1) 首先step-over,直到esp的值产生变化,记录下esp值
(2)在命令中用dd,在数据窗口中跟随记录下的地址
(3)然后在该地址设置硬件断点,可以用命令hr xxxxxx
(4)F9执行程序,然后step-over到达程序的OEP
-
另一种查找尾部跳转的策略是在GetProcAddress函数设置断点。多数脱壳器会使用GetProcess函数来解析原始函数的导出表。在该函数上设置断点可以使你绕过脱壳存根的开头代码。
- 在原始程序调用且继续向后工作的函数上设置断点。
查找OEP
-
一种手动查找OEP的策略是在代码中每个循环后面设置断点。
-
调用GetModuleHandleA和GetVersion函数的开始地址就是OEP。
- 使用OllyDbg的RunTrace选项
手动修复导入表
导入表在内存中实际上有两个表:
- 函数名称或者序号列表,其中包含加载器或脱壳存根所需要的函数名称或者序号
- 所有导入函数的地址列表。
常见的壳
UPX、ASPack、Petite、WinUpack(Upack)、Themida
脱壳exe和dll的区别
-
DLL中的OEP是DllMain原始函数的开始地址,加壳DLL列出的开始地址是脱壳存根中的一个地址。 打开PE文件,定位到IMAGE_FILE_HEADER节的特征标志域,如果IMAGE_FILE_HEADER节0x2000处的比特位为1,则表示这个PE文件是DLL,为0表示是一个可执行文件。
-
exe的入口点只在开始时执行一次,而dLL的入口点在整个执行过程中至少执行两次,一次是在开始,另一次是在退出时,用来清理dll再退出。
OllyDump为什么能通过跨段找到OEP:
通常,脱壳存根在一个节里,而可执行程序被打包到另一节中,使用step-over或者step-into方法,当程序从一个节跳转到另一个节运行时,OllyDbg可以探测到这种转移,并且在那里进行中断。step-over方法跳过所有call指令,然而如果一个call函数没有返回,那么OllyDbg将会定位到OEP。
pushA指令:用来存在寄存器的栈地址,在这些地址上设置硬件断点
popAD指令:调用该指令时会触发设置的硬件断点,此时就能在不远的地方找到OEP(在尾部跳转之前会有一个popad或者popfd指令)
课后习题
Lab18-1:直接找到尾部跳转(JMP),然后找到OEP
Lab18-2:利用插件(find oep by section hop(Trace Over))
Lab18-3:插件无法利用,查找可能的尾部跳转(查找指令retn),设置硬件断点,但是没有命中断点。找到程序开头处pushFD和pushAD,在esp第一次改变的地址上设下硬件访问断点。
Lab18-4:和实验三一样的思路
Lab18-5:用ctrl+G定位,在LoadLibrary和GetProcAddress上设置断点,单步执行直到找到OEP