Skip to content

Assembly

Assembly

Intro to RE

Code and compiled assembly back to back

Tutorials:
ASCII table
x86_64 NASM Assembly Quick Reference
x86 Architecture Overview
ARM Assembly to HEX
Intel Introduction to x64 Assembly
x86 and amd64 instruction reference
ARM Assembly Basics

Basics

Stack operations:
- push value: pushes a value into the stack (decrements ESP by 4, the size of one stack ‘unit’).
- pop register: pops a value to a register (increments ESP by 4).

Data transfer:
- mov destination, source: moves copies a value from/to a register.
- mov destination, [expression]: copies a value from a memory address resolved from a ‘register expression’ (single register or arithmetic expression involving one or more registers) into a register.

Flow control:
- jmp destination: jumps into a code location (sets EIP (instruction pointer)).
- jz/je destination: jumps into a code location if ZF (the zero flag) is set.
- jnz/jne destination: jumps into a code location if ZF is not set.

Operations:
- cmp operand1, operand2: compares the 2 operands and sets ZF if they’re equal.
- add operand1, operand2: operand1 += operand2;
- sub operand1, operand2: operand1 -= operand2;

Function transitions:
- call function: calls a function (pushes current EIP, then jumps to the function).
- retn: returns to caller function (pops back the previous EIP).

Functions

Function prologue:
A function prologue is some initial code embedded in the beginning of most functions, it serves to set up a new stack frame for said function.

55          push    ebp        ; preserve caller function's base pointer in stack
8B EC       mov     ebp, esp   ; caller function's stack pointer becomes base pointer (new stack frame)
83 EC XX    sub     esp, X     ; adjust the stack pointer by X bytes to reserve space for local variables

Function epilogue:*
The epilogue is simply the opposite of the prologue - it undoes its steps to restore the stack frame of the caller function, before it returns to it:

8B E5    mov    esp, ebp    ; restore caller function's stack pointer (current base pointer) 
5D       pop    ebp         ; restore base pointer from the stack
C3       retn               ; return to caller function

Now at this point, you might be wondering - how do functions talk to each other? How exactly do you send/access arguments when calling a function, and how do you receive the return value? That’s precisely why we have calling conventions.

Calling conventions

__cdecl:

;func(1, 2, 3);
6A 03             push    3
6A 02             push    2
6A 01             push    1
E8 XX XX XX XX    call    func

Putting it together

int __cdecl func(int, int, int):

           prologue:
55           push    ebp               ; save base pointer
8B EC        mov     ebp, esp          ; new stack frame

           body:
8B 45 08     mov     eax, [ebp+8]      ; load first argument to EAX (return value)
03 45 0C     add     eax, [ebp+0Ch]    ; add 2nd argument
03 45 10     add     eax, [ebp+10h]    ; add 3rd argument

           epilogue:
5D           pop     ebp               ; restore base pointer
C3           retn                      ; return to caller