我正在尝试修改以下C程序,使得主函数跳过printf("x is 1")语句,只打印"x is 0"。
void func(char *str) {
char buffer[24];
int *ret;
ret = buffer + 28; // Supposed to set ret to the return address of func
(*ret) += 32; // Add the offset needed so that func will skip over printf("x is 1")
strcpy(buffer, str);
}
int main(int argc, char **argv) {
int x;
x = 0;
func(argv[1]);
x = 1;
printf("x is 1");
printf("x is 0");
getchar();
}
正如评论所示,ret指针需要首先设置为函数的返回地址。然后我需要添加一个偏移量,将其推移到我想要跳过的行。我正在使用2 x Intel(R) Xeon(TM) CPU 3.20GHz的Linux系统运行此代码。我使用gcc版本4.7.2 (Debian 4.7.2-5)进行编译。我还尝试使用此链接(http://insecure.org/stf/smashstack.html)中的example3.c作为参考。以下是使用gdb对主函数进行反汇编的结果:
Dump of assembler code for function main:
0x0000000000400641 <+0>: push %rbp
0x0000000000400642 <+1>: mov %rsp,%rbp
0x0000000000400645 <+4>: sub $0x20,%rsp
0x0000000000400649 <+8>: mov %edi,-0x14(%rbp)
0x000000000040064c <+11>: mov %rsi,-0x20(%rbp)
0x0000000000400650 <+15>: movl $0x0,-0x4(%rbp)
0x0000000000400657 <+22>: mov -0x20(%rbp),%rax
0x000000000040065b <+26>: add $0x8,%rax
0x000000000040065f <+30>: mov (%rax),%rax
0x0000000000400662 <+33>: mov %rax,%rdi
0x0000000000400665 <+36>: callq 0x4005ac <func>
0x000000000040066a <+41>: movl $0x1,-0x4(%rbp)
0x0000000000400671 <+48>: mov $0x40075b,%edi
0x0000000000400676 <+53>: mov $0x0,%eax
0x000000000040067b <+58>: callq 0x400470 <printf@plt>
0x0000000000400680 <+63>: mov $0x400762,%edi
0x0000000000400685 <+68>: mov $0x0,%eax
0x000000000040068a <+73>: callq 0x400470 <printf@plt>
0x000000000040068f <+78>: callq 0x400490 <getchar@plt>
0x0000000000400694 <+83>: leaveq
0x0000000000400695 <+84>: retq
End of assembler dump.
根据我从示例中读到的内容,我的缓冲区长度为24字节,我应该再添加4个字节以获取SFP大小。这意味着我要添加28个字节才能到达<+41>的返回地址。然后看起来我想跳转到最后一个printf调用处<+73>,这应该是32的偏移量。然而,当我执行代码时,“x is 1”仍然被打印出来。我似乎找不出原因。我的数学或假设有问题吗?