const {P,H2,H3,Callout,Code,Ul,Related,PostHead}=window;
function Article(){
return <>
<PostHead cat="/TOOLS" date="2026-07-27" title="Static is a hypothesis, dynamic is the measurement" lede="Ghidra tells a story about the binary. A debugger, an emulator, or a hook tells you whether that story is true on the bytes that actually ran."/>
<P>Static analysis is cheap and incomplete. Dynamic analysis is true for one run and easy to over-fit. The desk uses both. The mistake is treating either as the finding.</P>
<Callout>Attach only to processes you own or have in writing. Emulate offline samples when you cannot. “Staging that looks like prod” is still prod if the auth letter does not name it.</Callout>
<H2>What each dynamic tool is</H2>
<H3>GDB / LLDB</H3>
<P>Breakpoints, watchpoints, registers. Native, honest, slow to script across a whole parser. Use when you have a runnable binary and a crashing input, or when you need to see one function’s arguments on a device you control.</P>
<H3>Frida</H3>
<P>User-space instrumentation. You inject a JS agent into a running process and intercept functions you already named in the static pass. It is not a substitute for reading the binary. It is how you confirm “this JNI method is what the Java layer actually calls.”</P>
<P>We do not publish hook scripts that defeat licensing, pinning, or root checks as a product. In an authorized Android review we may observe those surfaces and write them down as trust boundaries. The report says what the app trusts. It does not ship a bypass kit.</P>
<H3>QEMU</H3>
<P>User-mode: run a foreign ELF on your laptop. System-mode: boot a firmware you extracted, if you must see the init scripts actually run. Heavy. Use when Unicorn is too small (you need libc, files, a network stub) and a real device is not in scope.</P>
<H3>Unicorn</H3>
<P>Micro-execution. Forty instructions, not a process. This is how we vote on struct layouts: set registers, map a fake buffer, run the load, see which offsets were touched.</P>
<H3>strace / dtruss / procmon</H3>
<P>Syscall traces. Fast inventory of what a sample touches on disk and net — after you agreed that running it is allowed. Sandbox first. This is reconnaissance of your own sample, not of someone else’s server.</P>
<H2>The combination that does not lie as often</H2>
<Code lang="flow.txt">{`Ghidra names  parse_header @ 0x401200
     │
     ├─ Unicorn: run 0x401200..0x4012c0 on a fake buf
     │     → offsets 0x00, 0x04, 0x08 touched
     │
     └─ if we have a device in scope:
           GDB or Frida on that function
           → same offsets, or we were wrong`}</Code>
<P>If static and dynamic disagree, dynamic on the authorized sample wins, and we write why the decompiler lied (tail padding, overlay, packed overlay). If we cannot run it, we label the static recovery as unconfirmed. That sentence is the difference between a report and a vibe.</P>
<H2>When we refuse dynamic</H2>
<Ul items={[
'No writable lab image and the only copy is production.',
'The sample looks like malware and we do not have a detonation agreement.',
'The customer wants “just hook their users’ apps.” That is not an audit. That is a product we do not sell.'
]}/>
<Related items={[
['post-re-stack.html','The reverse-engineering desk'],
['post-ida-ghidra.html','IDA vs Ghidra vs Binary Ninja vs radare2']
]}/>
</>;
}
window.Article=Article;
mountPost();
