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. – Keelan 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

Not the answer you're looking for? Browse other questions tagged or ask your own question.