Registers and Memory Layout
3 minutes read
Registers (x64)
| Register | Low 32-bits | Low 16-bits | Low 8-bits | Notes |
|---|---|---|---|---|
%rax | %eax | %ax | %al | a function's return value, caller-saved |
%rdi | %edi | %di | %dil | 1st argument of a function, caller-saved |
%rsi | %esi | %si | %sil | 2nd argument of a function, caller-saved |
%rdx | %edx | %dx | %dl | 3rd argument of a function, caller-saved |
%rcx | %ecx | %cx | %cl | 4th argument of a function, caller-saved |
%r8 | %r8d | %r8w | %r8b | 5th argument of a function, caller-saved |
%r9 | %r9d | %r9w | %r9b | 6th argument of a function, caller-saved |
%r10 | %r10d | %r10w | %r10b | temporary register, caller-saved |
%r11 | %r11d | %r11w | %r11b | temporary register, caller-saved |
%rbp | %ebp | %bp | %bpl | base pointer, pointing to the base of the current stack frame, callee-saved |
%rsp | %esp | %sp | %spl | stack pointer, pointing to the topmost element in the stack, callee-saved |
%rbx | %ebx | %bx | %bl | local variable, callee-saved |
%r12 | %r12d | %r12w | %r12b | local variable, callee-saved |
%r13 | %r13d | %r13w | %r13b | local variable, callee-saved |
%r14 | %r14d | %r14w | %r14b | local variable, callee-saved |
%r15 | %r15d | %r15w | %r15b | local variable, callee-saved |
%rip | instruction pointer |
Memory Layout

Stack Frame Layout
A stack is allocated at a high address and grows towards lower addresses.

Position Independent Executables (PIE)
The memory addresses are not fully randomized, particularly the lower 3 bits of the base address, even when PIE is enabled.
1 pwndbg> info proc mappings
2 process 67443
3 Mapped address spaces:
4
5 Start Addr End Addr Size Offset Perms File
6 0x0000555555554000 0x0000555555555000 0x1000 0x0 r--p /ptr/vuln
7 0x0000555555555000 0x0000555555556000 0x1000 0x1000 r-xp /ptr/vuln
8 0x0000555555556000 0x0000555555557000 0x1000 0x2000 r--p /ptr/vuln
9 0x0000555555557000 0x0000555555558000 0x1000 0x2000 r--p /ptr/vuln
10 0x0000555555558000 0x0000555555559000 0x1000 0x3000 rw-p /ptr/vuln
11 0x00007ffff7c00000 0x00007ffff7c28000 0x28000 0x0 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
12 0x00007ffff7c28000 0x00007ffff7db0000 0x188000 0x28000 r-xp /usr/lib/x86_64-linux-gnu/libc.so.6
13 0x00007ffff7db0000 0x00007ffff7dff000 0x4f000 0x1b0000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
14 0x00007ffff7dff000 0x00007ffff7e03000 0x4000 0x1fe000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
15 0x00007ffff7e03000 0x00007ffff7e05000 0x2000 0x202000 rw-p /usr/lib/x86_64-linux-gnu/libc.so.6
16 0x00007ffff7e05000 0x00007ffff7e12000 0xd000 0x0 rw-p
17 0x00007ffff7fa0000 0x00007ffff7fa3000 0x3000 0x0 rw-p
18 0x00007ffff7fbd000 0x00007ffff7fbf000 0x2000 0x0 rw-p
19 0x00007ffff7fbf000 0x00007ffff7fc1000 0x2000 0x0 r--p [vvar]
20 0x00007ffff7fc1000 0x00007ffff7fc3000 0x2000 0x0 r--p [vvar_vclock]
21 0x00007ffff7fc3000 0x00007ffff7fc5000 0x2000 0x0 r-xp [vdso]
22 0x00007ffff7fc5000 0x00007ffff7fc6000 0x1000 0x0 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
23 0x00007ffff7fc6000 0x00007ffff7ff1000 0x2b000 0x1000 r-xp /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
24 0x00007ffff7ff1000 0x00007ffff7ffb000 0xa000 0x2c000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
25 0x00007ffff7ffb000 0x00007ffff7ffd000 0x2000 0x36000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
26 0x00007ffff7ffd000 0x00007ffff7fff000 0x2000 0x38000 rw-p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
27 0x00007ffffffdd000 0x00007ffffffff000 0x22000 0x0 rw-p [stack]
28 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall]
Heap
Unlike the stack, the heap segment starts at a low address and grows towards higher memory addresses. The basic concept in the heap meamory allocation is chunk, as defined below.
/*
This struct declaration is misleading (but accurate and necessary).
It declares a "view" into memory allowing access to necessary
fields at known offsets from a given base. See explanation below.
*/
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
House of Force
"House Of Force" is an exploitation approach against the heap memory. This exploitation requires the attacker can override the size field in the top chunk's header. Then, the attacker can leverage the integer overflow to control the memory address that malloc will return, further leading to arbitrary memory read/write.
References
- Memory Layout of C Program
- Stack frame layout on x86-64 - Eli Bendersky's website
- x64 Cheat Sheet
- CS107 Guide to x86-64
- Position Independent Executables < BorderGate
- Heap Structure - CTF Wiki
- House Of Force - CTF Wiki
- >House of Force | heap-exploitation
- malloc.c - malloc/malloc.c - Glibc source code glibc-2.42 - Bootlin Elixir Cross Referencer