Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stack manipulation in C without using inline assembly [closed]

Tags:

c

I've been preparing for a coding contest, and came across this question on the Internet:

#include <stdio.h>

void a(); 
void b(); 
void c();

int main() { a(); printf("\n"); return 0; }

void a() { b(); printf("hi "); }

void b() { c(); printf("there "); }

void c()
{
    int x;
    // code here and nowhere else
}

The solution is to write code that would print out "hi there" instead of "there hi" (no additional printing functions may be used and code only goes in the comment block).

Since I've done some basic assembly coding, I realized that this could be done with stack manipulation using the integer x as the base.

I tried using gdb to find the return address of the functions and then swapped the return addresses of a and b. The compiler throws a segmentation fault, and thus I assume that I haven't used the proper return address.

How do I properly calculate the offset to find the return address? Info frame command on gdb wasn't helpful, as using the stack address value given there didn't work.

I'm running this on Linux using gcc.

like image 660
Justeeson Sebastin Avatar asked Dec 09 '16 23:12

Justeeson Sebastin


2 Answers

I am not sure if the following will count. It's portable on POSIX. Basically you change the buffer of printf before its first call and manipulate that before before it's flushed to terminal

void c()
{
    static int first = 1;

    if (first) {
        first = 0;
        char buf0[BUFSIZ];
        char buf1[BUFSIZ];
        setvbuf(stdout, buf0, _IOFBF, BUFSIZ);
        a();
        memcpy(buf1, buf0 + 6, 3);
        memcpy(buf1 + 3, buf0, 6);
        memcpy(buf0, buf1, 9);
        buf0[8] = '\n';
        fflush(stdout);
        exit(0);
    }
}

You will get warnings on implicitly declaring library functions memcpy and exit. It's legal on C89 though discouraged. But in your case, no trick is too dirty, I guess. You can avoid the memcpy by copy the characters manually. You can avoid exit by instead redirect stdout through freopen. You can change BUFSIZ to a large constants if the system has a strangely small buffer size (smaller than 9). There are variants of this solution that don't require you to manually insert that \n and instead let the program exit normally from main and has the printf("\n") to put that end of line

like image 141
Yan Zhou Avatar answered Oct 20 '22 04:10

Yan Zhou


This problem cannot be solved unless you smash the stack in the same way as an attacker smashes the stack of some process.

And to smesh the stack can be done only if you know each detail of implementation of the compiler, the problem is unsolvable otherwise.

If you know the details of the compilation (the stack structure in particular) you can use the address of the local x variable in order to obtain the addres of the current frame from the stack (of FRAME_C); in each frame is the base pointer of the previous frame and modify it.

The stack looks like that:

   FRAME_MAIN = RET_OS   some-data 
   FRAME_A    = RET_MAIN some-data 
   FRAME_B    = RET_A    some-data 
   FRAME_C    = RET_B    some-data(including the variable `x`) 

Using the &x we can detect the position of the FRAME_C.

One solution is

  1. to print "Hi" in function c()
  2. Modify FRAME_B such that RET_A to become RET_MAIN
  3. return from function c() with return

The tricky operation is 2. but if each frame has a size that is known, then we can modify the return pointer RET_A of the frame B and detect RET_MAIN something like that:

*(&x+FRAME_C_SIZE+some-small-offset1) =                  /* *&RET_A = */
*(&x+(FRAME_C_SIZE+FRAME_B_SIZE)+some-small-offset2).    /* *&RET_MAIN */

As you can see, you need to know a lot of details about the implementation of the compiler , so this is not at all a portable solution.


Other solution would be to print "hi, there" and redirect the stdout to /dev/null. I suppose that exit() or other compiler-depedent tricks are not allowed, otherwise the problem has no meaning for a contest.

like image 43
alinsoar Avatar answered Oct 20 '22 04:10

alinsoar