Expand description
Recursive-descent function disassembly over real PE bytes (iced-x86).
Given a function entry VA, we decode instructions and follow the function’s
intra-function control flow (conditional branches + their fallthrough,
unconditional JMP rel) until every reachable path terminates at a RET /
interrupt / undecodable byte. Along the way we harvest, purely from the
decoded operands, every fact that lets us catch a rebuild hallucination:
direct_calls— targets ofCALL rel16/rel32(the call graph proper)tail_calls—JMP relleaving the body (a tail call into another fn)indirect_calls/indirect_jumps— counts of register/memory dispatchvcall_slots— displacements ofCALL/JMP [reg+0xNN](vtable slots)iat_calls— absolute targets ofCALL [0x00a28xxx](IAT imports)field_offsets— displacements of[reg+0xNN]accesses (struct fields), excluding ESP/EBP (those are stack locals/args)globals— absolute data addresses referenced as[0x00bXXXXX]imm_addrs— in-image immediates (MOV [esi],0x00a7e38cvtable VAs, function pointers, string-literal addresses)
This is structural ground truth: no decompiler in the loop.
Structs§
- Call
Graph - Call
Site - One direct call site with the argument set-up recovered by a short backward scan of its basic
block.
ecx/edxare the fastcall/thiscall register args (the receiver lands inecx);stackis the pushed args in source (left-to-right) order.None/empty means “not recovered in-block”.
Enums§
- ArgKind
- The recovered “kind” of a single call argument, harvested from the instruction that set it
up (a register load or a
PUSH). Coarse on purpose — only the distinctions a faithful port must preserve, and only those a short local scan can recover without false positives.
Functions§
- analyze
- Walk the function at
entryand return its facts, sourced purely from bytes. - reg_
params - Heuristically determine whether the function at
addrtakes register parameters in ECX / EDX (i.e. is thiscall/fastcall). Scans the entry block for a READ of the register before any write: thiscall reads ECX (thethis), fastcall also reads EDX, cdecl/stdcall read neither. Used to align a caller’s recovered register args to the callee’s actual parameters (so a stray EDX in a caller is not mistaken for an argument to a thiscall callee). Conservative: under-detection just means a position is skipped, never a false mismatch. - resolve_
thunk - If
addris a one-instruction thunk (JMP target), returntarget. Callers often invoke a function through such a thunk (a tail-jump stub, or/OPT:ICF-folded forwarder), so the byte call edge points at the thunk, not the real callee — following it one level lets the call-graph check see the true target.