npx claudepluginhub vzco/arc-probe --plugin arc-probeThis skill uses the workspace's default tool permissions.
Compare a function between two sessions (e.g., before and after a binary update). Use a byte signature to relocate the function in the new binary, then compare disassembly to identify what changed.
Generates stable byte signatures for binary functions using disassembly and wildcards to survive updates. Useful for reverse engineering and locating functions post-rebuild.
Queries IDA disassembly for functions, segments, instructions, blocks, operands, control flow, and raw code structure. Use for binary inspection and low-level analysis.
Performs depth-first reverse engineering on Ghidra binaries, answering questions like function behavior, crypto usage, or C2 addresses via iterative analysis and database improvements.
Share bugs, ideas, or general feedback.
Compare a function between two sessions (e.g., before and after a binary update). Use a byte signature to relocate the function in the new binary, then compare disassembly to identify what changed.
This skill has two phases:
signature_or_address (required): Either a byte signature pattern (e.g., "48 89 5C 24 08 57 48 83 EC 20 48 8B D9 E8 ?? ?? ?? ??") or a function address (hex) to capturemodule (optional): Module name to search inRun this phase while the current binary is loaded. The goal is to record everything needed to find and compare the function later.
If given an address:
probe.exe "modules list"
Determine the module and RVA:
RVA = address - module_base
If given a signature:
probe.exe "pattern <signature> <module>"
Verify the signature matches exactly one location. If multiple matches, narrow the search or extend the signature.
probe.exe "disasm func <function_address>"
Record the full disassembly. Pay attention to:
For each string reference, read the string:
probe.exe "read_string <resolved_lea_target>"
For each call target, check if it has a name:
probe.exe "disasm <call_target> 3"
If not already provided as a signature:
probe.exe "sig <function_address> 32 <module>"
Test uniqueness:
probe.exe "pattern <signature> <module>"
If not unique, extend:
probe.exe "sig <function_address> 64 <module>"
Store this information (present it to the user to save):
Function Capture:
Name: <description or label>
Module: <module_name>
Address: 0x<addr> (RVA: 0x<rva>)
Size: <N> bytes (<M> instructions)
Signature: <pattern>
Disassembly: (full listing)
Strings: (list with offsets)
Callees: (list with offsets)
Tell the user: "Save this capture. After the binary updates, run this skill again with the signature to compare."
Run this phase after the binary has been updated (new build, game patch, etc.). The module will be loaded at a different base address and the function may have changed.
probe.exe "pattern <signature> <module>"
If found (1 match): The function exists at a new address. Proceed to comparison.
If found (multiple matches): The signature is no longer unique — the update added similar code. Try:
If not found (0 matches): The function was significantly modified. Strategies:
a. Try a sub-signature — use just the first 16 bytes of the original signature (the prologue is less likely to change):
probe.exe "pattern <first_16_bytes_of_sig> <module>"
b. Search by string reference — if the function referenced a unique string, find that string and trace xrefs:
probe.exe "strings find <unique_string> <module>"
probe.exe "strings xref <string_addr> <module>"
c. Search by export name — if the function was an export, check if the export still exists:
probe.exe "pe exports <module>"
d. Search by RTTI — if the function was a virtual method, the class likely still exists:
probe.exe "rtti vtable <class_name> <module>"
Check the same vtable index.
e. The function was removed or completely rewritten — report this finding. The update fundamentally changed this code path.
probe.exe "disasm func <new_function_address>"
Record the new disassembly with the same level of detail as the capture.
Analyze the differences between the captured (old) and current (new) disassembly:
Structural comparison:
Instruction-level comparison:
Walk through both listings instruction by instruction. Ignore expected differences:
Flag actual differences:
Semantic comparison:
For each changed region, determine the semantic meaning:
cmp/test + jcc — a new conditional check was addedcall — a new function is being called (what does it do?)call — a function call was dropped (inlined? removed?)[rcx+0x354] became [rcx+0x358]) — struct layout changedIf field access offsets changed (e.g., [rcx+0x354] in the old version vs [rcx+0x358] in the new), this indicates a struct layout change. A field was inserted before this offset, pushing everything down. Document:
Struct offset shift detected:
Old: [rcx+0x354] (m_iHealth)
New: [rcx+0x358] (m_iHealth — shifted by +4)
Cause: 4 bytes inserted before offset 0x354
probe.exe "sig <new_function_address> 32 <module>"
Test and verify the new signature:
probe.exe "pattern <new_signature> <module>"
curl -s -X POST http://localhost:9996 -H "Content-Type: application/json" -d '{
"action":"batch","actions":[
{"action":"activity","status":"working","message":"Labeling updated function..."},
{"action":"store","store":"label","method":"setLabel","args":["0x<new_addr>","<function_name> (updated)"]},
{"action":"navigate","tab":"disasm","address":"0x<new_addr>"},
{"action":"activity","status":"idle","message":"Done — function diff complete"}
]
}'
Function Diff: CBaseEntity::TakeDamage
=======================================
Old: 0x7FFB2194FE40 (client.dll + 0x3BFE40) — 96 instructions, 0x1A0 bytes
New: 0x7FFB21A5F300 (client.dll + 0x4CF300) — 102 instructions, 0x1C8 bytes
(+6 instructions, +0x28 bytes)
Signature:
Old: 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 E8 ?? ?? ?? ??
New: 48 89 5C 24 08 57 48 83 EC 30 48 8B D9 E8 ?? ?? ?? ??
(stack frame grew from 0x20 to 0x30)
Changes:
1. [+0x1A] NEW: cmp dword ptr [rcx+0x3FC], 0
NEW: jz +0x12
Analysis: New null/zero check on a field at +0x3FC (new field?)
2. [+0x42] CHANGED: mov eax, [rcx+0x354] --> mov eax, [rcx+0x358]
Analysis: m_iHealth offset shifted from 0x354 to 0x358 (+4 bytes)
3. [+0x8A] NEW: call 0x7FFB21B02000
Analysis: New function call added — appears to be a validation check
(target function references string "damage validation failed")
4. [+0xC0] REMOVED: call 0x7FFB2190A000
Analysis: Old logging call removed (was calling LogMessage with "damage applied")
Struct Offset Changes:
m_iHealth: 0x354 -> 0x358 (+4)
m_iMaxHealth: 0x350 -> 0x354 (+4)
m_lifeState: 0x35C -> 0x360 (+4)
Likely cause: 4-byte field inserted before 0x350
New Signature: 48 89 5C 24 08 57 48 83 EC 30 48 8B D9 E8 ?? ?? ?? ??
If you're not comparing across sessions but want to compare two similar functions in the same binary (e.g., overridden virtual function in base vs derived class):