《逆向工程核心原理》读书笔记——第15章 调试UPX压缩的notepad程序

  本章将调试UPX压缩的notepad_upx.exe程序, 进一步了解运行时压缩的相关概念。我们的目标是通过调试一点点地跟踪代码, 最终找出原notepad.exe程序代码。 最后再简单讲解一下经过UPX压缩的文件如何通过调试器。
提示
  本章示例使用的是Windows XP SP3中的notepad.exe程序。

15.1 notepad.exe的EP代码

  首先看一下原notepad.exe程序的EP代码, 如图15-1所示。
在这里插入图片描述

图15-1 notepad.exe的EP代码

  在010073B2地址处调用了GetModuleHandleAO API,获取notepad.exe程序的lmageBase。然后在010073B4与010073CO地址处比较MZ与PE签名。希望各位熟记原notepad.exe的EP代码。

15.2 notepad_upx.exe的EP代码

  使用OllyDbg打开notepad_upx.exe时, 弹出图15-2所示的警告消息框。
在这里插入图片描述

图15-2 OllyDbg警告消息框

  调试器判断该文件为压缩文件, 在“是”与“否"中任选一个, 显示出UPX EP代码, 如图15-3所示。
在这里插入图片描述

图15-3 notepad_upx.exe的EP代码

  EP地址为01015330, 该处即为第二个节区的末端部分。 实际压缩的notepad源代码存在于EP地址(01015330) 的上方。
  下面看一下代码的开始部分(01015330)。

01015330 > $  60            pushad
01015331   .  BE 00100101   mov esi,notepad_.01011000
01015336   .  8DBE 0000FFFF lea edi,dword ptr ds:[esi-0x10000]

  首先使用PUSHAD命令将EAX~EDI寄存器的值保存到栈 , 然后分别把第二个节区的起始地址(01011000)与第一个节区的起始地址(01001000)设置到ESI与EDI寄存器。UPX文件第一个节区仅存在于内存。该处即是解压缩后保存源文件代码的地方。
  调试时像这样同时设置ESI与EDI,就能预见从ESI所指缓冲区到EDI所指缓冲区的内存发生了复制。此时从Source(ESI)读取数据, 解压缩后保存到Destination(EDI)。我们的目标是跟踪图15-3中的全部UPX EP代码,并最终找到原notepad的EP代码,如图15-1所示。
提示
  •代码逆向分析称源文件的 EP为OEP。
  •“跟踪”一词的含义是通过逐一分析代码进行追踪。
  •实际的代码逆向分析中并不会逐一跟踪执行压缩代码, 常使用自动化脚本、 特 殊技巧等找到 OEP。 但是对于初次学习运行时压缩文件的朋友而言, 逐一跟踪代码才是正确的学习方法。

15.3 跟踪UPX文件

  下面开始跟踪代码, 跟踪数量庞大的代码时, 请遵循如下法则。
"遇到循环(Loop)时, 先了解作用再跳出。”
  整个解压缩过程由无数循环组成。因此,只有适当跳出循环才能加快速度。

15.3.1 OllyDbg的跟踪命令

  跟踪数量庞大的代码时,通常不会使用Step Into(F7)命令,而使用OllyDbg中另外提供的跟踪调试命令, 如表15-1所示。

表15-1 OllyDbg的跟踪命令
命 令快捷键说 明
Animate IntoCtrl+F7反复执行Step Into命令(画面显示)
Animate OverCtrl+F8反复执行Step Over命令(画面显示)
Trace IntoCtrl+F11反复执行Step fnto命令(画面不显示)
Trace OverCtrl+Fl2反复执行Step Over命令(画面不显示)

  除了画面显示的之外,Animate命令与跟踪命令是类似的,由于Animate命令要把跟踪过程显示在画面中,所以执行速度略徵慢一些。而两者最大的差别在千,跟踪命令会自动在事先设置的跟踪条件处停下来,并生成日志文件。在UPX文件跟踪中将使用Animate Over(Ctrl+F8)命令。

15.3.2 循环#1

  在EP代码处执行An皿ate Over(Ctrl+F8)命令,开始跟踪代码。 可以看到光标快速上下移动。
  若想停止跟踪,执行Step Into(F7)命令即可。
  开始跟踪代码不久后, 会遇到一个短循环。 暂停跟踪, 仔细查看相应循环,如图15-4所示。
在这里插入图片描述

图15-4 第一个循环

  循环次数ECX=36B,循环内容为“从EDX(01001000)中读取一个字节写入EDI(01001001)”。
  EDI寄存器所指的01001000地址即是第一个节区(UPXO)的起始地址,仅存在与内存中的节区(反正内容全部为NULL)。
  调试经过运行时压缩的文件时,遇到这样的循环应该跳出来。在010153E6地址处按F2键设置好断点后,按F9跳出循环。

15.3.3 循环#2

  在断点处再次使用Animate Over(Ctrl+F8)命令继续跟踪代码 ,不久后遇到图15-5所示的循环(比前面那个循环略大一些)。
在这里插入图片描述

图15-5 第二个循环

  该循环是正式的解码循环(或称为解压缩循环)01015348-010153FD,这个循环包含了循环#1。
  先从ESI所指的第二个节区(UPXl)地址中依次读取值,经过适当的运算解压缩后,将值写入EDI所指的第一个节区(UPXO)地址 。该过程中使用的指令如下:

0101534B   .  8807          mov byte ptr ds:[edi],al
0101534D   .  47            inc edi                                  ;  notepad_.01014D58
……
010153E0   .  8807          mov byte ptr ds:[edi],al
010153E2   .  47            inc edi                                  ;  notepad_.01014D58
……
010153F1   .  8907          mov dword ptr ds:[edi],eax
010153F3   .  83C7 04       add edi,0x4
* 解压缩后的数据在AL(EAX)中,EDI指向第一个节区的地址.

  只要在01015402地址处设置好断点再运行, 即可跳出第二个循环,如图15-5所示。运行到01015402地址后,在转储窗口中可以看到解压缩后的代码已经被写入第一个节区(UPXO)区域(01007000),如图15-5中原来用NULL填充的区域:
在这里插入图片描述

15.3.4 循环 #3

  重新跟踪代码,稍后会遇到图15-6所示的第三个循环。
在这里插入图片描述

图15-6 第三个循环

  该段循环代码用于恢复源代码的CALL/JMP指令(操作码:E8/E9)的destination地址:
在这里插入图片描述

  从地址01001000到01001829逐字节sub al,0xE8,之后在01015434继续循环loopd short notepad_.0101540F跳转到0101540F。
在这里插入图片描述

  在01015436地址处设置断点运行后即可跳出循环。到此几乎接近尾声了,只要再设置好IAT,UPX解压缩代码就结束了。
提示
  对于普通的运行时压缩文件 ,源文件代码、数据、资源解压缩之后,先设置好IAT再转到OEP。

15.3.5 循环 #4

  重新跟踪代码,再稍微进行一段。
  图15-7深色显示的部分即为设置IAT的循环。 在01015436地址处设置EDI=Ol014000, 它指向第二个节区(UPXl)区域,该区域中保存着原notepad.exe调用的API函数名称的字符串(参考图 15-8)。
在这里插入图片描述

图15-7 第四个循环

在这里插入图片描述

图15-8 API名称字符串

  UPX压缩原notepad.exe文件时, 它会分析其IAT , 提取出程序中调用的API名称列表,形成API名称字符串。
  用这些API名 称字符串调用图15-7中01015467地址处的GetProcAddress()函数,获取API的起始地址,然后把API地址输入EBX寄存器所指的原notepad.exe的IAT区域。该过程会反复进行至
API名称字符串结束,最终恢复原notepad.exe的IAT。
  notepad.exe全部解压缩完成后,应该将程序的控制返回到OEP处。图15-9显示的就是跳转到OEP的代码。
在这里插入图片描述

图15-9 JUMP to OEP

  另外,010154AD地址处的POPAD命令与UPX代码的第一条PUSHAD命令对应,用来把当前寄存器恢复原状(参考图15-3)。
  最终,使用010154BB地址处的JMP命令跳转到OEP处,要跳转到的目标地址为0100739D ,
  它就是原notepad.exe的EP地址(请各位确认)。

15.4 快速查找UPX OEP的方法

  各位都像上面这样顺利完成代码跟踪了吗?代码逆向技术的初学者一定要亲自试试,这有助于调试用其他压缩器压缩的文件。但每次都使用上述方法(跳出循环)查找OEP非常麻烦,实际代码逆向分析中有一些更简单的方法可以找到OEP(以UPX压缩的文件为例)。

15.4.1 在POPAD指令后的JMP指令处设置断点

  UPX压缩器的特征之一是,其EP代码被包含在PUSHAD/POPAD指令之间。并且,跳转到OEP代码的JMP指令紧接着出现在POPAD指令之后。只要在JMP指令处设置好断点,运行后就能直接找到OEP。
提示
  •PUSHAD指令将8个通用寄存器(EAX~EDI)的值保存到栈。
  •POPAD指令把PUSHAD命令存储在栈的值再次恢复到各个寄存器。

15.4.2 在栈中设置硬件断点

  该方法也利用UPX的PUSHAD/POPAD指令的特点。在图15-3中执行01015330地址处的PUSHAD命令后,查看栈,如图15-10所示。
在这里插入图片描述

图15-10 执行PUSHAD指令后栈的情况

  EAX到EDI寄存器的值依次被存储到栈。从OllyDbg的Dump窗口进入栈地址(006FFA4)。将鼠标光标准确定位到6FFA4地址,使用鼠标右键菜单设置硬件断点,如图15-11所示。
在这里插入图片描述

图15-11 硬件断点

  硬件断点是CPU支持的断点,最多可以设置4个。与普通断点不同的是,设置断点的指令执行完成后才暂停调试。在这种状态下运行,程序就会边解压缩边执行代码,在执行POPAD的瞬间访问设置有硬件断点的0006FFA4地址,然后暂停调试。其下方即是跳转到OEP的JMP指令(熟悉该方法的操作原理才能在以后调试各种文件时得心应手)。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值