use*_*119 6 c linux debugging gdb
我正在学习Linux上的一些反调试技术,并发现了一段代码,用于检查内存中的0xcc字节以检测gdb中的断点.这是代码:
if ((*(volatile unsigned *)((unsigned)foo + 3) & 0xff) == 0xcc)
{
printf("BREAKPOINT\n");
exit(1);
}
foo();
Run Code Online (Sandbox Code Playgroud)
但它不起作用.我甚至试图在foo()函数上设置断点并观察内存中的内容,但没有看到为断点写的任何0xcc字节.这是我做的:
(gdb) b foo
Breakpoint 1 at 0x804846a: file p4.c, line 8.
(gdb) x/x 0x804846a
0x804846a <foo+6>: 0xe02404c7
(gdb) x/16x 0x8048460
0x8048460 <frame_dummy+32>: 0x90c3c9d0 0x83e58955 0x04c718ec 0x0485e024
0x8048470 <foo+12>: 0xfefae808 0xc3c9ffff .....
Run Code Online (Sandbox Code Playgroud)
如您所见,似乎没有在foo()函数的入口点上写入0xcc字节.有谁知道发生了什么或我可能错在哪里?谢谢.
第二部分很容易解释(正如Flortify正确陈述的那样):GDB显示原始内存内容,而不是断点"字节".在默认模式下,它实际上甚至会在调试器挂起时删除断点,并在继续之前重新插入它们.用户通常希望查看其代码,而不是用于断点的奇怪修改指令.
使用您的C代码,您错过了几个字节的断点.GDB 在 函数序言之后设置断点,因为函数序言通常不是gdb用户想要看到的.因此,如果你把break放到foo,那么实际的断点通常会在那之后位于几个字节之后(取决于与函数有关的序言代码本身,因为它可能或者可能不需要保存堆栈指针,帧指针等).但很容易检查.我用过这段代码:
#include <stdio.h>
int main()
{
int i,j;
unsigned char *p = (unsigned char*)main;
for (j=0; j<4; j++) {
printf("%p: ",p);
for (i=0; i<16; i++)
printf("%.2x ", *p++);
printf("\n");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我们自己运行这个程序,它打印:
0x40057d: 55 48 89 e5 48 83 ec 10 48 c7 45 f8 7d 05 40 00 0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6 0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7 0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01
现在我们在gdb中运行它(输出重新格式化为SO).
(gdb) break main Breakpoint 1 at 0x400585: file ../bp.c, line 6. (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep y 0x0000000000400585 in main at ../bp.c:6 (gdb) disas/r main,+32 Dump of assembler code from 0x40057d to 0x40059d: 0x000000000040057d (main+0): 55 push %rbp 0x000000000040057e (main+1): 48 89 e5 mov %rsp,%rbp 0x0000000000400581 (main+4): 48 83 ec 10 sub $0x10,%rsp 0x0000000000400585 (main+8): 48 c7 45 f8 7d 05 40 00 movq $0x40057d,-0x8(%rbp) 0x000000000040058d (main+16): c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp) 0x0000000000400594 (main+23): eb 5a jmp 0x4005f0 0x0000000000400596 (main+25): 48 8b 45 f8 mov -0x8(%rbp),%rax 0x000000000040059a (main+29): 48 89 c6 mov %rax,%rsi End of assembler dump.
有了这个我们验证,该程序正在打印正确的字节.但这也表明断点已插入0x400585(即在函数序言之后),而不是在函数的第一个指令处.如果我们现在在gdb(运行)下运行程序,然后在命中断点后"继续",我们得到这个输出:
(gdb) cont Continuing. 0x40057d: 55 48 89 e5 48 83 ec 10 cc c7 45 f8 7d 05 40 00 0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6 0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7 0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01
现在显示0xcc被打印为地址9字节到main.
| 归档时间: |
|
| 查看次数: |
1242 次 |
| 最近记录: |