OD的基本使用2 - demo修改

A00

ODBG110: https://pan.baidu.com/s/1VklVhE7wH7qrEW2OOLElqw 提取码:uuhg
ODBG110BasicPlugins: https://pan.baidu.com/s/1QG0ealpvKTTtjd26U9himQ 提取码:6fym
ODBG Very More Plugins: https://pan.baidu.com/s/1VQoodK3ArkiGYzJazUToiw 提取码:daoo
[教程]使用OllyDbg从零开始Cracking: https://pan.baidu.com/s/1l094huv-bQvka-QOhgNhhg 提取码:65jv

了解软件

我们直接运行打开CRACKME.EXE文件进行注册,随机输入用户名和注册码,点击注册,软件报错,序列号不对,好吧,这才是正常的逻辑。现在尝试着修改软件,使我们输入任意的用户名和序列号,均通过验证。

A01

程序弹出验证错误的消息框,调用的是系统的 MessageBoxA 方法,其它软件应该也是类似的吧。

消息框的标题是“No luck!”,文本是“No luck there, mate!”。

以上这是我们已知的重要信息,也是我们破解的关键地方。

开始破解

使用OD打开CRACKME.EXE,界面如下:

A02

我们通过插件Command Bar(位于OD最下方)对消息弹窗函数 MessageBoxA() 加断点,断点的位置位于该函数的第一个指令处,这意味着如果程序遇到调用该函数的指令,会在跳转到该函数所在的内存区域后停留在第一个指令处。

加断点的命令为:bp MessageBoxA

A03

加断点后点击B按钮查看断点标记情况,可以看到背景自动变灰的哪一行就是我们上一步加断点的地方。

A04

我们可以看出,MessageBoxA() 函数的一些基本信息:

  • 该函数存储的位置为 750F8700 到某个未知位置
  • 该函数的代码位于 USER32 模块中
  • 该函数的第一个指令是 MOV EDI, EDI

我们在该条目上右键选择 Follw in Disassembler 或者直接按回车键进入该函数存储的指令区域。

A05

如下图,指令区域跳转至 750F8700 处并自动高亮显示。第一列地址处红色高亮,说明此处添加了断点。

我们往下数直到第一个 RETN 出现的区域为 MessageBoxA() 函数的内存区域。

A06

如果我们此时执行程序,程序会运行到端点处暂停,因为没有实际执行 MessageBoxA() 函数,所以不会有注册成功或者注册失败的消息弹出。

第一次按下 F9 会跳转到 00401000,这个位置是程序执行的入口。

再次按下 F9 运行程序。

A07

此时弹出了一个笑脸窗口,这个就是模拟软件的主窗口。

同时我们观察 EIP = 777BA8FC,说明程序并未执行到我们设置的断点(750F8700)处,为什么呢?因为执行 MessageBoxA() 函数的前提是进行注册,而注册是用户手动完成的。因此我们需要在模拟软件中手动注册。

点击 Help 按钮选择注册,这里我们特定随机输入用户名“123qwe”,密码为“asdzxc”,点击 OK。

接着OD中程序暂停在我们设置的断点上,注意此时 EIP = 750F8700。A08

观察堆栈的信息:

  • 当前栈顶位置为 0019FDB8,存储在寄存器 ESP 中
  • 当前子程序执行完之后会跳回到 004013C1
  • 程序是从 004013BC 跳转到当前断点位置的,004013BC 处进行了 MessageBoxA() 函数的调用(CALL)
  • 在调用 004013BC 处的 MessageBoxA() 函数之前,该函数的参数也被压入栈中。调用该函数提供了四个参数,分别是 Style, Title, Text, hOwner。观察它们的值可以发现,调用这个函数将会告诉用户注册失败。

A09

我们在栈顶位置右键选择 Follw in Disassembler 或者直接按回车打开 004013BC 处调用 MessageBoxA() 函数的位置A10

指令区域显示的并不是 004013BC 处调用 MessageBoxA() 函数的位置,而是调用结束后跳转继续执行的位置 004013C1

A11

滑动滚轮或者拉动滑条,观察 004013C1 上面的几行命令

A12

004013C1 处调用了 MessageBoxA() 函数,该函数需要的参数在 004013AD ~ 004013B9。

可以预见的是,程序会在这里调用 MessageBoxA() 函数,对我们输入的注册码做出回应,并且告诉我们很遗憾。

那么是什么导致程序会选择在这里调用 MessageBoxA() 函数呢?

因为指令都是按顺序执行的,我们去 004013C1 上面找寻答案。

A13

因为 004013AD ~ 004013BC 是在定义 MessageBoxA() 函数的参数和调用,我们点击它们上面的 POP ESI,哎,我们在下面的信息栏中发现了一条重要信息:“Jump from 0040138B”,说明 POP ESI 指令从 0040138B 跳转而来,并且之后继续执行了 MessageBoxA() 函数。

我们跳转到 0040138B 位置,查看附近的指令:

A14

0040138B 是一条 JB 跳转指令,而且在它的上面有这么一条 CMP AL, 41 指令。这表示:当前仅当寄存器 AL 的值 小于 41 时才会跳转到 004013AC 处执行 POP ESI 和调用 MessageBoxA() 函数。

那如果不管 CMP AL, 41 的结果如何,下面都不进行跳转是不是就不会弹出让人遗憾的消息框了?

这里我们将 CMP AL, 41 篡改成 CMP AL, AL ,这使得 JB 跳转永远不会执行。

双击 CMP AL, 41 指令即可修改。修改后结果如下:

A15

第二列变为红色字体,表示改行经过修改;指令也已经发生变化。

按下 F9 执行程序,弹出消息框:

A16

呀,还是注册不通过~

按下“确定”按钮,OD中程序中又暂停在了 750F8700 的位置,是不是有点眼熟这个位置?

A17

唯一不同的在这个地方:

A18

这表示有两个不同的地方调用了 MessageBoxA() 函数,一个是 004013BC,一个是 00401378。

前者我们已经解决了,后者是新出现的。

这表示有两个甚至多个验证方法检查我们的注册信息,而且明显 004013BC 处的检查排在 00401378 前面。

下面跳转到 00401378 附近:

A19

我们逐级向上检查,发现在 00401362 的 PUSH 0 处出现了 “Local call from 00401245”,接着调用了另一个USER32库中的函数 MessageBeep,然后就调用了即将给我们抛出遗憾信息的 MessageBoxA 函数。

我们跳转到 00401245:

A20

这里首先比较了 EAX 和 EBX 的值,然后根据比较结果进行跳转:

  • 如果相等,JE 指令被执行,跳转到 0040124C 执行 CALL ~.0040134D
  • 如果不等,JE 指令不执行,直接执行 CALL ~.00401362
  • 不管怎样,最终都会跳转到 004011E6

我们知道,如果 EAX 和 EBX 的值如果不相等,程序就会跳转到 00401362 继续执行,从而调用 MessageBoxA 函数使用户感到遗憾。那么如果 EAX 和 EBX 的值如果相等会怎么样?0040134D 又是什么东西?我们定位到 0040134D 瞅一下:

A21

我们可以看到,0040134D ~ 0040135C 区域依然在单纯地调用 MessageBoxA 函数,只是函数参数变得善良了,也就是说,这块区域只有在我们的注册信息有效的前提下才会被调用。而下面的 00401362 ~ 00401378 区域恰好是我们我们注册信息不通过会被执行的指令。

回到 00401245:

A20

如果我们使 00401241 处的 CMP 结果恒成立会怎么样?例如 CMP EAX, EAX

那么此时,不管我们怎么输注册信息,都只会跳转 0040134D 执行注册成功的信息。

修改后的结果如下:

A22

这个模拟程序对注册信息进行了两次验证,我们也进行了两次修改,从而屏蔽掉了有效性检查。

保存成果

修改完成后在指令窗口的任意位置右键选择 Copy to executable 中的 All modifications:

A23

选择 Copy all:

A24

弹出了一个新的指令集页面:

A25

该页面内任意位置右键选择 Save file:

A26

重命名例如 CRACKME2.EXE,保存即可A27

关闭OD,验证破解成果。

>>>>>>>>>>>>> 转载请注明出处 <<<<<<<<<<<<<
0%