Introduction to x64
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Introduction to x64
x64, also known as x86-64, is a 64-bit processor architecture predominantly used in desktop and server computing. Originating from the x86 architecture produced by Intel and later adopted by AMD with the name AMD64, it's the prevalent architecture in personal computers and servers today.
Registers
x64 expands upon the x86 architecture, featuring 16 general-purpose registers labeled rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi, and r8 through r15. Each of these can store a 64-bit (8-byte) value. These registers also have 32-bit, 16-bit, and 8-bit sub-registers for compatibility and specific tasks.
rax- Traditionally used for return values from functions.rbx- Often used as a base register for memory operations.rcx- Commonly used for loop counters.rdx- Used in various roles including extended arithmetic operations.rbp- Base pointer for the stack frame.rsp- Stack pointer, keeping track of the top of the stack.rsiandrdi- Used for source and destination indexes in string/memory operations.r8tor15- Additional general-purpose registers introduced in x64.
Calling Convention
The x64 calling convention varies between operating systems. For instance:
Windows: The first four parameters are passed in the registers
rcx,rdx,r8, andr9. Further parameters are pushed onto the stack. The return value is inrax.System V (commonly used in UNIX-like systems): The first six integer or pointer parameters are passed in registers
rdi,rsi,rdx,rcx,r8, andr9. The return value is also inrax.
If the function has more than six inputs, the rest will be passed on the stack. RSP, the stack pointer, has to be 16 bytes aligned, which means that the address it points to must be divisible by 16 before any call happens. This means that normally we would need to ensure that RSP is properly aligned in our shellcode before we make a function call. However, in practice, system calls work many times even if this requirement is not met.
Calling Convention in Swift
Swift have its own calling convention that can be found in https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64
Common Instructions
x64 instructions have a rich set, maintaining compatibility with earlier x86 instructions and introducing new ones.
mov: Move a value from one register or memory location to another.Example:
mov rax, rbx— Moves the value fromrbxtorax.
pushandpop: Push or pop values to/from the stack.Example:
push rax— Pushes the value inraxonto the stack.Example:
pop rax— Pops the top value from the stack intorax.
addandsub: Addition and subtraction operations.Example:
add rax, rcx— Adds the values inraxandrcxstoring the result inrax.
mulanddiv: Multiplication and division operations. Note: these have specific behaviors regarding operand usage.callandret: Used to call and return from functions.int: Used to trigger a software interrupt. E.g.,int 0x80was used for system calls in 32-bit x86 Linux.cmp: Compare two values and set the CPU's flags based on the result.Example:
cmp rax, rdx— Comparesraxtordx.
je,jne,jl,jge, ...: Conditional jump instructions that change control flow based on the results of a previouscmpor test.Example: After a
cmp rax, rdxinstruction,je label— Jumps tolabelifraxis equal tordx.
syscall: Used for system calls in some x64 systems (like modern Unix).sysenter: An optimized system call instruction on some platforms.
Function Prologue
Push the old base pointer:
push rbp(saves the caller's base pointer)Move the current stack pointer to the base pointer:
mov rbp, rsp(sets up the new base pointer for the current function)Allocate space on the stack for local variables:
sub rsp, <size>(where<size>is the number of bytes needed)
Function Epilogue
Move the current base pointer to the stack pointer:
mov rsp, rbp(deallocate local variables)Pop the old base pointer off the stack:
pop rbp(restores the caller's base pointer)Return:
ret(returns control to the caller)
macOS
syscalls
There are different classes of syscalls, you can find them here:
Then, you can find each syscall number in this url:
So in order to call the open syscall (5) from the Unix/BSD class you need to add it: 0x2000000
So, the syscall number to call open would be 0x2000005
Shellcodes
To compile:
To extract the bytes:
Shell
Taken from here and explained.
Read with cat
The goal is to execute execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL), so the second argument (x1) is an array of params (which in memory these means a stack of the addresses).
Invoke command with sh
Bind shell
Bind shell from https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html in port 4444
Reverse Shell
Reverse shell from https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html. Reverse shell to 127.0.0.1:4444
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Last updated