5

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.

6

I'm on a 64-bit machine.

Your code in function_b() treats pointers as 32-bit values instead of 64-bit values. You should be using uint64_t* instead of uint32_t*.

1

As Jason writes, I should use 64-bit pointers. Besides that, it also turns out that I had to copy four numbers from the stack frame. This is working code:

uint64_t * my_ptr = &buf;
int * x = my_ptr;

while (*(++x)  != 0xa0b1c2d3);  // Find the beacon. We could of course simply have a look
uint64_t * y = x + 1;           // with gdb where it's stored, but this works generically.

*(my_ptr+7) = *(y+3);           // Copy frame information
*(my_ptr+6) = *(y+2);
*(my_ptr+5) = *(y+1);
*(my_ptr+4) = *y;

Typically you need to fiddle a bit with what addresses you have to copy. You can get a rough idea using gdb, as you did. The exact numbers depend on the functions and their variables.

  • 1
    "I'd appreciate it if I would get a hint only, not a full answer" -- Yet you accepted your non-hint full-answer as the accepted response :\ – Jason Geffner Mar 18 '15 at 16:43
  • I thought we agreed that I would edit my working code in, in the comments. Yet you rolled back my edit without explanation. – user187 Mar 19 '15 at 7:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy