一般的压缩壳,如Aspack等都有专用的脱壳机 。而加密壳(如ASProtect,Armadillo) 一般很少有脱壳机,必须手工脱壳。手工脱壳一般情况是分三步:一是查找程序的真正入口点(OEP);二是抓取内存映像文件;三是输入表重建。(当然现在的加密壳复杂些,要考虑更多的东西)
OEP是Original Entry Point缩写,即程序加壳前的真正的入口点。
外壳初始化的现场环境(各寄存器值)与原程序的现场环境是相同的。加壳程序初始化时保存各寄存器的值,外壳执行完毕,会恢复各寄存器内容。其代码形式一般如下:
PUSHFD ; 将标志寄存器入栈保存
PUSHAD ; push eax, ecx, edx, ebx, esp, ebp, esi, edi
…… ; 外壳代码部分
POPAD ; pop edi, esi, ebp, esp, ebx, edx, ecx, eax
POPFD ; 恢复标志寄存器
JMP OEP ;
OEP: …… ; 解压后的程序原代码
为了讲述方便,本节用UPX加壳的Win98记事本来演示。首先用PEid查看加壳前的记事本:
PEid显示Notepad.exe程序是用Microsoft Visual C++ 6.0编译的,接下来用UPX来加壳,方法是开个DOS窗口,用命令upx notepad.exe。如下图所示:
这时再用PEid查看加壳的文件,PEid会给出如下信息:UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo
UPX的壳可以用UPX.exe自身来脱,命令是:upx -d 文件名 。一些变种的UPX壳用UPX.EXE自身脱不了,这时可以试试UPX ShellEx 这款工具。
本节实例下载:notepad.upx.rar
脱壳前建议用PE工具LordPE打开目标文件查看一下区块,以尽可能地多了解一些信息,对脱壳有帮助,如下图:
1.根据跨段指令寻找OEP
推荐用Ollydbg来调试脱壳,比SoftICE和TRW2000方便多了。运行Ollydbg,点击菜单“选项/调试设置”,将第一次暂停设在WinMain函数上。再用Ollydbg打开实例notepad.upx.exe就可中断在外壳的入口点处了:
上图相关代码如下:
0040E8C0 > 60 pushad //一开始Ollydbg就会中断这行,这个就是外壳的入口点,注意这个pushad指令
绝大多数加壳程序在被加密的程序中加上一个或多个段,所以依据跨段的转移指令(JMP)就可找到真正的入口点,此时就会有POPAD/POPFD指令出现。UPX 用了一次跨段的转移指令(JMP),在跳到OEP处会看到虚拟地址的值有一个突变,此时就能确定OEP了。
UPX壳比较简单,大家不必要跟踪去找这个跨段的转移指令,中断WinMain后,只需要在Ollydbg里往下翻屏,就会发现这个跨段转移指令:
上图相关代码如下:
0040EA0E 61 popad //注意这里的popad指令,和开始的pushad对应
0040EA0F - E9 B826FFFF jmp 004010CC //这里跳到OEP,将光标移到这,按F4执行到这行
这一句0040EA0F jmp 004010CC 就是跳到OEP的指令,执行到这,UPX外壳己将程序解压完毕,并模拟Windows加载器的将原始程序加载到内存,004010CC 就是映射到内存目标程序的入口点,此时就可抓取内存映像文件了。
2.根据堆栈平衡原理找OEP
这个堆栈平衡原理其找OEP原理这篇文档描述的比较详细:寻找真正的入口(OEP)--广义ESP定律 作者:Lenus
操作方法:多数壳在运行到OEP的时候ESP=0012FFC4,这就是说程序的第一句是对0012FFC0进行写入操作,只要在0012FFC0下硬件写入断点(命令行里键入HW 12FFC0),我们就能停在OEP的第二句处。
注意:并不是所有程序加载时,ESP的值是0012FFC4,这个值是什么由操作系统决定,将SizeOfStackCOmmit改大ESP就会变,这是因为操作系统从这个页向上找一个足够大地方当作stack了(感谢forgot解释)。你只要记住你系统加载时的ESP值,对其设断即可。
用OllyDBG重新加载实例程序notepad.upx.exe,在命令行下硬件写断点:
按F9执行程序,就会中断在OEP第二行:
此时如果将光标向上移,会发现第一句代码变乱了:
004010C7 000D 0A000055 add [5500000A], cl
004010CD 8BEC mov ebp, esp
这是因为Ollydbg将数据当汇编代码来分析了,你可以按 Ctrl+ALT+向上光标键 将当前显示的代码向上滚动一个字节就可看到正确的汇编代码了:
004010CC 55 push ebp
004010CD 8BEC mov ebp, esp //中断在这行
004010CF 83EC 44 sub esp, 44
004010D2 56 push esi
004010D3 FF15 E4634000 call [4063E4] ; kernel32.GetCommandLineA
中断后,别忘点击菜单“调试/硬件断点/”打开硬件断点面板,将刚才的硬件断点删除。
小知识: 硬件断点的原理 作者:Lenus
3.根据编译语言特点找OEP
各类语言编译的文件入口点都有一些规律,可以这利用这点来寻找入口点。
1)Delphi程序
执行程序,用LordPE(或Prodump)选dump(full)脱壳,存为dump.exe。接着用Hex Workshop打开dump.exe,搜索文本“runtime”,搜到后,向前查找离“runtime”最近的十六进制数字“55 8B EC”,数字所在的地址就是程序的OEP。
2)Visual C程序
可以利用Visual C启动部分的几个函数GetCommandLineA(W)、GetVersion、GetModuleHandleA(W)、GetStartupInfoA(W) 等来定位程序的OEP。
常见的各类编译语言的入口汇编代码都要熟悉,因为一些加密强壳会偷OEP处的代码到壳里,一般情况各编译语言入口代码都相同,到时只需要直接引用相关程序的入口代码,这给我们恢复代码带来方便。
分享到:
相关推荐
### 常见寻找OEP的方法 在软件逆向工程领域,寻找原始入口点(Original Entry Point,简称OEP)是一项基本且重要的技能。对于初学者来说,掌握正确的技巧能够大大提高效率并减少不必要的麻烦。本文将详细介绍几种...
寻找真正的入口(OEP)--广义ESP定律
我们可以利用OD的Debugging options-SFX功能,选择Trace real entry blockwise(inaccurate)来尝试找到OEP。不过,有时OEP可能被"stolen bytes"所影响,这是壳层用来混淆真实入口点的一种技术。 要找到stolen bytes...
广义ESP定律是逆向工程师在实践中总结的一种方法,用于在PE文件的混淆或自我保护机制下寻找OEP。定律的核心思想是利用ESP寄存器的变化来定位程序执行流程中的关键点,例如函数调用、异常处理等。通过跟踪ESP的变化,...
在手动脱壳的过程中,需要寻找OEP(Original Entry Point),即程序的原入口点。OEP是壳程序在完成了对原程序的还原后,开始跳转到刚还原的程序执行的地址。寻找OEP的方法有多种,例如单步跟踪法、堆栈平衡法等。 ...
本文将重点介绍查壳与寻找OEP的技巧。 ##### 1. 查壳 查壳是指识别出软件是否被加壳及其类型。常见的查壳工具包括File Identifier(FI)与Portable Executable Identifier(PEiD)。然而,有时候这些工具可能无法识别...
它允许在内存访问特定地址时中断程序执行,通常用于检测特定内存区域的变化,比如在寻找OEP时,可以在壳代码可能读取或修改的地址设置内存断点。内存断点的原理涉及到处理器的调试寄存器DR0-DR7,它们用于监视内存...
- **寻找OEP**:原始入口点是未加壳代码开始执行的位置。识别OEP是脱壳的关键步骤。通常,通过观察`PUSHAD`和`POPAD`指令可以定位到OEP附近。 #### 使用OllyDbg进行脱壳 OllyDbg是一款强大的动态调试工具,广泛...
【标签】"finder HumanOEPFinder" 指出这个工具的核心功能是寻找OEP,并且与"HumanOEPFinder"这个名字紧密相关。这可能是一个命令行工具或者图形用户界面应用,为用户提供查找OEP的便捷方法。 【压缩包子文件的文件...
6. **静态分析**:对于更复杂的文件,可能需要静态分析PE文件的汇编代码,寻找调用或跳转指令,来确定OEP。 7. **计算OEP**:结合动态和静态分析的结果,最终确定OEP的准确位置。 这个VC++ 6.0工程可能包含了一个...
- 加载时查找:在DLL首次加载时寻找OEP。 - 卸载时查找:利用DLL卸载时的流程简短特性来更轻松地确定OEP。 #### 实例分析 以下是对EdrLib.dll文件进行脱壳的具体步骤: 1. **使用工具加壳**:首先使用专门的工具...
1. **寻找OEP(原始入口点)** - **PUSHAD**指令通常用来保存寄存器的状态,在程序入口处使用较为常见,因此可以作为一个初步定位OEP的方法之一。 - **POPAD**指令用于恢复寄存器状态,通常与PUSHAD成对出现,可以...
3. **特征码匹配**:脚本利用特征码匹配的方法来寻找OEP。特征码是预先定义的一段二进制模式,可以通过查找这些模式来识别特定的代码段或函数。 ```assembly findopeip, #7301# findopeip, #C3# findopeip, #...
寻找OEP的方法多种多样,但通常基于以下几种思路: - **ESP定律**:由于加壳过程中通常会对堆栈进行操作,因此可以通过观察ESP寄存器的变化来推测OEP。 - **API调用**:有些壳会在解压后调用一些特定的API(如...
14. 程序脱壳简介(第14章)解释了什么是加壳,如何加载加壳文件,文件和内存占用分析,STUB和OEP的概念,寻找OEP,API函数的使用,脱壳后数据库的保存,以及通过执行断点寻找OEP的方法。 15. 转存并重建导入函数表...
在OllyDbg中寻找OEP通常是逆向工程师的首要任务,因为它是理解程序执行流程的关键。编写特定的OllyDbg脚本可以自动化这一过程,帮助用户快速定位到OEP,即使在面对复杂的保护机制如Themida时也是如此。这通常涉及到...
2. **寻找OEP(Original Entry Point)**: - OEP是程序未经保护时的入口点,通过单步调试找到`JNZ`和`JMP`指令的组合,接着在`JMP`处下断点,运行到`JNZ`后,继续调试直至到达OEP,并记录其地址。 3. **配置脚本*...
这种方法适用于寻找OEP。首先定位到`pushad`指令,然后通过单步执行,观察ESP的变化。当ESP指向的数据段中出现灰色部分时,通常意味着到达了OEP。此时可以通过设置硬件访问断点,跟踪到具体位置。 ##### 2. ESP定律...
逆向工程师通常会寻找这个点来分析程序的执行流程。然而,加壳技术通过改变OEP的位置和添加额外的保护层,使得这个过程变得更加复杂。 ACProtect的加壳机制是基于动态地址计算的,它不直接硬编码OEP到壳代码中,...
5. **寻找OEP**:到达`POPFD`指令后,继续单步执行直至遇到`RETN`指令,之后一步即可到达OEP。 6. **Dump程序**:在找到OEP后,使用调试器的功能dump程序,但此时运行dump出的程序会出错,因为还需要修复IAT。 7. **...