一键导入
xrefs
Analyze IDA cross-references. Use when asked about callers, callees, imports, data refs, call graphs, or dependency chains.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Analyze IDA cross-references. Use when asked about callers, callees, imports, data refs, call graphs, or dependency chains.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Triage and audit IDA binaries. Use when asked to analyze a binary, find suspicious behavior, detect crypto/network activity, review decompiled code against source, or run multi-table queries.
Edit IDA databases. Use when asked to add comments, rename symbols, apply types, create bookmarks, or clean up decompiled code for review.
Connect to IDA databases and bootstrap sessions. Use when starting analysis, routing to other skills, or setting up CLI/HTTP/MCP connections.
Query IDA strings, bytes, and binary data. Use when asked to search strings, find byte patterns, rebuild string tables, or analyze binary content.
IDA debugger operations. Use when asked to set breakpoints, patch bytes, add conditions, or manage a patch inventory.
Decompile and analyze IDA functions. Use when asked for pseudocode, ctree AST analysis, local variables, labels, or decompiler-driven cleanup.
| name | xrefs |
| description | Analyze IDA cross-references. Use when asked about callers, callees, imports, data refs, call graphs, or dependency chains. |
| metadata | {"argument-hint":"[function-name or address]"} |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
Use this skill when user asks:
Route to:
grep for candidate entity lookup by name/pattern before relationship analysisanalysis for broader triage contextdecompiler for semantic interpretation after graph narrowingdisassembly for instruction-level call-site proof-- 1) Core relation volume
SELECT COUNT(*) AS xref_count FROM xrefs;
-- 2) Top imports (dependency hints)
SELECT module, COUNT(*) AS import_count
FROM imports
GROUP BY module
ORDER BY import_count DESC;
-- 3) Most called functions
SELECT printf('0x%X', to_addr) AS callee, COUNT(*) AS callers
FROM xrefs
WHERE is_code = 1
GROUP BY to_addr
ORDER BY callers DESC
LIMIT 20;
Interpretation guidance:
to_addr/from_addr) for fast response.to_addr = X or from_addr = X constraints.names table or explicit EA literals.imports, strings, or disasm_calls joins.struct_member_xrefs (filter by type_name/type_ordinal/member_id).
Do NOT LIKE-scan instructions.disasm / instruction_operands.text for the
field name — it is the slow, crash-adjacent pattern this table replaces.xrefs WHERE to_addr = X may then
return only .rdata rows. Walk back to the table head, then re-query
xrefs against the table's address.
-- 1) find the head of the item that contains the target
SELECT addr FROM heads
WHERE addr <= 0x140027D50 ORDER BY addr DESC LIMIT 1;
-- 2) xrefs into the table head (where the code consumer points)
SELECT * FROM xrefs WHERE to_addr = <head> AND is_code = 1;
xrefs -> decompiler for top candidate function semantics.xrefs -> analysis for campaign-level synthesis.xrefs -> annotations to persist relationship findings.Cross-references - the most important table for understanding code relationships.
| Column | Type | Description |
|---|---|---|
from_addr | INT | Source address (who references) |
to_addr | INT | Target address (what is referenced) |
type | INT | Xref type code (never the ordinary-flow code, see below) |
is_code | INT | 1=code xref (call/jump), 0=data xref |
from_func | INT | Pre-computed containing function address (NULL when not in a function) |
Semantics: the surface exposes real references only — ordinary fall-through
flow edges (fl_F: each instruction "referencing" the next) are excluded on both
the full scan and the to_addr/from_addr/from_func fast paths, matching
IDA's Ctrl-X view and the other xsql tools. Counts therefore reflect
calls/jumps/data refs, not instruction adjacency.
-- Who calls function at 0x401000?
SELECT printf('0x%X', from_addr) as caller FROM xrefs WHERE to_addr = 0x401000 AND is_code = 1;
-- What does function at 0x401000 reference?
SELECT printf('0x%X', to_addr) as target FROM xrefs WHERE from_addr >= 0x401000 AND from_addr < 0x401100;
Cross-references to a specific struct/union member (Issue 11). Resolves the
member's IDA tid and enumerates xrefs directly — use this instead of LIKE
scans over instructions.disasm / instruction_operands.text. Requires a
filter on type_ordinal, type_name, or member_id (an unfiltered query
errors). Embedded members are expanded recursively with a dotted member_path.
| Column | Type | Description |
|---|---|---|
type_ordinal / type_name | INT/TEXT | Queried (top-level) type |
member_index | INT | Leaf index within its immediate parent type |
member_name / member_path | TEXT | Leaf name / dotted path (payload.leaf.data) |
member_offset / member_offset_bits | INT | Cumulative offset within the queried type |
member_id | INT | Member tid (also a filter key) |
xref_from | INT | Referencing address |
xref_to | INT | Member tid (== member_id) |
xref_type | INT | Raw IDA xref type code |
xref_kind | TEXT | read / write / offset / call / jump / flow |
function_addr / function_name | INT/TEXT | Containing function (NULL if none) |
operand_index | INT | Operand referencing the member (best-effort; NULL) |
instruction_text | TEXT | Disasm line at xref_from (NULL if not an instruction) |
access_offset / access_size | INT | Access sub-offset / width (best-effort; NULL) |
-- Who writes _EH3_EXCEPTION_REGISTRATION.TryLevel?
SELECT member_path, xref_kind, function_name, instruction_text
FROM struct_member_xrefs
WHERE type_name = '_EH3_EXCEPTION_REGISTRATION' AND member_name = 'TryLevel';
-- All member references for a type (incl. nested), grouped by member
SELECT member_path, count(*) AS refs FROM struct_member_xrefs
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'db_entry_t')
GROUP BY member_path;
Imported functions from external libraries.
| Column | Type | Description |
|---|---|---|
addr | INT | Import address (IAT entry) |
name | TEXT | Import name |
module | TEXT | Module/DLL name |
ordinal | INT | Import ordinal |
folder_path | TEXT | Writable import folder path |
full_path | TEXT | Full import dirtree path |
-- Imports from kernel32.dll
SELECT name FROM imports WHERE module LIKE '%kernel32%';
-- Organize network-related imports
UPDATE imports
SET folder_path = 'idasql/imports/network'
WHERE name LIKE '%socket%' OR name LIKE '%connect%' OR name LIKE '%send%';
Who calls each function. Caller names are resolved by the view from the funcs and names tables.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Target function address |
caller_addr | INT | Xref source address |
caller_name | TEXT | Calling function name |
caller_func_addr | INT | Calling function start (from from_func) |
Underlying query:
SELECT x.to_addr as func_addr, x.from_addr as caller_addr,
COALESCE((SELECT name FROM names WHERE addr = x.from_func LIMIT 1), printf('sub_%X', x.from_func)) as caller_name,
x.from_func as caller_func_addr
FROM xrefs x WHERE x.is_code = 1 AND x.from_func != 0
-- Who calls function at 0x401000?
SELECT caller_name, printf('0x%X', caller_addr) as from_addr
FROM callers WHERE func_addr = 0x401000;
-- Most called functions
SELECT printf('0x%X', func_addr) as addr, COUNT(*) as callers
FROM callers GROUP BY func_addr ORDER BY callers DESC LIMIT 10;
What each function calls. Inverse of callers view. Uses from_func for efficient function-level grouping.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Calling function address (from from_func) |
func_name | TEXT | Calling function name |
callee_addr | INT | Called address |
callee_name | TEXT | Called function/symbol name |
-- What does main call?
SELECT callee_name, printf('0x%X', callee_addr) as addr
FROM callees WHERE func_name LIKE '%main%';
-- Functions making most calls
SELECT func_name, COUNT(*) as call_count
FROM callees GROUP BY func_addr ORDER BY call_count DESC LIMIT 10;
Pre-joined view of string cross-references with containing function info.
| Column | Type | Description |
|---|---|---|
string_addr | INT | Address of the string |
string_value | TEXT | String content |
string_length | INT | String length |
ref_addr | INT | Address of the referencing instruction |
func_addr | INT | Containing function address |
func_name | TEXT | Containing function name |
-- Strings referenced by a specific function
SELECT string_value, func_name FROM string_refs WHERE func_addr = 0x401000;
-- Find functions referencing password-related strings
SELECT string_value, func_name FROM string_refs WHERE string_value LIKE '%password%';
-- Most referenced strings
SELECT string_value, COUNT(*) as ref_count
FROM string_refs GROUP BY string_addr ORDER BY ref_count DESC LIMIT 10;
Cached table of data (non-code) cross-references with containing function info. Whole-program aggregates are supported.
| Column | Type | Description |
|---|---|---|
from_addr | INT | Source address of the reference |
to_addr | INT | Target data address |
from_func_addr | INT | Containing function address |
from_func_name | TEXT | Containing function name |
ref_type | INT | Xref type code |
-- Data references from a specific function
SELECT * FROM data_refs WHERE from_func_addr = 0x401000;
-- Functions with most data references
SELECT from_func_name, COUNT(*) as data_ref_count
FROM data_refs GROUP BY from_func_addr ORDER BY data_ref_count DESC LIMIT 10;
Table-valued function for BFS call graph traversal. Uses HIDDEN parameters for traversal control.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Function address in the graph |
func_name | TEXT | Function name |
depth | INT | BFS depth from start |
parent_addr | INT | Parent function address in the traversal |
start | INT | HIDDEN — Starting function address |
direction | TEXT | HIDDEN — 'down' (callees), 'up' (callers), or 'both' |
max_depth | INT | HIDDEN — Maximum traversal depth |
Always provide WHERE constraints for all 3 hidden parameters.
-- Forward call tree from main
SELECT func_name, depth FROM call_graph
WHERE start = (SELECT addr FROM funcs WHERE name = 'main')
AND direction = 'down' AND max_depth = 5;
-- All transitive callers
SELECT func_name, depth FROM call_graph
WHERE start = 0x405000 AND direction = 'up' AND max_depth = 10;
-- Bidirectional exploration
SELECT func_name, depth FROM call_graph
WHERE start = 0x401000 AND direction = 'both' AND max_depth = 3;
-- Join with string_refs to find strings reachable from a function
SELECT DISTINCT sr.string_value, sr.func_name
FROM call_graph cg
JOIN string_refs sr ON sr.func_addr = cg.func_addr
WHERE cg.start = 0x401000 AND cg.direction = 'down' AND cg.max_depth = 3;
-- Imported APIs reachable from a function's call tree
SELECT DISTINCT i.module, i.name as api
FROM call_graph cg
JOIN disasm_calls dc ON dc.func_addr = cg.func_addr
JOIN imports i ON dc.callee_addr = i.addr
WHERE cg.start = 0x401000 AND cg.direction = 'down' AND cg.max_depth = 5
ORDER BY i.module, i.name;
Performance: BFS with visited set. O(reachable functions). Always constrain hidden params. Use this pattern when the destination is an import.
Table-valued function for finding the shortest call path between two functions. Uses bidirectional BFS.
| Column | Type | Description |
|---|---|---|
step | INT | Step number in the path (0 = source) |
func_addr | INT | Function address at this step |
func_name | TEXT | Function name at this step |
from_addr | INT | HIDDEN — Source function address |
to_addr | INT | HIDDEN — Destination function address |
max_depth | INT | HIDDEN — Maximum search depth |
Always provide WHERE constraints for all 3 hidden parameters.
Both endpoints must resolve to functions. Imported API addresses from imports
are not valid shortest_path endpoints.
-- Find shortest call path between two functions
SELECT step, func_name FROM shortest_path
WHERE from_addr = (SELECT addr FROM funcs WHERE name = 'main')
AND to_addr = (SELECT addr FROM funcs WHERE name = 'target_func')
AND max_depth = 20;
-- Check reachability between two functions
SELECT COUNT(*) > 0 as reachable FROM shortest_path
WHERE from_addr = 0x401000 AND to_addr = 0x405000 AND max_depth = 20;
-- Annotate path steps with call count and string refs
SELECT sp.step, sp.func_name,
(SELECT COUNT(*) FROM disasm_calls dc WHERE dc.func_addr = sp.func_addr) as calls_made,
(SELECT COUNT(*) FROM string_refs sr WHERE sr.func_addr = sp.func_addr) as strings_used
FROM shortest_path sp
WHERE sp.from_addr = 0x401000 AND sp.to_addr = 0x405000 AND sp.max_depth = 20
ORDER BY sp.step;
Performance: Bidirectional BFS. O(b^(d/2)) where b is branching factor and d is path length. Returns empty result set if no path exists within max_depth.
-- Incoming references to an address
SELECT from_addr, to_addr, type, is_code, from_func
FROM xrefs
WHERE to_addr = 0x401000;
-- Exact outgoing references from an item address
SELECT from_addr, to_addr, type, is_code, from_func
FROM xrefs
WHERE from_addr = 0x401000;
-- Outgoing references from anywhere inside a function
SELECT from_addr, to_addr, type, is_code, from_func
FROM xrefs
WHERE from_func = 0x401000;
Use grep to resolve internal symbols, types, and members before doing relationship analysis. Use imports when the callee may exist only as an imported API.
Canonical usage lives in ../grep/SKILL.md.
For canonical schema and owner mapping, see ../connect/references/schema-catalog.md (grep).
-- Resolve internal functions with grep
SELECT name, kind, addr
FROM grep
WHERE pattern = 'main%' AND kind = 'function'
ORDER BY name;
-- Resolve imported APIs with imports
SELECT module, name, addr
FROM imports
WHERE name LIKE 'CreateFile%'
ORDER BY module, name;
-- Then pivot into callers/callees/xrefs
SELECT caller_name, printf('0x%X', caller_addr) AS from_addr
FROM callers
WHERE func_addr = (
SELECT addr
FROM imports
WHERE name = 'CreateFileW'
ORDER BY name
LIMIT 1
);
The xrefs table has optimized filters using efficient IDA SDK APIs:
| Filter | Cost | Behavior |
|---|---|---|
to_addr = X | 0.5 | O(xrefs to X) — fast, uses IDA's xref index |
from_addr = X | 0.5 | O(xrefs from X) — fast, uses IDA's xref index |
from_func = X | 1.0 | O(callees of X) — uses XrefsFromFuncIterator |
No equality filter on to_addr / from_addr / from_func | — | Falls back to a cache of xrefs to function entry points only — avoid relying on it for complete import/data/non-function coverage |
Always filter xrefs by to_addr, from_addr, or from_func. Avoid unconstrained scans.
-- FAST: xrefs to a specific target
SELECT * FROM xrefs WHERE to_addr = 0x401000;
-- FAST: xrefs from a specific source
SELECT * FROM xrefs WHERE from_addr = 0x401000;
-- FAST: all xrefs originating from a function
SELECT * FROM xrefs WHERE from_func = 0x401000;
-- INCOMPLETE/avoid: unconstrained scan falls back to a function-entry cache
SELECT * FROM xrefs WHERE is_code = 1;
SELECT f.name, COUNT(*) as caller_count
FROM funcs f
JOIN xrefs x ON f.addr = x.to_addr
WHERE x.is_code = 1
GROUP BY f.addr
ORDER BY caller_count DESC
LIMIT 10;
SELECT DISTINCT (SELECT name FROM funcs WHERE from_addr >= addr AND from_addr < end_addr LIMIT 1) as caller
FROM xrefs
WHERE to_addr = (SELECT addr FROM imports WHERE name = 'CreateFileW');
SELECT s.content, (SELECT name FROM funcs WHERE x.from_addr >= addr AND x.from_addr < end_addr LIMIT 1) as used_by
FROM strings s
JOIN xrefs x ON s.addr = x.to_addr
WHERE s.content LIKE '%password%';
-- Which modules does each function depend on?
SELECT f.name as func_name, i.module, COUNT(*) as api_count
FROM funcs f
JOIN disasm_calls dc ON dc.func_addr = f.addr
JOIN imports i ON dc.callee_addr = i.addr
GROUP BY f.addr, i.module
ORDER BY f.name, api_count DESC;
-- Functions referencing data sections
SELECT
f.name,
s.name as segment,
COUNT(*) as data_refs
FROM funcs f
JOIN xrefs x ON x.from_addr BETWEEN f.addr AND f.end_addr
JOIN segments s ON x.to_addr BETWEEN s.start_addr AND s.end_addr
WHERE s.class = 'DATA' AND x.is_code = 0
GROUP BY f.addr, s.name
ORDER BY data_refs DESC
LIMIT 20;
Prefer
call_graphover manual CTEs. Thecall_graphtable uses C++ BFS with a visited set — correct BFS depths, no duplicate expansion on diamond-shaped call graphs, and early termination.
Before (recursive CTE — no visited tracking, exponential on diamond graphs):
WITH RECURSIVE call_chain(root, current_func, depth) AS (
SELECT 0x401000, callee_addr, 1
FROM disasm_calls WHERE func_addr = 0x401000
UNION ALL
SELECT cc.root, dc.callee_addr, cc.depth + 1
FROM call_chain cc
JOIN disasm_calls dc ON dc.func_addr = cc.current_func
WHERE cc.depth < 10
)
SELECT DISTINCT current_func, MIN(depth) FROM call_chain GROUP BY current_func;
After (call_graph table — C++ BFS with visited set, correct depths):
SELECT func_addr, func_name, depth FROM call_graph
WHERE start = 0x401000 AND direction = 'down' AND max_depth = 10;
Note: For targeted traversal, prefer the
call_graphtable which uses C++ BFS with visited tracking. Use recursive CTEs only when you need custom join logic (e.g., filtering by callee properties at each step).
Find all functions reachable from a starting function (up to depth 5):
-- Preferred: use call_graph table
SELECT func_name, depth FROM call_graph
WHERE start = (SELECT addr FROM funcs WHERE name = 'main')
AND direction = 'down' AND max_depth = 5;
-- Manual CTE (when custom filtering is needed at each step):
WITH RECURSIVE cg AS (
SELECT addr as func_addr, name, 0 as depth
FROM funcs WHERE name = 'main'
UNION ALL
SELECT f.addr, f.name, cg.depth + 1
FROM cg
JOIN disasm_calls dc ON dc.func_addr = cg.func_addr
JOIN funcs f ON f.addr = dc.callee_addr
WHERE cg.depth < 5
AND dc.callee_addr != 0
)
SELECT DISTINCT func_addr, name, MIN(depth) as min_depth
FROM cg
GROUP BY func_addr
ORDER BY min_depth, name;
Note: For targeted traversal, prefer the
call_graphtable withdirection = 'up'. Use recursive CTEs only when you need custom join logic.
Trace callers transitively up to depth 5:
-- Preferred: use call_graph table
SELECT func_name, depth FROM call_graph
WHERE start = 0x401000 AND direction = 'up' AND max_depth = 5;
-- Manual CTE (when custom filtering is needed at each step):
WITH RECURSIVE callers_cte AS (
SELECT DISTINCT dc.func_addr, 1 as depth
FROM disasm_calls dc
WHERE dc.callee_addr = 0x401000
UNION ALL
SELECT DISTINCT dc.func_addr, c.depth + 1
FROM callers_cte c
JOIN disasm_calls dc ON dc.callee_addr = c.func_addr
WHERE c.depth < 5
)
SELECT (SELECT name FROM funcs WHERE func_addr >= addr AND func_addr < end_addr LIMIT 1) as caller, MIN(depth) as distance
FROM callers_cte
GROUP BY func_addr
ORDER BY distance, caller;
WITH malloc_callers AS (
SELECT DISTINCT func_addr
FROM disasm_calls
WHERE callee_name LIKE '%malloc%'
),
null_checkers AS (
SELECT DISTINCT func_addr
FROM ctree_v_comparisons
WHERE rhs_num = 0 AND op_name = 'cot_eq'
)
SELECT f.name
FROM funcs f
JOIN malloc_callers m ON f.addr = m.func_addr
JOIN null_checkers n ON f.addr = n.func_addr;
WITH allocators AS (
SELECT func_addr, COUNT(*) as alloc_count
FROM disasm_calls
WHERE callee_name LIKE '%alloc%' OR callee_name LIKE '%malloc%'
GROUP BY func_addr
),
freers AS (
SELECT func_addr, COUNT(*) as free_count
FROM disasm_calls
WHERE callee_name LIKE '%free%'
GROUP BY func_addr
)
SELECT f.name,
COALESCE(a.alloc_count, 0) as allocations,
COALESCE(r.free_count, 0) as frees
FROM funcs f
LEFT JOIN allocators a ON f.addr = a.func_addr
LEFT JOIN freers r ON f.addr = r.func_addr
WHERE a.alloc_count > 0 AND COALESCE(r.free_count, 0) = 0
ORDER BY allocations DESC;
More efficient than JOIN + DISTINCT for existence checks:
SELECT f.name
FROM funcs f
WHERE EXISTS (
SELECT 1 FROM xrefs x
JOIN strings s ON x.to_addr = s.addr
WHERE x.from_addr BETWEEN f.addr AND f.end_addr
);
SELECT f.name, f.size
FROM funcs f
WHERE NOT EXISTS (
SELECT 1 FROM disasm_calls dc
WHERE dc.func_addr = f.addr
)
ORDER BY f.size DESC;
disassembly — call-site context (disasm_at, disasm_calls, operand-level reads).data — string/data targets behind a to_addr; the canonical pivot when xrefs returns .rdata-only rows.decompiler — calling-code logic and indirect-call resolution via callee types.