25

在我以前的雇主中,我们使用了一个第三方组件,它基本上只是一个 DLL 和一个头文件。该特定模块在 Win32 中处理打印。但是,制造该组件的公司破产了,所以我无法报告我发现的错误。

所以我决定自己修复错误并启动调试器。我很惊讶地发现反调试代码几乎无处不在,通常IsDebuggerPresent是这样,但引起我注意的是:

    ; some twiddling with xor 
    ; and data, result in eax 
    jmp eax 
    mov eax, 0x310fac09 
    ; rest of code here 

乍一看,我只是跳过了被调用两次的例程,然后事情就变得一团糟。过了一会儿,我意识到位旋转的结果总是一样的,即 jmp eax 总是直接跳到mov eax, 0x310fac09指令中。我剖析了这些字节,它是用于测量 DLL 中一些调用之间所用时间0f31的指令。rdtsc

所以我的问题是:你最喜欢的反调试技巧是什么?

4

10 回答 10

27

我最喜欢的技巧是为一个不起眼的微处理器编写一个简单的指令仿真器。

然后将为微处理器编译复制保护和一些核心功能(GCC 在这里很有帮助)并作为二进制 blob 链接到程序中。

这背后的想法是,普通 x86 代码中不存在复制保护,因此无法反汇编。您也不能删除整个模拟器,因为这会从程序中删除核心功能。

破解程序的唯一机会是对微处理器仿真器的功能进行逆向工程。

我使用 MIPS32 进行仿真,因为它很容易仿真(只需要 500 行简单的 C 代码)。为了让事情变得更加模糊,我没有使用原始的 MIPS32 操作码。相反,每个操作码都与它自己的地址进行异或。

复制保护的二进制文件看起来像垃圾数据。

强烈推荐!花了 6 个多月的时间才出现破解(这是为了一个游戏项目)。

于 2009-02-21T15:08:01.723 回答
6

我一直是许多 RCE 社区的成员,并且在黑客和破解方面有过相当的份额。从那时起,我就意识到这种脆弱的技巧通常是不稳定的,而且是徒劳的。大多数通用的反调试技巧都是特定于操作系统的,根本不是“可移植的”。

在上述示例中,您可能正在使用内联汇编和naked函数__declspec,在 x64 架构上编译时,MSVC 不支持这两者。当然仍然有实现上述技巧的方法,但是任何已经反转足够长的时间的人都可以在几分钟内发现并击败该技巧。

所以一般来说,我建议不要在利用IsDebuggerPresentAPI 进行检测之外使用反调试技巧。相反,我建议您编写存根和/或虚拟机。我编写了自己的虚拟机,并且多年来一直在改进它,老实说,这是迄今为止我在保护我的代码方面做出的最好的决定。

于 2009-02-21T14:46:18.233 回答
6

分拆作为调试器附加到父进程的子进程并修改关键变量。保持子进程驻留并使用调试器内存操作作为某些关键操作的一种 IPC 的奖励积分。

在我的系统上,您不能将两个调试器附加到同一个进程。

关于这一点的好处是,除非他们试图篡改任何东西,否则不会破坏任何东西。

于 2009-02-21T16:50:20.197 回答
4

引用未初始化的内存!(和其他黑魔法/伏都教......)

这是一个非常酷的读物: http ://spareclockcycles.org/2012/02/14/stack-necromancy-defeating-debuggers-by-raising-the-dead/

于 2012-02-28T18:39:06.780 回答
3

最现代的混淆方法似乎是虚拟机。

基本上,您获取目标代码的一部分,并将其转换为您自己的字节码格式。然后添加一个小型虚拟机来运行此代码。正确调试此代码的唯一方法是为您的 VM 指令格式编写模拟器或反汇编程序。当然你也需要考虑性能。过多的字节码会使您的程序运行得比本机代码慢。

大多数旧技巧现在都没用了:

  • Isdebuggerpresent :非常蹩脚且易于修补
  • 其他调试器/断点检测
  • Ring0 的东西:用户不喜欢安装驱动程序,你实际上可能会破坏他们系统上的某些东西等。
  • 每个人都知道的其他琐碎的东西,或者使您的软件不稳定的东西。请记住,即使破解使您的程序不稳定但它仍然有效,这种不稳定将归咎于您。

如果您真的想自己编写 VM 解决方案(有很好的程序出售),请不要只使用一种指令格式。使其具有多态性,这样您就可以使代码的不同部分具有不同的格式。这样一来,您的所有代码都无法通过仅编写一个仿真器/反汇编器来破坏。例如,一些人提供的 MIPS 解决方案似乎很容易被破坏,因为 MIPS 指令格式有据可查,并且像 IDA 这样的分析工具已经可以反汇编代码。

IDA pro反汇编器支持的指令格式列表

于 2009-02-21T15:21:21.597 回答
3

我更希望人们编写可靠、可靠并能按照广告宣传的方式编写软件。他们还以合理的价格和合理的许可证出售它。

我知道我已经浪费了太多时间与那些拥有复杂许可方案的供应商打交道,这些方案只会给客户和供应商带来问题。我始终建议避免使用这些供应商。在核电站工作,我们被迫使用某些供应商的产品,因此不得不处理他们的许可计划。我希望有一种方法可以找回我个人浪费的时间来处理他们为我们提供工作许可产品的失败尝试。这似乎是一件小事,但对于那些为了自己的利益而变得过于棘手的人来说,这似乎是一件困难的事情。

于 2009-02-21T16:32:11.583 回答
2

我支持虚拟机建议。我实现了一个 MIPS I 模拟器,它(现在)可以执行使用 mipsel-elf-gcc 生成的二进制文件。添加到代码/数据加密功能(AES 或您选择的任何其他算法)、自我模拟能力(因此您可以拥有嵌套模拟器)并且您拥有一个非常好的代码混淆器。

选择 MIPS I 的好处是 1) 它易于实现,2) 我可以用 C 编写代码,在我的桌面上调试它,并在完成后将它交叉编译为 MIPS。无需调试自定义操作码或为自定义 VM 手动编写代码。

于 2009-02-21T15:01:54.343 回答
2

我个人最喜欢的是 Amiga,它有一个协处理器(Blitter),独立于处理器进行大数据传输;该芯片将被指示清除所有内存,并从定时器 IRQ 复位。

当您连接 Action Replay 磁带时,停止 CPU 将意味着 Blitter 将继续清除内存。

于 2012-03-09T07:21:45.750 回答
1

我最喜欢在看起来合法但真正隐藏实际指令指令的中间计算跳转。无论如何,它们很容易被人类检测到,但自动化工具经常把它搞砸。

替换堆栈上的返回地址也很浪费时间。

于 2009-02-21T16:13:50.083 回答
0

使用nop通过调试器删除程序集是一个有用的技巧。当然,放回代码要困难得多!!!

于 2009-02-21T14:33:15.330 回答