安全中国首页 > 文章中心 > 基础知识
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

13.5.1 寻找OEP(图)

更新时间:2008-8-23 1:24:30
责任编辑:阿loosen
热 点:

第13章 脱壳技术

任何事物都有两面性,有加壳,就必有脱壳。加壳与脱壳有着紧密的联系,一些脱壳技术是针对加壳而产生的,脱壳的进步,又迫使加壳软件不断创新发展。现在越来越多的软件都加壳保护,脱壳有时是分析一个软件不可缺少的步骤。

……略……

13.5  DLL文件脱壳

DLL是Dynamic Link Library(动态链接库)的缩写形式,是一个共享函数库的可执行文件。DLL文件的脱壳与EXE文件步骤差不多,DLL文件多了个基址重定位表等要考虑。

13.5.1  寻找OEP

当DLL被初次映射到进程的地址空间中时,系统将调用DllMain函数,当卸载DLL时也会再次调用DllMain函数。也就是说,DLL文件相比EXE文件运行有一些特殊性,EXE的入口点只在开始时执行一次,而DLL的入口点在整个执行过程中至少要执行两次。一次是在开始时,用来对DLL做一些初始化。至少还有一次是在退出时,用来清理DLL再退出。

工作,如IAT初始化等。退出时再次进入入口点时,外壳将跳过相关的初始化代码,这时程序代码流程会短些。所以找OEP也有两条路可以走,一是载入时找,二是在退出时找,退出时流程短些,相对来说更容易找到OEP。

用第16章编写的加壳工具对实例EdrLib.dll进行加壳处理。用LordPE查看其PE信息,获得EntryPoint为D000h,ImageBase为400000h,区块的信息如图13.41所示。

 
图13.41  查看区块信息
DLL本身不能直接执行,但可以调用LoadLibrary将DLL的文件映像映射到调用进程的地址空间中,退出时调用FreeLibrary卸载DLL。为了调试DLL,OllyDbg提供了一个类似原理的辅助程序loaddll.exe,这个程序被压缩存放在资源段里,如果OllyDbg所在文件夹内没有loaddll.exe,则会释放这个文件。用OllyDbg打开DLL,将会询问启动loaddll.exe,如图13.42所示。然后链接库被加载并停在程序的入口(ModuleEntryPoint),现在就可以正常调试DLL程序了。
 
(点击查看大图)图13.42  提示是否启动loaddll.exe
OllyDbg加载EdrLib.dll将停在外壳代码第一行。细心的读者会发现,此时EdrLib.dll并没有被映射到默认的400000h内存地址中,而是选择了另一个地址。按“Alt+M”键打开内存映像窗口,将会发现EdrLib.dll被映射到地址E20000h,如图13.43所示。
 
(点击查看大图)图13.43  查看DLL被映射的地址

注意:由于DLL被映射的地址是由系统动态分配的,因此在读者系统中显示的地址可能与本书不同,操作时以当前系统基址为准。下面将忽略所有基地址注释,读者操作时以实际的映像地址来操作。

外壳的入口代码如下:

00E2D000  pushad
00E2D001  call    00E2D0C8                      
……
00E2D0C9  sub     ebp, 6
00E2D0CF  mov     eax, dword ptr [ebp+C0]  ;[ebp+C0]是一个计数器变量,此时为0
00E2D0D5  or      eax, eax     ;如果是0,表示首次加载,将执行初始化代码
00E2D0D7  je      short 00E2D0E0               
00E2D0D9  push    ebp                          ;dll文件退出时走这里
00E2D0DA  jmp     dword ptr [ebp+C4]
00E2D0E0  inc     dword ptr [ebp+C0]   ;[ebp+C0]计数器变量加1
此时可以按正常的思路跟踪代码寻找OEP,由于DLL退出时也会来到入口一次,本例演示一下DLL退出时寻找OEP的过程。先在外壳的入口00E2D000处按F2键设置一个断点,按F9键数次让DLL跑起来,DLL装载成功后,loaddll.exe将出现如图13.44所示的界面。
 

13.44  加载DLL成功后的界面

然后将如图13.44所示的窗口关闭,DLL将被卸载,将再次中断在外壳的入口点处。
00E2D000  pushad                        ;退出时,会再次来到这里
00E2D001  call    00E2D0C8                      
……
00E2D0C9  sub     ebp, 6
00E2D0CF  mov     eax, dword ptr [ebp+C0]   ;[ebp+C0]的值此时是1
00E2D0D5  or      eax, eax     
00E2D0D7  je      short 00E2D0E0               
00E2D0D9  push    ebp                      
00E2D0DA  jmp     dword ptr [ebp+C4]
00E2D0E0  inc     dword ptr [ebp+C0]      ;dll文件退出时将走这条线路
来到外壳代码的第二段,这段是解压还原、初始化原程序,为避免重复初始化,第二次进入入口点后将会跳过这些初始化代码。
003E0000  call    003E0005
003E0005  pop     edx
003E0006  sub     edx, 5
003E0009  pop     ebp
003E000A  mov     eax, dword ptr [edx+359]   ;计数器变量
003E0010  or      eax, eax
003E0012  je      short 003E001A
003E0014  popad
003E0015  jmp     0E21240                  ;dll退出时从这里进入OEP
跳过外壳初始化代码后,将直接到OEP处。
003E0283  push    0E21240   
003E0288  retn                              ;返回到OEP,即1240h(RVA值)

此时,OEP的RVA值 = E21240 h-映像地址=E21240 h-E20000h = 1240h。

技巧:一般加壳软件用同一套外壳代码处理EXE和DLL,因此在处理EXE文件时,外壳里也有判断是不是多次加载的代码,找到这些跳转,强行改变,这样程序虽不能运行,但能很快定位到OEP相关的代码。

OllyDbg加载某些外壳的DLL文件,不能正常地暂停在外壳的入口点,会直接运行起来。碰到这种情况,可以将外壳的入口点改成死循环,机器码是EBFEh。一个示例如下:

 00401000 EB FE           jmp     short 00401000

OllyDbg加载修改后的DLL,由于入口死循环,OllyDbg的CPU窗口显示白屏,按F12键让OllyDbg暂停即可看到代码,再将入口代码恢复成原指令,又可单步调试了。详细操作见光盘映像文件中动画演示。

·上一篇: 9.2.1 PE结构的扩展(2)(图)
·下一篇: 暂时空缺
 
相关文章
一日一文章
 
一日一软件
一日一动画