---
title: "Dynamic Analysis Workflow"
type: synthesis
tags: [dynamic-analysis, debugging, instrumentation, tracing, record-replay, checkpoints, process-capture, core-dumps, evidence, sandboxing, gdb, frida, rea]
created: 2026-10-16
updated: 2026-10-16
confidence: medium
sources: ["raw/web_community-breakpoints-debugging-with-gdb.md", "raw/web_community-set-watchpoints-debugging-with-gdb.md", "raw/web_community-attach-debugging-with-gdb.md", "raw/web_community-process-record-and-replay-debugging-with-gdb.md", "raw/web_community-checkpoint-restart-debugging-with-gdb.md", "raw/web_community-core-file-generation-debugging-with-gdb.md", "raw/web_community-server-debugging-with-gdb.md", "raw/github_doc-i18n-en-docs-modes-md.md", "raw/github_doc-i18n-en-docs-index-md.md", "raw/github_doc-i18n-en-docs-frida-trace-md.md", "raw/github_doc-i18n-en-docs-gadget-md.md", "raw/github_doc-docs-frida-instrumentation-md.md", "raw/github_doc-docs-process-capture-md.md", "raw/github_doc-docs-recorded-crashes-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-runtime-o.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-disclaimer-md.md"]
---

# Dynamic Analysis Workflow

Static analysis tells you what code *could* do; dynamic analysis shows what it *does* on a given run. This page helps you pick the right runtime technique for the question, run it without hurting your host, and keep results you can defend later. For tool detail see [[entities/gdb-and-pwndbg]] and [[entities/frida]].

Running a program is a separate act from reading it. The disclaimer of REA (rea-agents, an agent-driven reverse-engineering toolkit; see [[entities/rea]]) makes the point directly: permission to inspect an artifact does not necessarily cover executing it, intercepting its traffic or changing a device, and having a file or a reachable debugging endpoint does not by itself grant permission. Settle that first; see [[concepts/legal-and-ethics]].

## Comparison

| Technique | Best question it answers | How intrusive | Platform notes | What you keep |
|---|---|---|---|---|
| **Debugger** (GDB, pwndbg) | "What is the exact state at this instruction, and who wrote this value?" | Stops the process; software watchpoints single-step and run hundreds of times slower | GDB attach needs an OS with processes and permission to signal the target. REA's GDB sessions are Linux-only | Session notes, `gcore` snapshots, backtraces |
| **Instrumentation** (Frida scripts) | "Every time this function runs, what were its arguments and result?" | Code runs inside the target with the target's memory, file and network authority; the process keeps running | Injected mode needs frida-server (root/jailbreak on mobile); Gadget embedded in your own build on non-rooted devices | Message logs; REA records script path and SHA-256 |
| **Tracing** (`frida-trace`) | "Which of these APIs get called, and in what order?" | Light: auto-generated hooks that log and keep going | Same as Frida | `-o` writes the trace to a file |
| **Record/replay** (GDB `record`) | "How did we get here?" Step backwards through a recorded window | Heavy: `full` method records every instruction (default cap 200000) | GNU/Linux on x86, ARM, AArch64, PowerPC, RISC-V, S/390 and others; also via gdbserver | `record save` writes the log to a file |
| **Checkpoints** (GDB `checkpoint`) | "Let me retry from just before the bug." | Cheap: a snapshot copy of the process | GNU/Linux only | In-session only |
| **Process capture** (REA) | "Did two runs of the same scenario behave the same?" | Runs the command as you; no isolation | Capture on Linux or macOS; not native Windows | Evidence JSON with terminal output, exit, process tree, file before/after hashes |
| **Core inspection** (GDB, REA `inspect-recorded-crash`) | "What was the state when it crashed?" | None at analysis time; reads a file | REA reads Linux ELF64 cores, x86-64 and AArch64 | The core file plus its SHA-256 |

## Analysis

### Choosing a technique

Start from the question, not the tool.

1. **You don't yet know where to look.** Trace first. `frida-trace -i "recv*" -i "read*" <target>` or `-I <module>` gives a cheap call timeline that tells you which functions matter, and it does not stop the program. Tracing is usually also the least disruptive option for UI apps and services that time out when paused.
2. **You know the function and need the values.** Write a small Frida script that hooks it and reports arguments and return values back to the host, or set a GDB breakpoint there. Pick Frida when stopping would change behaviour (timeouts, watchdogs, network peers) or on mobile; pick GDB when you need to stop and look around: registers, stack, heap, nearby memory.
3. **You know the data and need the writer.** A GDB hardware watchpoint (`watch *(int *) 0xADDR`) stops at the exact instruction that changed it. If only software watchpoints are available it still works, just much more slowly, and it reports at the next statement instead.
4. **The bug happens long before the symptom.** Use record/replay: `start`, then `record` (the process must already be running), run to the failure, then step backwards or `record goto begin`. The `full` method stops at 200000 instructions by default (`set record full insn-number-max` changes it), so start recording close to the region you care about. Intel's `record btrace` (`bts` or `pt`) has lower overhead but records no data, so variables and registers are unavailable when you step backwards.
5. **You keep overshooting.** Drop a `checkpoint` before the suspect area and `restart <id>` instead of re-running. On Linux a checkpoint is an identical process copy, so addresses stay put even with ASLR, which keeps address breakpoints valid. It rewinds file positions but cannot un-write file contents or recall bytes already sent to a device.
6. **You need to compare two builds or two runs.** REA process capture runs one scenario (`rea capture-process ./scenario.json --json > capture.json`) and `rea compare-process-captures a.json b.json` reports where terminal output, exit, files or process trees differ. It refuses to compare captures taken under different working directories, environments or observation paths, so keep those identical.
7. **It already crashed.** Analyse the core rather than reproducing. In a live session `gcore` saves one on demand. REA's `inspect-recorded-crash` reads Linux ELF64 cores for x86-64 and AArch64 and can optionally add pwndbg memory-map context. It needs a caller-supplied Python environment with pinned parsing libraries, and it treats the PIDs recorded in a core as metadata only, never as a live process to attach to.

For browser and Electron targets, REA's runtime observation is passive by design: it attaches to a loopback DevTools (CDP) endpoint and never claims it clicked, navigated or ran page JavaScript unless you asked it to run a declared scenario. See [[syntheses/javascript-and-electron-apps]].

### Sandboxing untrusted targets

Every technique on this page except core inspection runs the target, and none of them contains it:

- **Process capture is explicitly not a sandbox.** The command runs with your user's permissions and inherits your environment; observation paths only choose what gets snapshotted, not what the process may touch.
- **Frida scripts** execute with the target process's memory, filesystem and network authority, so a hostile target is just as hostile while hooked.
- **REA's resource limits** on crash inspection are not a sandbox for the engine code either.
- **gdbserver has no authentication.** Whoever connects gets the privileges of the user running it, so never expose it on a public network. Frida's Gadget listens on `127.0.0.1` by default; keep it there, or set its `token` and `certificate` options.

REA's guidance is to "use an appropriate environment for untrusted targets" and to review agent-generated scripts before running them. For a suspicious sample, follow the safe-handling steps in [[syntheses/malware-triage]] before running anything. For mobile work, use a dedicated test device or an emulator rather than a personal phone.

### Keeping evidence

Dynamic results are only as good as your record of the run. Habits that hold up:

- **Hash inputs first.** Record the SHA-256 of the binary, script and any core file. REA does this automatically: Frida evidence stores the script's path and digest (not its source), and crash evidence stores the core's digest and size.
- **Save the run, not just your conclusion.** `frida-trace -o`, `record save <file>` (default name `gdb_record.<pid>`), `gcore` and REA's capture JSON all give you something a reviewer can re-examine. A saved record log can be loaded again with `record restore`.
- **Write down the scenario.** Arguments, environment overrides, working directory and timing all change behaviour. REA's capture commits these into the set of settings both captures must share, and inputs marked `sensitive` are stored only as a byte count.
- **Mark gaps honestly.** REA's evidence model records truncation and residual unknowns rather than treating missing data as absence: a filesystem snapshot is not a syscall trace and can miss short-lived changes, and a static/runtime correlation is a hypothesis, not proof of causality.
- **Protect what you captured.** Traces and captures can contain credentials and personal data; you are responsible for storing and sharing them appropriately.

## Recommendations

- **Default order:** trace, then hook, then break. Escalate only when the cheaper method can't answer the question.
- **On Linux desktop binaries:** GDB with pwndbg for state, `checkpoint` to iterate, `record` for short "how did we get here" windows, `gcore` before anything destructive.
- **On Android or iOS apps you are authorized to test:** Frida on a test device; see [[syntheses/android-apk-analysis]].
- **For regression or reconstruction checks:** REA process capture with identical scenarios on both sides; add `finalization_ms` if the target must write a final report before a timeout kills it.
- **Remote targets:** gdbserver over SSH (`target remote | ssh -T host gdbserver - prog`) avoids opening a listening port.
- **Agent-driven sessions:** REA's GDB sessions need Linux, and its process capture needs Linux or macOS; on Windows, run Linux REA inside WSL for Linux targets.

## Pages Compared

- [[entities/gdb-and-pwndbg]]: breakpoints, watchpoints, record/replay, checkpoints, gdbserver.
- [[entities/frida]]: injected, embedded and preloaded instrumentation; `frida-trace`.
- [[entities/rea]]: process capture, recorded crashes, Frida and GDB providers, evidence.
- [[syntheses/malware-triage]]: safe handling before execution.
- [[syntheses/triage-an-unknown-binary]]: static first look before running anything.

## Sources

- `raw/web_community-breakpoints-debugging-with-gdb.md`
- `raw/web_community-set-watchpoints-debugging-with-gdb.md`
- `raw/web_community-attach-debugging-with-gdb.md`
- `raw/web_community-process-record-and-replay-debugging-with-gdb.md`
- `raw/web_community-checkpoint-restart-debugging-with-gdb.md`
- `raw/web_community-core-file-generation-debugging-with-gdb.md`
- `raw/web_community-server-debugging-with-gdb.md`
- `raw/github_doc-i18n-en-docs-modes-md.md`
- `raw/github_doc-i18n-en-docs-index-md.md`
- `raw/github_doc-i18n-en-docs-frida-trace-md.md`
- `raw/github_doc-i18n-en-docs-gadget-md.md`
- `raw/github_doc-docs-frida-instrumentation-md.md`
- `raw/github_doc-docs-process-capture-md.md`
- `raw/github_doc-docs-recorded-crashes-md.md`
- `raw/github_doc-agents-skills-reverse-engineer-anything-references-runtime-o.md`
- `raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md`
- `raw/github_doc-docs-reverse-engineering-tools-md.md`
- `raw/github_doc-disclaimer-md.md`
