Monday, July 24, 2017

Beginning x86 disassembly - Understanding Prologues, Epilogues and stack building with Visual Studio 2017

In this series of posts, I’m going through the Open Security Training for beginning Assembly Language and thus am putting my own spin on things to enhance my knowledge of x86 disassembly. However, to make the most of these tutorials you may be better of reviewing the material from Open Security Training directly.

Let’s get started!
Here is some basic C Code, which was built with Visual Studio 2017.

/*
 * This file focuses on the basics of function creation and tear down in assembly
 * The ojective is to get a better understanding of prologue and epilogue
 * Author Nik Alleyne
 * Blog: securitynik.blogspot.com
 * File: stackbasics.c
 *
 */

int SecurityNik()
     {
           return "SecurityNik!";
     }
int main()
     {
           SecurityNik();
           return "Returning!!";
     }

The code is then disassembled in Visual Studio using its disassembler.

Here is the disassembled code for function “SecurityNik()”


int SecurityNik()
     {
00401330  push        ebp 
00401331  mov         ebp,esp 
           return "SecurityNik!";
00401333  mov         eax,407000h 
     }
00401338  pop         ebp
00401339  ret   

…. and here is the disassembled code for function “main()”

int main()
     {
00401340  push        ebp 
00401341  mov         ebp,esp 
           SecurityNik();
00401343  call        _SecurityNik (040119Fh) 
    return "Returning!!";
00401348  mov         eax,407010h 

     }
0040134D  pop         ebp
0040134E  ret

Let’s now try to understand what is going on by starting with function “main()”

Beginning with the registers:
EAX = 0F471944 EBX = 002BA000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401340 ESP = 0019FF08 EBP = 0019FF18 EFL = 00000202

The first action in our main function is to “push ebp”. Looking at the registers we see EBP register has a value of “0019FF18”. This means this value will be pushed unto the stack: Let’s verify this by “stepping” through the code to the next instruction and then looking at the memory at the location occupied by “ESP”.

First peaking at the registers again.

EAX = 0FD61944 EBX = 0033C000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401341 ESP = 0019FF04 EBP = 0019FF18 EFL = 00000202

Looking at the memory address occupied by ESP, we see the value of the previous EBP register is now there. The first highlighted portion is the EBP being placed on the stack as main function builds its stack. The second highlighted 4 bytes “
0x0040178e” must then be the return pointer for the function which called main().


0x0019FF04 
0019ff18  .ÿ.. – ESP (top of the stack) – has most recent pushed value
0x0019FF08  0040178e  Ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0075cfe8  èÏu.
0x0019FF14  00758558  X.u.
0x0019FF18  0019ff70  pÿ..
0x0019FF1C  004015f0  ð.@.
0x0019FF20  9b9af0d4  Ôðš.
0x0019FF24  00401023  #.@.

Our next instruction is to move the value of ESP into EBP (“mov ebp, esp”) as we continue to build the stack frame for main.

The current value of ESP is
ESP = 0019FF04 as shown in our register above. So pushing ESP into EBP should now change the value of EBP to reflect “0019FF04. Let’s verify this by stepping and looking at our register.

EAX = 0FD61944 EBX = 0033C000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401343 ESP = 0019FF04 EBP = 0019FF04 EFL = 00000202

Ok, as seen above the EBP register was changed to reflect the current value of ESP.

Next step is to call function SecurityNik() at address “040119Fh”. This now moves execution to the SecurityNik function. So one again we start building our stack frame. However, an important thing for us to take away is that once execution is switched to function “SecurityNik()”, then before EBP is pushed unto the stack, the return pointer of return "Returning!!";” must be set just before EBP. Therefore, considering the next instruction in “main()” after function “SecurityNik()” is returned is “mov eax,407010h” which is at address “00401348”, we then expect to see this on the stack before the next “EBP” value.

Looking first at the registers now that we have stepped into function “SecurityNik()”.
EAX = 0FF21944 EBX = 00359000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401330 ESP = 0019FF00 EBP = 0019FF04 EFL = 00000202

Now that we have the value of EBP highlighted, let’s step to the next instruction which is “push ebp”

Looking at the registers again:
EAX = 0FF21944 EBX = 00359000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401331 ESP = 0019FEFC EBP = 0019FF04 EFL = 00000202

Let’s look at the memory occupied by ESP to verify the EBP “EBP = 0019FF04” value has been pushed unto the stack. While there, let’s verify that the return pointer “00401348”,  has also been pushed unto the stack.

0x0019FEFC  0019ff04  .ÿ.. – ESP Points to top of stack – EBP value at ESP
0x0019FF00  00401348  H.@. – Return pointer for main()
0x0019FF04  0019ff18  .ÿ..
0x0019FF08  0040178e  Ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0053e3e0  àãS.
0x0019FF14  00538558  X.S.
0x0019FF18  0019ff70  pÿ..
0x0019FF1C  004015f0  ð.@.

Good stuff! From above we have the value of EBP pushed unto the stack but most importantly we see the address of 00401348” which is for “mov eax, 407010h”. “407010h”  is the pointer to the string "Returning!!", which is our return value.

What comes next? Well we are still building our stack frame, so the next instruction is to move the value in ESP to EBP (mov ebp,esp)

ESP currently has a value of ESP = 0019FEFC. After execution we expect ESP and EBP to be the same. Let’s verify.
EAX = 0F1D1944 EBX = 002FC000 ECX = 00000001 EDX = 004043A8 ESI = 004013A0 EDI = 004013A0 EIP = 00401003 ESP = 0019FEFC EBP = 0019FEFC EFL = 00000202

Looks good! Next instruction says “mov eax,407000h”.  This will move the value “407000h” into the EAX register. Point to note is that the EAX register is used for storing return values and in this case, the address “407000h” points to our return string “SecurityNik” as shown below.

0x00407000  75636553  Secu
0x00407004  79746972  rity
0x00407008  216b694e  Nik!
0x0040700C  00000000  ....
0x00407010  75746552  Retu
0x00407014  6e696e72  rnin
0x00407018  00212167  g!!.
0x0040701C  00000000  ....
0x00407020  00000000  ....
From the register print out above, we see “EAX = 0F1D1944”. Let’s now step into the code and revisit our registers.

EAX = 00407000 EBX = 00359000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401338 ESP = 0019FEFC EBP = 0019FEFC EFL = 00000202


As we can see EAX now has the value for our memory location. Most importantly, the EIP points to code back in the main function.

However before, we go back to main, let’s clean up the stack and pop the value of EBP off of the stack.  Currently EBP = 0019FEFC and ESP = 0019FEFC. This would be safe to conclude that the value of EBP is at the top of the stack. So popping this off increases the stack size by 4 bytes and puts the value “0019ff04” into EBP.

So we now have our registers as follow after execution of “pop ebp”:

EAX = 00407000 EBX = 00359000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 00401339 ESP = 0019FF00 EBP = 0019FF04 EFL = 00000202

Note also that EBP points to our EBP which was setup for main as we have shown above.

Once we have completed “pop”ing ebp, the next instruction was “ret” which returned execution to main().

Now that we are back in main(), the next instruction is to return "Returning!!"; which is performed via “mov eax,407010h”. Similarly to above a memory address is being placed into “eax’ register. Once again, EAX holds our return value. Looking at the memory address “407010h” we see:

0x00407010  75746552  Retu
0x00407014  6e696e72  rnin
0x00407018  00212167  g!!.
0x0040701C  00000000  ....
0x00407020  00000000  ....
0x00407024  ffffffff  ÿÿÿÿ
0x00407028  00000001  ....
0x0040702C  359603eb  ë.–5
0x00407030  ca69fc14  .üiÊ

Once we have executed the instruction, our registers now look like:

EAX = 00407010 EBX = 00359000 ECX = 00000001 EDX = 00407578 ESI = 00401023 EDI = 00401023 EIP = 0040134D ESP = 0019FF04 EBP = 0019FF04 EFL = 00000202

Once again, EAX holds our return value.

Next we “pop” the ebp value off of the stack and then return execution to the code that called main.

Ok. That’s it for this entry. I now have a better understand of the function stacks, prologues and epilogues. Do you?



Other posts in this series:
8. Beginning x86 disassembly – Understanding the basics of “memcpy” with Visual Studio 2017

No comments:

Post a Comment