在我以前的雇主,我们使用了第三方组件,它基本上只是一个DLL和一个头文件。该特定模块在Win32中处理打印。然而,制造该组件的公司破产了,所以我无法报告我发现的错误。
所以我决定自己修复bug并启动调试器。我很惊讶地发现几乎无处不在的反调试代码,通常IsDebuggerPresent
,但引起我注意的是:
; some twiddling with xor
; and data, result in eax
jmp eax
mov eax, 0x310fac09
; rest of code here
乍一看,我刚刚跨过了两次叫做的例程,然后事情就变成了香蕉。过了一会儿,我意识到比特结果总是一样的,即jmp eax总是直接跳到mov eax, 0x310fac09
指令。
我解剖了字节,0f31
指的是rdtsc
指令,用于测量DLL中某些调用之间的时间。
所以我的问题是:你最喜欢的反调试技巧是什么?
答案 0 :(得分:27)
我最喜欢的技巧是为一个不起眼的微处理器编写一个简单的指令仿真器。
然后将为微处理器编译复制保护和一些核心功能(GCC在这里是一个很好的帮助),并作为二进制blob链接到程序中。
这背后的想法是,普通的x86代码中不存在复制保护,因此无法进行反汇编。您无法删除整个模拟器,因为这会从程序中删除核心功能。
破解程序的唯一机会是对微处理器仿真器的工作进行逆向工程。
我使用MIPS32进行仿真,因为它很容易模拟(只需要500行简单的C代码)。为了使事情变得更加模糊,我没有使用原始的MIPS32操作码。相反,每个操作码都与它自己的地址xor'ed。
复制保护的二进制文件看起来像垃圾数据。
强烈推荐!在裂缝出现之前花了超过6个月(这是一个游戏项目)。
答案 1 :(得分:6)
我一直是许多RCE社区的成员,并且已经公平地分享了黑客攻击行为。开裂。从我的时间开始,我意识到这种脆弱的技巧通常是不稳定的,而且相当无用。大多数通用的反调试技巧都是特定于操作系统的,根本不是“可移植的”。
在前面提到的示例中,您可能使用内联汇编和naked
函数__declspec
,这两种函数在x64架构上进行编译时都不受MSVC支持。当然,仍然有办法实现上述技巧,但任何已经反转足够长时间的人都可以在几分钟内找到并击败这个技巧。
因此,我建议不要在使用IsDebuggerPresent
API进行检测之外使用反调试技巧。相反,我建议您编写存根和/或虚拟机的代码。我编写了自己的虚拟机并且已经改进了很多年了,我可以诚实地说,到目前为止,它是迄今为止我在保护代码方面做出的最佳决定。
答案 2 :(得分:6)
将附加到父级的子进程分离为调试器&修改关键变量。用于保持子进程驻留并使用调试器内存操作作为某种键操作的IPC的加值点。
在我的系统上,您无法将两个调试器连接到同一进程。
关于这个问题的好处是,除非他们试图篡改任何事情,否则没有任何损失。
答案 3 :(得分:4)
参考未初始化的内存! (和其他黑魔法/ vodoo ......)
这是一篇非常酷的读物: http://spareclockcycles.org/2012/02/14/stack-necromancy-defeating-debuggers-by-raising-the-dead/
答案 4 :(得分:3)
最现代的混淆方法似乎是虚拟机。
您基本上可以获取目标代码的某些部分,并将其转换为您自己的字节码格式。然后添加一个小型虚拟机来运行此代码。正确调试此代码的唯一方法是为VM的指令格式编写仿真器或反汇编程序代码。当然,你也需要考虑性能。太多的字节码会使您的程序比本机代码运行得慢。
现在大多数旧技巧都没用了:
如果您真的想自己编写VM解决方案(有很好的销售程序),请不要只使用一种指令格式。使其具有多态性,以便您可以让代码的不同部分具有不同的格式。这样,只需编写一个模拟器/反汇编程序就无法破解所有代码。例如,一些人提供的MIPS解决方案似乎很容易被破解,因为MIPS指令格式已有详细记录,IDA等分析工具已经可以对代码进行反汇编。
List of instruction formats supported by IDA pro disassembler
答案 5 :(得分:3)
我希望人们能够编写可靠且可靠的软件并完成广告宣传的软件。他们还以合理的价格以合理的许可证出售它。
我知道我浪费了太多时间处理那些只会给客户和供应商带来问题的复杂许可方案的供应商。我始终建议避开这些供应商。在核电站工作,我们被迫使用某些供应商的产品,因此被迫必须处理他们的许可计划。我希望有一种方法可以回到我个人浪费时间处理他们未能给我们提供有效许可产品的尝试。这似乎是一个小问题,但对于那些因自己的利益而过于棘手的人来说似乎是一件困难的事情。
答案 6 :(得分:2)
我是第二个虚拟机建议。我实现了一个MIPS I模拟器,它现在可以执行使用mipsel-elf-gcc生成的二进制文件。添加到代码/数据加密功能(AES或您选择的任何其他算法),自我模拟的能力(因此您可以使用嵌套模拟器),并且您有一个非常好的代码混淆器。
选择MIPS I的一个很好的功能是:1)它易于实现,2)我可以用C编写代码,在桌面上调试代码,并在完成后只为MIPS交叉编译。无需调试自定义操作码或手动编写自定义VM的代码..
答案 7 :(得分:2)
我个人最喜欢的是Amiga,那里有一个协处理器( Blitter ),独立于处理器进行大量数据传输;将指示该芯片清除所有存储器,并从定时器IRQ复位。
当您连接动作重放盒式磁带时,停止CPU将意味着Blitter将继续清除内存。
答案 8 :(得分:1)
在合法的外观中计算跳跃,但真正隐藏了实际的指令指令是我的最爱。无论如何,它们很容易被人类检测到,但是自动化工具经常搞砸它。
同样替换堆栈上的返回地址可以节省时间。
答案 9 :(得分:0)
使用nop通过调试器删除程序集是一个有用的技巧。当然,放回代码要困难得多!!!