返回介绍

第二十四章 - OllyDbg 反调试之综合 CrackMe

发布于 2025-01-31 21:06:57 字数 14201 浏览 0 评论 0 收藏 0

在我们介绍异常处理之前,我们先把上一章留下的 antisocial1 这个反调试的综合练习讲解一下。

这是一个加过壳的程序,当然,我们还没有介绍壳的相关知识点,我们只需要知道该程序加载到内存中以后,壳会解密原区段的各个区段的数据,然后跳转到原入口点(OEP) 处执行原程序的代码。当外壳程序解密/解压还原并跳转到 OEP 处,此时的内存映像就是已解压/解密过的程序,这个时候将内存映像抓取并保存为文件即可(该过程称之为 Dump)。

首先我们用之前重命名过的 OD,并且带上之前介绍过的所有插件,运行起来,我们会发现程序会终止,我们来尝试修复它。

好了,现在我们用重命名过的 OD 加载 antisocial,将反反调试插件的选项都勾选上。

该提示表明该程序可能被加壳了,我们选择”是”按钮,然后就停在了入口点处。

这里我们会看到一些奇怪的东西,POPAD 指令,该指令是从堆栈中恢复各个寄存器的值。正常情况下,应该是首先 PUSHAD 保存各个寄存器的值,而这里并没有执行 PUSHAD 指令,就比较可疑了。

我们运行起来看看会发生什么。

这里

这里提示错误-PUSH 指令尝试压栈,但是这里没有写权限,但是通常来说堆栈应该是具有写权限的。我们来看一看堆栈。

当前栈顶指针指向的是 130000,我们重新启动程序。

我们可以看到当前各个区段的情况,我的机器上堆栈是从 12C000 开始,到 12FFFF 结束。而现在操作是以 130000 起始的内存,它并不是堆栈,并没有写权限,所以会报错。

我们再次来到发生错误的地方。

我们可以看到该程序执行了另一个 POPAD 指令,接着就是条件跳转指令 JNZ 跳转到产生异常的 PUSH 的指令处,我们给 POPAD 指令这一行设置一个断点。

现在,我们重新运行该程序让其断在该断点处。

我们现在来看下堆栈。

当前栈顶指针还属于堆栈的范围,紧接着执行 POPAD 指令。

当前栈顶指针已经超出了堆栈的范围,这是由刚刚的 POPAD 指令导致的,正常情况下来说应该是一开始执行 PUSHAD 指令将各个寄存器的值保存到堆栈中,然后才是执行 POPAD 指令将堆栈的值恢复到各个寄存器中。好了,我们现在将开始处的 POPAD 指令替换成 PUSHAD 指令看看会发生什么,我们重新启动该程序。

我们按下空格键。

我们输入 PUSHAD。

现在我们运行起来,断在了第二个 POPAD 指令处。

但此时的堆栈情况如下:

此时执行 POPAD 指令堆栈并不会越界,我们按 F8 键单步看看。

我们可以看到堆栈并没有越界。

我们到达了 PUSH 指令处,紧接着是 RET,我们按 F8 键单步步过 PUSH 和 RET 指令。

好了,这里的 OD 分析有点问题,OD 将这部分代码当做数据解释了。

这里,我们单击鼠标右键选择 Analysis-Remove analysis from module。现在代码开起来正常了吧,我们运行起来看看会发生什么。

程序终止了。我们查看一下日志信息,可以看到一些有趣的东西。

我们可以看到断在了 POPAD 指令处,然后就发生了异常。

我们重新启动程序,重复前面的步骤再次来到这里。

为了让程序发生异常可以停下来,我们去掉忽略所有异常的选项,第一个选项还是保持勾选。

运行起来。

就像刚刚日志中描述的一样,发生异常停了下来。

INT 68 指令是少数 OD 无法处理的异常之一。我们直接使用 NOP 指令填充即可。

另外,该程序里面可能还存在其他 INT 68 指令会对我们进行干扰,我们直接搜索 INT 68 指令,将其填充为 NOP 即可。

我们可以看到找到了另一个 INT 68 指令,我们直接 NOP 掉。

再次搜索,又找到了一个,继续 NOP 掉。

我们继续 CTRL + L 搜索,提示搜索结束,找不到其他的 INT 68 指令了,我们运行起来。

以上是我们使用了带反反调试插件的 OllyDbg 调试的情况,现在我们尝试使用不带插件的原版的 OllyDbg 1.0 来调试,手动来绕过该反调试。

(PS:odbg110 FINAL sin plugins:表示不带插件的 OllyDbg)

我们打开不带反反调试插件的 OllyDbg,由于命令栏插件我们还是需要的,所以我们将插件目录指定为只包含命令栏插件的目录。

我们可以看到这里面只有一个命令栏插件,我们运行 OD。

还是跟之前一样,将 POPAD 指令替换成 PUSHAD 指令。

我们还是给后面的 POPAD 指令设置断点,运行起来看看是否会断下来。

我们到了壳解压完毕处。

我们清空掉所有的忽略异常的选项,当我们运行起来,遇到 INT 68 指令时,将其 NOP 掉。而并不是使用 SHIFT + F9 忽略异常。

现在我们来看看程序中使用了哪些 API 函数。

还有一点就是别忘了勾选这个选项:

选择了该选项后,就会显示我们当前所在区段的相关信息。

该列表中显示没有几个 API 函数,并没有看到什么可疑的,但是这里有个 GetProcAddress,该程序可以通过 GetProcAddress 函数来加载其他 API 函数,我们给该函数设置一个断点。

我们运行起来。

这个函数没什么可疑的,我们继续运行,直到断在了比较可疑的函数处。

这里我们看到了第一个可疑的 API 函数 CreateToolhelp32Snapshot,该函数给当前运行的所有进程创建快照。我们执行到返回,这时,EAX 保存的就是 CreateToolhelp32Snapshot 函数的首地址了,我们接着使用 BP EAX 命令给该 API 函数设置断点。

别忘了给该 API 函数添加上注释。

好了,我们继续运行。

这里是 Toolhelp32ReadProcessMemory 这个函数,跟 CreateToolhelp32Snapshot 类似,同上,我们给该函数也设置一个断点。

继续运行。

给 Process32First 这个函数也设置一个断点。

同上。

现在断在了创建进程快照处,我们知道该处的检测 OD 是基于这个进程快照的,该进程快照包含了进程列表中所有进程的相关信息,我们可以尝试 patch 这个函数,让该函数返回的快照句柄为空,现在我们来到 CreateToolhelp32Snapshot 这个函数的返回处。

我们可以看到这里有一些空余的空间,我们可以在返回之前将 EAX 赋值为零。

这样 CreateToolhelp32Snapshot 这个函数返回的快照句柄就为空了,该程序就不能通过进程快照来检测 OD 了。当然我们还有另一种方式-修改主程序中的代码,而并不修改 CreateToolhelp32Snapshot 的实现代码。

按 F8 键单步跟踪,我们可以看到这里有个 JNZ 条件跳转指令会跳转至 TerminateProcess 处结束掉 OD 进程。OD 的进程句柄在之前通过 OpenProcess 获取。我们可以看到这里有五个分支判断。

这里我们将这几处 JNZ 指令修改为 JMP 指令,这样就可以避免程序执行 TerminateProcess 结束掉 OD 进程。

这样反调试的第一个部分我们就搞定了,现在我们来解决反调试的第二个部分,我们运行起来。

我们停在了 INT 68 指令处,我们将该 INT 68 指令用 NOP 指令填充掉,然后运行起来会发生程序终止了。

如果我们加载 HideDebugger1.23f 插件,并勾选上 FindWindows/EnumWindows 选项,然后重复之前的步骤会发现运行的很正常。

刚刚导致 OD 终止的地方是这里。

我们跟进都这个 CALL 4047F0 里面。

这里,我们可以看到比较指令。

这里当比较出是 OllyDbg 的话,就会终止掉当前进程。这里我们为了避免 JNZ 条件跳转指令不成立进而去调用下面的 CALL 4532CC 结束掉进程,我们将该 JNZ 指令修改为 JMP 指令。

这里将该关键跳转修改为 JMP 指令。

我们再来看看我们绕过的第二个 CALL 指令里面具体是怎么结束进程的。

该 CALL 指令里面是调用 PostQuitMessage 退出主线程。

好了,现在你可能会问了,你是怎么定位上面那个 JNZ 473305 关键跳转的呢?很简单。

我们按照之前的步骤干掉了该反调试的第一部分以后,就可以给 PostQuitMessage 这个 API 函数设置一个断点。

断在了该 API 函数处,我们看下堆栈,看看该调用来至哪里。

堆栈中信息显示该调用来至于 4532D7 处,我们定位到该地址。

这里说明前面的 JE 指令跳转没有发生,进而调用 PostQuitMessage,这里如果我们继续执行 PostQuitMessage 话,程序就退出了,所以这里我们直接在堆栈中查看返回地址是多少。

这里我们可以看到返回地址为 473305。

好了,这里我们就比较熟悉了,我们可以将 4732F7 处的 JNZ 指令修改为 JMP 指令,避免让该程序执行下面的 CALL 中 PostQuitMessage 结束掉进程。这样我们就手工的解决这个反调试,并没有借助反反调试插件。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文