2

I was practicing some reverse engineering crack-mes as part of our university curriculum, and I have a question around the arrangement of variables on the stack.

I have a very basic C++ code, like so:

void foo(int x){
    int a=0;
    int b=x;
    int c=3;
    int z=a+b+c;
    return;
}

int main(){
     foo(5);
     return 0;
}

I compile the program, like so:

g++ program.cpp -o program -ggdb 

I run gdb with

gdb -q program

And inside gdb

set disassembly-flavor intel
disass foo

I expect the stack frame layout of foo to have the variable a on top of b, followed by c and then z. But that does not seem to be the case.

I have stumbled across this answer in which the explanation shows a similar layout of how variables are arranged. I'd expect that x would be at the highest address in the frame, right below ebp. But the answer clearly shows z being the closest to ebp, given that it is at ebp - 4 but x is at ebp - 12, which seems counter intuitive to me.

I have read a bunch of books, and have seen a couple of online videos on buffer overflows where it is said that the first variable the compiler encounters is the first to be placed on the stack; and order of variable declaration can effect what variables are overwritten in case there is a buffer next to them that's overflown. Is this still a valid statement to make?

Why do I see variables arranged in such an order? Kindly help me out, I'm not sure if my facts are outdated or am I missing something fundamental.

PS: I am using Ubuntu 16.04 Desktop, with the latest version of GCC/G++

Edit 1: Adding disassembly of function foo

ubuntu@Ubuntu:~$ gdb -q program 
Reading symbols from program... 
(gdb) set disassembly intel 
(gdb) disass foo 
Dump of assembler code for function foo(int): 
    0x0000000000001125 <+0>:    push rbp    
    0x0000000000001126 <+1>:    mov rbp,rsp 
    0x0000000000001129 <+4>:    mov DWORD PTR [rbp-0x14],edi 
    0x000000000000112c <+7>:    mov DWORD PTR [rbp-0x10],0x0 
    0x0000000000001133 <+14>:   mov eax,DWORD PTR [rbp-0x14]
    0x0000000000001136 <+17>:   mov DWORD PTR [rbp-0xc],eax
    0x0000000000001139 <+20>:   mov DWORD PTR [rbp-0x8],0x3
    0x0000000000001140 <+27>:   mov edx,DWORD PTR [rbp-0x10]
    0x0000000000001143 <+30>:   mov eax,DWORD PTR [rbp-0xc]
    0x0000000000001146 <+33>:   add edx,eax 
    0x0000000000001148 <+35>:   mov eax,DWORD PTR [rbp-0x8]
    0x000000000000114b <+38>:   add eax,edx 
    0x000000000000114d <+40>:   mov DWORD PTR [rbp-0x4],eax  
    0x0000000000001150 <+43>:   nop 
    0x0000000000001151 <+44>:   pop rbp 
    0x0000000000001152 <+45>:   ret 
End of assembler dump. 
(gdb) b *foo+43 
Breakpoint 1 at 0x1150: file program.cpp, line 6. 
(gdb) r Starting program: /home/ubuntu/program Breakpoint 1, foo (x=5) at program.cpp:6 
6    return; 
(gdb) p &a 
$1 = (int *) 0x7fffffffdfb0 
(gdb) p $rbp-0x10 
$2 = (void *) 0x7fffffffdfb0 

(gdb) p &b 
$3 = (int *) 0x7fffffffdfb4 
(gdb) p $rbp-0xc 
$4 = (void *) 0x7fffffffdfb4 

(gdb) p &c 
$5 = (int *) 0x7fffffffdfb8 
(gdb) p $rbp-0x8 
$6 = (void *) 0x7fffffffdfb8 

(gdb) p &z 
$7 = (int *) 0x7fffffffdfbc 
(gdb) p $rbp-0x4 
$8 = (void *) 0x7fffffffdfbc 
(gdb)
  • 1
    Please include the disassembly of the foo function – julian Nov 22 '19 at 16:08
  • Added the disassembly. I use x64 machine, btw. I'd expect to see variable a to have the highest address and closest to RBP, but that is not the case apparently. – user148898 Nov 22 '19 at 16:45
1

Keep in mind Your program as is when compiled with -O will become just

mov eax,0
return

enter image description here

every thing out there in your Source is Dead Code and Will be eliminated

since you are compiling this in debug mode without any optimizations the compiler provides you all those variables

i am not sure what you mean by nearer to ebp

in debugmode compiler as far as possible allocates the variables in the same order as it encounters them

here is a colour coded nonoptimzed output for the same code

as you can see compiler first instruction in white color is your int a=0; which is at rbp-4

enter image description here

but the std iirc does not specify any standard for allocation of variable addresses

quoting from standard linked in that thread

Each parameter has automatic storage duration; its identifier is an lvalue.164) The layout of the storage for parameters is unspecified.

| improve this answer | |

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.