Monday, May 08, 2006

Finding the Saved EIP

So I was reading Aleph One's Smashing the Stack for Fun and Profit, and I just couldn't get the third example (example3.c) to come out right: the stack allocation size was completely different, and when trying to increment the eip, it just kept segfaulting. But, after slaving over gdb for a few days, I finally figured out how to get this right, and I figured I'd better put this down on paper before I forget!

This is the version of function() in example3.c that I got to work on my machine:

function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;

ret = buffer1 + 28;
(*ret) += 7;

How did I arrive at the magic numbers 28 and 7? Let me explain...

To start, I compiled example3.c with the debugging flags, and ran it through gdb:

$ gcc -g -o example3 example3.c
$ gdb -q example3
Using host libthread_db library "/lib/tls/".

Then, I needed to set a breakpoint right before the ret = buffer + 28 call so I can figure out what address is in buffer. So I disassembled function():

(gdb) disas function
Dump of assembler code for function function:
0x08048394 <function+0>: push %ebp
0x08048395 <function+1>: mov %esp,%ebp
0x08048397 <function+3>: sub $0x38,%esp
0x0804839a <function+6>: lea 0xffffffe8(%ebp),%eax
0x0804839d <function+9>: add $0x1c,%eax
(lines omitted)

End of assembler dump.

I need to set my breakpoint right before the add $0x1c,%eax call. So:

(gdb) break *0x0804839d
Breakpoint 1 at 0x804839d: file example3.c, line 7.

Then I run to the breakpoint:

(gdb) run
Starting program: /home/simmoril/shellcode/example3

Breakpoint 1, 0x0804839d in function (a=1, b=2, c=3) at example3.c:12
12 ret = buffer1 + 28;

Now I have the starting address in %eax:

(gdb) info registers eax
eax 0xbfb0af10 -1078939888

So this is what buffer is. Now we need to know where the saved eip on the stack is:

(gdb) info f
Stack level 0, frame at 0xbfb0af30:
eip = 0x804839d in function (example3.c:12); saved eip 0x80483f1
called by frame at 0xbfb0af60
source language c.
Arglist at 0xbfb0af28, args: a=1, b=2, c=3
Locals at 0xbfb0af28, Previous frame's sp is 0xbfb0af30
Saved registers:
ebp at 0xbfb0af28, eip at 0xbfb0af2c

Now the math. The saved eip address, minus our starting address gives me the offset we need to add to buffer:

0xbfb0af2c - 0xbfb0af10 = 0x1c = 28 (decimal)

Thus, this is where the value 28 comes from.

What about the 7? Well, we need to determine how much to add to eip to skip over the x = 1 line:

(gdb) disas main
Dump of assembler code for function main:
(lines omitted)

0x080483ec <main+58>: call 0x8048394 <function>
0x080483f1 <main+63>: movl $0x1,0xfffffffc(%ebp)
0x080483f8 <main+70>: mov 0xfffffffc(%ebp),%eax
0x080483fb <main+73>: mov %eax,0x4(%esp)
0x080483ff <main+77>: movl $0x8048508,(%esp)
0x08048406 <main+84>: call 0x80482d0 <printf@plt>
0x0804840b <main+89>: leave
0x0804840c <main+90>: ret
---Type <return> to continue, or q <return> to quit---
End of assembler dump.

From the info f command run above, we see that the saved eip is 0x80483f1. We want to skip to the instruction at 0x080483f8. Subtracting the two, we see we need to add 7 to the saved eip - our second magic value.

Once again, putting this all together, function() now looks like:

function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;

ret = buffer1 + 28;
(*ret) += 7;

Magic numbers explained and altered to suit our needs; now to see if example3 works:

$ ./example3

And it does! Huzzah!


Post a Comment

<< Home