SuperAPI AI Directory

re-gdb

Security & auditing

View repository

Updated 10-15 21:34

About this skill

GDB/pwndbg/gef dynamic debugging

When to use / when not to use

  • Use: dynamic debugging of Linux targets (attach/start/breakpoints/memory read-write); core file analysis; debugging PE processes under Wine
  • Don't use: native Windows targets (use [[re-x64dbg]], or gdb inside Wine see [[re-analyze/platform-tips]] Linux branch); macOS targets (use [[re-lldb]])
  • Don't use: read-only memory without debugging (dumping first by default, use [[re-memdump]])

Tool preparation

Refer to [[re-analyze/platform-tips]]: dynamic execution defaults to sandbox; Wine process attach experience in the Linux branch;直读 vs 转储 decision — if attach fails, switch to [[re-memdump]].

gdb

  • Linux: apt install gdb / dnf install gdb / pacman -S gdb
  • macOS: brew install gdb(requires a self-signed certificate, generally more convenient to use lldb directly)
  • WSL: Linux packages are directly usable (attaching across the Windows boundary is not feasible, see [[re-analyze/platform-tips]] WSL branch)
  • Verify: gdb --version

pwndbg / gef (choose one)

  • pwndbg: official portable install script (main path for Linux/macOS):
    curl --proto '=https' --tlsv1.2 -LsSf 'https://install.pwndbg.re' | sh -s -- -t pwndbg-gdb
    
    For the LLDB version, replace -t with pwndbg-lldb; there is also Homebrew (brew install pwndbg/tap/pwndbg-gdb), Nix and distro packages as options. The repo's git clone + ./setup.sh is legacy/for development (internally calls sudo requiring root), no longer the main path
  • gef:
    curl -L https://github.com/hugsy/gef/raw/master/gef.py -o ~/.gdbinit
    
  • Verify: entering gdb shows the pwndbg/gef banner
  • Note: don't install both (hooks interfere with each other); the pwndbg portable version is loaded via a wrapper script and doesn't write ~/.gdbinit, different from gef's ~/.gdbinit injection method; versions roll quickly, for feature differences refer to each project's official README (see [[gotchas]])

checksec (binary protection check)

  • pwndbg built-in checksec command (usable once pwndbg is installed)
  • or pip install pwntools → pwn checksec --file ./target
  • Verify: gdb -q -ex 'checksec' -ex quit ./target outputs NX/Canary/RELRO/PIE

Operation steps

  1. Check ptrace permissions before attach:

    cat /proc/sys/kernel/yama/ptrace_scope
    # 1 = 仅父进程可 attach(默认);0 = 任意同属主;容器内常被强制禁止
    sudo sysctl -w kernel.yama.ptrace_scope=0   # 临时放宽(重启还原)
    
    gdb -q -p <pid>          # 同属主或 root;失败(Operation not permitted)→ 见坑 1
    

    Attach inside a sandbox container is often blocked by seccomp → go directly to [[re-memdump]] for dumping.

  2. Breakpoints/single-step/conditional breakpoints:

    (gdb) file ./target
    (gdb) b *0x401000          # 地址断点
    (gdb) b sym.check if argc == 2    # 条件断点
    (gdb) r arg1 arg2          # 运行并传参
    (gdb) ni / si              # 单步(跳过/进入调用)
    (gdb) c                    # 继续
    (gdb) info b               # 列出断点
    

    Dynamic analysis command with arguments: gdb -q -ex 'b main' -ex 'r' -ex 'x/10i $rip' ./target

    • Data breakpoints: watch *(int*)0x601000(trigger on write) / rwatch(trigger on read) — find the moment keys are written/the decryption landing point
    • Syscall breakpoints: catch syscall openat— clarify file/network behavior, combined with commands ... end to automatically print arguments and then continue
    • Breakpoint hit automation (without changing the execution flow, batch-verify arguments):
      (gdb) b check
      (gdb) commands
        silent
        printf "arg=%s\n", $rdi
        continue
      end
      
  3. View/modify memory and registers:

    (gdb) x/20wx $rsp          # 栈上 20 个 word
    (gdb) x/s 0x601000         # 字符串
    (gdb) p $rax               # 寄存器
    (gdb) set $rax = 0         # 改寄存器
    (gdb) set {int}0x601000 = 0x90909090   # 写内存(绕过校验)
    (gdb) find 0x400000, 0x410000, "flag{"  # 内存搜索字符串
    
  4. Anti-debugging bypass:

    • Change flag bits (common anti-debug checkpoints):
      (gdb) p $eflags
      (gdb) set $eflags = $eflags | 0x100     # 置 TF 位
      
    • ptrace self-check: ptrace(PTRACE_TRACEME) return value is checked → break at the call site and directly set $eax = 0(x86) to continue running
    • Timing difference detection (rdtsc): first p $rax record the difference between two calls, exit if it exceeds the threshold — break at the comparison point and patch the comparison register
    • The above modifications only affect the current run and do not change the file (for persistent patching, modify the binary and re-hash for comparison)
  5. gcore dump (dumping first by default):

    (gdb) gcore out
    

    or external command: gcore -o out <pid>(shipped with the gdb package, includes register/thread ELF notes) Per [[re-analyze/platform-tips]] "direct read vs dump": default to dump first; unpacking must wait until OEP is decrypted before dumping; core directly gdb ./target core for retrospective analysis (bt look at the crash stack,info proc mappings look at mappings).

  6. Scripted batch processing (-x / python):

    gdb -q -batch -x script.gdb ./target      # 非交互跑完整脚本
    

    script.gdb can contain commands ... end、define custom commands,python embedded Python (gdb has a built-in Python interpreter, on which pwndbg/gef are based) — repetitive analysis (batch-printing call arguments, running a path through) can be solidified into scripts for reuse; interactive analysis conclusions can be recorded with gdb -q -ex ... -ex quit as one-liners.

Cross-domain connections

  • [[re-address-space]]: base address conversion (align info proc mappings with link addresses)

  • [[re-binary-core]]: workflow step 6 (Linux debugger)

  • [[re-anti-analysis]]: unpacking verification (break on OEP) and anti-debugging bypass

  • [[re-ctf]]: pwn debugging

  • [[re-malware]]: dynamic observation of Linux malware samples

  • complements [[re-memdump]] (attach failure → dump)

Common pitfalls and traps

  • ptrace disabled → dump as fallback: with yama ptrace_scope=1, attach from a non-parent process is denied; container seccomp directly kills attach — don't keep struggling, per [[re-analyze/platform-tips]] switch to [[re-memdump]]
  • anti-debugging (ptrace self-check, timing difference): the sample uses ptrace(PTRACE_TRACEME) self-check or rdtsc timing difference to detect the debugger — first statically locate the check point, then patch at the breakpoint
  • Wine process attach: under Wine, a PE process is a Linux process and gdb can attach, but the address space mixes PE mappings with Wine structures — handle it per the Linux branch experience in [[re-analyze/platform-tips]] (check /proc/<pid>/maps to locate the PE image sections)
  • Debugger injection traces (LD_PRELOAD/environment variables) will be detected — use unset env LD_PRELOAD -style methods to clean up before attaching
  • Timing countermeasures fall into three categories: symptom — the sample detects a timing anomaly (wrong timing multiplier, abnormal single-step duration, unexpected clock source) and then exits or changes behavior; cause — timing countermeasures fall into three categories: timing multiplier detection / single-step delay detection / VM clock source detection; countermeasure — first determine the category, then respond separately: for the timing multiplier type, restore the real clock or patch the comparison point; for the single-step delay type, use hardware breakpoints to reduce the number of measured steps; for the VM clock source type, handle it per the environment fingerprinting approach in the sandbox branch of [[re-analyze/platform-tips]]
  • Breakpoint failure ≠ code not executed: symptom — a breakpoint set at the target address never triggers, leading to the misjudgment that the path wasn't run and skipping key logic; cause — four mechanisms make "breakpoint didn't hit" ≠ "code wasn't executed": self-modifying code (the int3 byte is overwritten or verified at runtime), memory remapping (code moves to a new mapping, old address becomes invalid), exception mechanisms (flow jumps via an exception-handling path, not through the breakpoint instruction), anti-debugging bypass (the sample scans for 0xCC / verifies code section bytes and then reroutes); countermeasure — first investigate the four categories:x/i check whether the breakpoint location is still int3 (self-modification), check /proc/<pid>/maps compare mapping changes (remapping), find the real jump target in the exception context (exception mechanism), statically locate the 0xCC scan and section verification points first (anti-debugging), then decide whether to change the breakpoint location / set a memory breakpoint / patch the check point (see the analysis methodology R17 in [[re-binary-core]])
  • Single-step exception → check anti-debugging (trap flag / exception handling): Symptom —si an unexpected SIGTRAP/ is triggered during single-stepping,#DB, or the sample's behavior jumps after single-stepping (for the timing-difference type, see the "clock-based anti-debugging falls into three categories" pitfall); Cause — trap flag detection (the sample reads the TF bit / exploits the single-step exception itself) and exception-handling-mechanism anti-debugging (int3 taken over by the sample's own handler, the SEH chain handling control-flow jumps, exceptions as control flow); Countermeasure — first rule out timing detection, then statically locate pushf/lahf after which check the checkpoints for the TF and the int3 write points, break at the handler entry to see the real flow, patch the checkpoints, or switch to hardware breakpoints (see [[re-binary-core]] analysis methodology R18)
  • For a command quick reference (breakpoints/memory/scripts/pwndbg-gef command families) see [[commands]]; for tool-specific pitfalls and version differences see [[gotchas]]