几个名词解释:
1.POSHAD:将32位通用寄存器压入堆栈,压栈顺序为EAX ECX EDX EBX ESP EBP ESI EDI。
2.POPAD:与POSHAD对应,将32位通用寄存器移出堆栈,顺序相反。
3.OEP:(Original Entry Point) 程序的真正入口地址。
常用的几种方法:
1.单步跟踪 2.ESP定律脱壳 3.内存跟踪 4.跟踪出口法 5.最后一次异常法 6.模拟跟踪法
方法一:单步跟踪
1.原理:壳的特点是在原程序运行前得到控制权限,等壳运行完毕后,在将控制权交给原程序。即加壳程序的入口点是壳程序的入口点,单步跟踪实际就是从壳的入口点一步步运行到原程序的入口点即(OEP)的过程。
2.过程:OD载入—单步步过(F8)或步入(F7)—遇到程序往回跳(红色跳转线向上跳转),选择下一行,右键右健单击代码点断点(p)选运行到选定位置(F4)或直接F4—遇到运行到某个CALL程序就运行的,就在这个CALL中步入(F7)—遇到大跨段跳转或关键词(jmp XXXXXX 或者 JE XXXXXX 或者有RETN、POPAD、RETN等)一般很快就会到程序的OEP。
3.技巧:近CALL F7 远CALL F8(用法可通过比较call的目标地址和当前地址的差值区分是否为变形Jmp,若两者的差值很小,一般为变形Jmp,用F7步入。若用F8步过,程序将运行,直接导致跟踪失败;若两者差值较大,应F8步过,若再F7步入,被调用函数执行完毕时将返回到CALL的下一行,浪费大量的时间和精力。F8步过主要应用在压缩壳中,F7步入在加密壳中被大量使用) 。大跨段一般跳到OEP处(由于壳程序是在原程序编译完成后添加而成,故不在相同的区段中,若要实现从壳程序到原程序的转换过程必定需要一个段间跳转来实现,而JMP******;JE******;RETN等正是具有这样功能的语句。)无法跳出循环或程序跟到某处必定跑飞(运行)时,应在附近寻找到一个向下的较远跳转,回车跟到跳转处;并下INT3断点,F9运行到该位置,然后继续跟踪。
4.局限性:若壳程序的入口点和原程序的入口点距离较远,单步到OEP将耗费大量时间;但由于单步跟踪是模拟程序在内存中运行的顺序逐条语句执行的,在理论上已充分证明其可行性。
方法二: ESP定律法
1.原理:ESP定律是堆栈平衡原理在实践中的一个应用。所谓堆栈平衡原理,即加壳程序运行时,需要先保存原程序的初始现场,将现场状态压入堆栈,待壳运行完毕后,将原程序的现场状态出栈,此时开始运行原程序。在具体应用时,通过记录堆栈寄存器存储原程序初始现场状态的地址,并使程序在为将初始状态出栈而访问以记录的地址时中断,程序中断处便在OEP附近。
2.过程:OD载入—单步看寄存器中ESP首次变化—右键寄存器ESP行,数据窗口中跟随(或在命令行下:dd 0012FFA4(0012FFA4指在当前代码中的ESP地址按回车)—在数据窗口选中ESP地址行右键断点(P)、硬件访问、字(或在命令行下:hr 0012FFA4(0012FFA4指在当前代码中的ESP地址按回车)—运行(F9)—单步步过(F8)—OPE。
3.局限性:几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用。
方法三: 内存镜像法
1.原理:程序运行需要先对各个区段进行解码,即将壳的代码写入到原程序的代码段中,然后在从原程序的代码段中读取代码并执行。若找到一个code段已解压完毕但又未开始执行的地址并让它中断下来,当再次对CODE段下内存访问断点时,就可以停在原程序code段的第一条指令的位置上,而这个位置正是原程序的入口点。一般程序解压都是按照地址从低到高的顺序对原程序的各个段进行解压。所以在实际的应用过程中,是通过首先在内存镜像中地址高于code段的其他段上下INT3断点,运行程序后再在code段下INT3断点,运行程序后将中断在OEP处。
2.过程:OD载入—设置OD忽略所有异常—打开内存镜像(Alt+M)或点快捷键“M”—对首个“资源”(.rsrc)下INT3断点(F2)—运行(F9)—再打开内存镜像(Alt+M)—对首个“代码”(.code)下INT3断点—运行(F9)—OEP。
3. 技巧:可以选用忽略异常运行Shift+F9
4.局限性:若壳在JMP到OEP前的一行代码仍在对code段解压,该方法将不在适用。
方法四:跟踪出口法(快速查找法)
1.原理:此法实为ESP定律的实际应用,即压栈原程序初始状态后,再一次访问堆栈寄存器,并将所存数据出栈后,将运行原程序,并跳到原程序入口处,即OEP。
2.过程:OD载入—打开查找命令(Ctrl+F),输入“popad”,开始查找—单步步过(F8)直到附近出现大跨段时下断(F2)—运行到此(F9)—从大跨段跳走后—OEP。
3.局限性:只使用于少数壳,如UPX和ASPACK。不过经使用,发现一些其他的壳也是可以用此方法的,如北斗壳(Nspack)在第一个CALL步入后,即可使用此法。
方法五:最后一次异常法
1.原理:加密壳有反跟踪代码,许多SEH陷阱使OD调试时产生异常,当壳程序执行完毕后,将没有异常。若Shift+F9略过所有异常,并找到最后一次异常处,再在恢复异常处(即SE句柄处的地址)下断,OEP即在附近。
2.过程:OD载入—调试选项,异常,勾全部去掉—重载(Ctrl+F2)—略过所有异常运行(Shift+F9)—直到程序运行,记下按Shift+F9的次数n—重载(Ctrl+F2)—按Ctrl+F9(n-1)次—在OD堆栈栏看见有一SE句柄,按CTRL+G,输入SE句柄前的地址—下断点(F2)—略过所有异常运行(Shift+F9—去掉断点(F2),按F8慢慢向下走—OEP。
3.技巧:对于程序Shift+F9后直接退出,说明壳检测调试器,可以通过OD插件隐藏OD的方法来解决。
4.局限性:由于普通压缩壳Od调试时候没有异常,该方法只适用于加密壳。
方法六:模拟跟踪法
1.过程:试运行、跟踪程序,检查是否存在SEH暗桩—ALT+M打开内存镜像,找到标志项目(包含=SFX,imports,relocations)。
内存镜像,项目 30
地址=0054B000
大小=00002000 (8192.)
Owner=check 00400000
区段=.aspack
包含=SFX,imports,relocations
类型=Imag 01001002
访问=R
初始访问=RWE
—在命令行输入tc eip<0054B000(该项目所在的地址),回车—单步—OEP。
2.技巧:不同版本的OD,标志项目的标志有可能不同,区别在于译者如何翻译。
3.局限性:有的没有标志项目,无法跟踪。
方法七:“SFX”法
1:设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
2:切换到SFX选项卡,选择“字节模式跟踪实际入口(速度非常慢)”,确定。
3:重载程序(如果跳出是否“压缩代码?”选择“否”,OD直接到达OEP)