逆向工程核心原理-11

逆向工程核心原理-第十一章-实战破解reverseme1.exex

运行程序

首先有一个nag(唠叨)窗口

Untitled

点击确认后进入主界面, 点击取消则退出程序

Untitled

目标

  • 首先我们要除去所有的唠叨窗口
  • 我们要破解regcode注册码

目标一 去除唠叨窗口

首先使用OD打开程序

Untitled

我们开始分析: 既然我们现在的目标是去除唠叨窗口, 那我们只用查找所有的对唠叨窗口的调用即可. 所以我们使用右键 → 查找 → 所有模块调用, 即可看到所有模块的调用, 而我们要找的是窗口函数, 即MSVBVM50.rtcMSGBox函数

Untitled

这样一个一个找太麻烦了,

我们点击上方的表目即可(或者右键点排序选项也可以), 按照目标文件排序

Untitled

然后找到了所有的窗口调用, 下完断点后的任务就是找到哪个才是我们目标的唠叨窗口

Untitled

第一个窗口函数

我们要知道的是, 在调用窗口函数之前, 窗口中的内容都会以参数的形式传入窗口函数, 所以我们可以根据参数中的字符串来判断这个窗口是否是我们要找的唠叨窗口, 而参数的传递是在调用函数之前进程了, 所以我们要查看的是调用指令之前的汇编指令

我们向上看指令

Untitled

根据字符串的意思很容易判断出这不是我们要找的唠叨窗口, 所以我们查看下一个

第二个窗口函数

分析跟第一个窗口函数一样, 根据字符串的意思判断出不是唠叨窗口

Untitled

第三个窗口函数, 发现唠叨窗口

根据字符串的意思判断出了这个就是唠叨窗口

Untitled

虽然我们找到了唠叨窗口, 但是注意唠叨窗口可能有两个, 因为在开头的时候有一个唠叨窗口弹出, 在进入主界面的时候也有一个Nag的按钮可以生成一个唠叨窗口, 我们无法判断这两个唠叨窗口是同一个调用还是不同的调用, 所以我们要使用调试来检验.

这是开头进入程序生成唠叨窗口时的位置

Untitled

记录一下位置: 0x402cfe

我们继续调试

再点击完Nag!选项以后, 我们再次观察IP位置

Untitled

位置: 0x402cfe, 跟上面相同, 所以开头的唠叨窗口跟我们点击了Nag!按钮后的函数是同一个.

接下来的任务就是把这个函数去除掉.

我们无法更改msgbox函数本身, 因为是库函数. 所以我们只能修改它的启动函数. 而这里我们又要考虑到修改函数调用需要注意的事项:

  • 栈的处理
  • 返回值
  • 指令大小

必须要保证上述的条件都达到要求才能够骗过处理器, 修改该程序.

栈的处理

要知道该怎么处理栈, 最好的方法就是调试, 看看调用前后ESP的值就能知道了, 静态分析是个费力不讨好的方法, 既要费更多的事件去分析, 还更容易出错, 一般调试用不了的情况下才使用静态分析.

我们来看看调用前的栈情况

Untitled

可以看到ESP的值为0x19f0fc

我们步过一下

Untitled

可以看到从msgbox返回的时候ESP的值为0x19f110

调用前后ESP相差为20(十六进制为0x14).

返回值

我们再来看看返回值, 这里我们要得到的是点击确认后的返回值, 这样才能一直运行程序, 要是我们修改程序改成的是”点击取消”的返回值, 那么程序会直接退出的. 一定要明白返回值对于程序意义重大, 这是直接决定程序走向的东西.

Untitled

在我们点击确认后观察寄存器eax, 可以看到返回值为 1.

指令长度

观察汇编界面

Untitled

占了五个字节, 所以我们修改的总指令长度只能小于等于5, 否则会覆盖掉后面的语句.

我们在这里总结一下, 栈处理我们可以通过sub指令修改ESP来实现, 而返回值我们可以使用mov指令来实现, 但是指令长度这一个条件我们很难实现, 因为一条mov指令需要五个字节, 所以无法在这里修改全部的指令

所以我们需要切换思路, 在调用masbox的函数中无法修改, 那我们就修改调用这个函数的函数.

Untitled

寻找上一级调用的函数

我们向上翻, 查找函数开头的部分, 因为函数调用约定, 在函数调用的起始处将返回地址压入栈中, 而返回地址就是我们要找的上级调用函数.

Untitled

在该处设下断点, 然后开始调试

Untitled

可以看到返回地址为0x7401e5a9

我们ctrl + g将汇编界面跳转至目标地址

Untitled

第一个红框内为调用的启动函数, 第二个红框内为返回的指令

既然找到了上级调用函数, 这时候我们开始做出修改, 但是在这之前我们有两个选择:

  • 在上级调用函数中修改
  • 在被调用的函数中修改

为什么我们之前不用做选择, 因为msgbox无法修改.

我们先看看上级调用函数的能够修改的语句

Untitled

满打满算就只有5个字节, 这里的调用约定好像是在外面恢复esp跟ebp. 只能容下一个mov指令, 那就变成第一次尝试时一样的问题了, 所以我们选择在被调用的函数中修改.

修改还是要注意那三个要点:

  • 栈的处理
  • 返回值
  • 指令长度

栈的处理

还是跟上次尝试一样, 我们下好断点后, 调试观察栈的处理

在调用启动函数之前

Untitled

可以看到ESP的值为0x19f1d0

Untitled

调用后ESP的值为0x19f1d4, 二者相差为4

返回值

观察调用完成后的eax寄存器

Untitled

可以看到返回值为0

指令内存

由于我们是在被调用者中修改指令, 所以整个函数所占据的空间我们都可以修改

Untitled

直接修改成一条指令: RETN 4

但是我们根据前面返回值的判断修改为: MOV RAX, 0

                                                              RETN     4

Untitled

这里要注意的是调用的中间是由一个跳转的, 前面直接F9了, 所以没注意到

Untitled

然后右键 → 复制到可执行文件 → 所有修改 → 全部复制 → 右键 → 保存文件

检验

启动程序后没有弹出唠叨窗口

Untitled

点击Nag?选项也没有弹出唠叨窗口

破解注册码

我们先看看程序的反应

Untitled

这里的思路与上面不同, 因为我们所寻找的是验证部分, 而不是窗口, 所以可以选择比寻找窗口更有效的方法来找到对应错误结果的分支, 使用字符串来查找(因为窗口函数一般有多个, 而特征的字符串只有一个)

我们右键 → 查找 → 所有参考文本字符串

Untitled

找到了上面失败所打印出来的字符串, 双击即可进入字符串出现的汇编地址

进入汇编窗口后我们向上查找, 一般都能找到验证的部分(验证在结果出现之前)

于是找到了可疑的passcode, 我们当然不能断定这就是正确的passcode, 但是试试绝对不亏.

Untitled

验证发现就是正确的passcode

Untitled

文章作者: LamのCrow
文章链接: http://example.com/2022/03/21/ReMain-第十一 2486d/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LamのCrow