x86 Overview

Reverse Engineering Workshop

Agenda

In this session, we will talk about:

  • The Workshop
  • What is RE and why do it
  • x86 Overview - Going Deeper
  • IDA Basics
  • Exercises

The Workshop

There are 3 goals to this workshop:

  1. Introduce you to the world of RE
  2. Prove you that it’s possible
  3. Show you that it’s challenging

RE

  • What is Reverse Engineering?
    • Reverse engineering means to take some product and break it down in order to understand how it was produced
    • In hardware: slicing electrical components and analyzing their logical gates
    • In a restaurant: tasting an amazing dish and trying to reproduce it at home

The Enigma was also RE’d ;)

Software RE

  • In software reverse engineering:
    • The research object is a program - the machine code of an executable file
    • The goal is to understand what the program does and how

Why RE?

  • because sometimes you can’t run the program and you need to analyze it statically
  • because ‘basic’ analysis does not provide the whole picture:
    • knowing that a program X uses a function F is one thing, but why is F used? What are its parameters? What does it return?
    • knowing that a program X sends a packet P does not tell us exactly what is in P, how it’s parsed, etc.

Reverse Engineering is Challenging

Why?

  • Real-life software is not easy to analyze:
    • it might be obfuscated
    • it might be packed
    • it will probably be huge
  • But one still has to start somewhere, right? :)

x86 Overview

Why Assembly?

Assembly is the most popular low-level language* (more precisely, a class of languages)

Low-level language: a human-readable version of a computer architecture’s instruction set.

Compilation & Disassembly

The program author writes code in some high-level language, say C.

The C code is compiled into machine code - a series of bytes that the CPU understands.

The researcher usually has no access to the C source code, only to the bytes of machine code.

To make life easier, a disassembler translates these bytes into an easier-to-read textual representation.

All images in these slides are from Michael Sikorsi & Andrew Honig’s “Practical Malware Analysis”

x86 Architecture

As a program runs, the following loop is executed:

  1. A CPU instruction is read from the main memory by the Control Unit
  2. The instruction is processed and executed by the Arithmetic-Logic Unit, along with input from the user or the registers
  3. The operation’s output is stored in the CPU’s registers or sent to an output device

Let’s understand what an x86 instruction looks like.

Instructions

Assembly instruction = mnemonic + optional operand(s). For example:

mov eax, 0xFF ~ B8 FF 00 00 00

An operand can be:

  • an immediate - 0x3
  • a register - eax
  • a memory address - [0x400100 + 4]

Opcode: the bytes that correspond to the instruction and its operands

  • Data storage
    • mov
    • lea
  • Logic
    • or
    • and
    • xor
    • shr
  • Control-Flow
    • test
    • cmp
    • jmp
    • jcc
  • Arithmetic
    • shl
    • add
    • sub
  • Stack
    • inc
    • dec
    • push
    • mul
    • pop
    • div
    • call
    • ret

Do you know all these? ;)

Quiz

What does each of the following instructions do? (answers are in the next slides, revealed progressively)

  • mov eax, ebx

  • mov eax, 0x42

  • mov eax, [0x4037c4]

  • mov eax, [ebx]

  • mov eax, [ebx+esi*4]

  • mov eax, ebx - move what’s in ebx to eax

  • mov eax, 0x42

  • mov eax, [0x4037c4]

  • mov eax, [ebx]

  • mov eax, [ebx+esi*4]

  • mov eax, ebx - move what’s in ebx to eax

  • mov eax, 0x42 - move 0x42 to eax

  • mov eax, [0x4037c4]

  • mov eax, [ebx]

  • mov eax, [ebx+esi*4]

  • mov eax, ebx - move what’s in ebx to eax

  • mov eax, 0x42 - move 0x42 to eax

  • mov eax, [0x4037c4] - move what’s in address 0x4037c4 to eax

  • mov eax, [ebx]

  • mov eax, [ebx+esi*4]

  • mov eax, ebx - move what’s in ebx to eax

  • mov eax, 0x42 - move 0x42 to eax

  • mov eax, [0x4037c4] - move what’s in address 0x4037c4 to eax

  • mov eax, [ebx] - move what’s in the address in ebx to eax

  • mov eax, [ebx+esi*4]

  • mov eax, ebx - move what’s in ebx to eax

  • mov eax, 0x42 - move 0x42 to eax

  • mov eax, [0x4037c4] - move what’s in address 0x4037c4 to eax

  • mov eax, [ebx] - move what’s in the address in ebx to eax

  • mov eax, [ebx+esi4] - move what’s in address ebx+esi4 to eax

What’s the difference? (answer is in the next slide)

  • mov eax, [ebx + 8]
  • lea eax, [ebx + 8]

What’s the difference?

  • mov eax, [ebx + 8] - move what’s in address ebx+8 (0x20) to eax
  • lea eax, [ebx + 8] - move the value ebx+8 (0xB30048) to eax

Registers

A register is the CPU’s basic data storage unit, whose access time is the fastest.

  • General Registers: EAX (AX, AH, AL), EBX (BX, BH, BL), ECX (CX, CH, CL), EDX (DX, DH, DL)

  • Segment Registers: CS [code section], SS [stack section], DS [data section], ES, FS, GS [general]

  • EFLAGS: a register with 32 bit-flags that provide information on previous operations (TBC)

  • EIP: this register always holds the address of the next instruction to execute

  • EBP (BP), ESP (SP), ESI (SI), EDI (DI): these point to the base address of different memory sections

Register Breakdown

EAX, EBX, ECX & EDX can be broken-down as follows (EAX is used as example):

  • EAX - all 32 bits
  • AX - 16 least-significant bits of EAX
  • AH - 8 most-significant bits of AX
  • AL - 8 least-significant bits of AX

Can you think how the 16 most-significant bits of EAX can be accessed? (answer is in the next slide)

SHR EAX, 0x10 : Use AX

Register Conventions

  • EAX - A function’s return value
  • ECX - Counters (loop variables)
  • EAX:EDX - Quotient and remainder in multiplication and division

EFLAGS Register

32 bit-flags that give information on the result of previous computation. The most common flags are:

  • Zero Flag: set if an operation result is 0; otherwise cleared.
  • Carry Flag: set if an operation results is too large or too small for the destination operand; otherwise cleared
  • Sign Flag: set if the MSB is set (namely, the result is negative); otherwise cleared

EFLAGS Quiz!

mov eax, 0x1
mov ebx, 0x0
sub ebx, eax

What is the status of the flags (answers are revealed progressively in the next slides):

  • zero-flag?

  • carry-flag?

  • sign-flag?

  • zero-flag? 0

  • carry-flag?

  • sign-flag?

  • zero-flag? 0

  • carry-flag? 0

  • sign-flag?

  • zero-flag? 0

  • carry-flag? 0

  • sign-flag? 1

Branching (Control Flow)

  • Two types of jumps in x86:
    • Unconditional - just jump to where I tell you
      • jmp 0x401072
    • Conditional - check the result of some computation, jump accordingly
      • cmp eax, 0x10 - compare the value of eax with 0x10
      • jge 0x401072 - jump to 0x401072 if eax is greater-equal than 0x10

Jumps

There are many types of conditional jumps. The set of conditional jump instructions is often referred to as jcc (where the j stands for jump and the c for condition).

Each jump instruction performs different checks on the EFLAGS register to determine whether the jump should be performed or not.

Conditionals

  • Two operations are commonly used before conditional jumps:
    • test ~ perform a logical AND
    • cmp ~ perform subtraction

Both instructions do not store the result, but change the flags in EFLAGS as needed

An Example

Here’s a pair of instructions you will see a lot (not necessarily with eax…)

test eax, eax
jz 0x400100

Since test is practically a logical AND, and since X AND X X is always true, the result of the first line is either zero (if EAX 0) or some non-zero value (otherwise).

Therefore, this is an efficient way of checking if EAX equals zero or not.

How would you say in x86…?

(answers revealed progressively in the next slides)

  • if (a == b) goto 0x1000;

  • if (a < b) goto 0x1000;

  • if (a) goto 0x1000;

  • if (a == b) goto 0x1000; cmp a, b; jz 0x1000;

  • if (a < b) goto 0x1000;

  • if (a) goto 0x1000;

  • if (a == b) goto 0x1000; cmp a, b; jz 0x1000;

  • if (a < b) goto 0x1000; cmp a,b; jl 0x1000;

  • if (a) goto 0x1000;

  • if (a == b) goto 0x1000; cmp a, b; jz 0x1000;

  • if (a < b) goto 0x1000; cmp a,b; jl 0x1000;

  • if (a) goto 0x1000; test a, a; jnz 0x1000;

Main Memory

We have seen before how the CPU “talks” to the main memory (“RAM”).

The following are (some of) the different sections of a process loaded into the RAM:

  • Data: static / global variables, put in place when the program is loaded
  • Code: the program’s CPU instructions
  • Heap: dynamic memory, allocated and freed during runtime
  • Stack: variables and arguments local to the program’s functions

The Stack

  • A LIFO data structure with push & pop operations
  • Stack-relevant registers:
    • ESP - Stack Pointer, always points to the top of the stack, therefore dynamic
    • EBP - Base Pointer, stays consistent within a function and is used to reference the function’s local variables and parameters
  • Stack-relevant instructions: pop, push, call, ret (and also enter, leave…)

Function Calls - Demo

In the following slides, x86 code will be presented along with the stack in its current state.

The code shows how a function named caller calls another function sum.

Each slide, look at the next instruction and try to predict the side-effects and changes to come.

Note: instructions in bold have been just executed and their side-effects are already presented on the slide.

Trazas paso a paso

Cada bloque muestra el código, la pila y los registros tal como aparecían en la diapositiva correspondiente. Las diapositivas repiten el listado completo en cada paso, marcando en negrita (perdida en la extracción) la instrucción recién ejecutada; el contenido numérico se preserva exactamente como en el original, incluidos los fragmentos de tabla rota del extractor que no se pudieron recomponer de forma inequívoca.

Paso 1

caller:
…
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
; calculate sum
00401303 sub esp, 0x8
00401306 …
00401320 mov eax, 0x6
00401328 mov esp, ebp
0040132A pop ebp
0040132B ret
Registers
EIP 00401298
EBP 0012F072
ESP 00000003 ( arg #3) 0012F050
ESP 0012F050
EAX 00000000

Paso 2

caller:
 …
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
 ; calculate sum
00401303 sub esp, 0x8
- 00401306
 - …
 -
 -
00401320 mov eax, 0x6
00401328 mov esp, ebp
0040132A pop ebp
0040132B ret
Registers
- EIP
 - 0040129A
 - ESP
 - 00000002 ( arg #2)
0012F04C
- EBP
 - 0012F072
 -
 -
00000003 ( arg #3) 0012F050
- ESP
 - 0012F04C
 -
 -
- EAX
 - 00000000
 -
 -

Paso 3

caller:
 …
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
 ; calculate sum
00401303 sub esp, 0x8
- 00401306
 - …
 -
 -
 -
00401320 mov eax, 0x6
00401328 mov esp, ebp
0040132A pop ebp
0040132B ret
| | | ESP | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 0040129C
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F072
 -
 -
 -
| | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F048
 -
 -
 -
- EAX
 - 00000000
 -
 -
 -

Paso 4

caller:
 …
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
 ; calculate sum
00401303 sub esp, 0x8
- 00401306
 - …
 -
 -
 -
00401320 mov eax, 0x6
00401328 mov esp, ebp
0040132A pop ebp
0040132B ret
| | | ESP | 004012A1 ( return add.) | 0012F044 |
| | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 00401300
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F072
 -
 -
 -
| | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F044
 -
 -
 -
- EAX
 - 00000000
 -
 -
 -

Paso 5

caller:
…
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
; calculate sum
00401303 sub esp, 0x8
00401306 …
00401320 mov eax, 0x6
00401328 mov esp, ebp ESP 0012F072 ( original EBP) 0012F040
0040132A pop ebp
0040132B ret
004012A1 ( return add.) 0012F044
00000001 ( arg #1) 0012F048
Registers
EIP 00401301 00000002 ( arg #2) 0012F04C
EBP 0012F072
00000003 ( arg #3) 0012F050
ESP 0012F040
EAX 00000000

Paso 6

caller:
…
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
; calculate sum
00401303 sub esp, 0x8
00401306 …
00401320 mov eax, 0x6
00401328 mov esp, ebp ESP 0012F072 ( original EBP) 0012F040
0040132A pop ebp
0040132B ret
004012A1 ( return add.) 0012F044
00000001 ( arg #1) 0012F048
Registers
EIP 00401303 00000002 ( arg #2) 0012F04C
EBP 0012F040
00000003 ( arg #3) 0012F050
ESP 0012F040
EAX 00000000

Paso 7

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | ESP | 12BF97AC ( uninitialized) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
957BC02A ( uninitialized)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 00401306
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F040
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F038
 -
 -
 -
 -
- EAX
 - 00000000
 -
 -
 -
 -

Paso 8

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | ESP | 00000005 ( local var) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( local var)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 00401320
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F040
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F038
 -
 -
 -
 -
- EAX
 - 00000000
 -
 -
 -
 -

Paso 9

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | ESP | 00000005 ( EBP - 8) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( EBP - 4)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( EBP + 8) | 0012F048 |
Registers
- EIP
 - 00401320
 -
 -
 - 00000002 ( EBP + C)
 -
0012F04C
- EBP
 - 0012F040
 -
 -
 -
 -
| | | | | 00000003 ( EBP + 10) | 0012F050 |
- ESP
 - 0012F038
 -
 -
 -
 -
- EAX
 - 00000000
 -
 -
 -
 -

Paso 10

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | ESP | 00000005 ( local var) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( local var)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 00401328
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F040
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F038
 -
 -
 -
 -
- EAX
 - 00000006
 -
 -
 -
 -

Paso 11

caller:
 …
00401296 push 3
00401298 push 2
0040129A push 1
0040129C call sum
004012A1 add esp, 0xC
sum:
00401300 push ebp
00401301 mov ebp, esp
| | | 00000005 ( local var) | 0012F038 |
 ; calculate sum
00401303 sub esp, 0x8
00000001 ( local var)
- 00401306
 - …
 -
 - 0012F03C
00401320 mov eax, 0x6
00401328 mov esp, ebp ESP 0012F072 ( original EBP) 0012F040
0040132A pop ebp
0040132B ret
| | | 004012A1 ( return add.) | 0012F044 |
| | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 0040132A
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F040
 -
 -
| | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F040
 -
 -
- EAX
 - 00000006
 -
 -

Paso 12

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | | 00000005 ( local var) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( local var)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | ESP | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 0040132B
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F072
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F044
 -
 -
 -
 -
- EAX
 - 00000006
 -
 -
 -
 -

Paso 13

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | | 00000005 ( local var) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( local var)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | ESP | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 004012A1
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F072
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F048
 -
 -
 -
 -
- EAX
 - 00000006
 -
 -
 -
 -

Paso 14

caller:
 …
- 00401296 push
 -
 - 3
 -
 -
 -
- 00401298 push
 -
 - 2
 -
 -
 -
- 0040129A push
 -
 - 1
 -
 -
 -
- 0040129C call
 -
 - sum
 -
 -
 -
- 004012A1 add
 -
 - esp, 0xC
 -
 -
 -
sum:
- 00401300 push
 -
 - ebp
 -
 -
 -
- 00401301 mov
 -
 - ebp, esp
 -
 -
 -
| | | | | 00000005 ( local var) | 0012F038 |
 ; calculate sum
- 00401303 sub
 -
 - esp, 0x8
 -
 -
 -
00000001 ( local var)
- 00401306
 - …
 -
 -
 -
 - 0012F03C
- 00401320 mov
 -
 - eax, 0x6
 -
 -
 -
- 00401328 mov
 -
 - esp, ebp
 -
 - 0012F072 ( original EBP)
 - 0012F040
- 0040132A pop
 -
 - ebp
 -
 -
 -
0040132B ret
| | | | | 004012A1 ( return add.) | 0012F044 |
| | | | | 00000001 ( arg #1) | 0012F048 |
Registers
- EIP
 - 004012A4
 -
 -
 - 00000002 ( arg #2)
 -
0012F04C
- EBP
 - 0012F072
 -
 -
 -
 -
| | | | | 00000003 ( arg #3) | 0012F050 |
- ESP
 - 0012F054
 -
 -
 -
 -
- EAX
 - 00000006
 -
 - ESP
 -
 -

Function Calls - Zoom Out

In the previous slides we saw how a single stack frame is generated.

In the illustration on the right we can see multiple stack frames on top of each other, each has its own parameters (arguments), return address, its caller’s EBP and local variables.

Now that we know the architecture pretty well, let’s see how high-level language is compiled into 0x86 assembly.

C to x86

  • A C program has two arguments for the main function:
    • int main(int argc, char** argv)

For example, a program which is executed from the command line like that:

awesome.exe -r pathtofile.txt

will have the following argc, argv values:

  • argc = 3
  • argv = [address of “awesome.exe” string in memory, address of “-r” string in memory, address of “pathtofile.txt” string in memory]

Remember #1

  • mov [ebp+myvar], somevalue

What does it mean?

  • myvar is an offset (-4, -8, -C…) from EBP to the stack address where myvar is stored (thanks IDA for helping us and renaming it!)
  • The meaning of this expression is “assign the value somevalue to myvar”

Remember #2

  • function(a, b, c) : push c; push b; push a;

Function parameters are pushed in reverse order.

Remember #3

mov eax, [ebp+argv]
; argv is again an offset from EBP to where argv's address is stored
mov ecx, [eax+4*i]
; This means "set ecx to equal argv[i]"

El programa C

Let’s look at the following C program. What does it do?

  1. It verifies that the number of arguments passed to the program is 3 (including the program’s path).
  2. It checks if the second argument is a flag “-r”.
  3. If that’s the case, it deletes the file provided in the third argument.

Análisis paso a paso

First, we compare argc to 3. We learned that cmp is practically a sub - so 3 is subtracted from the value of argc. If the result is 0, then argc is indeed 3 and we jump to 0x004113DA.

If the result is non zero, then argc is not equal to 3. We zeroize EAX by XORing it with itself and then jump to an address where the function returns (trust me with that).

Next, we can see a call to strncmp. The following parameters are pushed to it:

  1. 2, the number of characters to compare
  2. a literal string “-r”, to which some other string should be compared
  3. ECX - what does it hold?

ECX stores whatever is in address eax+4. EAX, in turn, stores whatever is in address ebp+argv, which is the address to the argv array.

Therefore, ECX = *(argvaddress + 4) = argv[1]

Given that parameters are pushed in reverse, the actual call is:

strncmp(argv[1], "-r", 2)

which is exactly what we see in our C code :)

If the comparison holds (namely, the strings are equal, and the user indeed passed “-r” as the second argument) - EAX will be equal to zero and there will not be a jump. Otherwise - if the strings are not equal - we jump and return zero (trust me once again…)

For the case in which the string are equal, we reach the following code. We push ECX, which (similarly to the previous block) hold *(argv + 8) = argv[2]. Then we call DeleteFileA to delete the file whose path was just pushed.

C to x86 - All Code

Awesome work! Keep on going!