From arc-probe
Builds reverse call tree from target function address by tracing callers upward multiple levels using xref scans and disassembly. Shows argument setup and call hierarchy.
npx claudepluginhub vzco/arc-probe --plugin arc-probeThis skill uses the workspace's default tool permissions.
Build a reverse call tree by following the call chain upward from a target function. Finds direct callers, then their callers, up to N levels deep. Shows argument setup at each call site and builds a visual tree of the call hierarchy.
Finds all callers of a function address in binaries via xref scans, disassembles argument setup before call sites, and shows containing functions and string refs. Useful for reverse engineering native x64 code.
Analyzes IDA cross-references to find callers, callees, imports, data references, call graphs, and dependency chains using SQL queries on xrefs and imports tables.
Finds function call sites in binaries using VulHunt Lua queries. Useful for analyzing callers of functions, checking call relationships, or identifying API invocations.
Share bugs, ideas, or general feedback.
Build a reverse call tree by following the call chain upward from a target function. Finds direct callers, then their callers, up to N levels deep. Shows argument setup at each call site and builds a visual tree of the call hierarchy.
address (required): Address of the target function (hex). Can be absolute or module+offset.depth (optional): Number of levels to trace upward (default: 2, max recommended: 3).module (optional): Module to search in. If omitted, determined automatically.probe.exe "ping"
probe.exe "modules list"
Identify which module contains the target address. Record the module name and base address.
Confirm the address is a function start:
probe.exe "disasm <address> 5"
Look for a prologue (push rbp, sub rsp, etc.). If mid-function, search backwards for the start.
probe.exe "xref scan <address> <module> --type CALL --limit 15"
Record each caller:
call_site -- address of the CALL instructionenclosing_function -- start of the function containing the call (from .pdata)For each caller, grab a quick summary -- disassemble 3-4 instructions before the call to see argument setup:
probe.exe "disasm <call_site - 0x18> 8"
Note any string references in the argument setup (resolve lea reg, [rip+...] targets).
If zero callers found:
--type CALL,MOV for indirect referencesrtti scanFor each unique enclosing function from Level 1, repeat the xref scan:
probe.exe "xref scan <level1_function> <module> --type CALL --limit 10"
Limit to 10 callers per function to avoid combinatorial explosion. If a function has more than 10 callers, it is likely a utility function -- note it as "widely called" and don't trace further up from it.
Again, for each caller found, grab argument setup:
probe.exe "disasm <call_site - 0x18> 8"
If depth is 3, repeat for each Level 2 function. Apply the same limits:
Cycle detection: Keep a set of all function addresses already visited. If an xref scan returns a function already in the set, mark it as (recursive/cycle) and don't trace further.
Practical limits: Beyond depth 3, the tree becomes unwieldy. Recommend stopping at depth 2-3 and going deeper only for specific branches of interest.
For each function in the tree, try to identify it:
a. Check for string references (fast heuristic):
probe.exe "disasm func <function_address>"
Scan for lea instructions with RIP-relative operands. Resolve strings:
probe.exe "read_string <resolved_address>"
b. Check the function store:
probe.exe "functions at <function_address>"
c. Check for labels (if GUI bridge is running):
curl -s -X POST http://localhost:9996 -H "Content-Type: application/json" \
-d '{"action":"store","store":"label","method":"getLabel","args":["0x<function_address>"]}'
d. Check RTTI if the function is at a vtable entry:
probe.exe "rtti find <partial_name>"
If no name is found, use the address as the label: sub_7FF612345678.
Assemble the collected data into a tree structure. Each node shows:
target: sub_7FF612345678 (client.dll + 0x5678)
"ProcessDamage" — refs: "damage_type"
===========================================================
sub_7FF612345678 (client.dll + 0x5678)
|
+-- [caller] sub_7FF612340000 (client.dll + 0x0000)
| | call site: +0x42, args: mov rcx,rsi / mov edx,[rbx+0x354]
| | refs: "GameRules::ProcessDamage"
| |
| +-- [caller] sub_7FF612338000 (client.dll - 0xD678)
| | | call site: +0x1A, args: lea rcx,[rip+...] -> "game_rules"
| | | refs: "OnTick"
| | |
| | +-- [caller] sub_7FF612330000 (widely called, 15+ callers)
| | (tick dispatcher — not traced further)
| |
| +-- [caller] sub_7FF61234A000 (client.dll + 0x4422)
| | call site: +0x8C, args: mov rcx,rdi / xor edx,edx
| | refs: "CombatSystem::Update"
| |
| +-- (no callers found — likely a virtual function)
|
+-- [caller] sub_7FF612342800 (client.dll + 0x2800)
| | call site: +0x42, args: mov rcx,[rbp+0x30] / mov edx,1
| | refs: "AI_TakeDamage"
| |
| +-- [caller] sub_7FF612350000 (client.dll + 0xA422)
| | call site: +0x64, args: mov rcx,r14 / lea rdx,[rip+...] -> "npc"
| | refs: "AI::Think"
| |
| +-- [caller] sub_7FF612360000 (client.dll + 0x1A422)
| call site: +0x30, args: mov rcx,[rsp+0x40]
| (no string refs)
|
+-- [caller] sub_7FF612346000 (client.dll + 0x0422)
| call site: +0x22, args: xor ecx,ecx / xor edx,edx
| (no string refs — possibly a test/debug caller)
|
+-- (no callers found)
Summary:
Level 0 (target): 1 function
Level 1 (direct callers): 3 functions
Level 2 (indirect callers): 4 functions
Total unique functions: 8
Widely-called functions skipped: 1
Label all discovered functions and navigate to the target:
curl -s -X POST http://localhost:9996 -H "Content-Type: application/json" -d '{
"action":"batch","actions":[
{"action":"activity","status":"working","message":"Labeling call tree..."},
{"action":"store","store":"label","method":"setLabel","args":["0x<target>","target: <name>"]},
{"action":"store","store":"label","method":"setLabel","args":["0x<caller1>","caller L1: <name>"]},
{"action":"store","store":"label","method":"setLabel","args":["0x<caller2>","caller L1: <name>"]},
{"action":"store","store":"label","method":"setLabel","args":["0x<caller1_1>","caller L2: <name>"]},
{"action":"navigate","tab":"disasm","address":"0x<target>"},
{"action":"activity","status":"idle","message":"Done — traced N callers across M levels"}
]
}'
Present the tree (as shown in step 6) followed by a summary:
Reverse Call Tree for sub_7FF612345678
=======================================
[tree as above]
Key Findings:
- Main call path: OnTick -> GameRules::ProcessDamage -> target
- AI path: AI::Think -> AI_TakeDamage -> target
- The target function is called from 3 direct callers
- Deepest chain: 3 levels (OnTick -> ProcessDamage -> target)
- "sub_7FF612330000" is a central dispatcher (15+ callers), likely a tick/update loop
If a function has many callers at Level 1 (>8), prioritize:
Skip or summarize "utility" functions that are called from many places (allocators, logging, validation helpers). These create noise in the tree without adding understanding.
call [rax+offset] which xref scan can't resolve