From x64dbg-skills
Hunts vulnerabilities in x64dbg debuggees: analyzes imports/exports, triages I/O attack surfaces, tests bugs like overflows/wraps, generates PoCs.
npx claudepluginhub dariushoule/x64dbg-skillsThis skill is limited to using the following tools:
Hunt for vulnerabilities in a running debuggee. Performs import/export reconnaissance, triages attack surface by I/O context, then iteratively tests for bugs (buffer overflows, integer wraps, logic flaws, etc.) and builds proof-of-concept exploits.
Solves CTF pwn challenges by discovering and exploiting memory corruption vulnerabilities like buffer overflows, format strings, heap exploits, ROP to read flags.
Analyzes ELF binaries for buffer overflows and ROP chains using pwntools, checksec, and ROPgadget. For CTF challenges and authorized security assessments.
Loads raw shellcode into x64dbg for unpacking, static disassembly, and dynamic analysis with breakpoints, stepping, and registers.
Share bugs, ideas, or general feedback.
Hunt for vulnerabilities in a running debuggee. Performs import/export reconnaissance, triages attack surface by I/O context, then iteratively tests for bugs (buffer overflows, integer wraps, logic flaws, etc.) and builds proof-of-concept exploits.
Confirm the debugger is connected and the debuggee is paused:
mcp__x64dbg__get_debugger_status — verify status is pausedmcp__x64dbg__pausemcp__x64dbg__get_register for rip (64-bit) or eip (32-bit) to determine bitness and current locationmcp__x64dbg__get_memory_map to get an overview of loaded modulesNote the main module name and base address for subsequent steps.
IF the debuggee looks packed (e.g., entry point is in a non-standard section, imports look obfuscated, or YARA signatures match known packers), run the /find-oep skill first to unpack and find the real entry point.
The goal is to identify all program entry points that handle external (attacker-controllable) input.
Use the LIEF-based enumeration script to parse the PE's imports, exports, and security features:
Bash("python ${SKILL_DIR}/enum_imports.py <target_pe_path> --output imports.json")
Packed binaries: LIEF parses the on-disk PE, so packed binaries will show only the packer's minimal IAT (e.g. GetProcAddress, LoadLibraryA). For packed targets:
/find-oep)/state-snapshot to dump all memory to disk--snapshot-dir <snapshot_dir> --base <module_base> to parse the resolved IAT from the memory dump insteadRead the output and the generated JSON. Categorize each import by I/O context:
| Category | Example APIs |
|---|---|
| Network | recv, recvfrom, WSARecv, InternetReadFile, HttpQueryInfo, WinHttpReadData, getaddrinfo |
| File | ReadFile, CreateFileA/W, fread, fgets, MapViewOfFile, NtReadFile, mmioOpen, mmioRead |
| Registry | RegQueryValueExA/W, RegGetValueA/W, RegEnumValueA/W |
| Environment | GetEnvironmentVariableA/W, getenv |
| Command line | GetCommandLineA/W, CommandLineToArgvW |
| Clipboard / UI | GetClipboardData, GetWindowTextA/W, GetDlgItemTextA/W |
| IPC / Pipes | ReadFile on pipe handles, PeekNamedPipe, TransactNamedPipe |
| Memory / String | memcpy, strcpy, strcat, sprintf, wcscat, lstrcpyA/W, MultiByteToWideChar — these are sinks, not sources, but are critical for buffer overflow detection |
| Allocation | malloc, HeapAlloc, VirtualAlloc, LocalAlloc, GlobalAlloc — track buffer sizes |
Also note dangerous formatting/conversion functions: sprintf, vsprintf, swprintf, sscanf, atoi, atol, strtol — these may be involved in format string or integer conversion bugs.
Exports indicate externally callable interfaces (DLL entry points, COM interfaces, etc.) that may accept untrusted input.
For each interesting import identified above, find where it is called in the main module.
Preferred approach — IAT byte-pattern search via Python/LIEF:
The most reliable way to find xrefs is to search the .text section for byte patterns that reference IAT entries. This works even when the debugger's findcalls command fails or returns incomplete results. Write and run an inline Python script:
import lief, struct
binary = lief.parse("<target_pe_path>")
disk_base = binary.optional_header.imagebase # e.g. 0x400000
runtime_base = <module_base> # e.g. 0x160000
rebase = runtime_base - disk_base
# Get .text section bytes
text = [s for s in binary.sections if s.name == '.text'][0]
text_data = bytes(text.content)
text_va = disk_base + text.virtual_address
# For each import, compute IAT VA using DISK base (not runtime base!)
for imp in binary.imports:
for entry in imp.entries:
disk_iat_va = disk_base + entry.iat_address
# Search for FF 15 <iat_va_le> (call dword ptr [IAT]) — direct callers
pattern_call = b'\xff\x15' + struct.pack('<I', disk_iat_va)
# Search for FF 25 <iat_va_le> (jmp dword ptr [IAT]) — thunk stub
pattern_jmp = b'\xff\x25' + struct.pack('<I', disk_iat_va)
# Find all occurrences in .text
for i in range(len(text_data) - 5):
chunk = text_data[i:i+6]
if chunk == pattern_call:
caller_runtime = text_va + i + rebase
# Record direct caller
elif chunk == pattern_jmp:
thunk_runtime = text_va + i + rebase
# Record thunk address
# For thunks: also find E8 <rel32> callers of the thunk
if thunk_found:
thunk_disk = thunk_runtime - rebase
for i in range(len(text_data) - 4):
if text_data[i] == 0xE8:
rel32 = struct.unpack('<i', text_data[i+1:i+5])[0]
target = text_va + i + 5 + rel32
if target == thunk_disk:
caller_runtime = text_va + i + rebase
# Record thunk caller
Key detail: IAT addresses in on-disk code use the PE's ImageBase (e.g. 0x400000), NOT the runtime base address. The code is not patched for ASLR relocation — the loader fixes up IAT entries at runtime, but the FF 15/FF 25 instruction operands remain as disk addresses. Always use binary.optional_header.imagebase for IAT VA computation.
Fallback approach — debugger commands:
If the Python approach is impractical, use mcp__x64dbg__execute_command with the findcalls command:
mcp__x64dbg__execute_command("findcalls <import_address>")
Record each call site address. These are the xrefs — the primary targets for triage.
Important: Be selective. Focus on the most security-relevant imports first (network inputs, file reads, string copies). Do not enumerate xrefs for every import — that would bloat the context.
For each xref group (organized by I/O function), evaluate the surrounding context:
mcp__x64dbg__disassemblemcp__x64dbg__set_label (e.g., vuln_candidate_recv_handler, vuln_candidate_file_parser)mcp__x64dbg__set_commentAfter triaging, present the ranked list to the user:
## Triaged Attack Surface
| Rank | Address | Function | I/O Source | Sink | Risk |
|------|---------|----------|------------|------|------|
| 1 | 0x... | ... | Network | Stack buffer | High |
| 2 | 0x... | ... | File | Heap alloc | Medium |
| ... | ... | ... | ... | ... | ... |
Ask the user via AskUserQuestion: "Here is the triaged attack surface. Which targets should I investigate? (all / specific ranks / let me choose)"
For each selected target, perform the following loop. Do one target at a time to stay focused and conserve context.
mcp__x64dbg__disassemble/decompile via Skill("decompile") for a higher-level viewsub rsp, N (stack frame), push N / mov ecx, N before HeapAlloc/malloc, static .data/.bss bufferscmp, ja/jb guardsadd, imul, shl on values derived from inputsprintf/printf family?jl vs jb), TOCTOU patternsBased on the analysis, describe the suspected vulnerability:
recv buffer > 256 bytes when the stack buffer is 256")Present the hypothesis to the user.
Set up the debugger to observe the target code path:
mcp__x64dbg__set_breakpointstrcpy), the length check (if any), the return/tracealyzer via Skill("tracealyzer") to trace through the functionCreate an input that should trigger the suspected bug. Use Bash to write a Python script that generates the payload:
The test input should be diagnostic first — use recognizable patterns (e.g., "A" * 300 for overflow, "%x" * 20 for format string) to confirm the bug before refining to a PoC.
Write the script to ./exploits/test_<target_name>.py.
Bashmcp__x64dbg__go to resume executionmcp__x64dbg__wait_for_event or mcp__x64dbg__get_debugger_statusmcp__x64dbg__get_all_registersmcp__x64dbg__read_memorymcp__x64dbg__disassemblemcp__x64dbg__execute_command("InitDebug") to restart, orRepeat steps 4a–4f for each target until bugs are found or all targets are exhausted.
For each confirmed bug, develop a PoC that demonstrates impact.
Plan a PoC that demonstrates a meaningful impact:
calc.exe, writing a marker file, or connecting back to a listenerConsider the target's mitigations:
mcp__x64dbg__get_memory_map (look at page protections) and examine the binary's PE headersWrite a Python PoC script to ./exploits/poc_<vuln_name>.py. The script should:
Bash (or ask the user to trigger it if manual interaction is required)Repeat steps 5a–5c until the PoC is reliable or the user decides to move on.
Ask via AskUserQuestion: "Would you like a markdown vulnerability report?"
If yes, read the report template at ${CLAUDE_PLUGIN_ROOT}/skills/vuln-hunter/report_template.md and fill in every section based on findings. Write the completed report to ./reports/vuln_report_<timestamp>.md via Write. Omit table rows or sections that have no findings, but preserve the overall structure.