Skip to main content

ffi.disasm

x86-64 disassembly utilities backed by Capstone. All addresses are Lua numbers (doubles representing 64-bit pointers). Capstone is initialised lazily on first use; if initialisation fails, functions return an empty table or nil rather than raising an error.

Functions

ffi.disasm.at(address, count?)

Disassembles up to count instructions starting at address and returns them as an array. Each element is an instruction table with the following fields:

FieldTypeDescription
addressnumberVirtual address of this instruction.
mnemonicstringInstruction mnemonic (e.g. "mov", "call").
op_strstringOperand string as printed by Capstone (e.g. "rax, qword ptr [rip + 0x1234]").
sizenumberByte length of the instruction.
bytestableArray of number — the raw bytes of the instruction (1-indexed).
operandstableArray of operand tables (see below).

Each operand table always contains type ("reg", "imm", "mem", or "unknown") and size (number of bytes the operand accesses). Additional fields depend on type:

  • "reg": reg (string) — register name.
  • "imm": imm (number) — immediate value.
  • "mem": base (string, optional), index (string, optional), scale (number), disp (number).

Parameters

NameTypeDescription
addressnumber

Starting address to disassemble from.

count?number

Maximum number of instructions to decode. Defaults to 1.

Returns

TypeDescription
table

Array of instruction tables. Empty if Capstone failed to initialise or could not decode any instructions.

ffi.disasm.at_bytes(address, byte_count)

Disassembles as many complete instructions as fit within byte_count bytes starting at address. Unlike at, the limit is measured in bytes rather than instruction count, which pairs naturally with disasm.size. Returns an array of instruction tables with the same shape as at.

Parameters

NameTypeDescription
addressnumber

Starting address to disassemble from.

byte_countnumber

Maximum number of bytes to consume.

Returns

TypeDescription
table

Array of instruction tables. Empty if Capstone failed to initialise or could not decode any instructions.

ffi.disasm.pull_global(address)

Decodes the single instruction at address and, if it is a RIP-relative mov of the form mov <reg>, qword ptr [rip + offset], resolves and returns the absolute target address. This is the standard compiler pattern for loading the address of a global variable. Returns nil if the instruction is not that pattern, if disassembly failed, or if Capstone could not be initialised.

Parameters

NameTypeDescription
addressnumber

Address of the instruction to inspect.

Returns

TypeDescription
number?

Resolved global address, or nil if the instruction does not match the expected pattern.

ffi.disasm.pull_all_globals(address, max_size?)

Scans up to max_size instructions starting at address and collects the resolved target address of every RIP-relative mov <reg>, qword ptr [rip + offset] instruction found (the pattern used by the compiler to access global variables). Scanning stops early if an INT3 padding byte is encountered (indicating the end of the function body). Unlike size, this function does not stop at ret or jmp, because globals can be loaded after such instructions (e.g. into a return register in the function epilogue). Returns an array of resolved addresses in the order they were found.

Parameters

NameTypeDescription
addressnumber

Starting address to scan from.

max_size?number

Maximum number of instructions to examine. Defaults to 128.

Returns

TypeDescription
table

Array of number — resolved global addresses in encounter order. Empty if Capstone failed to initialise, no globals were found, or disassembly produced no instructions.

ffi.disasm.pull_calls(address, max_size?)

Scans up to max_size instructions starting at address and collects the resolved target address of every call instruction found. Both direct (call imm) and RIP-relative indirect (call qword ptr [rip + offset]) forms are resolved to absolute addresses. Other indirect forms (e.g. call rax) are skipped because the target cannot be determined statically. Scanning stops early at the first INT3 padding byte. This is useful for finding thunk addresses of virtual-function calls, where hooking the thunk's inner target is more practical than hooking the thunk itself. Returns an array of resolved call-target addresses in encounter order.

Parameters

NameTypeDescription
addressnumber

Starting address to scan from.

max_size?number

Maximum number of instructions to examine. Defaults to 128.

Returns

TypeDescription
table

Array of number — resolved call-target addresses in encounter order. Empty if Capstone failed to initialise, no resolvable calls were found, or disassembly produced no instructions.

ffi.disasm.size(address)

Returns the byte size of the function that contains address. Primary method: RtlLookupFunctionEntry reads the .pdata RUNTIME_FUNCTION table, which covers all non-leaf functions on x86-64 Windows. Fallback: For leaf functions (which have no .pdata entry), Capstone linearly sweeps up to 0x1000 bytes and stops at the first run of INT3 padding bytes. A lone INT3 surrounded by non-INT3 instructions is treated as a live __debugbreak() or assertion trap, not as padding — only a INT3 immediately after a ret/jmp, or two or more consecutive INT3s, triggers the boundary cut. Returns nil if neither method produces a result.

Parameters

NameTypeDescription
addressnumber

Any address within the function to measure (typically the function entry point).

Returns

TypeDescription
number?

Size of the function in bytes, or nil if it could not be determined.

ffi.disasm.autosig(address, size)

Copies size bytes from address and auto-masks them into a byte-pattern signature string with wildcard (?) bytes in place of relocatable values (e.g. relative offsets in call/jmp instructions). The resulting string is suitable for use with pattern scanners. Returns nil if the masking process produces an empty signature.

Parameters

NameTypeDescription
addressnumber

Starting address of the region to signature.

sizenumber

Number of bytes to read and mask.

Returns

TypeDescription
string?

The auto-generated signature string, or nil if one could not be produced.