plugins/idasql/skills/debugger/SKILL.md
IDA debugger operations. Use when asked to set breakpoints, patch bytes, add conditions, or manage a patch inventory.
npx skillsauth add allthingsida/idasql-skills debuggerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when user asks to:
Route to:
analysis/xrefs for selecting meaningful targets firstdisassembly for opcode-level patch contextannotations for documenting patch rationale and outcomes-- 1) Current breakpoint inventory
SELECT printf('0x%X', address) AS addr, type_name, enabled
FROM breakpoints
ORDER BY address;
-- 2) Current patch inventory (fast: backed by IDA's patch list)
SELECT printf('0x%X', ea) AS ea, original_value, value AS patched_value
FROM bytes WHERE is_patched = 1
ORDER BY ea
LIMIT 50;
-- 3) Validate target bytes before patch
SELECT ea, value, original_value, is_patched
FROM bytes
WHERE ea = 0x401000;
Interpretation guidance:
bytes (and WHERE is_patched = 1), then retry with precise address.DELETE FROM bytes WHERE ea = ... and reassess target instruction context.debugger -> disassembly to validate instruction semantics around patch site.debugger -> xrefs to assess blast radius of patched/broken call paths.debugger -> annotations to leave durable analyst breadcrumbs.Debugger breakpoints. Supports full CRUD (SELECT, INSERT, UPDATE, DELETE). Breakpoints persist in the IDB even without an active debugger session. folder_path is the folder-oriented spelling of IDA's breakpoint group; updating either updates the same underlying breakpoint grouping.
| Column | Type | RW | Description |
|--------|------|----|-------------|
| address | INT | R | Breakpoint address |
| enabled | INT | RW | 1=enabled, 0=disabled |
| type | INT | RW | Breakpoint type (0=software, 1=hw_write, 2=hw_read, 3=hw_rdwr, 4=hw_exec) |
| type_name | TEXT | R | Type name (software, hardware_write, etc.) |
| size | INT | RW | Breakpoint size (for hardware breakpoints) |
| flags | INT | RW | Breakpoint flags |
| pass_count | INT | RW | Pass count before trigger |
| condition | TEXT | RW | Condition expression |
| loc_type | INT | R | Location type code |
| loc_type_name | TEXT | R | Location type (absolute, relative, symbolic, source) |
| module | TEXT | R | Module path (relative breakpoints) |
| symbol | TEXT | R | Symbol name (symbolic breakpoints) |
| offset | INT | R | Offset (relative/symbolic) |
| source_file | TEXT | R | Source file (source breakpoints) |
| source_line | INT | R | Source line number |
| is_hardware | INT | R | 1=hardware breakpoint |
| is_active | INT | R | 1=currently active |
| group | TEXT | RW | Breakpoint group name |
| bptid | INT | R | Breakpoint ID |
| folder_path | TEXT | RW | Alias for breakpoint group folder; NULL means root |
| full_path | TEXT | R | Full breakpoint dirtree path when available |
-- List all breakpoints
SELECT printf('0x%08X', address) as addr, type_name, enabled, condition
FROM breakpoints;
-- Add software breakpoint
INSERT INTO breakpoints (address) VALUES (0x401000);
-- Add hardware write watchpoint
INSERT INTO breakpoints (address, type, size) VALUES (0x402000, 1, 4);
-- Add conditional breakpoint
INSERT INTO breakpoints (address, condition) VALUES (0x401000, 'eax == 0');
-- Move breakpoint into/out of an IDA breakpoint folder
UPDATE breakpoints SET folder_path = 'idasql/breakpoints/network' WHERE address = 0x401000;
UPDATE breakpoints SET folder_path = NULL WHERE address = 0x401000;
-- Disable a breakpoint
UPDATE breakpoints SET enabled = 0 WHERE address = 0x401000;
-- Delete a breakpoint
DELETE FROM breakpoints WHERE address = 0x401000;
-- Find which functions have breakpoints
SELECT b.address, f.name, b.type_name, b.enabled
FROM breakpoints b
JOIN funcs f ON b.address >= f.address AND b.address < f.end_ea;
Pure mapped-byte program view with patch support. This table is one row per
mapped byte address; IDA item metadata such as size/type belongs to heads.
| Column | Type | RW | Description |
|--------|------|----|-------------|
| ea | INT | R | Byte address |
| value | INT | RW | Current byte value (UPDATE patches 1 byte) |
| word | INT | RW | 2-byte little-endian value (UPDATE patches 2 bytes) |
| dword | INT | RW | 4-byte little-endian value (UPDATE patches 4 bytes) |
| qword | INT | RW | 8-byte little-endian value (UPDATE patches 8 bytes) |
| original_value | INT | R | Original byte value before patch |
| is_patched | INT | R | 1 if byte differs from original (WHERE is_patched = 1 enumerates patches fast) |
| fpos | INT | R | Physical/input file offset (NULL when unavailable) |
Revert a patch with DELETE FROM bytes WHERE ea = ... (or WHERE is_patched = 1).
-- Read one address
SELECT ea, value, original_value, is_patched
FROM bytes WHERE ea = 0x401000;
-- Read a byte range, including item-tail bytes
SELECT ea, value
FROM bytes
WHERE ea >= 0x401000 AND ea < 0x401010
ORDER BY ea;
-- Get item metadata separately
SELECT address, size, type, flags, disasm
FROM heads
WHERE address = 0x401000;
-- Patch via table update (single byte, or width columns word/dword/qword)
UPDATE bytes SET value = 0x90 WHERE ea = 0x401000;
UPDATE bytes SET dword = 0x90909090 WHERE ea = 0x401000; -- little-endian
-- Inspect patch inventory (fast: backed by IDA's patch list)
SELECT printf('0x%X', ea) AS ea, original_value, value AS patched_value
FROM bytes WHERE is_patched = 1 ORDER BY ea LIMIT 20;
-- Persist once done
SELECT save_database();
All byte patching is done through the writable bytes table.
| Column | RW | Meaning |
|--------|----|---------|
| value | RW | Current byte; UPDATE patches 1 byte |
| word / dword / qword | RW | UPDATE patches 2/4/8 bytes little-endian |
| original_value | R | Original (pre-patch) byte |
| is_patched | R | 1 if patched; WHERE is_patched = 1 enumerates patches fast |
SELECT printf('0x%X', ea) AS ea,
printf('0x%02X', original_value) AS old,
printf('0x%02X', value) AS new
FROM bytes WHERE is_patched = 1
ORDER BY ea;
bytes TableAll byte reads and patches go through the bytes table. Bounded-read
shapes are documented in data; this skill focuses on the patching
workflow. load_file_bytes(...) writes a file's bytes into the IDB at
a given range; use it when the patch content already lives in a file.
| Function / Shape | Description |
|------------------|-------------|
| SELECT hex(blob_concat(value)) FROM (SELECT value FROM bytes WHERE start_ea = X AND n = N ORDER BY ea) | Read N bytes as uppercase hex |
| SELECT blob_concat(value) FROM (SELECT value FROM bytes WHERE start_ea = X AND n = N ORDER BY ea) | Read N bytes as BLOB |
| load_file_bytes(path, file_offset, address, size[, patchable]) | Write a file's bytes into the IDB at the target range |
-- Read 16 bytes as hex
SELECT hex(blob_concat(value))
FROM (SELECT value FROM bytes WHERE start_ea = 0x401000 AND n = 16 ORDER BY ea);
-- Patch one byte (example: NOP) and a 4-byte little-endian value
UPDATE bytes SET value = 0x90 WHERE ea = 0x401000;
UPDATE bytes SET dword = 0x90909090 WHERE ea = 0x401000;
-- Verify current vs original
SELECT value AS current, original_value AS original
FROM bytes WHERE ea = 0x401000;
-- Revert patch (one byte, or every patch)
DELETE FROM bytes WHERE ea = 0x401000;
DELETE FROM bytes WHERE is_patched = 1;
-- Persist patches explicitly
SELECT save_database();
Use disasm_calls to find every call site and batch-insert breakpoints:
-- Breakpoint on every call to VirtualAlloc (or similar)
INSERT INTO breakpoints (address)
SELECT ea FROM disasm_calls WHERE callee_name LIKE '%VirtualAlloc%';
-- Verify
SELECT printf('0x%08X', address) AS addr, type_name, enabled
FROM breakpoints;
After recovering a struct, set hardware watchpoints on specific field offsets:
-- Hardware write watchpoint on a 4-byte field (e.g., config.flags at base+0x10)
-- First, find where the struct base is stored (requires manual analysis)
INSERT INTO breakpoints (address, type, size) VALUES (0x402010, 1, 4);
-- type=1 is hardware_write, size=4 for DWORD field
Set breakpoints that only trigger when specific conditions are met:
-- Break when first argument (rcx on x64 fastcall) equals a specific enum value
INSERT INTO breakpoints (address, condition)
VALUES (0x401000, 'rcx == 3');
-- Break on error return
INSERT INTO breakpoints (address, condition)
VALUES (0x401050, 'rax == 0xFFFFFFFF');
Find and neutralize IsDebuggerPresent checks:
-- Find calls to IsDebuggerPresent
SELECT dc.ea, (SELECT name FROM funcs WHERE dc.func_addr >= address AND dc.func_addr < end_ea LIMIT 1) AS func_name,
disasm_at(dc.ea, 2) AS context
FROM disasm_calls dc
WHERE dc.callee_name LIKE '%IsDebuggerPresent%';
-- Patch the conditional jump after the check (example: jnz → nop nop)
-- First inspect the instruction after the call
SELECT disasm_at(0x401030, 3);
-- Then patch (adjust addresses based on actual binary)
UPDATE bytes SET value = 0x90 WHERE ea = 0x401035;
UPDATE bytes SET value = 0x90 WHERE ea = 0x401036;
-- Full patch report: what was changed and where
SELECT printf('0x%X', ea) AS address,
(SELECT name FROM funcs WHERE ea >= address AND ea < end_ea LIMIT 1) AS func_name,
printf('0x%02X', original_value) AS original,
printf('0x%02X', value) AS patched,
disasm_at(ea) AS context
FROM bytes WHERE is_patched = 1
ORDER BY ea;
| Table | Size | Constraint | Notes |
|-------|------|-----------|-------|
| breakpoints | Small (<100 typical) | none needed | Always fast |
| bytes | All mapped bytes | ea | Critical — constrain to one address or a tight range |
| bytes WHERE is_patched = 1 | Small (patch count) | is_patched = 1 | Fast — iterates only patched locations via IDA's patch list |
breakpoints table is small — full scans are fine.bytes table emits one row per mapped byte. Use WHERE ea = X or a tight ea range.bytes WHERE is_patched = 1 iterates only patched locations — always fast.disassembly — instruction context around a patch site (disasm_at, operand semantics).annotations — record patch rationale via comments/bookmarks before mutating.data — canonical owner of byte-read shapes (table vs. scalar disambiguation).data-ai
Analyze IDA cross-references. Use when asked about callers, callees, imports, data refs, call graphs, or dependency chains.
tools
Capture live IDA UI context. Use when the user references what's on screen, what's selected, or asks about the current view in IDA's GUI.
tools
IDA type system. Use when asked to create, modify, or apply structs, unions, enums, typedefs, or parse C declarations.
data-ai
Persistent key-value storage in IDA databases. Use when asked to store metadata, track progress, or persist session state via netnode_kv.