Monday, July 24, 2017

Beginning x86 disassembly – Understanding "bit shifting" 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 bit shifting, let’s start with the code below:

/*
* This file focuses on bit shifting left and right
* The objective is to get a better understanding of how these are disassembled in C
* Author Nik Alleyne
* Blog: securitynik.blogspot.com
* File: shl_shr.c
*
*/
#include <stdio.h>

int main()
{
  unsigned int a, b, c;
  a = 0x40;
  b = a * 8;
  c = b / 16;
  return c;
}

Here is the disassembled code:

int main()
{
00401000  push        ebp 
00401001  mov         ebp,esp 
00401003  sub         esp,0Ch 
  unsigned int a, b, c;
  a = 0x40;
00401006  mov         dword ptr [ebp-4],40h 
  b = a * 8;
0040100D  mov         eax,dword ptr [ebp-4] 
00401010  shl         eax,3 
00401013  mov         dword ptr [ebp-8],eax 
  c = b / 16;
00401016  mov         ecx,dword ptr [ebp-8] 
00401019  shr         ecx,4 
0040101C  mov         dword ptr [ebp-0Ch],ecx 
  return c;
0040101F  mov         eax,dword ptr [ebp-0Ch] 
}
00401022  mov         esp,ebp 
00401024  pop         ebp 
00401025  ret 


Since this example builds on the other posts in this series, I will not being going through all the instructions with details. Instead I will give the attention to the newer instructions.

Looking at the disassembly, we see the typical stuff associated with the prologue, that is “push ebp” and  “mov ebp,esp”. See this post for more on prologue and epilogue.

Next up we see “sub esp,0Ch”. This reserves 12 bytes for the variables “int a, b, c”. Let’s peak at the registers before the sub …
EAX = 66CD1944 EBX = 00251000 ECX = 00000001 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 00401003 ESP = 0019FF04 EBP = 0019FF04 EFL = 00000202


… and the memory
0x0019FF04  0019ff18  .ÿ.. - EBP
0x0019FF08  0040139e  ž.@. – Return Pointer
0x0019FF0C  00000001  ....
0x0019FF10  0051bd18  ..Q.
0x0019FF14  00518338  8ƒQ.
0x0019FF18  0019ff70  pÿ..
0x0019FF1C  00401280  €.@.

Let’s now execute the instruction “sub esp, 0Ch” and revisit the register …
EAX = 66CD1944 EBX = 00251000 ECX = 00000001 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 00401006 ESP = 0019FEF8 EBP = 0019FF04 EFL = 00000212

… and now the stack with the 12 bytes allocated
0x0019FEF8  00000000  .... – [ebp-c] – location of int c
0x0019FEFC  0019ff10  .ÿ.. – [ebp-8] – location of int b
0x0019FF00  66c256e5  åVÂf – [ebp-4] – location of int a
0x0019FF04  0019ff18  .ÿ.. - EBP
0x0019FF08  0040139e  ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0051bd18  ..Q.

From above we see the 12 bytes have been allocated for the 3 integer (int) variables. Remember each int is 4 bytes or 32 bits. Therefore since we have 3 integers, 4x3 bytes have been allocated for local variable storage.

Moving along …

Next command “mov dword ptr [ebp-4],40h”  states to move hex 40 or decimal 64 into the memory location occupied by “[ebp-4]”. After executing the instruction and looking at the stack we see …
0x0019FEF8  00000000  ....
0x0019FEFC  0019ff10  .ÿ..
0x0019FF00  00000040  @... – [ebp-4]
0x0019FF04  0019ff18  .ÿ.. - EBP
0x0019FF08  0040139e  ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0051bd18  ..Q.

The next instruction “mov eax,dword ptr [ebp-4]” states to take our value “0x40” at “[ebp-4]” and pace it in the “EAX” register. Upon executing this instruction our register looks like …

EAX = 00000040 EBX = 00251000 ECX = 00000001 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 00401010 ESP = 0019FEF8 EBP = 0019FF04 EFL = 00000212

Next instruction “shl eax,3” is one of our first new instruction. Let’s look at this a bit more. “shl” is shift to the left and is similar to multiplying by 2n where “n” is the number of bits to be shifted.

Let’s look at this through an example. If we have the number “0000 0010” or 2 in decimal and decide to shift this 1 bit, we get the following “0000 0100”. Notice the “1” has been shifted to the left. This value “0000 0100” is now 4. Remember our original value 2 and we shift by 1. Therefore 21 is 2 hence we multiply 2*2 and got 4.

Let’s look at it through another example using the same number “0000 0010” or 2 in decimal. If we shift this left by 2 bits (22 =4), we get “0000 1000”. Hence we now have 4 * 2 = 8. 

Ok! One more to reinforce the point. If we have the number “0000 0010” or 2 in decimal and decide to shift this left 3 bit (23=8), we get the number 0001 0000 which is 16. As we know from our calculations 8 * 2=16

Now that we have those examples clearly explained, let’s pay attention to our specific instruction “shl eax,3”.

As we know from above EAX has a value of 0x40 (dec 64) which is “0100 0000”. When this value is shifted left by 3 bits we get “10 0000 0000” (512 decimal) and (x200). Once we execute the instruction “shl eax,3” and revisit the registers, we see …

EAX = 00000200 EBX = 00251000 ECX = 00000001 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 00401013 ESP = 0019FEF8 EBP = 0019FF04 EFL = 00000206

Now that EAX has “x200” this value is now placed on the stack at the position occupied by “[ebp-8]” which is for the variable “b”. Executing the next instruction “dword ptr [ebp-8],eax” and looking at the stack we see …
0x0019FEF8  00000000  ....
0x0019FEFC  00000200  .... – [ebp-8]
0x0019FF00  00000040  @... – [ebp-4]
0x0019FF04  0019ff18  .ÿ.. - EBP
0x0019FF08  0040139e  ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0051bd18  ..Q.

Our stack now has the values of “a” and “b”.

The next instruction “mov ecx,dword ptr [ebp-8]” takes our “x200” which is at “[ebp-8]” and place it into the ECX register. From the previous printout of the registers we see “ECX = 00000001”. After executing the instruction and looking at the registers again we see …

EAX = 00000200 EBX = 00251000 ECX = 00000200 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 00401019 ESP = 0019FEF8 EBP = 0019FF04 EFL = 00000206

Our next instruction is another new one “shr” or “shr ecx,4”. Whereas our “shl” shifted to the left, the “shr” shifts to the right and is used for division of multiple of 2.

Looking at it through the lens of an example, if we have the number “0000 0010” or 2 in decimal and decide to shift this 1 bit (21=2) to the right, we get the following “0000 0001” which (1). Basically 2/2 = 1.

Another example, using the number if we have the number “0000 1000” or 8 in decimal and decide to shift this 2 bit (22=4) to the right, we get the following “0000 0010” which (2). Basically 8/4 = 2.

One final example, if we have the number “0100 0000” or 64 in decimal and decide to shift this 3 bit (23=8) to the right, we get the following “0000 1000” which (8). Basically 64/8 = 8.

Now that we have that out of the way let’s look at our specific example “shr ecx,4”. The value in ECX is 0x200 which is “10 0000 0000” (512 decimal) and (x200). Shifting the binary value “10 0000 0000” to the right by 4, means we are dividing 512*16. Remember we are shifting y 4 bytes, this means we are shifting by 24 which is 16.

Therefore when we right shift by 4, the value of variable “c” will be “32” (0x20) . Let’s execute our instruction “shr ecx,4” after which we see the registers showing ...

EAX = 00000200 EBX = 00251000 ECX = 00000020 EDX = 00404388 ESI = 004013B0 EDI = 004013B0 EIP = 0040101C ESP = 0019FEF8 EBP = 0019FF04 EFL = 00000202

Our next instruction “mov dword ptr [ebp-0Ch],ecx” now takes our ECX value 0x20 and places it in the position held by the variable “c” thus completing the values of all our variables. Once this instruction is executed, our stack looks like …

0x0019FEF8  00000020   ... – [ebp-0c]
0x0019FEFC  00000200  .... – [ebp-8]
0x0019FF00  00000040  @... – [ebp-4]
0x0019FF04  0019ff18  .ÿ.. - EBP
0x0019FF08  0040139e  ž.@.
0x0019FF0C  00000001  ....
0x0019FF10  0051bd18  ..Q.

Our final instruction says “mov eax,dword ptr [ebp-0Ch]” says to take the value we have at “[ebp-0c]” and place it in EAX register. Do remember, the EAX register holds our return value, thus the value of “c” (0x20) is returned to the function.

After this the next set of code is our epilogue. See this post for more on prologue and epilogues.




References:
  


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

No comments:

Post a Comment