这是一个家庭作业,所以如果我能得到一个提示,而不是一个完整的答案,我将不胜感激。我写了这个程序,它应该打印以下内容:
Executing function_a
Executing function_b
Finished!
在main()
和function_a()
功能给予,而我只能更改function_b()
的标记部分。
#include <stdio.h>
#include <stdint.h>
void function_b(void) {
char buffer[4];
// edit between here...
uint32_t * x = &buffer;
while (*(x++) != 0xa0b1c2d3); // Find the beacon
*(uint32_t*)(&buffer + 6) = *(x + 2); // Copy return address from caller
*(uint32_t*)(&buffer + 5) = *(x + 1); // Copy frame pointer from caller
// ... and here
fprintf(stdout, "Executing function_b\n");
}
void function_a(void) {
int beacon = 0xa0b1c2d3;
fprintf(stdout, "Executing function_a\n");
function_b();
fprintf(stdout, "Executed function_b\n");
}
int main(void) {
function_a();
fprintf(stdout, "Finished!\n");
return 0;
}
问题当然是确保不输出“已执行的函数_b”。我们必须操纵堆栈,以便在返回时function_b()
我们不会回到它的实际父级,function_a()
而是返回到它的祖父main()
。
我写的那部分代码从中找到信标function_a()
,然后将 的返回地址和保存的帧指针复制function_a()
到function_b()
. 我的程序执行以下操作:
Executing function_a
Executing function_b
Finished!
Segmentation fault (core dumped)
所以它做正确的事情,除了段错误。从main()
函数返回时失败。我用 gdb 来得到这个:
(gdb) run
Starting program: /.../exercise2c
Executing function_a
Breakpoint 1, function_b () at exercise2c.c:9
9 *(uint32_t*)(&buffer + 6) = *(x + 2); // Copy return address from caller
(gdb) backtrace
#0 function_b () at exercise2c.c:9
#1 0x0000000000400607 in function_a () at exercise2c.c:18
#2 0x0000000000400630 in main () at exercise2c.c:23
(gdb) info frame
Stack level 0, frame at 0x7fffffffdcb0:
rip = 0x400593 in function_b (exercise2c.c:9); saved rip = 0x400607
called by frame at 0x7fffffffdcd0
source language c.
Arglist at 0x7fffffffdca0, args:
Locals at 0x7fffffffdca0, Previous frame's sp is 0x7fffffffdcb0
Saved registers:
rbp at 0x7fffffffdca0, rip at 0x7fffffffdca8
(gdb) frame 1
#1 0x0000000000400607 in function_a () at exercise2c.c:18
18 function_b();
(gdb) info frame
Stack level 1, frame at 0x7fffffffdcd0:
rip = 0x400607 in function_a (exercise2c.c:18); saved rip = 0x400630
called by frame at 0x7fffffffdce0, caller of frame at 0x7fffffffdcb0
source language c.
Arglist at 0x7fffffffdcc0, args:
Locals at 0x7fffffffdcc0, Previous frame's sp is 0x7fffffffdcd0
Saved registers:
rbp at 0x7fffffffdcc0, rip at 0x7fffffffdcc8
(gdb) step
10 *(uint32_t*)(&buffer + 5) = *(x + 1); // Copy frame pointer from caller
(gdb) step
12 fprintf(stdout, "Executing function_b\n");
(gdb) frame 0
#0 function_b () at exercise2c.c:12
12 fprintf(stdout, "Executing function_b\n");
(gdb) info frame
Stack level 0, frame at 0x7fffffffdcb0:
rip = 0x4005b5 in function_b (exercise2c.c:12); saved rip = 0x400630
called by frame at 0x7fffffffdcd0
source language c.
Arglist at 0x7fffffffdca0, args:
Locals at 0x7fffffffdca0, Previous frame's sp is 0x7fffffffdcb0
Saved registers:
rbp at 0x7fffffffdca0, rip at 0x7fffffffdca8
(gdb) backtrace
#0 function_b () at exercise2c.c:12
#1 0x0000000000400630 in main () at exercise2c.c:23
(gdb) continue
Continuing.
Executing function_b
Finished!
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400654 in main () at exercise2c.c:26
26 }(gdb)
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
您可以清楚地看到function_b()
确实返回到main()
,但出于某种原因,我不了解main()
崩溃。我能看到这种情况发生的唯一方法是我弄乱了 的堆栈框架main()
,我没有,或者我应该在那里改变一些东西 - 但我不知道是什么。
这里发生了什么?
注意:程序是用 GCC 和 flags 编译的-g -fno-omit-frame-pointer -fno-stack-protector
。我在 64 位机器上。