Master the fundamental concepts of binary formats through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksThe .text section contains the executable machine code of a program. It is read-only and mapped into memory with execute permissions. Every instruction your CPU runs from the binary lives here.
To extract it manually:
e_shoff.text using the .shstrtab string tablesh_offset and sh_size from its section headersh_offset in the fileA standard hex dump shows 16 bytes per line. For example, the classic x86-64 prologue appears as:
cLoading…
Those bytes decode to push rbp; mov rbp, rsp; sub rsp, 0x10.
You will find the .text section by name and print a formatted hex dump. Disassemblers start with these raw bytes and decode instructions, and malware analysts often need to extract shellcode from .text when packers encrypt or compress it.
The first bytes of .text often reveal compiler and optimization choices. An unoptimized build shows a full prologue; -O2 may omit the frame pointer. Security analysts compare .text hashes before and after an update to detect unauthorized code injection. Packers may encrypt .text at rest and decrypt it at runtime, which is why extracting this section is a common unpacker first step.
Decode a stream of x86-64 machine code one instruction at a time, for this subset (check the encodings in the Intel SDM or on felixcloutier.com):
| Bytes | Instruction | Length |
|---|---|---|
50+r | push r | 1 |
58+r | pop r | 1 |
B8+r imm32 | mov r, imm32 (4-byte little-endian immediate) | 5 |
89 ModRM | mov r/m32, r32 | 2 |
8B ModRM | mov r32, r/m32 | 2 |
83 ModRM imm8 | with ModRM reg = 5: sub r/m32, imm8 (sign-extended) | 3 |
C3 | ret | 1 |
90 | nop | 1 |
The register number r (low 3 bits of the opcode, or a ModRM field) names a 32-bit register: 0 eax, 1 ecx, 2 edx, 3 ebx, 4 esp, 5 ebp, 6 esi, 7 edi. ModRM splits into mod (bits 7-6), reg (bits 5-3) and rm (bits 2-0); only mod = 3, register to register, is decoded.
N (1 to 1024), then N bytes in hex.
decoded N bytes, then one line per instruction, then instructions: K. Each line has an exact format: the spacing is fixed, so copy these C formats.
| Instruction | Format |
|---|---|
| push | "push %s ; opcode 0x%02X = 50+rd, rd=%u" |
| pop | "pop %s ; opcode 0x%02X = 58+rd, rd=%u" |
| mov imm32 | "mov %s, 0x%X ; opcode B8+rd, rd=%u, imm32 LE" |
| 89, mod 3 | "mov %s, %s ; opcode 89 ModRM, mod=3 reg=%u rm=%u" with destination rm, source reg |
| 8B, mod 3 | "mov %s, %s ; opcode 8B ModRM, mod=3 reg=%u rm=%u" with destination reg, source rm |
| 83 /5 | "sub %s, %d ; opcode 83 /5, mod=3 rm=%u, imm8 sign-extended" |
| ret | "ret ; opcode C3" |
| nop | "nop ; opcode 90" |
Anything else prints a line and moves on:
(unknown opcode 0x91 at offset 5), advancing 1 byte.(unsupported ModRM mod=0 at offset 3), advancing 2 bytes.(unsupported 83 ModRM mod=3 reg=0 at offset 3), advancing 3 bytes.Offsets are decimal.