Debugging Malware with x64dbg
When to Use
- You need to observe a sample's runtime behavior at the instruction level on Windows.
- You are manually unpacking, decrypting strings, or reaching code guarded by anti-analysis.
- You want to dump a payload from memory after it is decoded but before it is hidden.
Do not use a debugger on a host you care about — debug only inside the isolated victim VM,
and revert the snapshot after.
Prerequisites
- x64dbg (and the matching x32/x64 build for the sample's bitness) inside the victim VM.
- A clean snapshot; the lab's simulated internet.
- Familiarity with Windows APIs commonly used by malware.
Safety & Handling
- The sample executes under the debugger; this is detonation. Stay in the isolated VM.
- Revert the snapshot after the session; treat memory dumps as live samples.
Workflow
Step 1: Set strategic API breakpoints
Rather than stepping from the entry point, break on APIs that mark interesting moments:
VirtualAlloc / VirtualProtect -> unpacking buffer about to be written/executed
CreateProcessInternalW -> process hollowing target
WriteProcessMemory -> injection payload in a register/buffer
CryptDecrypt / lstrcpy -> decoded data available
ResumeThread -> hollowed process about to run
Use bp VirtualAlloc then inspect the return value (allocated base) on return.
Step 2: Step through unpacking
Run to the allocation, set a memory breakpoint on the new region, and continue until the
unpacker writes and jumps to it. The tail jump to OEP marks the unpacked entry.
Step 3: Dump at the right moment
When the payload is decoded in memory (e.g. after VirtualProtect makes it executable), dump
the region with Scylla/the dump plugin and fix the import table for the unpacked PE.
Step 4: Defeat simple anti-debugging
Patch or skip checks like IsDebuggerPresent, PEB BeingDebugged, and timing checks (see the
anti-debugging skill). Set the return value to evade detection rather than removing the call.
Step 5: Record breakpoints and notes
Save a breakpoint plan and observations. The bundled script generates an x64dbg command
script of API breakpoints to bootstrap a session.
python scripts/analyst.py breakpoints --preset unpacking > bp.txt
Validation
- The dumped region is a valid PE (MZ/PE headers) and disassembles to real code.
- API breakpoints fire in an order consistent with unpacking/injection.
- Patched anti-debug checks no longer alter the execution path.
Pitfalls
- Stepping blindly from the entry point instead of using API breakpoints — slow and easy to
get lost.
- Dumping too early (still encrypted) or too late (already executed/freed).
- Removing anti-debug calls entirely, which can break control flow; prefer faking the result.
References