Core Dump RE
April 4, 2026 · View on GitHub
FREE Reverse Engineering Self-Study Course HERE
Core Dump RE
Core dump Reverse Engineering w/ LLDB on MAC and Linux.
Step 1: Enable Core Dumps
This step covers enabling core dumps on macOS and Linux so the OS writes a crash snapshot to disk.
Step 2: Compile With Debug Symbols
This step covers compiling the vulnerable program with full debug info baked into the binary.
Step 3: Extract Symbols to a Separate File
This step covers extracting the debug symbols into a standalone file, the equivalent of a .pdb on Windows.
Step 4: Strip the Binary
This step covers stripping all debug info from the binary so it looks like a shipped release build.
Step 5: Create Entitlements File (macOS Only)
This step covers creating the entitlements plist required for macOS to allow core dumps under SIP.
Step 6: Sign the Binary (macOS Only)
This step covers codesigning the binary with the com.apple.security.get-task-allow entitlement so macOS allows core dumps under SIP.
Step 7: Crash It
This step covers running the stripped binary to trigger a segfault and produce a core dump.
Step 8: Find the Core Dump
This step covers locating the core dump file on macOS and Linux.
Step 9: Open the Core Dump in LLDB
This step covers loading the core dump and the stripped binary into LLDB.
Step 10: Load Symbols
This step covers loading the separate symbol file into LLDB, the equivalent of loading a .pdb in WinDbg with .sympath and .reload.
Step 11: Analyze the Crash
This step covers using LLDB to determine the call stack, stop reason, registers, local variables, and disassembly at the crash site.
Step 12: LLDB RE Command Reference
This step provides a comprehensive reference of LLDB commands for reverse engineering core dumps.
Step 1: Enable Core Dumps
You only do this once per boot.
macOS
sudo launchctl limit core unlimited unlimited
Linux
ulimit -c unlimited
Step 2: Compile With Debug Symbols
cc -g -O0 vuln.c -o vuln
-g bakes debug info into the binary. -O0 turns off optimizations so assembly matches source line for line.
Step 3: Extract Symbols to a Separate File
This is the equivalent of a .pdb on Windows.
macOS
dsymutil vuln
This creates vuln.dSYM — a bundle containing all debug info (function names, variable names, line numbers, type info).
Linux
objcopy --only-keep-debug vuln vuln.debug
This creates vuln.debug — a file containing all debug info.
Step 4: Strip the Binary
Remove all symbols from the binary so it looks like a release build.
strip vuln
Now the binary has no debug info. If you tried to debug it right now you would only see raw addresses, no source, no variable names. Just like a shipped product.
Step 5: Create Entitlements File (macOS Only)
Create a file called entitlements.plist with this content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
This entitlement tells macOS to allow debugging and core dumps for the signed binary.
Skip this step on Linux.
Step 6: Sign the Binary (macOS Only)
macOS blocks core dumps unless the binary has a special entitlement.
codesign -s - --entitlements entitlements.plist -f ./vuln
Skip this step on Linux.
Step 7: Crash It
./vuln
You will see something like:
[*] Vulnerable program running...
Segmentation fault (core dumped)
The OS froze everything in the process (memory, registers, threads) and wrote it to a file. That file is the core dump.
Step 8: Find the Core Dump
macOS
Core dumps go to /cores/.
ls /cores/
You will see something like core.12345.
Linux
Core dumps usually land in your current directory.
ls core*
You will see core or core.12345.
Step 9: Open the Core Dump in LLDB
You give LLDB two things: the core dump (crash snapshot) and the stripped binary (no symbols).
macOS
lldb --core /cores/core.12345 ./vuln
Linux
lldb --core ./core ./vuln
Replace the core filename with whatever you found in Step 8.
At this point LLDB has no symbols. If you type bt you will only see raw addresses. You need to load the symbol file.
Step 10: Load Symbols
This is the key step. The binary is stripped. The symbols are in a separate file. You tell LLDB where they are.
macOS
target symbols add vuln.dSYM
Linux
target symbols add vuln.debug
Now LLDB has function names, variable names, line numbers, and types. This is the same as loading a .pdb in WinDbg with .sympath and .reload.
Step 11: Analyze the Crash
You are now inside LLDB looking at a dead process with symbols loaded. Run these commands one at a time.
See the call stack
bt
This shows every function that was running when it crashed. Frame 0 is where it died.
See why it stopped
thread list
Look for stop reason = signal SIGSEGV. That means it tried to read or write memory it was not allowed to touch.
See the CPU registers
register read
The important ones:
pc(orripon x86) — the instruction that was running when it crashedrsi,rdi— the values being passed to functions
See local variables
frame variable
This shows the variables in the crashing function. For our program you will see argc and argv.
See the assembly
disassemble --frame
Shows the machine instructions around the crash. The -> arrow points at the exact instruction that faulted.
Why it crashed (for this program)
Our program does printf("%s", argv[100]).
argcis 1 (just the program name)argvonly has 1 entryargv[100]reads memory way past the end of the array- That memory is not mapped, so the OS kills the process with SIGSEGV
- The OS writes the core dump
- You open the core dump in LLDB and prove all of the above
Step 12: LLDB RE Command Reference
Everything below is run inside LLDB after loading the core and symbols.
Stack Navigation
bt # full backtrace
bt 5 # only top 5 frames
frame select 0 # jump to frame 0 (crash site)
frame select 3 # jump to frame 3
up # move one frame up (toward caller)
down # move one frame down (toward callee)
Registers
register read # all general-purpose registers
register read pc # just the program counter
register read rdi rsi rdx # specific registers (x86_64 args 1-3)
register read x0 x1 x2 # specific registers (arm64 args 1-3)
register read --format hex # force hex output
Memory
memory read $pc # read memory at program counter
memory read $sp # read memory at stack pointer
memory read 0x7fff5a3c0000 # read memory at a specific address
memory read --size 8 --format x --count 16 $sp # 16 qwords from stack
memory read --size 1 --format c --count 64 $rdi # 64 bytes as chars
memory read --format s $rdi # read as null-terminated string
Disassembly
disassemble --frame # disassemble current frame
disassemble --name main # disassemble a function by name
disassemble --start-address 0x100003f40 --count 20 # 20 instructions from addr
disassemble --pc # disassemble around current program counter
Variables and Expressions
frame variable # all locals and args in current frame
frame variable argc # specific variable
frame variable *argv # dereference pointer
expression argc # evaluate an expression
expression argv[0] # array access
expression (char*)argv[0] # cast and print
expression (int)argc - 1 # arithmetic
Modules and Symbols
image list # all loaded modules (like lm in WinDbg)
image lookup --address $pc # map address to source file + line
image lookup --name main # find where a symbol lives
image lookup --type int # look up a type
image dump symtab # dump the symbol table
target symbols add file.dSYM # load symbols (macOS)
target symbols add file.debug # load symbols (Linux)
Threads
thread list # all threads and stop reasons
thread select 2 # switch to thread 2
thread info # detailed info on current thread
thread backtrace all # backtrace every thread
Searching Memory
memory find $sp $sp+0x1000 --expr "0x41414141" # search stack for pattern
memory find $sp $sp+0x1000 -s "AAAA" # search stack for string
Process Info
process status # stop reason, signal, pid
target show # binary path and arch