Monday, July 24, 2017

Beginning x86 disassembly – Understanding Unconditional Jumps 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!

To understand unconditional jumps, let’s start with the code below:

/*
* This file focuses on flow control via unconditional jumps using the "goto" statement and
* The objective is to get a better understanding of how these are disassembled in C
* Author Nik Alleyne
* Blog: securitynik.blogspot.com
* File: flow_control.c
*
*/
#include <stdio.h>

int main()
{
  goto label_SecurityNik;
  printf("This is skipped\n");

  label_SecurityNik:
    printf("We're at label_SecurityNik! \n");
    return 0x07;
   
}

Now that we have our code, let’s now disassemble this.

Here is our disassembled code for the code above:

int main()
{
00401000  push        ebp 
00401001  mov         ebp,esp 
  goto label_SecurityNik;
00401003  jmp         00401012 
  printf("This is skipped\n");
00401005  push        404000h 
0040100A  call        00401070 
0040100F  add         esp,4 

  label_SecurityNik:
    printf("We're at label_SecurityNik! \n");
00401012  push        404014h 
00401017  call        00401070 
0040101C  add         esp,4 
    return 0x07;
0040101F  mov         eax,7 
   
}
00401024  pop         ebp 
00401025  ret


As with the previous posts, this one does not analyze the prologue and epilogue. To learn more about these, see my post on prologue and epilogue available here.

Let’s focus on the first instruction after the “push ebp” and “mov ebp, esp”

As the first thing our code wants to do is “goto label_SecurityNik”, from the disassembly perspective, the first instruction we see is “00401003 jmp 00401012”. This means we are jumping to the instruction at memory address “00401012”.

From the disassembly above, we see the instruction at “
00401012” is “00401012 push 404014h”. This also means that the following instructions as been skipped with the EIP register and control being redirected to “00401012”:

00401005  push        404000h 
0040100A  call        00401070 
0040100F  add         esp,4

since the instruction at “00401012” is to “push 404014h”, let’s see what is at the memory address “404014h” that should be pushed unto the top of the stack.

0x00404014  72276557  We'r
0x00404018  74612065  e at
0x0040401C  62616c20   lab
0x00404020  535f6c65  el_S
0x00404024  72756365  ecur
0x00404028  4e797469  ityN
0x0040402C  20216b69  ik!
0x00404030  0000000a  ....


From the above we see our string “We're at label_SecurityNik! \n”. Therefore the value “404014h” will be pushed unto the stack. This value serves as a pointer to our string. Let’s execute the instruction “push 404014h” to see what we get.

EAX = 0FB21944 EBX = 00272000 ECX = 00000001 EDX = 004043CC ESI = 00401430 EDI = 00401430 EIP = 00401017 ESP = 0019FF00 EBP = 0019FF04 EFL = 00000202


0x0019FF00  00404014  .@@.
0x0019FF04  0019ff18  .ÿ..
0x0019FF08  0040141e  ..@.
0x0019FF0C  00000001  ....
0x0019FF10  005c5a50  PZ\.
0x0019FF14  0059c940  @ÉY.
0x0019FF18  0019ff70  pÿ..

As we can see from above, the memory address “404014h”  has been pushed to the top of the stack.

The next instruction says “call 00401070”. At this point if we look at this call as well as the one which was skipped above, we will see this is our call to the “printf” function. Note the address is the same for both calls. Since I know this is “printf” and do not wish to disassemble it, I will just “step over” this code. Once I step over, the output “We're at label_SecurityNik!” is written to the screen.

Next step is to a “add esp, 4” in which we add 4 bytes to the ESP register value, thus cleaning up the stack. Currently the registers look like:

EAX = 0000001D EBX = 00272000 ECX = 35C43FCA EDX = 0FB20BA4 ESI = 00401430 EDI = 00401430 EIP = 0040101C ESP = 0019FF00 EBP = 0019FF04 EFL = 00000206

… and the stack look like:


0x0019FF00  00404014  .@@.
0x0019FF04  0019ff18  .ÿ..
0x0019FF08  0040141e  ..@.
0x0019FF0C  00000001  ....
0x0019FF10  005c5a50  PZ\.
0x0019FF14  0059c940  @ÉY.
0x0019FF18  0019ff70  pÿ..

After the instruction “add esp, 4” the registers look like ….

EAX = 0000001D EBX = 00272000 ECX = 35C43FCA EDX = 0FB20BA4 ESI = 00401430 EDI = 00401430 EIP = 0040101F ESP = 0019FF04 EBP = 0019FF04 EFL = 00000202

…. And the stack looks like

0x0019FF04  0019ff18  .ÿ..
0x0019FF08  0040141e  ..@.
0x0019FF0C  00000001  ....
0x0019FF10  005c5a50  PZ\.
0x0019FF14  0059c940  @ÉY.
0x0019FF18  0019ff70  pÿ..
0x0019FF1C  00401300  ..@.

We then see our next instruction “mov eax, 7”. If we remember from our code above, we set a return value of “7”.

Now the value at the top of the stack “0x0019FF04” is “0019ff18”. The next instruction says “pop ebp”. This means the value at the top of the stack will now be pop’ed into the EBP register. Let’s verify this by executing the instruction and looking at the registers:

EAX = 00000007 EBX = 00272000 ECX = 35C43FCA EDX = 0FB20BA4 ESI = 00401430 EDI = 00401430 EIP = 00401025 ESP = 0019FF08 EBP = 0019FF18 EFL = 00000202

Final instruction states to return “ret” so the function which called main now regains control.




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

No comments:

Post a Comment