Detecting Breakpoints

gdb通过替换目标地址的字节为0xcc来实现断点, 这里给出一个简单的检测int 3断点的示例:

void foo() {
    printf("Hello\n");
}
int main() {
    if ((*(volatile unsigned *)((unsigned)foo) & 0xff) == 0xcc) {
        printf("BREAKPOINT\n");
        exit(1);
    }
    foo();
}

正常运行程序会输出Hello, 但是如果之前有在foo函数这里设置cc断点并运行, gdb则无法断下, 并会输出BREAKPOINT.

# gdb ./x
gdb> bp foo
Breakpoint 1 at 0x804838c
gdb> run
BREAKPOINT
Program exited with code 01.

这个要绕过也很简单, 那就是需要阅读汇编代码并注意设置断点不要在foo函数入口处. 实际情况就要看检测断点的位置是哪里.

这种监视断点的反调试技术, 关键不在于如何绕过它, 而是在于如何检测它. 在这个示例中可以很轻松的发现, 程序也有打印出相应的信息. 在实际情况中, 程序不会输出任何信息, 断点也无法轻易地断下. 我们可以使用perl脚本过滤反汇编代码中有关0xcc的代码出来进行检查.

我们可以使用perl脚本过滤反汇编代码中有关0xcc的代码出来进行检查

显示结果

检测到后, 既可以将0xcc修改成0x00或0x90, 也可以做任何你想做的操作.

改变0xcc也同样可能带来问题, 就如上篇介绍一样, 程序如果有进行文件校验, 那么我们的改变是会被检测到的. 可能的情况下, 程序也不只是对函数入口点进行检测, 也会在一个循环里对整个函数进行检测.

因此你也可以用十六进制编辑器手动放置一个ICEBP(0xF1)字节到需要断下的位置(而非int 3). 因为ICEBP也一样能让gdb断下来.

Reference: Beginners Guide to Basic Linux Anti Anti Debugging Techniques

Last updated