Sunday, April 18, 2010

Reverse Engineering - 4

We looked at the assembly version of a very simple program in the last post. Hopefully you understood most of it. Over the next 2 posts we'll take up more examples to reinforce these basics, because they'll be used all along.. all the time. We now pick up the example called functions.c from Chapter 6 but strip it a little so just 1 function is used. We'll try and understand how a single function looks on stack and then look at multiple functions. I'm using the following gcc compiler - so if you want to follow this step by step try and get the exact same version:

gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)

The reason I mention this is purely because multiple versions of code are on the Chapter 6 page; meaning that different gcc versions with different switches generate slightly different assembly. While all that is important no doubt, it isn't right now when we're taking small steps towards understanding the basics. Lets go on..Here's the edited function code that I'm using:
---------------------------------------------------------
1 #include
2
3 void function3args(int a, int b , int c)
4 {
5 printf("%d %d %d\n" , a , b , c);
6 }
7
8 int main(int argc, char **argv)
9 {
10 int a;
11 int *ptr;
12 function3args(1,2,3);
13 }

---------------------------------------------------------
Like last time , lets compile it with gdb support and open up the disassembly in gdb. Oh and you have that pen and paper with those columns too..rt? ;)
[arvind@dilby ~]$ gcc -ofunc1 -ggdb functions.c
[arvind@dilby ~]$ gdb -q func1
Using host libthread_db library "/lib/libthread_db.so.1".
0x080483ed : lea 0x4(%esp),%ecx
0x080483f1 : and $0xfffffff0,%esp
0x080483f4 : pushl 0xfffffffc(%ecx)
0x080483f7 : push %ebp
0x080483f8 : mov %esp,%ebp
0x080483fa : push %ecx

Here's the status of esp for the first 6 instructions:

lea 0x4(%esp),%ecx -- No change in esp
and $0xfffffff0,%esp -- Logical and changes esp to bfc49ec0
Then there are 3 push instructions which decrease the value of the stack by 12 . So after the first 6 instructions the value of ESP is bfc49eb4 ( bfc49ec0 - 12). Just before the last push ESP is saved into EBP. This value in ebp will not change at all till it is popped and the function main ends. You can check the value of esp and ebp after each instruction by using x/xw $esp and x/xw $ebp . To advance instructions type nexti.

Then there is a sub $0x24,%esp which is to allocate space for local variables on the stack. Why 0x24? Lets look at the code in main().
0x080483fb : sub $0x24,%esp

The 3 arguments are then pushed on to the stack . Note that the arguments are passed on to the stack in reverse.
0x080483fe : movl $0x3,0x8(%esp)
0x08048406 : movl $0x2,0x4(%esp)
0x0804840e : movl $0x1,(%esp)

Note down the values for esp and ebp carefully just before executing this instruction.
0x08048415 : call 0x80483c4

Now get the disassembly for the function - function3args and lets see what happens there:
0x080483c4 : push %ebp
0x080483c5 : mov %esp,%ebp

Notice that the stored value of ebp which had remained constant during the lifetime of main is pushed on to the stack? And the current stack pointer made the current value of ebp? If there's another function after this, ebp will be pushed on to the stack again and so on. Once the last function completes the ebp's of each function are popped off till you reach the ebp of main at which point the program exits.

0x080483c7 : sub $0x18,%esp
Values for variables are allocated on the stack for the function function3args.

0x080483ca : mov 0x10(%ebp),%eax
0x080483cd : mov %eax,0xc(%esp)
0x080483d1 : mov 0xc(%ebp),%eax
0x080483d4 : mov %eax,0x8(%esp)
0x080483d8 : mov 0x8(%ebp),%eax
0x080483db : mov %eax,0x4(%esp)
Move the arguments of the function on to the stack.

0x080483df : movl $0x8048500,(%esp)
0x080483e6 : call 0x80482dc
Call the printf function with the arguments.

0x080483eb : leave
If you look at the value of ebp just after this instruction , you'd see its value change back to its earlier value which means this function has exited.

0x080483ec : ret
Exit from function3args

0x0804841a : add $0x24,%esp
0x0804841d : pop %ecx
0x0804841e : pop %ebp
0x0804841f : lea 0xfffffffc(%ecx),%esp
0x08048422 : ret
Exit from main.

Hope that clarified things a little better. Next post we won't go so much into detail, we'll make a couple of assumptions based on the previous 2 posts and learn a little more. Have fun :)

No comments: