ts-capstone
Version:
This module provides bindings for the Capstone disassembly framework.
1,047 lines (1,009 loc) • 93.7 kB
text/typescript
import Module from './libcapstone';
import { Memory } from './memory';
import {
// ARM64 architecture
type cs_arm64_op,
ARM64,
cs_arm64,
// ARM architecture
type cs_arm_op,
ARM,
cs_arm,
// BPF architecture
type cs_bpf_op,
BPF,
cs_bpf,
// EVM architecture
EVM,
cs_evm,
// M680X architecture
type cs_m680x_op,
M680X,
cs_m680x,
// M68K architecture
type cs_m68k_op,
M68K,
cs_m68k,
// MIPS architecture
type cs_mips_op,
MIPS,
cs_mips,
// MOS65XX architecture
type cs_mos65xx_op,
MOS65XX,
cs_mos65xx,
// PPC architecture
type cs_ppc_op,
PPC,
cs_ppc,
// RISCV architecture
type cs_riscv_op,
RISCV,
cs_riscv,
// SH architecture
type cs_sh_op,
SH,
cs_sh,
// SPARC architecture
type cs_sparc_op,
SPARC,
cs_sparc,
// TMS320C64X architecture
type cs_tms320c64x_op,
TMS320C64X,
cs_tms320c64x,
// TRICORE architecture
type cs_tricore_op,
TRICORE,
cs_tricore,
// WASM architecture
type cs_wasm_op,
WASM,
cs_wasm,
// X86 architecture
type cs_x86_op,
X86,
cs_x86,
// XCORE architecture
type cs_xcore_op,
XCORE,
cs_xcore,
// SYSZ architecture
type cs_sysz_op,
SYSZ,
cs_sysz,
} from './arch';
const Wrapper: wasm_module = Module() as wasm_module;
type cs_err = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14; // All type of errors encountered by Capstone API. These are values returned by cs_errno()
type cs_arch = number; // Architecture type
type cs_mode = number; // Mode type
type cs_opt_type = number; // Runtime option for the disassembled engine
type cs_opt_value = number; // Runtime option value (associated with option type above)
type cs_group_type = number; // Common instruction groups - to be consistent across all architectures.
type cs_op_type = number; // Common instruction operand types - to be consistent across all architectures
type cs_ac_type = number; // Common instruction operand access types - to be consistent across all architectures. It is possible to combine access types, for example: CS_AC_READ | CS_AC_WRITE
type cs_regs = number[]; // Type of array to keep the list of registers
type csh = number; // Handle using with all API
type cs_skipdata_cb_t = (
code: number,
code_size: number,
offset: number,
user_data: any,
) => number; // User-defined callback function for SKIPDATA option
type pointer_t<T extends any> = number; // Points to a specific memory address
type wasm_arg = 'number' | 'string' | 'array' | 'boolean' | 'pointer' | null; // types of arguments for the C function.
type wasm_t = 'i8' | 'i16' | 'i32' | 'i64' | 'float' | 'double' | 'i8*' | '*'; // An LLVM IR type as a string
// Module object with attributes that Emscripten-generated code calls at various points in its execution.
interface wasm_module {
HEAP8: Int8Array; // View for 8-bit signed memory.
HEAPU8: Uint8Array; // View for 8-bit unsigned memory.
HEAP16: Int16Array; // View for 16-bit signed memory.
HEAPU16: Uint16Array; // View for 16-bit unsigned memory.
HEAP32: Int32Array; // View for 32-bit signed memory.
HEAPU32: Uint32Array; // View for 32-bit unsigned memory.
HEAPF32: Float32Array; // View for 32-bit float memory.
HEAPF64: Float64Array; // View for 8-bit float memory.
_cs_free: (insn: pointer_t<cs_insn>, count: number) => void; // Free memory allocated by _cs_malloc() or disasm()
_cs_malloc: (handle: csh) => pointer_t<cs_insn>; // Allocate memory for 1 instruction to be used by disasm_iter()
_malloc: (size: number) => pointer_t<any>; // Allocates a block of memory on the heap, must be paired with free(), or heap memory will leak! (use Memory.malloc()).
_free: (pointer: pointer_t<any>) => void; // Free allocated memory (use Memory.free()).
_cs_reg_write: (
handle: csh,
insn: pointer_t<cs_insn>,
reg_id: number,
) => number; // Check if a disassembled instruction IMPLICITLY modified a particular register.
_cs_reg_read: (
handle: csh,
insn: pointer_t<cs_insn>,
reg_id: number,
) => number; // Check if a disassembled instruction IMPLICITLY used a particular register.
_cs_insn_group: (
handle: csh,
insn: pointer_t<cs_insn>,
group_id: number,
) => number; // Check if a disassembled instruction belong to a particular group.
_cs_regs_access: (
handle: csh,
insn: pointer_t<cs_insn>,
regs_read: pointer_t<cs_regs>,
regs_read_count: pointer_t<number>,
regs_write: pointer_t<cs_regs>,
regs_write_count: pointer_t<number>,
) => cs_err; // Retrieve all the registers accessed by an instruction, either explicitly or implicitly.
_cs_op_count: (
handle: csh,
insn: pointer_t<cs_insn>,
op_type: number,
) => number; // Count the number of operands of a given type.
_cs_op_index: (
handle: csh,
insn: pointer_t<cs_insn>,
op_type: number,
position: number,
) => number; // Retrieve the position of operand of given type in <arch>.operands[] array.
_cs_insn_offset: (insns: pointer_t<cs_insn[]>, post: number) => number; // Calculate the offset of a disassembled instruction in its buffer, given its position in its array of disassembled insn.
_cs_detail_buffer: (insn: pointer_t<cs_insn>) => pointer_t<Uint8Array>; // Gets the raw buffer of the specified insns cs_detail.
_cs_insn_buffer: (insn: pointer_t<cs_insn>) => pointer_t<Uint8Array>; // Gets the raw buffer of the cs_insn
_x86_rel_addr: (insn: pointer_t<cs_insn>) => number; // Calculate relative address for X86-64, given cs_insn structure
ccall: (
ident: string, // name of C function
returnType: wasm_arg, // return type
argTypes: wasm_arg[], // argument types
args: any[], // arguments
opts?: {
async: boolean; // If true, implies that the ccall will perform an async operation. This assumes you are build with asyncify support.
},
) => any; // Call a compiled C function from JavaScript.
setValue: (pointer: number, value: any, type: wasm_t) => void; // Sets a value at a specific memory address at run-time (use Memory.write()).
getValue: (pointer: number, type: wasm_t) => any; // Gets a value at a specific memory address at run-time (use Memory.read()).
UTF8ToString: (pointer: number, maxBytesToRead?: number) => string; // Given a pointer pointer_t to a null-terminated UTF8-encoded string in the Emscripten HEAP, returns a copy of that string as a JavaScript String object.
addFunction: (func: Function, sig: string) => any; // You can use addFunction to return an integer value that represents a function pointer
writeArrayToMemory: (
array: number[] | Uint8Array | Buffer,
buffer: pointer_t<number[] | Uint8Array | Buffer>,
) => void; // Writes an array to a specified address in the heap. Note that memory should to be allocated for the array before it is written.
}
// Detail information of disassembled instruction
interface cs_insn {
id: number; // Instruction ID (basically a numeric ID for the instruction mnemonic) Find the instruction id in the 'ARCH_insn' enum in the header file of corresponding architecture, such as 'arm_insn' in arm.h for ARM, 'x86_insn' in x86.h for X86, etc... This information is available even when CS_OPT_DETAIL = CS_OPT_OFF NOTE: in Skipdata mode, "data" instruction has 0 for this id field.
address: number; // Address (EIP) of this instruction This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
size: number; // Size of this instruction This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
mnemonic: string; // Ascii text of instruction mnemonic This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
op_str: string; // Ascii text of instruction operands This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
bytes: Uint8Array; // Machine bytes of this instruction, with number of bytes indicated by @size above This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
detail?: cs_detail; // cs_detail object
buffer?: Uint8Array; // The raw detail buffer, this will only be present if CS.OPT_BUFFER is on.
}
// cs_detail object. NOTE: detail object is only valid when both requirements below are met: (1) CS_OP_DETAIL = CS_OPT_ON (2) Engine is not in Skipdata mode (CS_OP_SKIPDATA option set to CS_OPT_ON)
interface cs_detail {
[index: string]: any;
regs_read: cs_regs; // list of implicit registers read by this insn
regs_read_count: number; // number of implicit registers read by this insn
regs_write: cs_regs; // list of implicit registers modified by this insn
regs_write_count: number; // number of implicit registers modified by this insn
groups: number[]; // list of group this instruction belong to
groups_count: number; // number of groups this insn belongs to
writeback: boolean; // Instruction has writeback operands.
buffer?: Uint8Array; // The raw detail buffer, this will only be present if CS.OPT_BUFFER is on.
x86?: cs_x86; // X86 architecture, including 16-bit, 32-bit & 64-bit mode
arm?: cs_arm; // ARM64 architecture (aka AArch64)
arm64?: cs_arm64; // ARM architecture (including Thumb/Thumb2)
m68k?: cs_m68k; // M68K architecture
mips?: cs_mips; // MIPS architecture
ppc?: cs_ppc; // PowerPC architecture
sparc?: cs_sparc; // Sparc architecture
sysz?: cs_sysz; // SystemZ architecture
xcore?: cs_xcore; // XCore architecture
tms320c64x?: cs_tms320c64x; // TMS320C64x architecture
m680x?: cs_m680x; // M680X architecture
evm?: cs_evm; // Ethereum architecture
mos65xx?: cs_mos65xx; //MOS65XX architecture (including MOS6502)
wasm?: cs_wasm; // Web Assembly architecture
bpf?: cs_bpf; // Berkeley Packet Filter architecture (including eBPF)
riscv?: cs_riscv; // RISCV architecture
sh?: cs_sh; // SH architecture
tricore?: cs_tricore; // TriCore architecture
// alpha?: cs_alpha; // Alpha architecture
// hppa?: cs_hppa; // HPPA architecture
}
// User-customized setup for SKIPDATA option
interface cs_opt_skipdata {
mnemonic: string | null; // Capstone considers data to skip as special "instructions", User can specify the string for this instruction's "mnemonic" here (default = ".byte").
callback: cs_skipdata_cb_t | null; // User-defined callback function to be called when Capstone hits data (default = null).
user_data: object; // User-defined data to be passed to callback function.
}
// fmt() options
interface cs_opt_fmt {
hex_comment?: boolean; // Specifies if the output should include decimal comments for hexadecimal imm
colors?: boolean; // Specifies if the output should include coloring
bytes?: boolean; // Specifies if the formatted string should have the instructions bytes.
address?: boolean; // Specifies if the formatted string should include the instructions address.
ASCII?: boolean; // Specifies if the formatted string should include the bytes ASCII representation.
}
// Customize mnemonic for instructions with alternative name.
// To reset existing customized instruction to its default mnemonic,
// call option(CS.OPT_MNEMONIC) again with the same id and null value
interface cs_opt_mnem {
id: number; // ID of instruction to be customized obtained from the cs_insn object.
mnemonic: string | null; // Customized instruction mnemonic(or null).
}
namespace CS {
// Return codes
export const ERR_OK: cs_err = 0; // No error: everything was fine
export const ERR_MEM: cs_err = 1; // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
export const ERR_ARCH: cs_err = 2; // Unsupported architecture: cs_open()
export const ERR_HANDLE: cs_err = 3; // Invalid handle: cs_op_count(), cs_op_index()
export const ERR_CSH: cs_err = 4; // Invalid csh argument: cs_close(), cs_errno(), cs_option()
export const ERR_MODE: cs_err = 5; // Invalid/unsupported mode: cs_open()
export const ERR_OPTION: cs_err = 6; // Invalid/unsupported option: cs_option()
export const ERR_DETAIL: cs_err = 7; // Information is unavailable because detail option is OFF
export const ERR_MEMSETUP: cs_err = 8; // Dynamic memory management uninitialized (see OPT_MEM)
export const ERR_VERSION: cs_err = 9; // Unsupported version (bindings)
export const ERR_DIET: cs_err = 10; // Access irrelevant data in "diet" engine
export const ERR_SKIPDATA: cs_err = 11; // Access irrelevant data for "data" instruction in SKIPDATA mode
export const ERR_X86_ATT: cs_err = 12; // X86 AT&T syntax is unsupported (opt-out at compile time)
export const ERR_X86_INTEL: cs_err = 13; // X86 Intel syntax is unsupported (opt-out at compile time)
export const ERR_X86_MASM: cs_err = 14; // X86 Intel syntax is unsupported (opt-out at compile time)
// Architectures
export const ARCH_ARM: cs_arch = 0; // ARM architecture (including Thumb, Thumb-2)
export const ARCH_ARM64: cs_arch = 1; // ARM-64, also called AArch64
export const ARCH_AARCH64: cs_arch = 1; // AArch-64, also called ARM-64
export const ARCH_MIPS: cs_arch = 2; // Mips architecture
export const ARCH_X86: cs_arch = 3; // X86 architecture (including x86 & x86-64)
export const ARCH_PPC: cs_arch = 4; // PowerPC architecture
export const ARCH_SPARC: cs_arch = 5; // Sparc architecture
export const ARCH_SYSZ: cs_arch = 6; // SystemZ architecture
export const ARCH_XCORE: cs_arch = 7; // XCore architecture
export const ARCH_M68K: cs_arch = 8; // 68K architecture
export const ARCH_TMS320C64X: cs_arch = 9; // TMS320C64x architecture
export const ARCH_M680X: cs_arch = 10; // 680X architecture
export const ARCH_EVM: cs_arch = 11; // Ethereum architecture
export const ARCH_MOS65XX: cs_arch = 12; // MOS65XX architecture (including MOS6502)
export const ARCH_WASM: cs_arch = 13; // WebAssembly architecture
export const ARCH_BPF: cs_arch = 14; // Berkeley Packet Filter architecture (including eBPF)
export const ARCH_RISCV: cs_arch = 15; // RISCV architecture
export const ARCH_SH: cs_arch = 16; // SH architecture
export const ARCH_TRICORE: cs_arch = 17; // TriCore architecture
// export const ARCH_ALPHA = 18; // Alpha architecture
// export const ARCH_HPPA = 19; // HPPA architecture
export const ARCH_MAX: cs_arch = 18; // The maximum architecture value.
export const ARCH_ALL: cs_arch = 0xffff; // Represents a mask that includes all architecture values.
// Modes
export const MODE_LITTLE_ENDIAN: cs_mode = 0; // little-endian mode (default mode)
export const MODE_ARM: cs_mode = 0; // 32-bit ARM
export const MODE_16: cs_mode = 1 << 1; // 16-bit mode (X86)
export const MODE_32: cs_mode = 1 << 2; // 32-bit mode (X86)
export const MODE_64: cs_mode = 1 << 3; // 64-bit mode (X86, PPC)
export const MODE_THUMB: cs_mode = 1 << 4; // ARM's Thumb mode, including Thumb-2
export const MODE_MCLASS: cs_mode = 1 << 5; // ARM's Cortex-M series
export const MODE_V8: cs_mode = 1 << 6; // ARMv8 A32 encodings for ARM
export const MODE_MICRO: cs_mode = 1 << 4; // MicroMips mode (MIPS)
export const MODE_MIPS3: cs_mode = 1 << 5; // Mips III ISA
export const MODE_MIPS32R6: cs_mode = 1 << 6; // Mips32r6 ISA
export const MODE_MIPS2: cs_mode = 1 << 7; // Mips II ISA
export const MODE_V9: cs_mode = 1 << 4; // SparcV9 mode (Sparc)
export const MODE_QPX: cs_mode = 1 << 4; // Quad Processing eXtensions mode (PPC)
export const MODE_SPE: cs_mode = 1 << 5; // Signal Processing Engine mode (PPC)
export const MODE_BOOKE: cs_mode = 1 << 6; // Book-E mode (PPC)
export const MODE_PS: cs_mode = 1 << 7; // Paired-singles mode (PPC)
export const MODE_M68K_000: cs_mode = 1 << 1; // M68K 68000 mode
export const MODE_M68K_010: cs_mode = 1 << 2; // M68K 68010 mode
export const MODE_M68K_020: cs_mode = 1 << 3; // M68K 68020 mode
export const MODE_M68K_030: cs_mode = 1 << 4; // M68K 68030 mode
export const MODE_M68K_040: cs_mode = 1 << 5; // M68K 68040 mode
export const MODE_M68K_060: cs_mode = 1 << 6; // M68K 68060 mode
export const MODE_BIG_ENDIAN: cs_mode = 1 << 31; // big-endian mode
export const MODE_MIPS32: cs_mode = MODE_32; // Mips32 ISA (Mips)
export const MODE_MIPS64: cs_mode = MODE_64; // Mips64 ISA (Mips)
export const MODE_M680X_6301: cs_mode = 1 << 1; // M680X Hitachi 6301,6303 mode
export const MODE_M680X_6309: cs_mode = 1 << 2; // M680X Hitachi 6309 mode
export const MODE_M680X_6800: cs_mode = 1 << 3; // M680X Motorola 6800,6802 mode
export const MODE_M680X_6801: cs_mode = 1 << 4; // M680X Motorola 6801,6803 mode
export const MODE_M680X_6805: cs_mode = 1 << 5; // M680X Motorola/Freescale 6805 mode
export const MODE_M680X_6808: cs_mode = 1 << 6; // M680X Motorola/Freescale/NXP 68HC08 mode
export const MODE_M680X_6809: cs_mode = 1 << 7; // M680X Motorola 6809 mode
export const MODE_M680X_6811: cs_mode = 1 << 8; // M680X Motorola/Freescale/NXP 68HC11 mode
export const MODE_M680X_CPU12: cs_mode = 1 << 9; // M680X Motorola/Freescale/NXP CPU12
export const MODE_M680X_HCS08: cs_mode = 1 << 10; // M680X Freescale/NXP HCS08 mode
export const MODE_BPF_CLASSIC: cs_mode = 0; // Classic BPF mode (default)
export const MODE_BPF_EXTENDED: cs_mode = 1 << 0; // Extended BPF mode
export const MODE_RISCV32: cs_mode = 1 << 0; // RISCV RV32G
export const MODE_RISCV64: cs_mode = 1 << 1; // RISCV RV64G
export const MODE_RISCVC: cs_mode = 1 << 2; // RISCV compressed instructure mode
export const MODE_MOS65XX_6502: cs_mode = 1 << 1; // MOS65XXX MOS 6502
export const MODE_MOS65XX_65C02: cs_mode = 1 << 2; // MOS65XXX WDC 65c02
export const MODE_MOS65XX_W65C02: cs_mode = 1 << 3; // MOS65XXX WDC W65c02
export const MODE_MOS65XX_65816: cs_mode = 1 << 4; // MOS65XXX WDC 65816, 8-bit m/x
export const MODE_MOS65XX_65816_LONG_M: cs_mode = 1 << 5; // MOS65XXX WDC 65816, 16-bit m, 8-bit x
export const MODE_MOS65XX_65816_LONG_X: cs_mode = 1 << 6; // MOS65XXX WDC 65816, 8-bit m, 16-bit x
export const MODE_MOS65XX_65816_LONG_MX: cs_mode =
MODE_MOS65XX_65816_LONG_M | MODE_MOS65XX_65816_LONG_X;
export const MODE_SH2: cs_mode = 1 << 1; // SH2
export const MODE_SH2A: cs_mode = 1 << 2; // SH2A
export const MODE_SH3: cs_mode = 1 << 3; // SH3
export const MODE_SH4: cs_mode = 1 << 4; // SH4
export const MODE_SH4A: cs_mode = 1 << 5; // SH4A
export const MODE_SHFPU: cs_mode = 1 << 6; // w/ FPU
export const MODE_SHDSP: cs_mode = 1 << 7; // w/ DSP
export const MODE_TRICORE_110: cs_mode = 1 << 1; // Tricore 1.1
export const MODE_TRICORE_120: cs_mode = 1 << 2; // Tricore 1.2
export const MODE_TRICORE_130: cs_mode = 1 << 3; // Tricore 1.3
export const MODE_TRICORE_131: cs_mode = 1 << 4; // Tricore 1.3.1
export const MODE_TRICORE_160: cs_mode = 1 << 5; // Tricore 1.6
export const MODE_TRICORE_161: cs_mode = 1 << 6; // Tricore 1.6.1
export const MODE_TRICORE_162: cs_mode = 1 << 7; // Tricore 1.6.2
// export const MODE_TRICORE_162 = 1 << 7; // Tricore 1.6.2
// export const MODE_HPPA_11 = 1 << 1; // HPPA 1.1
// export const MODE_HPPA_20 = 1 << 2; // HPPA 2.0
// export const MODE_HPPA_20W = CS.MODE_HPPA_20 | (1 << 3); // HPPA 2.0 wide
// Runtime option for the disassembled engine
export const OPT_INVALID: cs_opt_type = 0; // No option specified
export const OPT_SYNTAX: cs_opt_type = 1; // Intel X86 asm syntax (CS_ARCH_X86 arch Assembly output syntax)
export const OPT_DETAIL: cs_opt_type = 2; // Break down instruction structure into details
export const OPT_MODE: cs_opt_type = 3; // Change engine's mode at run-time
export const OPT_MEM: cs_opt_type = 4; // Change engine's mode at run-time
export const OPT_SKIPDATA: cs_opt_type = 5; // Skip data when disassembling
export const OPT_SKIPDATA_SETUP: cs_opt_type = 6; // Setup user-defined function for SKIPDATA option
export const OPT_MNEMONIC: cs_opt_type = 7; // Customize instruction mnemonic
export const OPT_UNSIGNED: cs_opt_type = 8; // print immediate operands in unsigned form
export const OPT_NO_BRANCH_OFFSET: cs_opt_type = 9; // ARM, prints branch immediates without offset.
export const OPT_BUFFER: cs_opt_type = 10; // Adds the raw buffer to the insn and detail object.
// Capstone option value
export const OPT_OFF: cs_opt_value = 0; // Turn OFF an option - default option of CS_OPT_DETAIL
export const OPT_ON: cs_opt_value = 3; // Turn ON an option (CS_OPT_DETAIL)
// export const OPT_DETAIL_REAL: cs_opt_value = 1 << 1; // If enabled, always sets the real instruction detail. Even if the instruction is an alias.
// Capstone syntax value
export const OPT_SYNTAX_DEFAULT: cs_opt_value = 0; // Default assembly syntax of all platforms (CS_OPT_SYNTAX)
export const OPT_SYNTAX_INTEL: cs_opt_value = 1; // Intel X86 asm syntax - default syntax on X86 (CS_OPT_SYNTAX, CS_ARCH_X86)
export const OPT_SYNTAX_ATT: cs_opt_value = 2; // ATT asm syntax (CS_OPT_SYNTAX, CS_ARCH_X86)
export const OPT_SYNTAX_NOREGNAME: cs_opt_value = 3; // Asm syntax prints register name with only number - (CS_OPT_SYNTAX, CS_ARCH_PPC, CS_ARCH_ARM)
export const OPT_SYNTAX_MASM: cs_opt_value = 4; // X86 Intel Masm syntax (CS_OPT_SYNTAX).
export const OPT_SYNTAX_MOTOROLA: cs_opt_value = 5; // MOS65XX use $ as hex prefix.
// export const OPT_SYNTAX_CS_REG_ALIAS = 1 << 7; // Prints common register alias which are not defined in LLVM (ARM: r9 = sb etc.)
// export const OPT_SYNTAX_PERCENT = 1 << 8; // Prints the % in front of PPC registers.
// Common instruction groups - to be consistent across all architectures.
export const GRP_INVALID: cs_group_type = 0; // uninitialized/invalid group.
export const GRP_JUMP: cs_group_type = 1; // all jump instructions (conditional+direct+indirect jumps)
export const GRP_CALL: cs_group_type = 2; // all call instructions
export const GRP_RET: cs_group_type = 3; // all return instructions
export const GRP_INT: cs_group_type = 4; // all interrupt instructions (int+syscall)
export const GRP_IRET: cs_group_type = 5; // all interrupt return instructions
export const GRP_PRIVILEGE: cs_group_type = 6; // all privileged instructions
export const GRP_BRANCH_RELATIVE: cs_group_type = 7; // all relative branching instructions
// Common instruction operand types - to be consistent across all architectures.
export const OP_INVALID: cs_op_type = 0; // Uninitialized/invalid operand.
export const OP_REG: cs_op_type = 1; // Register operand.
export const OP_IMM: cs_op_type = 2; // Immediate operand.
export const OP_MEM: cs_op_type = 0x80; // Memory operand.
export const OP_FP: cs_op_type = 3; // Floating-Point operand.
// Common instruction operand access types - to be consistent across all architectures. It is possible to combine access types, for example: CS_AC_READ | CS_AC_WRITE
export const AC_INVALID: cs_ac_type = 0; // Uninitialized/invalid access type.
export const AC_READ: cs_ac_type = 1 << 0; // Operand read from memory or register.
export const AC_WRITE: cs_ac_type = 1 << 1; // Operand written to memory or register.
// query id for cs_support()
export const SUPPORT_DIET = ARCH_ALL + 1;
export const SUPPORT_X86_REDUCE = ARCH_ALL + 2;
// Manifest Constants
export const MNEMONIC_SIZE = 32;
export const INSN_SIZE = 240;
export const DETAIL_SIZE = 1864;
export const MAX_IMPL_W_REGS = 20;
export const MAX_IMPL_R_REGS = 20;
export const MAX_NUM_GROUPS = 8;
/**
* Retrieves the offset relative to the start of the buffer where the instruction resides.
*
* NOTE: this assumes position is (>=1)
* @param insns - The instructions to analyze.
* @param position - The index of the specific insn.
* @returns The offset of the instruction relative to the buffer.
*/
export function INSN_OFFSET(insns: cs_insn[], position: number): number {
const base: number = insns[0].address;
const positional: number = insns[position - 1].address;
return positional - base;
}
export class CAPSTONE {
private arch: cs_arch; // The chosen architecture for this instance(cannot be changed)
private mode: cs_mode; // The mode associated with the chooses arch(can be changed via CS.OPT_MODE)
private handle_ptr: pointer_t<csh>; // The address of the cash handle
private arch_info: { instance: any; name: string }; // Decides what architecture specific info will be present in cs_detail
private opt_buffer: boolean = false; // Option toggle for CS.OPT_BUFFER
/**
* Create a new instance of the Capstone disassembly engine.
*
* @param arch - The architecture type.
* @param mode - The mode type.
*/
constructor(arch: cs_arch, mode: cs_mode) {
this.arch = arch;
this.mode = mode;
this.handle_ptr = 0;
this.open();
this.arch_info = this.init(arch);
}
/**
* Return the Capstone library version as a string.
*
* @public
* @returns The Capstone library version as a string in the format "major.minor".
*/
public version(): string {
const major_ptr: number = Memory.malloc(4);
const minor_ptr: number = Memory.malloc(4);
Wrapper.ccall(
'cs_version',
'number',
['pointer', 'pointer'],
[major_ptr, minor_ptr],
);
const major: number = Memory.read(major_ptr, 'i32');
const minor: number = Memory.read(minor_ptr, 'i32');
Memory.free(major_ptr);
Memory.free(minor_ptr);
return `${major}.${minor}`;
}
/**
* Check if Capstone supports a specific query.
*
* @public
* @param query - The query ID to check.
* @returns A boolean indicating whether Capstone supports the given query.
*/
public support(query: number): boolean {
var ret: boolean = Wrapper.ccall(
'cs_support',
'number',
['number'],
[query],
);
return Boolean(ret);
}
/**
* Get the error message string for a given error code.
*
* @public
* @param code - The error code.
* @returns The error message string corresponding to the given error code.
*/
public strerror(code: number): string {
return Wrapper.ccall('cs_strerror', 'string', ['number'], [code]);
}
/**
* Get the error code for the most recent Capstone error that occurred with the given handle.
*
* @public
* @param handle - The handle for which to get the error code.
* @returns The error code for the most recent Capstone error.
*/
public errno(handle: csh): cs_err {
return Wrapper.ccall('cs_errno', 'number', ['pointer'], [handle]);
}
private init(arch: cs_arch): { instance: Function; name: string } {
const arch_map: { [key: number]: { instance: any; name: string } } = {
[CS.ARCH_ARM]: { instance: cs_arm, name: 'arm' },
[CS.ARCH_ARM64]: { instance: cs_arm64, name: 'arm64' },
[CS.ARCH_AARCH64]: { instance: cs_arm64, name: 'arm64' },
[CS.ARCH_MIPS]: { instance: cs_mips, name: 'mips' },
[CS.ARCH_X86]: { instance: cs_x86, name: 'x86' },
[CS.ARCH_PPC]: { instance: cs_ppc, name: 'ppc' },
[CS.ARCH_SPARC]: { instance: cs_sparc, name: 'sparc' },
[CS.ARCH_SYSZ]: { instance: cs_sysz, name: 'sysz' },
[CS.ARCH_XCORE]: { instance: cs_xcore, name: 'xcore' },
[CS.ARCH_TMS320C64X]: { instance: cs_tms320c64x, name: 'tms320c64x' },
[CS.ARCH_M680X]: { instance: cs_m680x, name: 'm680x' },
[CS.ARCH_M68K]: { instance: cs_m68k, name: 'm68k' },
[CS.ARCH_EVM]: { instance: cs_evm, name: 'evm' },
[CS.ARCH_MOS65XX]: { instance: cs_mos65xx, name: 'mos65xx' },
[CS.ARCH_WASM]: { instance: cs_wasm, name: 'wasm' },
[CS.ARCH_BPF]: { instance: cs_bpf, name: 'bpf' },
[CS.ARCH_RISCV]: { instance: cs_riscv, name: 'riscv' },
[CS.ARCH_SH]: { instance: cs_sh, name: 'sh' },
[CS.ARCH_TRICORE]: { instance: cs_tricore, name: 'tricore' },
};
return arch_map[arch];
}
/**
* Handler to parse the cs_opt_skipdata obj
*
* @private
* @param skipdata - User-customized setup for SKIPDATA option
* @returns The pointer to the cs_opt_skipdata struct
*/
private skipdata_cb(setup: any): number {
const { mnemonic, callback, user_data } = setup;
const skipdata_struct: pointer_t<cs_opt_skipdata> = Memory.malloc(24);
typeof mnemonic === 'string' &&
Memory.write(skipdata_struct, mnemonic, 'char*');
const callback_ptr: pointer_t<Function> = skipdata_struct + 8;
const user_data_ptr: pointer_t<any> = skipdata_struct + 16;
if (typeof callback === 'function') {
const cb_ptr = Wrapper.addFunction(function (
code_ptr: any,
code_size: any,
offset: any,
user_data: any,
): number {
const code = [];
for (let i = 0; i < code_size; i++)
code.push(Memory.read(parseInt(code_ptr), 'u8'));
return callback(code, code_size, offset /* TODO: user_data*/);
},
'iiiii');
Memory.write(callback_ptr, cb_ptr, '*');
}
return skipdata_struct;
}
/**
* Dereferences a pointer to a cs_insn strict to retrieve information about a disassembled instruction.
*
* @private
* @param insn_ptr - The pointer to the disassembled instruction.
* @returns Information about the disassembled instruction.
*/
private deref(insn_ptr: pointer_t<cs_insn>): cs_insn {
const insn_id: number = Memory.read(insn_ptr, 'u32');
const insn_addr: number = Memory.read(insn_ptr + 8, 'u64');
const insn_size: number = Memory.read(insn_ptr + 16, 'u16');
const insn_mn: string = Wrapper.UTF8ToString(insn_ptr + 42);
const insn_op_str: string = Wrapper.UTF8ToString(insn_ptr + 66 + 8);
const insn_bytes: number[] = [];
for (let j = 0; j < insn_size; j++) {
const byte = Memory.read(insn_ptr + 18 + j, 'u8');
insn_bytes.push(byte);
}
const insn: cs_insn = {
id: insn_id,
address: insn_addr,
size: insn_size,
mnemonic: insn_mn,
op_str: insn_op_str,
bytes: new Uint8Array(insn_bytes),
};
const detail_ptr: pointer_t<pointer_t<cs_detail>> = Memory.read(
insn_ptr + 238,
'*',
);
const has_detail = detail_ptr != Memory.nullptr;
if (has_detail) {
insn.detail = this.get_detail(detail_ptr);
}
if (this.opt_buffer) {
const heap = Wrapper.HEAPU8.buffer;
if (has_detail)
insn.detail.buffer = new Uint8Array(
heap,
Wrapper._cs_detail_buffer(insn_ptr),
DETAIL_SIZE,
);
insn.buffer = new Uint8Array(
heap,
Wrapper._cs_insn_buffer(insn_ptr),
DETAIL_SIZE,
);
}
return insn;
}
/**
* Converts an array of `cs_insn` objects into a pointer to an array of cs_insn structures.
*
* @private
* @param insns - Array of `cs_insn` objects to be converted.
* @returns A pointer to the array of cs_insn structures.
*/
private ref(insns: cs_insn[] | cs_insn): pointer_t<cs_insn[] | cs_insn> {
if (!Array.isArray(insns)) insns = [insns];
const count: number = insns.length;
const insns_ptr: pointer_t<cs_insn[]> = Memory.malloc(INSN_SIZE * count);
for (let i = 0; i < count; i++) {
const insn = insns[i];
const insn_ptr = insns_ptr + i * INSN_SIZE;
insn.id !== undefined &&
insn.id !== null &&
Memory.write(insn_ptr, insn.id, 'i32');
insn.address !== undefined &&
insn.address !== null &&
Memory.write(insn_ptr + 8, insn.address, 'i64');
insn.size !== undefined &&
insn.size !== null &&
Memory.write(insn_ptr + 16, insn.size, 'i16');
insn.mnemonic !== undefined &&
insn.mnemonic !== null &&
Memory.write(insn_ptr + 42, insn.mnemonic, 'char*');
insn.op_str !== undefined &&
insn.op_str !== null &&
Memory.write(insn_ptr + 66 + 8, insn.op_str, 'char*');
for (let j = 0; j < (insn.size || 0); j++) {
insn.bytes[j] !== undefined &&
insn.bytes[j] !== null &&
Memory.write(insn_ptr + 18 + j, insn.bytes[j], 'u8');
}
if (insn.detail) {
const detail: pointer_t<pointer_t<cs_detail>> = insn_ptr + 238;
const detail_ptr: pointer_t<cs_detail> = Memory.malloc(1864);
const arch_info_ptr: pointer_t<any> = detail_ptr + 96;
let arch;
let op_ptr;
let op;
Memory.write(detail, detail_ptr, '*');
for (let i = 0; i < (insn.detail.regs_read_count || 0); i++)
insn.detail.regs_read !== undefined &&
insn.detail.regs_read !== null &&
Memory.write(detail_ptr + i, insn.detail.regs_read[i], 'i16');
insn.detail.regs_read_count !== undefined &&
insn.detail.regs_read_count !== null &&
Memory.write(detail_ptr + 40, insn.detail.regs_read_count, 'ubyte');
for (let i = 0; i < (insn.detail.regs_write_count || 0); i++)
insn.detail.regs_write[i] !== undefined &&
insn.detail.regs_write[i] !== null &&
Memory.write(
detail_ptr + 42 + i,
insn.detail.regs_write[i],
'i16',
);
insn.detail.regs_write_count !== undefined &&
insn.detail.regs_write_count !== null &&
Memory.write(
detail_ptr + 82,
insn.detail.regs_write_count,
'ubyte',
);
for (let i = 0; i < (insn.detail.groups_count || 0); i++)
insn.detail.groups[i] !== undefined &&
insn.detail.groups[i] !== null &&
Memory.write(detail_ptr + 83 + i, insn.detail.groups[i], 'ubyte');
insn.detail.groups_count !== undefined &&
insn.detail.groups_count !== null &&
Memory.write(detail_ptr + 91, insn.detail.groups_count, 'ubyte');
insn.detail.writeback !== undefined &&
insn.detail.writeback !== null &&
Memory.write(detail_ptr + 92, insn.detail.writeback, 'bool');
switch (this.arch) {
case ARCH_ARM:
arch = insn.detail.arm;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 32, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 40 + i * 48;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr + 12, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case ARM.OP_SYSREG:
case ARM.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 16, op.reg, 'i32');
break;
case ARM.OP_IMM:
case ARM.OP_PIMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 16, op.imm, 'i32');
break;
case ARM.OP_FP:
op.fp !== undefined &&
op.fp !== null &&
Memory.write(op_ptr + 16, op.fp, 'double');
break;
case ARM.OP_SETEND:
op.setend !== undefined &&
op.setend !== null &&
Memory.write(op_ptr + 16, op.setend, 'i32');
break;
case ARM.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 16, op.mem.base, 'i32');
op.mem.index !== undefined &&
op.mem.index !== null &&
Memory.write(op_ptr + 20, op.mem.index, 'i32');
op.mem.scale !== undefined &&
op.mem.scale !== null &&
Memory.write(op_ptr + 24, op.mem.scale, 'i32');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 28, op.mem.disp, 'i32');
op.mem.lshift !== undefined &&
op.mem.lshift !== null &&
Memory.write(op_ptr + 32, op.mem.lshift, 'i32');
break;
}
}
break;
case ARCH_ARM64:
arch = insn.detail.arm64;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 7, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 8 + i * 56;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr + 20, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case ARM64.OP_REG:
case ARM64.OP_REG_MRS:
case ARM64.OP_REG_MSR:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 32, op.reg, 'i32');
break;
case ARM64.OP_CIMM:
case ARM64.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 32, op.imm, 'i64');
break;
case ARM64.OP_FP:
op.fp !== undefined &&
op.fp !== null &&
Memory.write(op_ptr + 32, op.fp, 'double');
break;
case ARM64.OP_PSTATE:
op.pstate !== undefined &&
op.pstate !== null &&
Memory.write(op_ptr + 32, op.pstate, 'i32');
break;
case ARM64.OP_SYS:
op.sys !== undefined &&
op.sys !== null &&
Memory.write(op_ptr + 32, op.sys, 'i32');
break;
case ARM64.OP_BARRIER:
op.barrier !== undefined &&
op.barrier !== null &&
Memory.write(op_ptr + 32, op.barrier, 'i32');
break;
case ARM64.OP_PREFETCH:
op.prefetch !== undefined &&
op.prefetch !== null &&
Memory.write(op_ptr + 32, op.prefetch, 'i32');
break;
case ARM64.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 32, op.mem.base, 'i32');
op.mem.index !== undefined &&
op.mem.index !== null &&
Memory.write(op_ptr + 36, op.mem.index, 'i32');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 32, op.mem.disp, 'i32');
break;
case ARM64.OP_SVCR:
op.sme_index.reg !== undefined &&
op.sme_index.reg !== null &&
Memory.write(op_ptr + 32, op.sme_index.reg, 'i32');
op.sme_index.base !== undefined &&
op.sme_index.base !== null &&
Memory.write(op_ptr + 36, op.sme_index.base, 'i32');
op.sme_index.disp !== undefined &&
op.sme_index.disp !== null &&
Memory.write(op_ptr + 40, op.sme_index.disp, 'i32');
break;
}
}
break;
case ARCH_MIPS:
arch = insn.detail.mips;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 0, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 8 + i * 24;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case MIPS.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 8, op.reg, 'i32');
break;
case MIPS.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 8, op.imm, 'long');
break;
case MIPS.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 8, op.mem.base, 'i32');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 12, op.mem.disp, 'long');
break;
}
}
break;
case ARCH_X86:
arch = insn.detail.x86;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 64, arch.op_count, 'ubyte');
arch.disp !== undefined &&
arch.disp !== null &&
Memory.write(arch_info_ptr + 16, arch.disp, 'long');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 72 + i * 48;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case X86.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 8, op.reg, 'i32');
break;
case X86.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 8, op.imm, 'long');
break;
case X86.OP_MEM:
op.mem.segment !== undefined &&
op.mem.segment !== null &&
Memory.write(op_ptr + 8, op.mem.segment, 'i32');
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 12, op.mem.base, 'i32');
op.mem.index !== undefined &&
op.mem.index !== null &&
Memory.write(op_ptr + 16, op.mem.index, 'i32');
op.mem.scale !== undefined &&
op.mem.scale !== null &&
Memory.write(op_ptr + 20, op.mem.scale, 'i32');
break;
}
}
break;
case ARCH_PPC:
arch = insn.detail.ppc;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 9, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 16 + i * 24;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case PPC.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 8, op.reg, 'i32');
break;
case PPC.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 8, op.imm, 'long');
break;
case PPC.OP_CRX:
op.crx.scale !== undefined &&
op.crx.scale !== null &&
Memory.write(op_ptr + 8, op.crx.scale, 'u32');
op.crx.reg !== undefined &&
op.crx.reg !== null &&
Memory.write(op_ptr + 12, op.crx.reg, 'i32');
op.crx.cond !== undefined &&
op.crx.cond !== null &&
Memory.write(op_ptr + 16, op.crx.cond, 'i32');
break;
case PPC.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 8, op.mem.base, 'i32');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 12, op.mem.disp, 'long');
break;
}
}
break;
case ARCH_SPARC:
arch = insn.detail.sparc;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 8, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 16 + i * 16;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case SPARC.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 8, op.reg, 'i32');
break;
case SPARC.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr, op.imm, 'i32');
break;
case SPARC.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 8, op.mem.base, 'ubyte');
op.mem.index !== undefined &&
op.mem.index !== null &&
Memory.write(op_ptr + 9, op.mem.index, 'ubyte');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 12, op.mem.disp, 'i32');
break;
}
}
break;
case ARCH_SYSZ:
arch = insn.detail.sysz;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 4, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 8 + i * 32;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case SYSZ.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 8, op.reg, 'i32');
break;
case SYSZ.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 8, op.imm, 'long');
break;
case SYSZ.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&
Memory.write(op_ptr + 8, op.mem.base, 'ubyte');
op.mem.index !== undefined &&
op.mem.index !== null &&
Memory.write(op_ptr + 9, op.mem.index, 'ubyte');
op.mem.length !== undefined &&
op.mem.length !== null &&
Memory.write(op_ptr + 16, op.mem.length, 'ulong');
op.mem.disp !== undefined &&
op.mem.disp !== null &&
Memory.write(op_ptr + 24, op.mem.disp, 'long');
break;
}
}
break;
case ARCH_XCORE:
arch = insn.detail.xcore;
arch.op_count !== undefined &&
arch.op_count !== null &&
Memory.write(arch_info_ptr + 0, arch.op_count, 'ubyte');
for (let i = 0; i < (arch.op_count || 0); i++) {
op_ptr = arch_info_ptr + 4 + i * 16;
op = arch.operands[i];
op.type !== undefined &&
op.type !== null &&
Memory.write(op_ptr, op.type, 'i32');
switch (arch.operands[i].type || 0) {
case XCORE.OP_REG:
op.reg !== undefined &&
op.reg !== null &&
Memory.write(op_ptr + 4, op.reg, 'i32');
break;
case XCORE.OP_IMM:
op.imm !== undefined &&
op.imm !== null &&
Memory.write(op_ptr + 4, op.imm, 'i32');
break;
case XCORE.OP_MEM:
op.mem.base !== undefined &&
op.mem.base !== null &&