103 Assembly Crash Course
103 Assembly Crash Course
Professional
3.1 Introduction
Introduction
Your journey into x64 Assembly…
CPU Architecture
AH AL
AX
EAX
RAX
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.22
3.2.3 CPU Architecture – General Purpose
Registers
Full Register 64-bit Lower 32-bit part Lower 16-bit part Special Access Lower 8-bit part
RAX EAX AX AH AL
RBX EBX BX BH BL
RCX ECX CS CH CL
RDX EDX DX DH DL
RDI EDI DI DIL
RSI ESI SI SIL
RBP EBP BP BPL
RSP ESP SP SPL
R8 R8D R8W R8B
R9 R9D R9W R9B
…R15 …R15D …R15W …R15B
Please note that three dots (…) in last row means that the same applies to register
R10, R11, R12, R13, and R14; they were removed for brevity.
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.23
3.2.3 CPU Architecture – General Purpose
Registers
Segment Registers:
• Before the 64-bit architecture (for example: x86); these
registers, controlled segmentation of memory in many
modes. In 64-bit architectures, they are always a flat
address space (base Zero for each segment).
The following is a quick view on the lower 32-bit part of the register.
Bit Name Meaning Bit Name Meaning Bit Name Meaning
0 CF Carry Flag 11 OF Overflow Flag 22 -- -Reserved-
1 -- -Reserved- 12 23 -- -Reserved-
IOPL I/O privilege Level field
2 PF Parity Flag 13 24 -- -Reserved-
3 -- -Reserved- 14 NT Nested Task flag 25 -- -Reserved-
4 AF Auxiliary Carry Flag 15 -- -Reserved- 26 -- -Reserved-
5 -- -Reserved- 16 RF Resume Flag 27 -- -Reserved-
6 ZF Zero Flag 17 VM Virtual-8086 Mode flag 28 -- -Reserved-
7 SF Sign Flag 18 AC Alignment Check flag 29 -- -Reserved-
8 TF Trap Flag 19 VIF Virtual Interrupt Flag 30 -- -Reserved-
9 IF Interrupt enabled Flag 20 VIP Virtual Interrupt Pending flag 31 -- -Reserved-
10 DG Direction Flag 21 ID Identification Flag
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.37
3.2.6 CPU Architecture – Instruction Pointer Flag
<instruction>[<white space><destination>[<,source>]]
Example:
mov eax, ebx ; this is to copy EBX value into EAX
This is a comment.
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.45
3.3.1 Instructions
More examples: MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.46
3.3.1 Instructions
31 23 0
For example:
• FADD is used to add values to a float
• FMUL is used for multiplication
For example:
mov rax, 0x100000000;now rax value is 0x00000001 0000 0000
mov eax, x0ffff ;now rax value is 0x00000001 0000 ffff
mov ah, 0 ;now rax value is 0x00000001 0000 00ff
In this example, we use SHL instruction, which shifts bits to the left
inside the target part of the register. Syntax:
SHL <register>, <bits count>
mov rbx, 0xa0000000f; new rbx value is 0x0000000a 0000 000f
shl ebx, 8 ; new rbx value is 0x0000000a 0000 0f00
shl rbx, 4 ; new rbx value is 0x000000a0 0000 f000
shl bx, 4 ; new rbx value is 0x000000a0 0000 0000
mov bl, 0xbb ; new rbx value is 0x000000a0 0000 00bb
mov rcx, 0xcc ; new rcx value is 0x00000000 0000 00cc
shl rcx, 32 ; new rcx value is 0x000000cc 0000 0000
mov ecx, ebx ; new rcx value is 0x000000cc 0000 00bb
(effected parts shown in red)
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.65
3.3.6 Mathematical Operations
Flags like Zero Flag (ZF) are affected by the result of these
instructions.
This will do a logical XOR for the value of EAX Register with
itself and save the result in the EAX Register. The result will
always be Zero, so the instruction is similar to:
mov eax, 0
Example:
eax (in binary)
Interrupts:
• INT instruction is a very special instruction that is used to
call kernel functions.
Interrupts (cont.):
• The program must fill few registers with specific values in
a specific way before calling an interrupt; each interrupt
has its own manual regarding that.
Sub-routines:
• CALL instruction is used similarly to JUMP to change
execution path unconditionally.
Sub-routines (cont.):
• A sub-routine is a virtual convention that is used to define
the chunk of instructions starting from first instruction
located by CALL, and ended by RET.
Sub-routines (cont.):
• Assembly Developers (and compilers for high level
languages) are responsible of keeping the sync between
CALL and RET. Each CALL must have a corresponding
RET.
_sub2:
;... do something else Sub-routine
ret
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.95
3.3.10 Accessing Memory
CALL and RET will always push and pop a 64-bit value
from/to RIP Register.
extern “C”
The Caller will always trust the Callee that it did not change
any value of any Non-Volatile Register.
As an example, we will start with a very simple C++ code, and see
how it would be converted into Assembly. Remember that (extern
“C”) will tell the compiler to use x64 fastcall convention:
int main() {
int result = _get_sum(5, 7);
}
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.121
3.3.12 x64 Calling Conventions
Before digging deeper into the previous example. We noticed that arguments
were passed in Registers. This is not something random. x64 fastcall
convention has its rules:
Now back to our simple example. Let’s trace execution of the code. We are
moving values to 32-bit registers because (int) is a 32-bit type. Memory
64bit items
Address of next statement pushed into the stack, then RIP is set to
point to the first statement of the Callee. Memory
64bit items
sub rsp, 0x20 EAX ????
mov ecx, 0x5
mov edx, 0x7 ECX 0x5
call _get_sum EDX 0x7
add rsp, 0x20
…… RSP
_get_sum: ????
????
RIP mov eax, ecx Shadow Space
????
add eax, edx ????
ret Some old value in the stack ????
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.130
3.3.12 x64 Calling Conventions
Preparing return value. Value of first argument copies from ECX to EAX.
Again, return value type is (int), which is 32-bit. Therefore, we use EAX. Memory
64bit items
sub rsp, 0x20 EAX 0x5
mov ecx, 0x5
mov edx, 0x7 ECX 0x5
call _get_sum EDX 0x7
add rsp, 0x20
…… RSP
_get_sum: ????
????
mov eax, ecx Shadow Space
????
RIP add eax, edx ????
ret Some old value in the stack ????
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.131
3.3.12 x64 Calling Conventions
Let’s assume that the value 0xFF is stored in ECX. If the Callee needs to use ECX then the
Value of ECX needs to be stored before doing so. Here is an example of how that can be
achieved:
Memory
64bit items
After the first instruction is executed, the ECX value is saved on the
stack. It is available to be used when needed.
Memory
64bit items
mov dword ptr[rsp+0x8], ecx EAX ??
RIP mov ecx, 0x1234
mov eax, dword ptr[rsp+0x8] ECX 0xFF
……
Next statement in Caller
RSP
1st
Reserved for argument. RSP+0x08 0xFF
Shadow Space Reserved for 2nd argument. RSP+0x10 ????
Reserved for 3rd argument. RSP+0x18 ????
Reserved for 4th argument. RSP+0x20 ????
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.138
3.3.12 x64 Calling Conventions
With the second instruction executed, the ECX value changed to 0x1234. This is
fine because now, we have the original value ion the Stack, so we can restore it
later on. Memory
64bit items
mov dword ptr[rsp+0x8], ecx EAX ??
mov ecx, 0x1234
RIP mov eax, dword ptr[rsp+0x8] ECX 0x1234
……
Next statement in Caller
RSP
1st
Reserved for argument. RSP+0x08 0xFF
Shadow Space Reserved for 2nd argument. RSP+0x10 ????
Reserved for 3rd argument. RSP+0x18 ????
Reserved for 4th argument. RSP+0x20 ????
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.139
3.3.12 x64 Calling Conventions
With the last instruction in the example, the EAX register loaded the
value of the first argument from the stack.
Memory
64bit items
mov dword ptr[rsp+0x8], ecx EAX 0xFF
mov ecx, 0x1234
mov eax, dword ptr[rsp+0x8] ECX 0x1234
RIP ……
Next statement in Caller
RSP
1st
Reserved for argument. RSP+0x08 0xFF
Shadow Space Reserved for 2nd argument. RSP+0x10 ????
Reserved for 3rd argument. RSP+0x18 ????
Reserved for 4th argument. RSP+0x20 ????
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.140
3.3.12 x64 Calling Conventions
Now pay attention to the Callee code. There is an 8 bytes shift when accessing
5th and 6th arguments. It is caused by the pushed (next RIP) value.
Memory
64bit items
mov eax, dword ptr[rsp+0x30] ECX 0x11
add eax, dword ptr[rsp+0x28] EDX 0x22
add eax, r9d R8D 0x33
R9D 0x44
add eax, r8d RSP <RIP>
add eax, edx st
Reserved for 1 argument. RSP+0x08 ????
add eax, ecx Shadow Space Reserved for 2nd argument. RSP+0x10 ????
ret
rd
Reserved for 3 argument. RSP+0x18 ????
RIP Reserved for 4th argument. RSP+0x20 ????
Reserved for 5th argument. RSP+0x28 0x55
Reserved for 6th argument. RSP+0x30 0x66
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.143
3.3.12 x64 Calling Conventions
Any other register can be used to point to the base and keep the
same logic, but the standard Register used by all compilers is
RBP.
Base of the stack does not mean bottom of the program stack. It
is the bottom of the Stack Frame inside the sub-routine.
MAPv1: Section 01, Module 03 - Caendra Inc. © 2020 | p.144
3.3.12 x64 Calling Conventions
For example, in the Callee, compare the address of the 5th argument in the
following situations. Keeping track of RSP moves will be a nightmare!
To resolve that, the Callee must push RBP value into the
stack before creating the Stack Frame.
Now this is the actual representation of Stack Frames in x64. Original RBP value is
pushed right after entering the Callee, then RBP is set to the same value of RSP.
Prolog: is the code for creating the Stack Frame. There are
primarily three steps:
• Push RBP to preserve its original value
• Set RBP to the same value of RSP
• Move RSP to allocate space for local variables
*NOTE: some courses contain several labs and manuals, please make sure to click the file icon as it may
be a zip that contains multiple lab manuals.