Lion Cipher Lab
Write a mini-debugger from scratch with ptrace() (software breakpoints)
- Foundations
- Advanced
- ~90 min
- Free · no account required
Why it matters
Every serious security discipline eventually runs into a debugger. Reverse engineers live in one; exploit developers step through crashes instruction by instruction; malware analysts watch a sample unpack itself in memory; and defenders read the artifacts all of that leaves behind. But most people treat gdb and lldb as opaque magic boxes -- they memorize commands without any idea what the tool is actually doing to the program underneath. This lab removes the mystery permanently by having you BUILD the machine. Once you have stamped a 0xCC byte over a running instruction with your own hands,…
What you'll learn
- what the ptrace() system call is and how one process gains god-like control over another (tracer vs tracee)
- starting a target under control: fork() a child, opt it in with ptrace(PTRACE_TRACEME), execvp() the target, and drive it from the parent with waitpid()
- setting a SOFTWARE breakpoint by hand: read the original byte with PTRACE_PEEKTEXT, stamp 0xCC (the x86 INT3 instruction) over its low byte with PTRACE_POKETEXT, and save the original
- catching the SIGTRAP with waitpid and reading the CPU register file with PTRACE_GETREGS -- and understanding why RIP lands one byte PAST the breakpoint
- the crux move every debugger makes: restore the original byte, rewind RIP by 1 with PTRACE_SETREGS, single-step one instruction, then re-arm the 0xCC
- reading a live program's arguments straight out of a register (RDI on the x86-64 System V ABI) while it is stopped
- the named failure modes that make this hard: not rewinding RIP, not restoring the byte before stepping, PIE/ASLR breaking a hardcoded address, waiting on the wrong child, and text-vs-data confusion
- the judgment: when to build your own vs use gdb, how anti-debugging malware detects a tracer via a failed PTRACE_TRACEME, and how pros go further with hardware debug registers (DR0-DR7) and gdb's remote protocol
Steps in this lab
- What a debugger really is, and what ptrace gives you
- Set up the tools and compile a tiny target (with a fixed address)
- The skeleton: fork the target, opt into tracing, and take the wheel
- Arm a software breakpoint: save the byte, stamp 0xCC
- Run it, catch the SIGTRAP, and read the registers
- The crux: step past the breakpoint correctly, then re-arm
- Assemble the complete dbg.c, compile it, and run it
- The named failure modes (this is what makes it hard)
- The judgment: when to build your own, and how the pros go further