This is a homework assignment, so I'd appreciate it if I would get a hint only, not a full answer. I wrote this program which is supposed to print the following:
Executing function_a
Executing function_b
Finished!
The main()
and function_a()
functions were given, and I'm only allowed to change function_b()
in the marked part.
#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;
}
The problem is of course to make sure that 'Executed function_b' is not outputted. We have to manipulate the stack so that when returning from function_b()
we don't go back to its actual parent function_a()
but to its grandfather main()
.
The part of the code I wrote finds the beacon from function_a()
and then copies the return address and saved frame pointer of function_a()
to the frame of function_b()
. My program does the following:
Executing function_a
Executing function_b
Finished!
Segmentation fault (core dumped)
So it does the right thing, except for the segfault. It fails when returning from the main()
function. I used gdb to get this:
(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.
You can clearly see that function_b()
indeed returns to main()
, but for some reason that I don't understand main()
crashes. The only way I could see that happen is that I messed with the stack frame of main()
, which I didn't, or that I should have changed something there - but I wouldn't know what.
What's going on here?
Note: the program is compiled with GCC and the flags -g -fno-omit-frame-pointer -fno-stack-protector
. I'm on a 64-bit machine.