Master Debugging Stripped Executables with GDB: A Step‑by‑Step Guide
This comprehensive guide explains why debugging stripped binaries is crucial, walks through installing GDB, shows how to disassemble code, set address‑based breakpoints, inspect memory, handle signals, use advanced features like backtraces, conditional breakpoints, watchpoints, remote debugging, and even basic heap analysis for C/C++ programs.
In software development, debugging is a critical skill, especially when dealing with stripped executables that lack symbol tables, which can occur due to special compiler options or third‑party libraries. Without symbols, developers face a "dark forest" of unknown function calls and variable changes, but GDB can illuminate the program’s behavior.
Debugging stripped binaries is also essential in security analysis, where malware and reverse engineering rely on inspecting program execution to understand attack mechanisms and devise defenses.
1. Interview Question Interpretation
Question: How to use GDB to debug an executable without debugging information?
Approach: Even without symbols, basic debugging is possible. Install GDB, start it with the program, and use commands like break (address or offset), run, next, step, and print to set breakpoints, step through code, and inspect memory or registers.
2. GDB Basics
2.1 What is GDB?
GDB (GNU Debugger) is a powerful open‑source debugger for C, C++, and other languages, widely used since 1986.
Official website: https://www.gnu.org/software/gdb/
Supported languages: Ada, C, C++, Objective‑C, Pascal, etc.
Works for local and remote debugging.
2.2 Installation and Startup
Linux (Debian/Ubuntu): sudo apt -y install gdb RedHat/CentOS/Fedora: sudo yum -y install gdb macOS (Homebrew): brew install gdb (additional permissions may be required) Windows (MinGW): install GDB component and add to PATH.
Start GDB with gdb program, optionally with a core file or PID.
2.3 Differences Between Symbolic and Stripped Debugging
With symbols, you can set breakpoints by line number or function name. Without symbols, you must use addresses or offsets, making debugging more challenging.
2.4 Core File Debugging
A core file records a program’s memory image at crash. Enable core dumps with ulimit -c unlimited and debug with gdb program core, then use bt to view the stack.
3. Common GDB Commands
3.1 Start and Exit
gdb <program>– start GDB and load the executable. q – quit GDB.
3.2 Viewing Source
listor 1 – show 10 lines of source. 1<line> – show lines around a specific line. 1<function> – show source of a function.
3.3 Breakpoints
Set breakpoints with break <line|function|address>. Conditional breakpoints: break ... if condition. Temporary breakpoints: tbreak. Function breakpoints: rbreak. Delete with clear or delete. Enable/disable with enable / disable.
3.4 Watchpoints
Monitor variable changes: watch var. Read watch: rwatch var. Read/write watch: awatch var.
3.5 Catchpoints
Catch events like exceptions, exec, fork, load, unload, etc., using catch <event>.
3.6 Signal Handling
Control how GDB handles signals with handle SIGNAL MODE where MODE can be stop, nostop, print, noprint, pass, nopass, etc.
3.7 Stack Inspection
Use backtrace ( bt) to view call stack, frame to select a frame, info args, info locals for arguments and locals, and info registers for registers.
3.8 Memory and Register Examination
Examine memory with x /nfu address where n is count, f format (x, d, u, o, t, a, c, f), and u unit size (b, h, w, g).
4. Debugging Workflow
Typical steps: start program, set breakpoints, run, inspect state, modify execution environment.
5. Debugging Stripped Executables with GDB
5.1 Preparation
Compile a simple C program without -g (e.g., gcc example.c -o example) to produce a stripped binary.
5.2 Disassembly
Load the binary in GDB ( gdb example) and disassemble functions ( disassemble main) to obtain instruction addresses.
Dump of assembler code for function main:
0x0804841d <+0>: push %ebp
0x0804841e <+1>: mov %esp,%ebp
...
0x0804845e <+65>: ret
End of assembler dump.5.3 Setting Breakpoints by Address
Use the disassembly addresses to set breakpoints, e.g., break *0x08048453 before the printf call, or break *0x0804843e at the addition instruction.
5.4 Debugging Commands
Run with run ( r), continue with continue ( c). Since variables lack symbols, inspect memory with x /1dw address after determining the variable’s stack location from the disassembly.
Step through with next ( n) or step ( s) to follow execution flow.
5.5 Common Issues
Breakpoint not hit: Verify address accuracy; compiler optimizations may change instruction layout. Re‑compile without optimizations or adjust addresses.
Unable to view variables: Use memory examination ( x) based on stack analysis, or set multiple breakpoints to observe changes.
6. Advanced GDB Features
6.1 Backtrace
Use bt to view the call stack with function names and arguments, aiding in pinpointing where an error originated.
(gdb) bt
#0 function_c (num=6) at test.c:5
#1 function_b (num=5) at test.c:9
#2 function_a () at test.c:13
#3 main () at test.c:176.2 Dynamic Memory Inspection
Load a heap‑analysis script (e.g., source /path/to/gdbheap.py) and attach to a running process ( attach <pid>) to view heap allocations, detect leaks, and spot illegal accesses.
(gdb) monitor heap6.3 Conditional Breakpoints & Watchpoints
Set breakpoints that trigger only when a condition is true, e.g., break func if i >= size. Use watchpoints ( watch var, rwatch var, awatch var) to stop execution when a variable changes or is accessed.
6.4 Remote Debugging
Run gdbserver :<port> /path/to/program on the target machine, then on the host machine connect with gdb local_program followed by target remote <host>:<port>. This enables full GDB functionality over the network.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
