good
This commit is contained in:
@@ -0,0 +1,499 @@
|
||||
/* diStorm 3.5.2 */
|
||||
|
||||
/*
|
||||
distorm.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DISTORM_H
|
||||
#define DISTORM_H
|
||||
|
||||
/*
|
||||
* 64 bit offsets support:
|
||||
* If the diStorm library you use was compiled with 64 bits offsets,
|
||||
* make sure you compile your own code with the following macro set:
|
||||
* SUPPORT_64BIT_OFFSET
|
||||
* Otherwise comment it out, or you will get a linker error of an unresolved symbol...
|
||||
* Turned on by default!
|
||||
*/
|
||||
|
||||
#if !(defined(DISTORM_STATIC) || defined(DISTORM_DYNAMIC))
|
||||
/* Define this macro for outer projects by default. */
|
||||
#define SUPPORT_64BIT_OFFSET
|
||||
#endif
|
||||
|
||||
/* TINYC has a problem with some 64bits library functions, so ignore 64 bit offsets. */
|
||||
#ifdef __TINYC__
|
||||
#undef SUPPORT_64BIT_OFFSET
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
/* Since MSVC < 2010 isn't shipped with stdint.h,
|
||||
* here are those from MSVC 2017, which also match
|
||||
* those in tinycc/libc. */
|
||||
typedef signed char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
#define OFFSET_INTEGER uint64_t
|
||||
#else
|
||||
/* 32 bit offsets are used. */
|
||||
#define OFFSET_INTEGER uint32_t
|
||||
#endif
|
||||
|
||||
/* Support C++ compilers */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* *** Helper Macros *** */
|
||||
|
||||
/* Get the ISC of the instruction, used with the definitions below. */
|
||||
#define META_GET_ISC(meta) (((meta) >> 8) & 0x1f)
|
||||
#define META_SET_ISC(di, isc) (((di)->meta) |= ((isc) << 8))
|
||||
/* Get the flow control flags of the instruction, see 'features for decompose' below. */
|
||||
#define META_GET_FC(meta) ((meta) & 0xf)
|
||||
|
||||
/* Get the target address of a branching instruction. O_PC operand type. */
|
||||
#define INSTRUCTION_GET_TARGET(di) ((_OffsetType)(((di)->addr + (di)->imm.addr + (di)->size)))
|
||||
/* Get the target address of a RIP-relative memory indirection. */
|
||||
#define INSTRUCTION_GET_RIP_TARGET(di) ((_OffsetType)(((di)->addr + (di)->disp + (di)->size)))
|
||||
|
||||
/*
|
||||
* Operand Size or Adderss size are stored inside the flags:
|
||||
* 00 - 16 bits
|
||||
* 01 - 32 bits
|
||||
* 10 - 64 bits
|
||||
* 11 - reserved
|
||||
*
|
||||
* If you call these set-macros more than once, you will have to clean the bits before doing so.
|
||||
*/
|
||||
#define FLAG_SET_OPSIZE(di, size) ((di->flags) |= (((size) & 3) << 8))
|
||||
#define FLAG_SET_ADDRSIZE(di, size) ((di->flags) |= (((size) & 3) << 10))
|
||||
#define FLAG_GET_OPSIZE(flags) (((flags) >> 8) & 3)
|
||||
#define FLAG_GET_ADDRSIZE(flags) (((flags) >> 10) & 3)
|
||||
/* To get the LOCK/REPNZ/REP prefixes. */
|
||||
#define FLAG_GET_PREFIX(flags) (((unsigned int)((int16_t)flags)) & 7)
|
||||
/* Indicates whether the instruction is privileged. */
|
||||
#define FLAG_GET_PRIVILEGED(flags) (((flags) & FLAG_PRIVILEGED_INSTRUCTION) != 0)
|
||||
|
||||
/*
|
||||
* Macros to extract segment registers from 'segment':
|
||||
*/
|
||||
#define SEGMENT_DEFAULT 0x80
|
||||
#define SEGMENT_GET(segment) (((segment) == R_NONE) ? R_NONE : ((segment) & 0x7f))
|
||||
#define SEGMENT_GET_UNSAFE(segment) ((segment) & 0x7f)
|
||||
#define SEGMENT_IS_DEFAULT(segment) (((int8_t)segment) < -1) /* Quick check it's a negative number that isn't -1, so it's (0x80 | SEGREG). */
|
||||
#define SEGMENT_IS_DEFAULT_OR_NONE(segment) (((uint8_t)(segment)) > 0x80)
|
||||
|
||||
/* Decodes modes of the disassembler, 16 bits or 32 bits or 64 bits for AMD64, x86-64. */
|
||||
typedef enum { Decode16Bits = 0, Decode32Bits = 1, Decode64Bits = 2 } _DecodeType;
|
||||
|
||||
typedef OFFSET_INTEGER _OffsetType;
|
||||
|
||||
typedef struct {
|
||||
_OffsetType codeOffset, addrMask;
|
||||
_OffsetType nextOffset; /* nextOffset is OUT only. */
|
||||
const uint8_t* code;
|
||||
int codeLen; /* Using signed integer makes it easier to detect an underflow. */
|
||||
_DecodeType dt;
|
||||
unsigned int features;
|
||||
} _CodeInfo;
|
||||
|
||||
typedef enum { O_NONE, O_REG, O_IMM, O_IMM1, O_IMM2, O_DISP, O_SMEM, O_MEM, O_PC, O_PTR } _OperandType;
|
||||
|
||||
typedef union {
|
||||
/* Used by O_IMM: */
|
||||
int8_t sbyte;
|
||||
uint8_t byte;
|
||||
int16_t sword;
|
||||
uint16_t word;
|
||||
int32_t sdword;
|
||||
uint32_t dword;
|
||||
int64_t sqword; /* All immediates are SIGN-EXTENDED to 64 bits! */
|
||||
uint64_t qword;
|
||||
|
||||
/* Used by O_PC: (Use GET_TARGET_ADDR).*/
|
||||
_OffsetType addr; /* It's a relative offset as for now. */
|
||||
|
||||
/* Used by O_PTR: */
|
||||
struct {
|
||||
uint16_t seg;
|
||||
/* Can be 16 or 32 bits, size is in ops[n].size. */
|
||||
uint32_t off;
|
||||
} ptr;
|
||||
|
||||
/* Used by O_IMM1 (i1) and O_IMM2 (i2). ENTER instruction only. */
|
||||
struct {
|
||||
uint32_t i1;
|
||||
uint32_t i2;
|
||||
} ex;
|
||||
} _Value;
|
||||
|
||||
typedef struct {
|
||||
/* Type of operand:
|
||||
O_NONE: operand is to be ignored.
|
||||
O_REG: index holds global register index.
|
||||
O_IMM: instruction.imm.
|
||||
O_IMM1: instruction.imm.ex.i1.
|
||||
O_IMM2: instruction.imm.ex.i2.
|
||||
O_DISP: memory dereference with displacement only, instruction.disp.
|
||||
O_SMEM: simple memory dereference with optional displacement (a single register memory dereference).
|
||||
O_MEM: complex memory dereference (optional fields: s/i/b/disp).
|
||||
O_PC: the relative address of a branch instruction (instruction.imm.addr).
|
||||
O_PTR: the absolute target address of a far branch instruction (instruction.imm.ptr.seg/off).
|
||||
*/
|
||||
uint8_t type; /* _OperandType */
|
||||
|
||||
/* Index of:
|
||||
O_REG: holds global register index
|
||||
O_SMEM: holds the 'base' register. E.G: [ECX], [EBX+0x1234] are both in operand.index.
|
||||
O_MEM: holds the 'index' register. E.G: [EAX*4] is in operand.index.
|
||||
*/
|
||||
uint8_t index;
|
||||
|
||||
/* Size in bits of:
|
||||
O_REG: register
|
||||
O_IMM: instruction.imm
|
||||
O_IMM1: instruction.imm.ex.i1
|
||||
O_IMM2: instruction.imm.ex.i2
|
||||
O_DISP: instruction.disp
|
||||
O_SMEM: size of indirection.
|
||||
O_MEM: size of indirection.
|
||||
O_PC: size of the relative offset
|
||||
O_PTR: size of instruction.imm.ptr.off (16 or 32)
|
||||
*/
|
||||
uint16_t size;
|
||||
} _Operand;
|
||||
|
||||
#define OPCODE_ID_NONE 0
|
||||
/* Instruction could not be disassembled. */
|
||||
#define FLAG_NOT_DECODABLE ((uint16_t)-1)
|
||||
/* The instruction locks memory access. */
|
||||
#define FLAG_LOCK (1 << 0)
|
||||
/* The instruction is prefixed with a REPNZ. */
|
||||
#define FLAG_REPNZ (1 << 1)
|
||||
/* The instruction is prefixed with a REP, this can be a REPZ, it depends on the specific instruction. */
|
||||
#define FLAG_REP (1 << 2)
|
||||
/* Indicates there is a hint taken for Jcc instructions only. */
|
||||
#define FLAG_HINT_TAKEN (1 << 3)
|
||||
/* Indicates there is a hint non-taken for Jcc instructions only. */
|
||||
#define FLAG_HINT_NOT_TAKEN (1 << 4)
|
||||
/* The Imm value is signed extended (E.G in 64 bit decoding mode, a 32 bit imm is usually sign extended into 64 bit imm). */
|
||||
#define FLAG_IMM_SIGNED (1 << 5)
|
||||
/* The destination operand is writable. */
|
||||
#define FLAG_DST_WR (1 << 6)
|
||||
/* The instruction uses RIP-relative indirection. */
|
||||
#define FLAG_RIP_RELATIVE (1 << 7)
|
||||
|
||||
/* See flag FLAG_GET_XXX macros above. */
|
||||
|
||||
/* The instruction is privileged and can only be used from Ring0. */
|
||||
#define FLAG_PRIVILEGED_INSTRUCTION (1 << 15)
|
||||
|
||||
/* No register was defined. */
|
||||
#define R_NONE ((uint8_t)-1)
|
||||
|
||||
#define REGS64_BASE 0
|
||||
#define REGS32_BASE 16
|
||||
#define REGS16_BASE 32
|
||||
#define REGS8_BASE 48
|
||||
#define REGS8_REX_BASE 64
|
||||
#define SREGS_BASE 68
|
||||
#define FPUREGS_BASE 75
|
||||
#define MMXREGS_BASE 83
|
||||
#define SSEREGS_BASE 91
|
||||
#define AVXREGS_BASE 107
|
||||
#define CREGS_BASE 123
|
||||
#define DREGS_BASE 132
|
||||
|
||||
#define OPERANDS_NO (4)
|
||||
|
||||
typedef struct {
|
||||
/* Used by ops[n].type == O_IMM/O_IMM1&O_IMM2/O_PTR/O_PC. Its size is ops[n].size. */
|
||||
_Value imm;
|
||||
/* Used by ops[n].type == O_SMEM/O_MEM/O_DISP. Its size is dispSize. */
|
||||
uint64_t disp;
|
||||
/* Virtual address of first byte of instruction. */
|
||||
_OffsetType addr;
|
||||
/* General flags of instruction, holds prefixes and more, if FLAG_NOT_DECODABLE, instruction is invalid. */
|
||||
uint16_t flags;
|
||||
/* Unused prefixes mask, for each bit that is set that prefix is not used (LSB is byte [addr + 0]). */
|
||||
uint16_t unusedPrefixesMask;
|
||||
/* Mask of registers that were used in the operands, only used for quick look up, in order to know *some* operand uses that register class. */
|
||||
uint32_t usedRegistersMask;
|
||||
/* ID of opcode in the global opcode table. Use for mnemonic look up. */
|
||||
uint16_t opcode;
|
||||
/* Up to four operands per instruction, ignored if ops[n].type == O_NONE. */
|
||||
_Operand ops[OPERANDS_NO];
|
||||
/* Number of valid ops entries. */
|
||||
uint8_t opsNo;
|
||||
/* Size of the whole instruction in bytes. */
|
||||
uint8_t size;
|
||||
/* Segment information of memory indirection, default segment, or overriden one, can be -1. Use SEGMENT macros. */
|
||||
uint8_t segment;
|
||||
/* Used by ops[n].type == O_MEM. Base global register index (might be R_NONE), scale size (2/4/8), ignored for 0 or 1. */
|
||||
uint8_t base, scale;
|
||||
uint8_t dispSize;
|
||||
/* Meta defines the instruction set class, and the flow control flags. Use META macros. */
|
||||
uint16_t meta;
|
||||
/* The CPU flags that the instruction operates upon, set only with DF_FILL_EFLAGS enabled, otherwise 0. */
|
||||
uint16_t modifiedFlagsMask, testedFlagsMask, undefinedFlagsMask;
|
||||
} _DInst;
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
/* Static size of strings. Do not change this value. Keep Python wrapper in sync. */
|
||||
#define MAX_TEXT_SIZE (48)
|
||||
typedef struct {
|
||||
unsigned int length;
|
||||
unsigned char p[MAX_TEXT_SIZE]; /* p is a null terminated string. */
|
||||
} _WString;
|
||||
|
||||
/*
|
||||
* Old decoded instruction structure in text format.
|
||||
* Used only for backward compatibility with diStorm64.
|
||||
* This structure holds all information the disassembler generates per instruction.
|
||||
*/
|
||||
typedef struct {
|
||||
_OffsetType offset; /* Start offset of the decoded instruction. */
|
||||
unsigned int size; /* Size of decoded instruction in bytes. */
|
||||
_WString mnemonic; /* Mnemonic of decoded instruction, prefixed if required by REP, LOCK etc. */
|
||||
_WString operands; /* Operands of the decoded instruction, up to 3 operands, comma-seperated. */
|
||||
_WString instructionHex; /* Hex dump - little endian, including prefixes. */
|
||||
} _DecodedInst;
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
|
||||
/* Register masks for quick look up, each mask indicates one of a register-class that is being used in some operand. */
|
||||
#define RM_AX 1 /* AL, AH, AX, EAX, RAX */
|
||||
#define RM_CX 2 /* CL, CH, CX, ECX, RCX */
|
||||
#define RM_DX 4 /* DL, DH, DX, EDX, RDX */
|
||||
#define RM_BX 8 /* BL, BH, BX, EBX, RBX */
|
||||
#define RM_SP 0x10 /* SPL, SP, ESP, RSP */
|
||||
#define RM_BP 0x20 /* BPL, BP, EBP, RBP */
|
||||
#define RM_SI 0x40 /* SIL, SI, ESI, RSI */
|
||||
#define RM_DI 0x80 /* DIL, DI, EDI, RDI */
|
||||
#define RM_FPU 0x100 /* ST(0) - ST(7) */
|
||||
#define RM_MMX 0x200 /* MM0 - MM7 */
|
||||
#define RM_SSE 0x400 /* XMM0 - XMM15 */
|
||||
#define RM_AVX 0x800 /* YMM0 - YMM15 */
|
||||
#define RM_CR 0x1000 /* CR0, CR2, CR3, CR4, CR8 */
|
||||
#define RM_DR 0x2000 /* DR0, DR1, DR2, DR3, DR6, DR7 */
|
||||
#define RM_R8 0x4000 /* R8B, R8W, R8D, R8 */
|
||||
#define RM_R9 0x8000 /* R9B, R9W, R9D, R9 */
|
||||
#define RM_R10 0x10000 /* R10B, R10W, R10D, R10 */
|
||||
#define RM_R11 0x20000 /* R11B, R11W, R11D, R11 */
|
||||
#define RM_R12 0x40000 /* R12B, R12W, R12D, R12 */
|
||||
#define RM_R13 0x80000 /* R13B, R13W, R13D, R13 */
|
||||
#define RM_R14 0x100000 /* R14B, R14W, R14D, R14 */
|
||||
#define RM_R15 0x200000 /* R15B, R15W, R15D, R15 */
|
||||
#define RM_SEG 0x400000 /* CS, SS, DS, ES, FS, GS */
|
||||
|
||||
/* RIP should be checked using the 'flags' field and FLAG_RIP_RELATIVE.
|
||||
* Segments should be checked using the segment macros.
|
||||
* For now R8 - R15 are not supported and non general purpose registers map into same RM.
|
||||
*/
|
||||
|
||||
/* CPU flags that instructions modify, test or undefine (are EFLAGS compatible!). */
|
||||
#define D_CF 1 /* Carry */
|
||||
#define D_PF 4 /* Parity */
|
||||
#define D_AF 0x10 /* Auxiliary */
|
||||
#define D_ZF 0x40 /* Zero */
|
||||
#define D_SF 0x80 /* Sign */
|
||||
#define D_IF 0x200 /* Interrupt */
|
||||
#define D_DF 0x400 /* Direction */
|
||||
#define D_OF 0x800 /* Overflow */
|
||||
|
||||
/*
|
||||
* Instructions Set classes:
|
||||
* if you want a better understanding of the available classes, look at disOps project, file: x86sets.py.
|
||||
*/
|
||||
/* Indicates the instruction belongs to the General Integer set. */
|
||||
#define ISC_INTEGER 1
|
||||
/* Indicates the instruction belongs to the 387 FPU set. */
|
||||
#define ISC_FPU 2
|
||||
/* Indicates the instruction belongs to the P6 set. */
|
||||
#define ISC_P6 3
|
||||
/* Indicates the instruction belongs to the MMX set. */
|
||||
#define ISC_MMX 4
|
||||
/* Indicates the instruction belongs to the SSE set. */
|
||||
#define ISC_SSE 5
|
||||
/* Indicates the instruction belongs to the SSE2 set. */
|
||||
#define ISC_SSE2 6
|
||||
/* Indicates the instruction belongs to the SSE3 set. */
|
||||
#define ISC_SSE3 7
|
||||
/* Indicates the instruction belongs to the SSSE3 set. */
|
||||
#define ISC_SSSE3 8
|
||||
/* Indicates the instruction belongs to the SSE4.1 set. */
|
||||
#define ISC_SSE4_1 9
|
||||
/* Indicates the instruction belongs to the SSE4.2 set. */
|
||||
#define ISC_SSE4_2 10
|
||||
/* Indicates the instruction belongs to the AMD's SSE4.A set. */
|
||||
#define ISC_SSE4_A 11
|
||||
/* Indicates the instruction belongs to the 3DNow! set. */
|
||||
#define ISC_3DNOW 12
|
||||
/* Indicates the instruction belongs to the 3DNow! Extensions set. */
|
||||
#define ISC_3DNOWEXT 13
|
||||
/* Indicates the instruction belongs to the VMX (Intel) set. */
|
||||
#define ISC_VMX 14
|
||||
/* Indicates the instruction belongs to the SVM (AMD) set. */
|
||||
#define ISC_SVM 15
|
||||
/* Indicates the instruction belongs to the AVX (Intel) set. */
|
||||
#define ISC_AVX 16
|
||||
/* Indicates the instruction belongs to the FMA (Intel) set. */
|
||||
#define ISC_FMA 17
|
||||
/* Indicates the instruction belongs to the AES/AVX (Intel) set. */
|
||||
#define ISC_AES 18
|
||||
/* Indicates the instruction belongs to the CLMUL (Intel) set. */
|
||||
#define ISC_CLMUL 19
|
||||
|
||||
/* Features for decompose: */
|
||||
#define DF_NONE 0
|
||||
/* The decoder will limit addresses to a maximum of 16 bits. */
|
||||
#define DF_MAXIMUM_ADDR16 1
|
||||
/* The decoder will limit addresses to a maximum of 32 bits. */
|
||||
#define DF_MAXIMUM_ADDR32 2
|
||||
/* The decoder will return only flow control instructions (and filter the others internally). */
|
||||
#define DF_RETURN_FC_ONLY 4
|
||||
/* The decoder will stop and return to the caller when the instruction 'CALL' (near and far) was decoded. */
|
||||
#define DF_STOP_ON_CALL 8
|
||||
/* The decoder will stop and return to the caller when the instruction 'RET' (near and far) was decoded. */
|
||||
#define DF_STOP_ON_RET 0x10
|
||||
/* The decoder will stop and return to the caller when the instruction system-call/ret was decoded. */
|
||||
#define DF_STOP_ON_SYS 0x20
|
||||
/* The decoder will stop and return to the caller when any of the branch 'JMP', (near and far) instructions were decoded. */
|
||||
#define DF_STOP_ON_UNC_BRANCH 0x40
|
||||
/* The decoder will stop and return to the caller when any of the conditional branch instruction were decoded. */
|
||||
#define DF_STOP_ON_CND_BRANCH 0x80
|
||||
/* The decoder will stop and return to the caller when the instruction 'INT' (INT, INT1, INTO, INT 3) was decoded. */
|
||||
#define DF_STOP_ON_INT 0x100
|
||||
/* The decoder will stop and return to the caller when any of the 'CMOVxx' instruction was decoded. */
|
||||
#define DF_STOP_ON_CMOV 0x200
|
||||
/* The decoder will stop and return to the caller when it encounters the HLT instruction. */
|
||||
#define DF_STOP_ON_HLT 0x400
|
||||
/* The decoder will stop and return to the caller when it encounters a privileged instruction. */
|
||||
#define DF_STOP_ON_PRIVILEGED 0x800
|
||||
/* The decoder will stop and return to the caller when an instruction couldn't be decoded. */
|
||||
#define DF_STOP_ON_UNDECODEABLE 0x1000
|
||||
/* The decoder will not synchronize to the next byte after the previosuly decoded instruction, instead it will start decoding at the next byte. */
|
||||
#define DF_SINGLE_BYTE_STEP 0x2000
|
||||
/* The decoder will fill in the eflags fields for the decoded instruction. */
|
||||
#define DF_FILL_EFLAGS 0x4000
|
||||
/* The decoder will use the addrMask in CodeInfo structure instead of DF_MAXIMUM_ADDR16/32. */
|
||||
#define DF_USE_ADDR_MASK 0x8000
|
||||
|
||||
/* The decoder will stop and return to the caller when any flow control instruction was decoded. */
|
||||
#define DF_STOP_ON_FLOW_CONTROL (DF_STOP_ON_CALL | DF_STOP_ON_RET | DF_STOP_ON_SYS | DF_STOP_ON_UNC_BRANCH | DF_STOP_ON_CND_BRANCH | DF_STOP_ON_INT | DF_STOP_ON_CMOV | DF_STOP_ON_HLT)
|
||||
|
||||
/* Indicates the instruction is not a flow-control instruction. */
|
||||
#define FC_NONE 0
|
||||
/* Indicates the instruction is one of: CALL, CALL FAR. */
|
||||
#define FC_CALL 1
|
||||
/* Indicates the instruction is one of: RET, IRET, RETF. */
|
||||
#define FC_RET 2
|
||||
/* Indicates the instruction is one of: SYSCALL, SYSRET, SYSENTER, SYSEXIT. */
|
||||
#define FC_SYS 3
|
||||
/* Indicates the instruction is one of: JMP, JMP FAR. */
|
||||
#define FC_UNC_BRANCH 4
|
||||
/*
|
||||
* Indicates the instruction is one of:
|
||||
* JCXZ, JO, JNO, JB, JAE, JZ, JNZ, JBE, JA, JS, JNS, JP, JNP, JL, JGE, JLE, JG, LOOP, LOOPZ, LOOPNZ.
|
||||
*/
|
||||
#define FC_CND_BRANCH 5
|
||||
/* Indiciates the instruction is one of: INT, INT1, INT 3, INTO, UD2. */
|
||||
#define FC_INT 6
|
||||
/* Indicates the instruction is one of: CMOVxx. */
|
||||
#define FC_CMOV 7
|
||||
/* Indicates the instruction is HLT. */
|
||||
#define FC_HLT 8
|
||||
|
||||
/* Return code of the decoding function. */
|
||||
typedef enum { DECRES_NONE, DECRES_SUCCESS, DECRES_MEMORYERR, DECRES_INPUTERR } _DecodeResult;
|
||||
|
||||
/* Define the following interface functions only for outer projects. */
|
||||
#if !(defined(DISTORM_STATIC) || defined(DISTORM_DYNAMIC))
|
||||
|
||||
/* distorm_decode
|
||||
* Input:
|
||||
* offset - Origin of the given code (virtual address that is), NOT an offset in code.
|
||||
* code - Pointer to the code buffer to be disassembled.
|
||||
* length - Amount of bytes that should be decoded from the code buffer.
|
||||
* dt - Decoding mode, 16 bits (Decode16Bits), 32 bits (Decode32Bits) or AMD64 (Decode64Bits).
|
||||
* result - Array of type _DecodeInst which will be used by this function in order to return the disassembled instructions.
|
||||
* maxInstructions - The maximum number of entries in the result array that you pass to this function, so it won't exceed its bound.
|
||||
* usedInstructionsCount - Number of the instruction that successfully were disassembled and written to the result array.
|
||||
* Output: usedInstructionsCount will hold the number of entries used in the result array
|
||||
* and the result array itself will be filled with the disassembled instructions.
|
||||
* Return: DECRES_SUCCESS on success (no more to disassemble), DECRES_INPUTERR on input error (null code buffer, invalid decoding mode, etc...),
|
||||
* DECRES_MEMORYERR when there are not enough entries to use in the result array, BUT YOU STILL have to check for usedInstructionsCount!
|
||||
* Side-Effects: Even if the return code is DECRES_MEMORYERR, there might STILL be data in the
|
||||
* array you passed, this function will try to use as much entries as possible!
|
||||
* Notes: 1)The minimal size of maxInstructions is 15.
|
||||
* 2)You will have to synchronize the offset,code and length by yourself if you pass code fragments and not a complete code block!
|
||||
*/
|
||||
|
||||
/* distorm_decompose
|
||||
* See more documentation online at the GitHub project's wiki.
|
||||
*
|
||||
*/
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
|
||||
_DecodeResult distorm_decompose64(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
|
||||
#define distorm_decompose distorm_decompose64
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
/* If distorm-light is defined, we won't export these text-formatting functionality. */
|
||||
_DecodeResult distorm_decode64(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
|
||||
void distorm_format64(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result);
|
||||
#define distorm_decode distorm_decode64
|
||||
#define distorm_format distorm_format64
|
||||
#endif /*DISTORM_LIGHT*/
|
||||
|
||||
#else /*SUPPORT_64BIT_OFFSET*/
|
||||
|
||||
_DecodeResult distorm_decompose32(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
|
||||
#define distorm_decompose distorm_decompose32
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
/* If distorm-light is defined, we won't export these text-formatting functionality. */
|
||||
_DecodeResult distorm_decode32(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
|
||||
void distorm_format32(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result);
|
||||
#define distorm_decode distorm_decode32
|
||||
#define distorm_format distorm_format32
|
||||
#endif /*DISTORM_LIGHT*/
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* distorm_version
|
||||
* Input:
|
||||
* none
|
||||
*
|
||||
* Output: unsigned int - version of compiled library.
|
||||
*/
|
||||
unsigned int distorm_version(void);
|
||||
|
||||
#endif /* DISTORM_STATIC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End Of Extern */
|
||||
#endif
|
||||
|
||||
#endif /* DISTORM_H */
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
mnemonics.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MNEMONICS_H
|
||||
#define MNEMONICS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
typedef struct WMnemonic {
|
||||
unsigned char length;
|
||||
unsigned char p[1]; /* p is a null terminated string, which contains 'length' characters. */
|
||||
} _WMnemonic;
|
||||
|
||||
typedef struct WRegister {
|
||||
unsigned int length;
|
||||
unsigned char p[6]; /* p is a null terminated string. */
|
||||
} _WRegister;
|
||||
|
||||
extern const unsigned char _MNEMONICS[];
|
||||
extern const _WRegister _REGISTERS[];
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End Of Extern */
|
||||
#endif
|
||||
|
||||
#define GET_REGISTER_NAME(r) (unsigned char*)_REGISTERS[(r)].p
|
||||
#define GET_MNEMONIC_NAME(m) ((_WMnemonic*)&_MNEMONICS[(m)])->p
|
||||
|
||||
typedef enum {
|
||||
I_UNDEFINED = 0, I_AAA = 66, I_AAD = 389, I_AAM = 384, I_AAS = 76, I_ADC = 31, I_ADD = 11, I_ADDPD = 3132,
|
||||
I_ADDPS = 3125, I_ADDSD = 3146, I_ADDSS = 3139, I_ADDSUBPD = 6416, I_ADDSUBPS = 6426,
|
||||
I_AESDEC = 9231, I_AESDECLAST = 9248, I_AESENC = 9189, I_AESENCLAST = 9206,
|
||||
I_AESIMC = 9172, I_AESKEYGENASSIST = 9817, I_AND = 41, I_ANDNPD = 3043, I_ANDNPS = 3035,
|
||||
I_ANDPD = 3012, I_ANDPS = 3005, I_ARPL = 111, I_BLENDPD = 9394, I_BLENDPS = 9375,
|
||||
I_BLENDVPD = 7641, I_BLENDVPS = 7631, I_BOUND = 104, I_BSF = 4368, I_BSR = 4380,
|
||||
I_BSWAP = 960, I_BT = 872, I_BTC = 934, I_BTR = 912, I_BTS = 887, I_CALL = 456,
|
||||
I_CALL_FAR = 260, I_CBW = 228, I_CDQ = 250, I_CDQE = 239, I_CLC = 492, I_CLD = 512,
|
||||
I_CLFLUSH = 4351, I_CLGI = 1855, I_CLI = 502, I_CLTS = 541, I_CMC = 487, I_CMOVA = 694,
|
||||
I_CMOVAE = 663, I_CMOVB = 656, I_CMOVBE = 686, I_CMOVG = 754, I_CMOVGE = 738,
|
||||
I_CMOVL = 731, I_CMOVLE = 746, I_CMOVNO = 648, I_CMOVNP = 723, I_CMOVNS = 708,
|
||||
I_CMOVNZ = 678, I_CMOVO = 641, I_CMOVP = 716, I_CMOVS = 701, I_CMOVZ = 671,
|
||||
I_CMP = 71, I_CMPEQPD = 4471, I_CMPEQPS = 4392, I_CMPEQSD = 4629, I_CMPEQSS = 4550,
|
||||
I_CMPLEPD = 4489, I_CMPLEPS = 4410, I_CMPLESD = 4647, I_CMPLESS = 4568, I_CMPLTPD = 4480,
|
||||
I_CMPLTPS = 4401, I_CMPLTSD = 4638, I_CMPLTSS = 4559, I_CMPNEQPD = 4510, I_CMPNEQPS = 4431,
|
||||
I_CMPNEQSD = 4668, I_CMPNEQSS = 4589, I_CMPNLEPD = 4530, I_CMPNLEPS = 4451,
|
||||
I_CMPNLESD = 4688, I_CMPNLESS = 4609, I_CMPNLTPD = 4520, I_CMPNLTPS = 4441,
|
||||
I_CMPNLTSD = 4678, I_CMPNLTSS = 4599, I_CMPORDPD = 4540, I_CMPORDPS = 4461,
|
||||
I_CMPORDSD = 4698, I_CMPORDSS = 4619, I_CMPS = 301, I_CMPUNORDPD = 4498, I_CMPUNORDPS = 4419,
|
||||
I_CMPUNORDSD = 4656, I_CMPUNORDSS = 4577, I_CMPXCHG = 898, I_CMPXCHG16B = 6395,
|
||||
I_CMPXCHG8B = 6384, I_COMISD = 2801, I_COMISS = 2793, I_CPUID = 865, I_CQO = 255,
|
||||
I_CRC32 = 9280, I_CVTDQ2PD = 6809, I_CVTDQ2PS = 3329, I_CVTPD2DQ = 6819, I_CVTPD2PI = 2703,
|
||||
I_CVTPD2PS = 3255, I_CVTPH2PS = 4183, I_CVTPI2PD = 2517, I_CVTPI2PS = 2507,
|
||||
I_CVTPS2DQ = 3339, I_CVTPS2PD = 3245, I_CVTPS2PH = 4193, I_CVTPS2PI = 2693,
|
||||
I_CVTSD2SI = 2723, I_CVTSD2SS = 3275, I_CVTSI2SD = 2537, I_CVTSI2SS = 2527,
|
||||
I_CVTSS2SD = 3265, I_CVTSS2SI = 2713, I_CVTTPD2DQ = 6798, I_CVTTPD2PI = 2636,
|
||||
I_CVTTPS2DQ = 3349, I_CVTTPS2PI = 2625, I_CVTTSD2SI = 2658, I_CVTTSS2SI = 2647,
|
||||
I_CWD = 245, I_CWDE = 233, I_DAA = 46, I_DAS = 56, I_DEC = 86, I_DIV = 1646,
|
||||
I_DIVPD = 3521, I_DIVPS = 3514, I_DIVSD = 3535, I_DIVSS = 3528, I_DPPD = 9637,
|
||||
I_DPPS = 9624, I_EMMS = 4122, I_ENTER = 340, I_EXTRACTPS = 9502, I_EXTRQ = 4158,
|
||||
I_F2XM1 = 1192, I_FABS = 1123, I_FADD = 1023, I_FADDP = 1549, I_FBLD = 1601,
|
||||
I_FBSTP = 1607, I_FCHS = 1117, I_FCLEX = 7311, I_FCMOVB = 1376, I_FCMOVBE = 1392,
|
||||
I_FCMOVE = 1384, I_FCMOVNB = 1445, I_FCMOVNBE = 1463, I_FCMOVNE = 1454, I_FCMOVNU = 1473,
|
||||
I_FCMOVU = 1401, I_FCOM = 1035, I_FCOMI = 1512, I_FCOMIP = 1623, I_FCOMP = 1041,
|
||||
I_FCOMPP = 1563, I_FCOS = 1311, I_FDECSTP = 1238, I_FDIV = 1061, I_FDIVP = 1594,
|
||||
I_FDIVR = 1067, I_FDIVRP = 1586, I_FEDISI = 1488, I_FEMMS = 574, I_FENI = 1482,
|
||||
I_FFREE = 1527, I_FIADD = 1317, I_FICOM = 1331, I_FICOMP = 1338, I_FIDIV = 1361,
|
||||
I_FIDIVR = 1368, I_FILD = 1418, I_FIMUL = 1324, I_FINCSTP = 1247, I_FINIT = 7326,
|
||||
I_FIST = 1432, I_FISTP = 1438, I_FISTTP = 1424, I_FISUB = 1346, I_FISUBR = 1353,
|
||||
I_FLD = 1074, I_FLD1 = 1141, I_FLDCW = 1098, I_FLDENV = 1090, I_FLDL2E = 1155,
|
||||
I_FLDL2T = 1147, I_FLDLG2 = 1170, I_FLDLN2 = 1178, I_FLDPI = 1163, I_FLDZ = 1186,
|
||||
I_FMUL = 1029, I_FMULP = 1556, I_FNCLEX = 7303, I_FNINIT = 7318, I_FNOP = 1111,
|
||||
I_FNSAVE = 7333, I_FNSTCW = 7288, I_FNSTENV = 7271, I_FNSTSW = 7348, I_FPATAN = 1213,
|
||||
I_FPREM = 1256, I_FPREM1 = 1230, I_FPTAN = 1206, I_FRNDINT = 1288, I_FRSTOR = 1519,
|
||||
I_FSAVE = 7341, I_FSCALE = 1297, I_FSETPM = 1496, I_FSIN = 1305, I_FSINCOS = 1279,
|
||||
I_FSQRT = 1272, I_FST = 1079, I_FSTCW = 7296, I_FSTENV = 7280, I_FSTP = 1084,
|
||||
I_FSTSW = 7356, I_FSUB = 1048, I_FSUBP = 1579, I_FSUBR = 1054, I_FSUBRP = 1571,
|
||||
I_FTST = 1129, I_FUCOM = 1534, I_FUCOMI = 1504, I_FUCOMIP = 1614, I_FUCOMP = 1541,
|
||||
I_FUCOMPP = 1409, I_FXAM = 1135, I_FXCH = 1105, I_FXRSTOR = 9914, I_FXRSTOR64 = 9923,
|
||||
I_FXSAVE = 9886, I_FXSAVE64 = 9894, I_FXTRACT = 1221, I_FYL2X = 1199, I_FYL2XP1 = 1263,
|
||||
I_GETSEC = 633, I_HADDPD = 4203, I_HADDPS = 4211, I_HLT = 482, I_HSUBPD = 4237,
|
||||
I_HSUBPS = 4245, I_IDIV = 1651, I_IMUL = 117, I_IN = 447, I_INC = 81, I_INS = 123,
|
||||
I_INSERTPS = 9569, I_INSERTQ = 4165, I_INT = 367, I_INT_3 = 360, I_INT1 = 476,
|
||||
I_INTO = 372, I_INVD = 555, I_INVEPT = 8306, I_INVLPG = 1727, I_INVLPGA = 1869,
|
||||
I_INVPCID = 8323, I_INVVPID = 8314, I_IRET = 378, I_JA = 166, I_JAE = 147,
|
||||
I_JB = 143, I_JBE = 161, I_JCXZ = 427, I_JECXZ = 433, I_JG = 202, I_JGE = 192,
|
||||
I_JL = 188, I_JLE = 197, I_JMP = 462, I_JMP_FAR = 467, I_JNO = 138, I_JNP = 183,
|
||||
I_JNS = 174, I_JNZ = 156, I_JO = 134, I_JP = 179, I_JRCXZ = 440, I_JS = 170,
|
||||
I_JZ = 152, I_LAHF = 289, I_LAR = 522, I_LDDQU = 7016, I_LDMXCSR = 9944, I_LDS = 335,
|
||||
I_LEA = 223, I_LEAVE = 347, I_LES = 330, I_LFENCE = 4287, I_LFS = 917, I_LGDT = 1703,
|
||||
I_LGS = 922, I_LIDT = 1709, I_LLDT = 1668, I_LMSW = 1721, I_LODS = 313, I_LOOP = 421,
|
||||
I_LOOPNZ = 406, I_LOOPZ = 414, I_LSL = 527, I_LSS = 907, I_LTR = 1674, I_LZCNT = 4385,
|
||||
I_MASKMOVDQU = 7141, I_MASKMOVQ = 7131, I_MAXPD = 3581, I_MAXPS = 3574, I_MAXSD = 3595,
|
||||
I_MAXSS = 3588, I_MFENCE = 4313, I_MINPD = 3461, I_MINPS = 3454, I_MINSD = 3475,
|
||||
I_MINSS = 3468, I_MONITOR = 1771, I_MOV = 218, I_MOVAPD = 2481, I_MOVAPS = 2473,
|
||||
I_MOVBE = 9273, I_MOVD = 3942, I_MOVDDUP = 2208, I_MOVDQ2Q = 6544, I_MOVDQA = 3968,
|
||||
I_MOVDQU = 3976, I_MOVHLPS = 2173, I_MOVHPD = 2367, I_MOVHPS = 2359, I_MOVLHPS = 2350,
|
||||
I_MOVLPD = 2190, I_MOVLPS = 2182, I_MOVMSKPD = 2837, I_MOVMSKPS = 2827, I_MOVNTDQ = 6871,
|
||||
I_MOVNTDQA = 7917, I_MOVNTI = 952, I_MOVNTPD = 2578, I_MOVNTPS = 2569, I_MOVNTQ = 6863,
|
||||
I_MOVNTSD = 2596, I_MOVNTSS = 2587, I_MOVQ = 3948, I_MOVQ2DQ = 6535, I_MOVS = 295,
|
||||
I_MOVSD = 2132, I_MOVSHDUP = 2375, I_MOVSLDUP = 2198, I_MOVSS = 2125, I_MOVSX = 939,
|
||||
I_MOVSXD = 10027, I_MOVUPD = 2117, I_MOVUPS = 2109, I_MOVZX = 927, I_MPSADBW = 9650,
|
||||
I_MUL = 1641, I_MULPD = 3192, I_MULPS = 3185, I_MULSD = 3206, I_MULSS = 3199,
|
||||
I_MWAIT = 1780, I_NEG = 1636, I_NOP = 581, I_NOT = 1631, I_OR = 27, I_ORPD = 3075,
|
||||
I_ORPS = 3069, I_OUT = 451, I_OUTS = 128, I_PABSB = 7710, I_PABSD = 7740, I_PABSW = 7725,
|
||||
I_PACKSSDW = 3871, I_PACKSSWB = 3703, I_PACKUSDW = 7938, I_PACKUSWB = 3781,
|
||||
I_PADDB = 7226, I_PADDD = 7256, I_PADDQ = 6503, I_PADDSB = 6952, I_PADDSW = 6969,
|
||||
I_PADDUSB = 6642, I_PADDUSW = 6661, I_PADDW = 7241, I_PALIGNR = 9432, I_PAND = 6629,
|
||||
I_PANDN = 6687, I_PAUSE = 10035, I_PAVGB = 6702, I_PAVGUSB = 2100, I_PAVGW = 6747,
|
||||
I_PBLENDVB = 7621, I_PBLENDW = 9413, I_PCLMULQDQ = 9669, I_PCMPEQB = 4065,
|
||||
I_PCMPEQD = 4103, I_PCMPEQQ = 7898, I_PCMPEQW = 4084, I_PCMPESTRI = 9748,
|
||||
I_PCMPESTRM = 9725, I_PCMPGTB = 3724, I_PCMPGTD = 3762, I_PCMPGTQ = 8109,
|
||||
I_PCMPGTW = 3743, I_PCMPISTRI = 9794, I_PCMPISTRM = 9771, I_PEXTRB = 9451,
|
||||
I_PEXTRD = 9468, I_PEXTRQ = 9476, I_PEXTRW = 6333, I_PF2ID = 1936, I_PF2IW = 1929,
|
||||
I_PFACC = 2050, I_PFADD = 1999, I_PFCMPEQ = 2057, I_PFCMPGE = 1960, I_PFCMPGT = 2006,
|
||||
I_PFMAX = 2015, I_PFMIN = 1969, I_PFMUL = 2066, I_PFNACC = 1943, I_PFPNACC = 1951,
|
||||
I_PFRCP = 1976, I_PFRCPIT1 = 2022, I_PFRCPIT2 = 2073, I_PFRSQIT1 = 2032, I_PFRSQRT = 1983,
|
||||
I_PFSUB = 1992, I_PFSUBR = 2042, I_PHADDD = 7397, I_PHADDSW = 7414, I_PHADDW = 7380,
|
||||
I_PHMINPOSUW = 8281, I_PHSUBD = 7473, I_PHSUBSW = 7490, I_PHSUBW = 7456, I_PI2FD = 1922,
|
||||
I_PI2FW = 1915, I_PINSRB = 9552, I_PINSRD = 9590, I_PINSRQ = 9598, I_PINSRW = 6316,
|
||||
I_PMADDUBSW = 7433, I_PMADDWD = 7095, I_PMAXSB = 8196, I_PMAXSD = 8213, I_PMAXSW = 6986,
|
||||
I_PMAXUB = 6670, I_PMAXUD = 8247, I_PMAXUW = 8230, I_PMINSB = 8128, I_PMINSD = 8145,
|
||||
I_PMINSW = 6924, I_PMINUB = 6612, I_PMINUD = 8179, I_PMINUW = 8162, I_PMOVMSKB = 6553,
|
||||
I_PMOVSXBD = 7776, I_PMOVSXBQ = 7797, I_PMOVSXBW = 7755, I_PMOVSXDQ = 7860,
|
||||
I_PMOVSXWD = 7818, I_PMOVSXWQ = 7839, I_PMOVZXBD = 8004, I_PMOVZXBQ = 8025,
|
||||
I_PMOVZXBW = 7983, I_PMOVZXDQ = 8088, I_PMOVZXWD = 8046, I_PMOVZXWQ = 8067,
|
||||
I_PMULDQ = 7881, I_PMULHRSW = 7560, I_PMULHRW = 2083, I_PMULHUW = 6762, I_PMULHW = 6781,
|
||||
I_PMULLD = 8264, I_PMULLW = 6518, I_PMULUDQ = 7076, I_POP = 22, I_POPA = 98,
|
||||
I_POPCNT = 4360, I_POPF = 277, I_POR = 6941, I_PREFETCH = 1894, I_PREFETCHNTA = 2424,
|
||||
I_PREFETCHT0 = 2437, I_PREFETCHT1 = 2449, I_PREFETCHT2 = 2461, I_PREFETCHW = 1904,
|
||||
I_PSADBW = 7114, I_PSHUFB = 7363, I_PSHUFD = 4010, I_PSHUFHW = 4018, I_PSHUFLW = 4027,
|
||||
I_PSHUFW = 4002, I_PSIGNB = 7509, I_PSIGND = 7543, I_PSIGNW = 7526, I_PSLLD = 7046,
|
||||
I_PSLLDQ = 9869, I_PSLLQ = 7061, I_PSLLW = 7031, I_PSRAD = 6732, I_PSRAW = 6717,
|
||||
I_PSRLD = 6473, I_PSRLDQ = 9852, I_PSRLQ = 6488, I_PSRLW = 6458, I_PSUBB = 7166,
|
||||
I_PSUBD = 7196, I_PSUBQ = 7211, I_PSUBSB = 6890, I_PSUBSW = 6907, I_PSUBUSB = 6574,
|
||||
I_PSUBUSW = 6593, I_PSUBW = 7181, I_PSWAPD = 2092, I_PTEST = 7651, I_PUNPCKHBW = 3802,
|
||||
I_PUNPCKHDQ = 3848, I_PUNPCKHQDQ = 3917, I_PUNPCKHWD = 3825, I_PUNPCKLBW = 3634,
|
||||
I_PUNPCKLDQ = 3680, I_PUNPCKLQDQ = 3892, I_PUNPCKLWD = 3657, I_PUSH = 16,
|
||||
I_PUSHA = 91, I_PUSHF = 270, I_PXOR = 7003, I_RCL = 977, I_RCPPS = 2975, I_RCPSS = 2982,
|
||||
I_RCR = 982, I_RDFSBASE = 9904, I_RDGSBASE = 9934, I_RDMSR = 600, I_RDPMC = 607,
|
||||
I_RDRAND = 10048, I_RDTSC = 593, I_RDTSCP = 1886, I_RET = 325, I_RETF = 354,
|
||||
I_ROL = 967, I_ROR = 972, I_ROUNDPD = 9318, I_ROUNDPS = 9299, I_ROUNDSD = 9356,
|
||||
I_ROUNDSS = 9337, I_RSM = 882, I_RSQRTPS = 2937, I_RSQRTSS = 2946, I_SAHF = 283,
|
||||
I_SAL = 997, I_SALC = 394, I_SAR = 1002, I_SBB = 36, I_SCAS = 319, I_SETA = 807,
|
||||
I_SETAE = 780, I_SETB = 774, I_SETBE = 800, I_SETG = 859, I_SETGE = 845, I_SETL = 839,
|
||||
I_SETLE = 852, I_SETNO = 767, I_SETNP = 832, I_SETNS = 819, I_SETNZ = 793,
|
||||
I_SETO = 761, I_SETP = 826, I_SETS = 813, I_SETZ = 787, I_SFENCE = 4343, I_SGDT = 1691,
|
||||
I_SHL = 987, I_SHLD = 876, I_SHR = 992, I_SHRD = 892, I_SHUFPD = 6358, I_SHUFPS = 6350,
|
||||
I_SIDT = 1697, I_SKINIT = 1861, I_SLDT = 1657, I_SMSW = 1715, I_SQRTPD = 2877,
|
||||
I_SQRTPS = 2869, I_SQRTSD = 2893, I_SQRTSS = 2885, I_STC = 497, I_STD = 517,
|
||||
I_STGI = 1849, I_STI = 507, I_STMXCSR = 9973, I_STOS = 307, I_STR = 1663, I_SUB = 51,
|
||||
I_SUBPD = 3401, I_SUBPS = 3394, I_SUBSD = 3415, I_SUBSS = 3408, I_SWAPGS = 1878,
|
||||
I_SYSCALL = 532, I_SYSENTER = 614, I_SYSEXIT = 624, I_SYSRET = 547, I_TEST = 206,
|
||||
I_TZCNT = 4373, I_UCOMISD = 2764, I_UCOMISS = 2755, I_UD2 = 569, I_UNPCKHPD = 2318,
|
||||
I_UNPCKHPS = 2308, I_UNPCKLPD = 2276, I_UNPCKLPS = 2266, I_VADDPD = 3161,
|
||||
I_VADDPS = 3153, I_VADDSD = 3177, I_VADDSS = 3169, I_VADDSUBPD = 6436, I_VADDSUBPS = 6447,
|
||||
I_VAESDEC = 9239, I_VAESDECLAST = 9260, I_VAESENC = 9197, I_VAESENCLAST = 9218,
|
||||
I_VAESIMC = 9180, I_VAESKEYGENASSIST = 9834, I_VANDNPD = 3060, I_VANDNPS = 3051,
|
||||
I_VANDPD = 3027, I_VANDPS = 3019, I_VBLENDPD = 9403, I_VBLENDPS = 9384, I_VBLENDVPD = 9703,
|
||||
I_VBLENDVPS = 9692, I_VBROADCASTF128 = 7694, I_VBROADCASTSD = 7680, I_VBROADCASTSS = 7666,
|
||||
I_VCMPEQPD = 5110, I_VCMPEQPS = 4708, I_VCMPEQSD = 5914, I_VCMPEQSS = 5512,
|
||||
I_VCMPEQ_OSPD = 5291, I_VCMPEQ_OSPS = 4889, I_VCMPEQ_OSSD = 6095, I_VCMPEQ_OSSS = 5693,
|
||||
I_VCMPEQ_UQPD = 5197, I_VCMPEQ_UQPS = 4795, I_VCMPEQ_UQSD = 6001, I_VCMPEQ_UQSS = 5599,
|
||||
I_VCMPEQ_USPD = 5400, I_VCMPEQ_USPS = 4998, I_VCMPEQ_USSD = 6204, I_VCMPEQ_USSS = 5802,
|
||||
I_VCMPFALSEPD = 5232, I_VCMPFALSEPS = 4830, I_VCMPFALSESD = 6036, I_VCMPFALSESS = 5634,
|
||||
I_VCMPFALSE_OSPD = 5441, I_VCMPFALSE_OSPS = 5039, I_VCMPFALSE_OSSD = 6245,
|
||||
I_VCMPFALSE_OSSS = 5843, I_VCMPGEPD = 5259, I_VCMPGEPS = 4857, I_VCMPGESD = 6063,
|
||||
I_VCMPGESS = 5661, I_VCMPGE_OQPD = 5471, I_VCMPGE_OQPS = 5069, I_VCMPGE_OQSD = 6275,
|
||||
I_VCMPGE_OQSS = 5873, I_VCMPGTPD = 5269, I_VCMPGTPS = 4867, I_VCMPGTSD = 6073,
|
||||
I_VCMPGTSS = 5671, I_VCMPGT_OQPD = 5484, I_VCMPGT_OQPS = 5082, I_VCMPGT_OQSD = 6288,
|
||||
I_VCMPGT_OQSS = 5886, I_VCMPLEPD = 5130, I_VCMPLEPS = 4728, I_VCMPLESD = 5934,
|
||||
I_VCMPLESS = 5532, I_VCMPLE_OQPD = 5317, I_VCMPLE_OQPS = 4915, I_VCMPLE_OQSD = 6121,
|
||||
I_VCMPLE_OQSS = 5719, I_VCMPLTPD = 5120, I_VCMPLTPS = 4718, I_VCMPLTSD = 5924,
|
||||
I_VCMPLTSS = 5522, I_VCMPLT_OQPD = 5304, I_VCMPLT_OQPS = 4902, I_VCMPLT_OQSD = 6108,
|
||||
I_VCMPLT_OQSS = 5706, I_VCMPNEQPD = 5153, I_VCMPNEQPS = 4751, I_VCMPNEQSD = 5957,
|
||||
I_VCMPNEQSS = 5555, I_VCMPNEQ_OQPD = 5245, I_VCMPNEQ_OQPS = 4843, I_VCMPNEQ_OQSD = 6049,
|
||||
I_VCMPNEQ_OQSS = 5647, I_VCMPNEQ_OSPD = 5457, I_VCMPNEQ_OSPS = 5055, I_VCMPNEQ_OSSD = 6261,
|
||||
I_VCMPNEQ_OSSS = 5859, I_VCMPNEQ_USPD = 5345, I_VCMPNEQ_USPS = 4943, I_VCMPNEQ_USSD = 6149,
|
||||
I_VCMPNEQ_USSS = 5747, I_VCMPNGEPD = 5210, I_VCMPNGEPS = 4808, I_VCMPNGESD = 6014,
|
||||
I_VCMPNGESS = 5612, I_VCMPNGE_UQPD = 5413, I_VCMPNGE_UQPS = 5011, I_VCMPNGE_UQSD = 6217,
|
||||
I_VCMPNGE_UQSS = 5815, I_VCMPNGTPD = 5221, I_VCMPNGTPS = 4819, I_VCMPNGTSD = 6025,
|
||||
I_VCMPNGTSS = 5623, I_VCMPNGT_UQPD = 5427, I_VCMPNGT_UQPS = 5025, I_VCMPNGT_UQSD = 6231,
|
||||
I_VCMPNGT_UQSS = 5829, I_VCMPNLEPD = 5175, I_VCMPNLEPS = 4773, I_VCMPNLESD = 5979,
|
||||
I_VCMPNLESS = 5577, I_VCMPNLE_UQPD = 5373, I_VCMPNLE_UQPS = 4971, I_VCMPNLE_UQSD = 6177,
|
||||
I_VCMPNLE_UQSS = 5775, I_VCMPNLTPD = 5164, I_VCMPNLTPS = 4762, I_VCMPNLTSD = 5968,
|
||||
I_VCMPNLTSS = 5566, I_VCMPNLT_UQPD = 5359, I_VCMPNLT_UQPS = 4957, I_VCMPNLT_UQSD = 6163,
|
||||
I_VCMPNLT_UQSS = 5761, I_VCMPORDPD = 5186, I_VCMPORDPS = 4784, I_VCMPORDSD = 5990,
|
||||
I_VCMPORDSS = 5588, I_VCMPORD_SPD = 5387, I_VCMPORD_SPS = 4985, I_VCMPORD_SSD = 6191,
|
||||
I_VCMPORD_SSS = 5789, I_VCMPTRUEPD = 5279, I_VCMPTRUEPS = 4877, I_VCMPTRUESD = 6083,
|
||||
I_VCMPTRUESS = 5681, I_VCMPTRUE_USPD = 5497, I_VCMPTRUE_USPS = 5095, I_VCMPTRUE_USSD = 6301,
|
||||
I_VCMPTRUE_USSS = 5899, I_VCMPUNORDPD = 5140, I_VCMPUNORDPS = 4738, I_VCMPUNORDSD = 5944,
|
||||
I_VCMPUNORDSS = 5542, I_VCMPUNORD_SPD = 5330, I_VCMPUNORD_SPS = 4928, I_VCMPUNORD_SSD = 6134,
|
||||
I_VCMPUNORD_SSS = 5732, I_VCOMISD = 2818, I_VCOMISS = 2809, I_VCVTDQ2PD = 6841,
|
||||
I_VCVTDQ2PS = 3360, I_VCVTPD2DQ = 6852, I_VCVTPD2PS = 3296, I_VCVTPS2DQ = 3371,
|
||||
I_VCVTPS2PD = 3285, I_VCVTSD2SI = 2744, I_VCVTSD2SS = 3318, I_VCVTSI2SD = 2558,
|
||||
I_VCVTSI2SS = 2547, I_VCVTSS2SD = 3307, I_VCVTSS2SI = 2733, I_VCVTTPD2DQ = 6829,
|
||||
I_VCVTTPS2DQ = 3382, I_VCVTTSD2SI = 2681, I_VCVTTSS2SI = 2669, I_VDIVPD = 3550,
|
||||
I_VDIVPS = 3542, I_VDIVSD = 3566, I_VDIVSS = 3558, I_VDPPD = 9643, I_VDPPS = 9630,
|
||||
I_VERR = 1679, I_VERW = 1685, I_VEXTRACTF128 = 9538, I_VEXTRACTPS = 9513,
|
||||
I_VFMADD132PD = 8409, I_VFMADD132PS = 8396, I_VFMADD132SD = 8435, I_VFMADD132SS = 8422,
|
||||
I_VFMADD213PD = 8689, I_VFMADD213PS = 8676, I_VFMADD213SD = 8715, I_VFMADD213SS = 8702,
|
||||
I_VFMADD231PD = 8969, I_VFMADD231PS = 8956, I_VFMADD231SD = 8995, I_VFMADD231SS = 8982,
|
||||
I_VFMADDSUB132PD = 8348, I_VFMADDSUB132PS = 8332, I_VFMADDSUB213PD = 8628,
|
||||
I_VFMADDSUB213PS = 8612, I_VFMADDSUB231PD = 8908, I_VFMADDSUB231PS = 8892,
|
||||
I_VFMSUB132PD = 8461, I_VFMSUB132PS = 8448, I_VFMSUB132SD = 8487, I_VFMSUB132SS = 8474,
|
||||
I_VFMSUB213PD = 8741, I_VFMSUB213PS = 8728, I_VFMSUB213SD = 8767, I_VFMSUB213SS = 8754,
|
||||
I_VFMSUB231PD = 9021, I_VFMSUB231PS = 9008, I_VFMSUB231SD = 9047, I_VFMSUB231SS = 9034,
|
||||
I_VFMSUBADD132PD = 8380, I_VFMSUBADD132PS = 8364, I_VFMSUBADD213PD = 8660,
|
||||
I_VFMSUBADD213PS = 8644, I_VFMSUBADD231PD = 8940, I_VFMSUBADD231PS = 8924,
|
||||
I_VFNMADD132PD = 8514, I_VFNMADD132PS = 8500, I_VFNMADD132SD = 8542, I_VFNMADD132SS = 8528,
|
||||
I_VFNMADD213PD = 8794, I_VFNMADD213PS = 8780, I_VFNMADD213SD = 8822, I_VFNMADD213SS = 8808,
|
||||
I_VFNMADD231PD = 9074, I_VFNMADD231PS = 9060, I_VFNMADD231SD = 9102, I_VFNMADD231SS = 9088,
|
||||
I_VFNMSUB132PD = 8570, I_VFNMSUB132PS = 8556, I_VFNMSUB132SD = 8598, I_VFNMSUB132SS = 8584,
|
||||
I_VFNMSUB213PD = 8850, I_VFNMSUB213PS = 8836, I_VFNMSUB213SD = 8878, I_VFNMSUB213SS = 8864,
|
||||
I_VFNMSUB231PD = 9130, I_VFNMSUB231PS = 9116, I_VFNMSUB231SD = 9158, I_VFNMSUB231SS = 9144,
|
||||
I_VHADDPD = 4219, I_VHADDPS = 4228, I_VHSUBPD = 4253, I_VHSUBPS = 4262, I_VINSERTF128 = 9525,
|
||||
I_VINSERTPS = 9579, I_VLDDQU = 7023, I_VLDMXCSR = 9963, I_VMASKMOVDQU = 7153,
|
||||
I_VMASKMOVPD = 7971, I_VMASKMOVPS = 7959, I_VMAXPD = 3610, I_VMAXPS = 3602,
|
||||
I_VMAXSD = 3626, I_VMAXSS = 3618, I_VMCALL = 1735, I_VMCLEAR = 10011, I_VMFUNC = 1803,
|
||||
I_VMINPD = 3490, I_VMINPS = 3482, I_VMINSD = 3506, I_VMINSS = 3498, I_VMLAUNCH = 1743,
|
||||
I_VMLOAD = 1833, I_VMMCALL = 1824, I_VMOVAPD = 2498, I_VMOVAPS = 2489, I_VMOVD = 3954,
|
||||
I_VMOVDDUP = 2256, I_VMOVDQA = 3984, I_VMOVDQU = 3993, I_VMOVHLPS = 2217,
|
||||
I_VMOVHPD = 2404, I_VMOVHPS = 2395, I_VMOVLHPS = 2385, I_VMOVLPD = 2236, I_VMOVLPS = 2227,
|
||||
I_VMOVMSKPD = 2858, I_VMOVMSKPS = 2847, I_VMOVNTDQ = 6880, I_VMOVNTDQA = 7927,
|
||||
I_VMOVNTPD = 2615, I_VMOVNTPS = 2605, I_VMOVQ = 3961, I_VMOVSD = 2165, I_VMOVSHDUP = 2413,
|
||||
I_VMOVSLDUP = 2245, I_VMOVSS = 2157, I_VMOVUPD = 2148, I_VMOVUPS = 2139, I_VMPSADBW = 9659,
|
||||
I_VMPTRLD = 10002, I_VMPTRST = 6407, I_VMREAD = 4150, I_VMRESUME = 1753, I_VMRUN = 1817,
|
||||
I_VMSAVE = 1841, I_VMULPD = 3221, I_VMULPS = 3213, I_VMULSD = 3237, I_VMULSS = 3229,
|
||||
I_VMWRITE = 4174, I_VMXOFF = 1763, I_VMXON = 10020, I_VORPD = 3088, I_VORPS = 3081,
|
||||
I_VPABSB = 7717, I_VPABSD = 7747, I_VPABSW = 7732, I_VPACKSSDW = 3881, I_VPACKSSWB = 3713,
|
||||
I_VPACKUSDW = 7948, I_VPACKUSWB = 3791, I_VPADDB = 7233, I_VPADDD = 7263,
|
||||
I_VPADDQ = 6510, I_VPADDSB = 6960, I_VPADDSW = 6977, I_VPADDUSW = 6651, I_VPADDW = 7248,
|
||||
I_VPALIGNR = 9441, I_VPAND = 6635, I_VPANDN = 6694, I_VPAVGB = 6709, I_VPAVGW = 6754,
|
||||
I_VPBLENDVB = 9714, I_VPBLENDW = 9422, I_VPCLMULQDQ = 9680, I_VPCMPEQB = 4074,
|
||||
I_VPCMPEQD = 4112, I_VPCMPEQQ = 7907, I_VPCMPEQW = 4093, I_VPCMPESTRI = 9759,
|
||||
I_VPCMPESTRM = 9736, I_VPCMPGTB = 3733, I_VPCMPGTD = 3771, I_VPCMPGTQ = 8118,
|
||||
I_VPCMPGTW = 3752, I_VPCMPISTRI = 9805, I_VPCMPISTRM = 9782, I_VPERM2F128 = 9287,
|
||||
I_VPERMILPD = 7592, I_VPERMILPS = 7581, I_VPEXTRB = 9459, I_VPEXTRD = 9484,
|
||||
I_VPEXTRQ = 9493, I_VPEXTRW = 6341, I_VPHADDD = 7405, I_VPHADDSW = 7423, I_VPHADDW = 7388,
|
||||
I_VPHMINPOSUW = 8293, I_VPHSUBD = 7481, I_VPHSUBSW = 7499, I_VPHSUBW = 7464,
|
||||
I_VPINSRB = 9560, I_VPINSRD = 9606, I_VPINSRQ = 9615, I_VPINSRW = 6324, I_VPMADDUBSW = 7444,
|
||||
I_VPMADDWD = 7104, I_VPMAXSB = 8204, I_VPMAXSD = 8221, I_VPMAXSW = 6994, I_VPMAXUB = 6678,
|
||||
I_VPMAXUD = 8255, I_VPMAXUW = 8238, I_VPMINSB = 8136, I_VPMINSD = 8153, I_VPMINSW = 6932,
|
||||
I_VPMINUB = 6620, I_VPMINUD = 8187, I_VPMINUW = 8170, I_VPMOVMSKB = 6563,
|
||||
I_VPMOVSXBD = 7786, I_VPMOVSXBQ = 7807, I_VPMOVSXBW = 7765, I_VPMOVSXDQ = 7870,
|
||||
I_VPMOVSXWD = 7828, I_VPMOVSXWQ = 7849, I_VPMOVZXBD = 8014, I_VPMOVZXBQ = 8035,
|
||||
I_VPMOVZXBW = 7993, I_VPMOVZXDQ = 8098, I_VPMOVZXWD = 8056, I_VPMOVZXWQ = 8077,
|
||||
I_VPMULDQ = 7889, I_VPMULHRSW = 7570, I_VPMULHUW = 6771, I_VPMULHW = 6789,
|
||||
I_VPMULLD = 8272, I_VPMULLW = 6526, I_VPMULUDQ = 7085, I_VPOR = 6946, I_VPSADBW = 7122,
|
||||
I_VPSHUFB = 7371, I_VPSHUFD = 4036, I_VPSHUFHW = 4045, I_VPSHUFLW = 4055,
|
||||
I_VPSIGNB = 7517, I_VPSIGND = 7551, I_VPSIGNW = 7534, I_VPSLLD = 7053, I_VPSLLDQ = 9877,
|
||||
I_VPSLLQ = 7068, I_VPSLLW = 7038, I_VPSRAD = 6739, I_VPSRAW = 6724, I_VPSRLD = 6480,
|
||||
I_VPSRLDQ = 9860, I_VPSRLQ = 6495, I_VPSRLW = 6465, I_VPSUBB = 7173, I_VPSUBD = 7203,
|
||||
I_VPSUBQ = 7218, I_VPSUBSB = 6898, I_VPSUBSW = 6915, I_VPSUBUSB = 6583, I_VPSUBUSW = 6602,
|
||||
I_VPSUBW = 7188, I_VPTEST = 7658, I_VPUNPCKHBW = 3813, I_VPUNPCKHDQ = 3859,
|
||||
I_VPUNPCKHQDQ = 3929, I_VPUNPCKHWD = 3836, I_VPUNPCKLBW = 3645, I_VPUNPCKLDQ = 3691,
|
||||
I_VPUNPCKLQDQ = 3904, I_VPUNPCKLWD = 3668, I_VPXOR = 7009, I_VRCPPS = 2989,
|
||||
I_VRCPSS = 2997, I_VROUNDPD = 9327, I_VROUNDPS = 9308, I_VROUNDSD = 9365,
|
||||
I_VROUNDSS = 9346, I_VRSQRTPS = 2955, I_VRSQRTSS = 2965, I_VSHUFPD = 6375,
|
||||
I_VSHUFPS = 6366, I_VSQRTPD = 2910, I_VSQRTPS = 2901, I_VSQRTSD = 2928, I_VSQRTSS = 2919,
|
||||
I_VSTMXCSR = 9992, I_VSUBPD = 3430, I_VSUBPS = 3422, I_VSUBSD = 3446, I_VSUBSS = 3438,
|
||||
I_VTESTPD = 7612, I_VTESTPS = 7603, I_VUCOMISD = 2783, I_VUCOMISS = 2773,
|
||||
I_VUNPCKHPD = 2339, I_VUNPCKHPS = 2328, I_VUNPCKLPD = 2297, I_VUNPCKLPS = 2286,
|
||||
I_VXORPD = 3117, I_VXORPS = 3109, I_VZEROALL = 4140, I_VZEROUPPER = 4128,
|
||||
I_WAIT = 10042, I_WBINVD = 561, I_WRFSBASE = 9953, I_WRGSBASE = 9982, I_WRMSR = 586,
|
||||
I_XABORT = 1007, I_XADD = 946, I_XBEGIN = 1015, I_XCHG = 212, I_XEND = 1811,
|
||||
I_XGETBV = 1787, I_XLAT = 400, I_XOR = 61, I_XORPD = 3102, I_XORPS = 3095,
|
||||
I_XRSTOR = 4295, I_XRSTOR64 = 4303, I_XSAVE = 4271, I_XSAVE64 = 4278, I_XSAVEOPT = 4321,
|
||||
I_XSAVEOPT64 = 4331, I_XSETBV = 1795, I__3DNOW = 10056
|
||||
} _InstructionType;
|
||||
|
||||
typedef enum {
|
||||
R_RAX, R_RCX, R_RDX, R_RBX, R_RSP, R_RBP, R_RSI, R_RDI, R_R8, R_R9, R_R10, R_R11, R_R12, R_R13, R_R14, R_R15,
|
||||
R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI, R_R8D, R_R9D, R_R10D, R_R11D, R_R12D, R_R13D, R_R14D, R_R15D,
|
||||
R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI, R_R8W, R_R9W, R_R10W, R_R11W, R_R12W, R_R13W, R_R14W, R_R15W,
|
||||
R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH, R_R8B, R_R9B, R_R10B, R_R11B, R_R12B, R_R13B, R_R14B, R_R15B,
|
||||
R_SPL, R_BPL, R_SIL, R_DIL,
|
||||
R_ES, R_CS, R_SS, R_DS, R_FS, R_GS,
|
||||
R_RIP,
|
||||
R_ST0, R_ST1, R_ST2, R_ST3, R_ST4, R_ST5, R_ST6, R_ST7,
|
||||
R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7,
|
||||
R_XMM0, R_XMM1, R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7, R_XMM8, R_XMM9, R_XMM10, R_XMM11, R_XMM12, R_XMM13, R_XMM14, R_XMM15,
|
||||
R_YMM0, R_YMM1, R_YMM2, R_YMM3, R_YMM4, R_YMM5, R_YMM6, R_YMM7, R_YMM8, R_YMM9, R_YMM10, R_YMM11, R_YMM12, R_YMM13, R_YMM14, R_YMM15,
|
||||
R_CR0, R_UNUSED0, R_CR2, R_CR3, R_CR4, R_UNUSED1, R_UNUSED2, R_UNUSED3, R_CR8,
|
||||
R_DR0, R_DR1, R_DR2, R_DR3, R_UNUSED4, R_UNUSED5, R_DR6, R_DR7
|
||||
} _RegisterType;
|
||||
|
||||
#endif /* MNEMONICS_H */
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
config.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
/* diStorm version number. */
|
||||
#define __DISTORMV__ 0x030502
|
||||
|
||||
#include <string.h> /* memset, memcpy - can be easily self implemented for libc independency. */
|
||||
|
||||
#include "../include/distorm.h"
|
||||
|
||||
|
||||
/*
|
||||
* 64 bit offsets support:
|
||||
* This macro should be defined from compiler command line flags, e.g: -DSUPPORT_64BIT_OFFSET
|
||||
* Note: make sure that the caller (library user) defines it too!
|
||||
*/
|
||||
/* #define SUPPORT_64BIT_OFFSET */
|
||||
|
||||
/*
|
||||
* If you compile diStorm as a dynamic library (.dll or .so) file, make sure you uncomment the next line.
|
||||
* So the interface functions will be exported, otherwise they are useable only for static library.
|
||||
* For example, this macro is being set for compiling diStorm as a .dll for Python with CTypes.
|
||||
*/
|
||||
/* #define DISTORM_DYNAMIC */
|
||||
|
||||
/*
|
||||
* If DISTORM_LIGHT is defined, everything involved in formatting the instructions
|
||||
* as text will be excluded from compilation.
|
||||
* distorm_decode(..) and distorm_format(..) will not be available.
|
||||
* This will decrease the size of the executable and leave you with decomposition functionality only.
|
||||
*
|
||||
* Note: it should be either set in the preprocessor definitions manually or in command line -D switch.
|
||||
* #define DISTORM_LIGHT
|
||||
*/
|
||||
|
||||
/*
|
||||
* diStorm now supports little/big endian CPU's.
|
||||
* It should detect the endianness according to predefined macro's of the compiler.
|
||||
* If you don't use GCC/MSVC you will have to define it on your own.
|
||||
*/
|
||||
|
||||
/* These macros are used in order to make the code portable. */
|
||||
#ifdef __GNUC__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define _DLLEXPORT_
|
||||
#define _FASTCALL_
|
||||
/* Keep inline as static (arrrrg) as it would break linux on some flavors otherwise. */
|
||||
#define _INLINE_ static
|
||||
/* GCC ignores this directive... */
|
||||
/*#define _FASTCALL_ __attribute__((__fastcall__))*/
|
||||
|
||||
/* Set endianity (supposed to be LE though): */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define BE_SYSTEM
|
||||
#endif
|
||||
|
||||
/* End of __GCC__ */
|
||||
|
||||
#elif __WATCOMC__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define _DLLEXPORT_
|
||||
#define _FASTCALL_
|
||||
#define _INLINE_ __inline
|
||||
|
||||
/* End of __WATCOMC__ */
|
||||
|
||||
#elif __DMC__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define _DLLEXPORT_
|
||||
#define _FASTCALL_
|
||||
#define _INLINE_ __inline
|
||||
|
||||
/* End of __DMC__ */
|
||||
|
||||
#elif __TINYC__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define _DLLEXPORT_
|
||||
#define _FASTCALL_
|
||||
#define _INLINE_ static
|
||||
|
||||
/* End of __TINYC__ */
|
||||
|
||||
#elif _MSC_VER
|
||||
|
||||
/* stdint alternative is defined in distorm.h */
|
||||
|
||||
#define _DLLEXPORT_ __declspec(dllexport)
|
||||
#define _FASTCALL_ __fastcall
|
||||
#define _INLINE_ __inline
|
||||
|
||||
/* Set endianity (supposed to be LE though): */
|
||||
#if !defined(_M_IX86) && !defined(_M_X64)
|
||||
#define BE_SYSTEM
|
||||
#endif
|
||||
|
||||
#endif /* #elif _MSC_VER */
|
||||
|
||||
/* If the library isn't compiled as a dynamic library don't export any functions. */
|
||||
#ifndef DISTORM_DYNAMIC
|
||||
#undef _DLLEXPORT_
|
||||
#define _DLLEXPORT_
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* Define stream read functions for big endian systems. */
|
||||
#ifdef BE_SYSTEM
|
||||
|
||||
/* Avoid defining 'static static' for GCC. */
|
||||
#ifndef __GNUC__
|
||||
#define STATIC_INLINE static _INLINE_
|
||||
#else
|
||||
#define STATIC_INLINE static
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assumption: These functions can read from the stream safely!
|
||||
* Swap endianity of input to little endian.
|
||||
*/
|
||||
STATIC_INLINE int16_t RSHORT(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8);
|
||||
}
|
||||
STATIC_INLINE uint16_t RUSHORT(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8);
|
||||
}
|
||||
STATIC_INLINE int32_t RLONG(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
|
||||
}
|
||||
STATIC_INLINE uint32_t RULONG(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
|
||||
}
|
||||
STATIC_INLINE int64_t RLLONG(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) | ((uint64_t)s[4] << 32) | ((uint64_t)s[5] << 40) | ((uint64_t)s[6] << 48) | ((uint64_t)s[7] << 56);
|
||||
}
|
||||
STATIC_INLINE uint64_t RULLONG(const uint8_t *s)
|
||||
{
|
||||
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) | ((uint64_t)s[4] << 32) | ((uint64_t)s[5] << 40) | ((uint64_t)s[6] << 48) | ((uint64_t)s[7] << 56);
|
||||
}
|
||||
|
||||
#undef STATIC_INLINE
|
||||
|
||||
#else
|
||||
/* Little endian macro's will just make the cast. */
|
||||
#define RSHORT(x) *(int16_t *)x
|
||||
#define RUSHORT(x) *(uint16_t *)x
|
||||
#define RLONG(x) *(int32_t *)x
|
||||
#define RULONG(x) *(uint32_t *)x
|
||||
#define RLLONG(x) *(int64_t *)x
|
||||
#define RULLONG(x) *(uint64_t *)x
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
decoder.c
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "decoder.h"
|
||||
#include "instructions.h"
|
||||
#include "insts.h"
|
||||
#include "prefix.h"
|
||||
#include "x86defs.h"
|
||||
#include "operands.h"
|
||||
#include "insts.h"
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
|
||||
/* Instruction Prefixes - Opcode - ModR/M - SIB - Displacement - Immediate */
|
||||
|
||||
static _DecodeType decode_get_effective_addr_size(_DecodeType dt, _iflags decodedPrefixes)
|
||||
{
|
||||
/*
|
||||
* Map from the current decoding mode to an effective address size:
|
||||
* Decode16 -> Decode32
|
||||
* Decode32 -> Decode16
|
||||
* Decode64 -> Decode32
|
||||
*/
|
||||
|
||||
/* Switch to non default mode if prefix exists, only for ADDRESS SIZE. */
|
||||
if (decodedPrefixes & INST_PRE_ADDR_SIZE) {
|
||||
if (dt == Decode32Bits) return Decode16Bits;
|
||||
return Decode32Bits;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
static _DecodeType decode_get_effective_op_size(_DecodeType dt, _iflags decodedPrefixes, unsigned int rex, _iflags instFlags)
|
||||
{
|
||||
/*
|
||||
* Map from the current decoding mode to an effective operand size:
|
||||
* Decode16 -> Decode32
|
||||
* Decode32 -> Decode16
|
||||
* Decode64 -> Decode16
|
||||
* Not that in 64bits it's a bit more complicated, because of REX and promoted instructions.
|
||||
*/
|
||||
|
||||
if (decodedPrefixes & INST_PRE_OP_SIZE) {
|
||||
if (dt == Decode16Bits) return Decode32Bits;
|
||||
return Decode16Bits;
|
||||
}
|
||||
|
||||
if (dt == Decode64Bits) {
|
||||
/*
|
||||
* REX Prefix toggles data size to 64 bits.
|
||||
* Operand size prefix toggles data size to 16.
|
||||
* Default data size is 32 bits.
|
||||
* Promoted instructions are 64 bits if they don't require a REX perfix.
|
||||
* Non promoted instructions are 64 bits if the REX prefix exists.
|
||||
*/
|
||||
/* Automatically promoted instructions have only INST_64BITS SET! */
|
||||
if (((instFlags & (INST_64BITS | INST_PRE_REX)) == INST_64BITS) ||
|
||||
/* Other instructions in 64 bits can be promoted only with a REX prefix. */
|
||||
((decodedPrefixes & INST_PRE_REX) && (rex & PREFIX_EX_W))) return Decode64Bits;
|
||||
return Decode32Bits; /* Default. */
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/*
|
||||
* A helper macro to convert from diStorm's CPU flags to EFLAGS.
|
||||
* Copy eflags from compact version (8 bits) to eflags compatible (16 bits).
|
||||
* From D_COMPACT_IF to D_IF, bit index 1 to 9.
|
||||
* From D_COMPACT_DF to D_DF, bit index 3 to 10.
|
||||
* From D_COMPACT_OF to D_OF, bit index 5 to 11.
|
||||
*/
|
||||
#define CONVERT_FLAGS_TO_EFLAGS(dst, src, field) dst->field = ((src->field & D_COMPACT_SAME_FLAGS) | \
|
||||
((src->field & D_COMPACT_IF) << (9 - 1)) | \
|
||||
((src->field & D_COMPACT_DF) << (10 - 3)) | \
|
||||
((src->field & D_COMPACT_OF) << (11 - 5)));
|
||||
|
||||
/* If DECRES_SUCCESS is returned, CI is in sync, otherwise it loses sync. */
|
||||
/* Important note: CI is keeping track only for code and codeLen, in case of a failure caller has to restart on their own. */
|
||||
static _DecodeResult decode_inst(_CodeInfo* ci, _PrefixState* ps, const uint8_t* startCode, _DInst* di)
|
||||
{
|
||||
/* Holds the info about the current found instruction. */
|
||||
_InstInfo* ii;
|
||||
_InstSharedInfo* isi;
|
||||
|
||||
/* Calculate (and cache) effective-operand-size and effective-address-size only once. */
|
||||
_DecodeType effOpSz, effAdrSz;
|
||||
_iflags instFlags;
|
||||
|
||||
/* The ModR/M byte of the current instruction. */
|
||||
unsigned int modrm = 0;
|
||||
int isPrefixed = 0;
|
||||
|
||||
ii = inst_lookup(ci, ps, &isPrefixed);
|
||||
if (ii == NULL) goto _Undecodable;
|
||||
|
||||
isi = &InstSharedInfoTable[ii->sharedIndex];
|
||||
instFlags = FlagsTable[isi->flagsIndex];
|
||||
|
||||
/* Cache the effective operand-size and address-size. */
|
||||
if (isPrefixed) {
|
||||
|
||||
/*
|
||||
* If both REX and OpSize are available we will have to disable the OpSize, because REX has precedence.
|
||||
* However, only if REX.W is set!
|
||||
* We had to wait with this test, since the operand size may be a mandatory prefix,
|
||||
* and we know it only after fetching opcode.
|
||||
*/
|
||||
if ((ps->decodedPrefixes & INST_PRE_OP_SIZE) &&
|
||||
(ps->prefixExtType == PET_REX) &&
|
||||
(ps->vrex & PREFIX_EX_W) &&
|
||||
(!ps->isOpSizeMandatory)) {
|
||||
ps->decodedPrefixes &= ~INST_PRE_OP_SIZE;
|
||||
prefixes_ignore(ps, PFXIDX_OP_SIZE);
|
||||
}
|
||||
|
||||
effAdrSz = decode_get_effective_addr_size(ci->dt, ps->decodedPrefixes);
|
||||
effOpSz = decode_get_effective_op_size(ci->dt, ps->decodedPrefixes, ps->vrex, instFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
effAdrSz = ci->dt; /* Default is current decoding type since there's no prefix. */
|
||||
effOpSz = decode_get_effective_op_size(ci->dt, 0, 0, instFlags);
|
||||
}
|
||||
|
||||
/*
|
||||
* In this point we know the instruction we are about to decode and its operands (unless, it's an invalid one!),
|
||||
* so it makes it the right time for decoding-type suitability testing.
|
||||
* Which practically means, don't allow 32 bits instructions in 16 bits decoding mode, but do allow
|
||||
* 16 bits instructions in 32 bits decoding mode, of course...
|
||||
|
||||
* NOTE: Make sure the instruction set for 32 bits has explicitly this specific flag set.
|
||||
* NOTE2: Make sure the instruction set for 64 bits has explicitly this specific flag set.
|
||||
|
||||
* If this is the case, drop what we've got and restart all over after DB'ing that byte.
|
||||
|
||||
* Though, don't drop an instruction which is also supported in 16 and 32 bits.
|
||||
*/
|
||||
|
||||
/* ! ! ! DISABLED UNTIL FURTHER NOTICE ! ! ! Decode16Bits CAN NOW DECODE 32 BITS INSTRUCTIONS ! ! !*/
|
||||
/* if (ii && (dt == Decode16Bits) && (instFlags & INST_32BITS) && (~instFlags & INST_16BITS)) ii = NULL; */
|
||||
|
||||
memset(di, 0, sizeof(_DInst));
|
||||
|
||||
if (instFlags & INST_MODRM_REQUIRED) {
|
||||
/* If the ModRM byte is not part of the opcode, skip the last byte code, so code points now to ModRM. */
|
||||
if (!(instFlags & INST_MODRM_INCLUDED)) {
|
||||
ci->code++;
|
||||
if (--ci->codeLen < 0) goto _Undecodable;
|
||||
}
|
||||
modrm = *ci->code;
|
||||
}
|
||||
|
||||
ci->code++; /* Skip the last byte we just read (either last opcode's byte code or a ModRM). */
|
||||
|
||||
di->addr = ci->codeOffset & ci->addrMask;
|
||||
di->opcode = ii->opcodeId;
|
||||
di->flags = isi->meta & META_INST_PRIVILEGED;
|
||||
|
||||
/*
|
||||
* Store the address size inside the flags.
|
||||
* This is necessary for the caller to know the size of rSP when using PUSHA for example.
|
||||
*/
|
||||
di->base = R_NONE;
|
||||
di->segment = R_NONE;
|
||||
|
||||
FLAG_SET_ADDRSIZE(di, effAdrSz);
|
||||
|
||||
/* Try to extract the next operand only if the latter exists. */
|
||||
if (isi->d != OT_NONE) {
|
||||
unsigned int opsNo = 1;
|
||||
_Operand* op = &di->ops[0];
|
||||
if (instFlags & (INST_MODRR_REQUIRED | INST_FORCE_REG0)) {
|
||||
/* Some instructions enforce that mod=11, so validate that. */
|
||||
if ((modrm < INST_DIVIDED_MODRM) && (instFlags & INST_MODRR_REQUIRED)) goto _Undecodable;
|
||||
/* Some instructions enforce that reg=000, so validate that. (Specifically EXTRQ). */
|
||||
if ((instFlags & INST_FORCE_REG0) && (((modrm >> 3) & 7) != 0)) goto _Undecodable;
|
||||
}
|
||||
if (!operands_extract(ci, di, ii, instFlags, (_OpType)isi->d, modrm, ps, effOpSz, effAdrSz, op++)) goto _Undecodable;
|
||||
|
||||
if (isi->s != OT_NONE) {
|
||||
if (!operands_extract(ci, di, ii, instFlags, (_OpType)isi->s, modrm, ps, effOpSz, effAdrSz, op++)) goto _Undecodable;
|
||||
opsNo++;
|
||||
/* Use third operand, only if the flags says this InstInfo requires it. */
|
||||
if (instFlags & INST_USE_OP3) {
|
||||
if (!operands_extract(ci, di, ii, instFlags, (_OpType)((_InstInfoEx*)ii)->op3, modrm, ps, effOpSz, effAdrSz, op++)) goto _Undecodable;
|
||||
opsNo++;
|
||||
/* Support for a fourth operand is added for (e.g:) INSERTQ instruction. */
|
||||
if (instFlags & INST_USE_OP4) {
|
||||
if (!operands_extract(ci, di, ii, instFlags, (_OpType)((_InstInfoEx*)ii)->op4, modrm, ps, effOpSz, effAdrSz, op++)) goto _Undecodable;
|
||||
opsNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy DST_WR flag. */
|
||||
di->flags |= (instFlags & INST_DST_WR) >> (31 - 6); /* Copy bit from INST_DST_WR (bit 31) to FLAG_DST_WR (bit 6). */
|
||||
/* operands_extract may touched it for FPU operands, so add on top. */
|
||||
di->opsNo += (uint8_t)opsNo;
|
||||
}
|
||||
|
||||
if (instFlags & (INST_3DNOW_FETCH |
|
||||
INST_PSEUDO_OPCODE |
|
||||
INST_NATIVE |
|
||||
INST_PRE_REPNZ |
|
||||
INST_PRE_REP |
|
||||
INST_PRE_ADDR_SIZE |
|
||||
INST_INVALID_64BITS |
|
||||
INST_64BITS_FETCH)) { /* 8 for 1! */
|
||||
|
||||
/* If it's a native instruction copy OpSize Prefix. */
|
||||
if (ps && instFlags & INST_NATIVE) ps->usedPrefixes |= (ps->decodedPrefixes & INST_PRE_OP_SIZE);
|
||||
|
||||
if (ci->dt != Decode64Bits) {
|
||||
/* If it's only a 64 bits instruction drop it in other decoding modes. */
|
||||
if (instFlags & INST_64BITS_FETCH) goto _Undecodable;
|
||||
}
|
||||
else {
|
||||
/* Drop instructions which are invalid in 64 bits. */
|
||||
if (instFlags & INST_INVALID_64BITS) goto _Undecodable;
|
||||
}
|
||||
|
||||
/* If it were a 3DNow! instruction, we will have to find the instruction itself now that we got its operands extracted. */
|
||||
if (instFlags & INST_3DNOW_FETCH) {
|
||||
ii = inst_lookup_3dnow(ci);
|
||||
if (ii == NULL) goto _Undecodable;
|
||||
isi = &InstSharedInfoTable[ii->sharedIndex];
|
||||
instFlags = FlagsTable[isi->flagsIndex];
|
||||
di->opcode = ii->opcodeId;
|
||||
}
|
||||
|
||||
/* Check whether pseudo opcode is needed, only for CMP instructions: */
|
||||
if (instFlags & INST_PSEUDO_OPCODE) {
|
||||
/* Used only for special CMP instructions which have pseudo opcodes suffix. */
|
||||
unsigned int cmpType;
|
||||
|
||||
if (--ci->codeLen < 0) goto _Undecodable;
|
||||
cmpType = *ci->code;
|
||||
ci->code++;
|
||||
|
||||
/*
|
||||
* The opcodeId is the offset to the FIRST pseudo compare mnemonic,
|
||||
* we will have to fix it so it offsets into the corrected mnemonic.
|
||||
* Therefore, we use another table to fix the offset.
|
||||
*/
|
||||
if (instFlags & INST_PRE_VEX) {
|
||||
/* AVX Comparison type must be between 0 to 32, otherwise Reserved. */
|
||||
if (cmpType >= INST_VCMP_MAX_RANGE) goto _Undecodable;
|
||||
|
||||
/* Use the AVX pseudo compare mnemonics table. */
|
||||
di->opcode = ii->opcodeId + VCmpMnemonicOffsets[cmpType];
|
||||
}
|
||||
else {
|
||||
/* SSE Comparison type must be between 0 to 8, otherwise Reserved. */
|
||||
if (cmpType >= INST_CMP_MAX_RANGE) goto _Undecodable;
|
||||
di->opcode = ii->opcodeId + CmpMnemonicOffsets[cmpType];
|
||||
}
|
||||
|
||||
goto _SkipOpcoding;
|
||||
}
|
||||
|
||||
/* Start with prefix REP/N/Z. */
|
||||
if (isPrefixed && (instFlags & (INST_PRE_REPNZ | INST_PRE_REP))) {
|
||||
if ((instFlags & INST_PRE_REPNZ) && (ps->decodedPrefixes & INST_PRE_REPNZ)) {
|
||||
ps->usedPrefixes |= INST_PRE_REPNZ;
|
||||
di->flags |= FLAG_REPNZ;
|
||||
}
|
||||
else if ((instFlags & INST_PRE_REP) && (ps->decodedPrefixes & INST_PRE_REP)) {
|
||||
ps->usedPrefixes |= INST_PRE_REP;
|
||||
di->flags |= FLAG_REP;
|
||||
}
|
||||
}
|
||||
|
||||
if (instFlags & INST_PRE_ADDR_SIZE) {
|
||||
/* If it's JeCXZ the ADDR_SIZE prefix affects them. */
|
||||
if (instFlags & INST_USE_EXMNEMONIC) {
|
||||
ps->usedPrefixes |= INST_PRE_ADDR_SIZE;
|
||||
if (effAdrSz == Decode16Bits) di->opcode = ii->opcodeId;
|
||||
else if (effAdrSz == Decode32Bits) di->opcode = ((_InstInfoEx*)ii)->opcodeId2;
|
||||
/* Ignore REX.W in 64bits, JECXZ is promoted. */
|
||||
else /* Decode64Bits */ di->opcode = ((_InstInfoEx*)ii)->opcodeId3;
|
||||
}
|
||||
|
||||
/* LOOPxx instructions are also native instruction, but they are special case ones, ADDR_SIZE prefix affects them. */
|
||||
else if (instFlags & INST_NATIVE) {
|
||||
di->opcode = ii->opcodeId;
|
||||
|
||||
/* If LOOPxx gets here from 64bits, it must be Decode32Bits because Address Size prefix is set. */
|
||||
ps->usedPrefixes |= INST_PRE_ADDR_SIZE;
|
||||
}
|
||||
|
||||
goto _SkipOpcoding;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached here the instruction was fully decoded, we located the instruction in the DB and extracted operands.
|
||||
* Use the correct mnemonic according to the DT.
|
||||
* If we are in 32 bits decoding mode it doesn't necessarily mean we will choose mnemonic2, alas,
|
||||
* it means that if there is a mnemonic2, it will be used.
|
||||
* Note:
|
||||
* If the instruction is prefixed by operand size we will format it in the non-default decoding mode!
|
||||
* So there might be a situation that an instruction of 32 bit gets formatted in 16 bits decoding mode.
|
||||
* Both ways should end up with a correct and expected formatting of the text.
|
||||
*/
|
||||
if (effOpSz == Decode32Bits) { /* Decode32Bits */
|
||||
|
||||
/* Set operand size. */
|
||||
FLAG_SET_OPSIZE(di, Decode32Bits);
|
||||
|
||||
/* Give a chance for special mnemonic instruction in 32 bits decoding. */
|
||||
if (instFlags & INST_USE_EXMNEMONIC) {
|
||||
/* Is it a special instruction which has another mnemonic for mod=11 ? */
|
||||
if (instFlags & INST_MNEMONIC_MODRM_BASED) {
|
||||
if (modrm < INST_DIVIDED_MODRM) di->opcode = ((_InstInfoEx*)ii)->opcodeId2;
|
||||
}
|
||||
else di->opcode = ((_InstInfoEx*)ii)->opcodeId2;
|
||||
ps->usedPrefixes |= INST_PRE_OP_SIZE;
|
||||
}
|
||||
}
|
||||
else if (effOpSz == Decode64Bits) { /* Decode64Bits, note that some instructions might be decoded in Decode32Bits above. */
|
||||
|
||||
/* Set operand size. */
|
||||
FLAG_SET_OPSIZE(di, Decode64Bits);
|
||||
|
||||
if (instFlags & (INST_USE_EXMNEMONIC | INST_USE_EXMNEMONIC2)) {
|
||||
/*
|
||||
* We shouldn't be here for MODRM based mnemonics with a MOD=11,
|
||||
* because they must not use REX (otherwise it will get to the wrong instruction which share same opcode).
|
||||
* See XRSTOR and XSAVEOPT.
|
||||
*/
|
||||
if ((modrm >= INST_DIVIDED_MODRM) && (instFlags & INST_MNEMONIC_MODRM_BASED)) goto _Undecodable;
|
||||
|
||||
/* Use third mnemonic, for 64 bits. */
|
||||
if ((instFlags & INST_USE_EXMNEMONIC2) && (ps->vrex & PREFIX_EX_W)) {
|
||||
ps->usedPrefixes |= INST_PRE_REX;
|
||||
di->opcode = ((_InstInfoEx*)ii)->opcodeId3;
|
||||
}
|
||||
else di->opcode = ((_InstInfoEx*)ii)->opcodeId2; /* Use second mnemonic. */
|
||||
}
|
||||
}
|
||||
else { /* Decode16Bits */
|
||||
|
||||
/* Set operand size. */
|
||||
FLAG_SET_OPSIZE(di, Decode16Bits);
|
||||
|
||||
/*
|
||||
* If it's a special instruction which has two mnemonics, then use the 16 bits one + update usedPrefixes.
|
||||
* Note: use 16 bits mnemonic if that instruction supports 32 bit or 64 bit explicitly.
|
||||
*/
|
||||
if ((instFlags & (INST_USE_EXMNEMONIC | INST_32BITS | INST_64BITS)) == INST_USE_EXMNEMONIC) ps->usedPrefixes |= INST_PRE_OP_SIZE;
|
||||
}
|
||||
|
||||
_SkipOpcoding:
|
||||
|
||||
/* Check VEX mnemonics: */
|
||||
if (isPrefixed && (instFlags & INST_PRE_VEX) &&
|
||||
(((((_InstInfoEx*)ii)->flagsEx & INST_MNEMONIC_VEXW_BASED) && (ps->vrex & PREFIX_EX_W)) ||
|
||||
((((_InstInfoEx*)ii)->flagsEx & INST_MNEMONIC_VEXL_BASED) && (ps->vrex & PREFIX_EX_L)))) {
|
||||
di->opcode = ((_InstInfoEx*)ii)->opcodeId2;
|
||||
}
|
||||
|
||||
/* Instruction's size should include prefixes too if exist. */
|
||||
di->size = (uint8_t)(ci->code - startCode);
|
||||
/*
|
||||
* There's a limit of 15 bytes on instruction length. The only way to violate
|
||||
* this limit is by putting redundant prefixes before an instruction.
|
||||
* start points to first prefix if any, otherwise it points to instruction first byte.
|
||||
*/
|
||||
if (di->size > INST_MAXIMUM_SIZE) goto _Undecodable;
|
||||
|
||||
/* Set the unused prefixes mask, if any prefixes (not) used at all. */
|
||||
if (isPrefixed) di->unusedPrefixesMask = prefixes_set_unused_mask(ps);
|
||||
|
||||
/* Copy instruction meta. */
|
||||
di->meta = isi->meta;
|
||||
|
||||
if (ci->features & DF_FILL_EFLAGS) {
|
||||
/* Copy CPU affected flags. */
|
||||
if (isi->testedFlagsMask) CONVERT_FLAGS_TO_EFLAGS(di, isi, testedFlagsMask);
|
||||
if (isi->modifiedFlagsMask) CONVERT_FLAGS_TO_EFLAGS(di, isi, modifiedFlagsMask);
|
||||
if (isi->undefinedFlagsMask) CONVERT_FLAGS_TO_EFLAGS(di, isi, undefinedFlagsMask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instruction can still be invalid if it's total length is over 15 bytes with prefixes.
|
||||
* Up to the caller to check that.
|
||||
*/
|
||||
return DECRES_SUCCESS;
|
||||
|
||||
_Undecodable: /* If the instruction couldn't be decoded for some reason, fail. */
|
||||
/* Special case for WAIT instruction: If it's dropped as a prefix, we have to return a valid instruction! */
|
||||
if (*startCode == INST_WAIT_INDEX) {
|
||||
int delta;
|
||||
memset(di, 0, sizeof(_DInst));
|
||||
di->addr = ci->codeOffset & ci->addrMask;
|
||||
di->imm.byte = INST_WAIT_INDEX;
|
||||
di->segment = R_NONE;
|
||||
di->base = R_NONE;
|
||||
di->size = 1;
|
||||
di->opcode = I_WAIT;
|
||||
META_SET_ISC(di, ISC_INTEGER);
|
||||
|
||||
/* Fix ci because WAIT could be a prefix that failed, and ci->code is now out of sync. */
|
||||
delta = (int)(ci->code - startCode); /* How many bytes we read so far. */
|
||||
ci->codeLen += delta - 1;
|
||||
ci->code = startCode + 1;
|
||||
/* codeOffset is fixed outside. */
|
||||
|
||||
return DECRES_SUCCESS;
|
||||
}
|
||||
|
||||
/* Mark that we didn't manage to decode the instruction well, caller will drop it. */
|
||||
return DECRES_INPUTERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_internal
|
||||
*
|
||||
* supportOldIntr - Since now we work with new structure instead of the old _DecodedInst, we are still interested in backward compatibility.
|
||||
* So although, the array is now of type _DInst, we want to read it in jumps of the old array element's size.
|
||||
* This is in order to save memory allocation for conversion between the new and the old structures.
|
||||
* It really means we can do the conversion in-place now.
|
||||
*/
|
||||
_DecodeResult decode_internal(_CodeInfo* _ci, int supportOldIntr, _DInst result[], unsigned int maxResultCount, unsigned int* usedInstructionsCount)
|
||||
{
|
||||
_CodeInfo ci = *_ci; /* A working copy, we don't touch user's _ci except OUT params. */
|
||||
_PrefixState ps;
|
||||
/* Bookkeep these from ci below, as it makes things way simpler. */
|
||||
const uint8_t* code;
|
||||
int codeLen;
|
||||
_OffsetType codeOffset;
|
||||
|
||||
_DecodeResult ret = DECRES_SUCCESS;
|
||||
|
||||
/* Current working decoded instruction in results. */
|
||||
_DInst* pdi = (_DInst*)&result[0]; /* There's always a room for at least one slot, checked earlier. */
|
||||
_DInst* maxResultAddr;
|
||||
|
||||
unsigned int features = ci.features;
|
||||
|
||||
unsigned int diStructSize;
|
||||
/* Use next entry. */
|
||||
#ifndef DISTORM_LIGHT
|
||||
if (supportOldIntr) {
|
||||
diStructSize = sizeof(_DecodedInst);
|
||||
maxResultAddr = (_DInst*)((size_t)&result[0] + (maxResultCount * sizeof(_DecodedInst)));
|
||||
}
|
||||
else
|
||||
#endif /* DISTORM_LIGHT */
|
||||
{
|
||||
diStructSize = sizeof(_DInst);
|
||||
maxResultAddr = &result[maxResultCount];
|
||||
}
|
||||
|
||||
ci.addrMask = (_OffsetType)-1;
|
||||
|
||||
#ifdef DISTORM_LIGHT
|
||||
supportOldIntr; /* Unreferenced. */
|
||||
|
||||
/*
|
||||
* Only truncate address if we are using the decompose interface.
|
||||
* Otherwise, we use the textual interface which needs full addresses for formatting bytes output.
|
||||
* So distorm_format will truncate later.
|
||||
*/
|
||||
if (features & DF_MAXIMUM_ADDR32) ci.addrMask = 0xffffffff;
|
||||
else if (features & DF_MAXIMUM_ADDR16) ci.addrMask = 0xffff;
|
||||
#endif
|
||||
|
||||
ps.count = 1; /* Force zero'ing ps below. */
|
||||
|
||||
/* Decode instructions as long as we have what to decode/enough room in entries. */
|
||||
while (ci.codeLen > 0) {
|
||||
code = ci.code;
|
||||
codeLen = ci.codeLen;
|
||||
codeOffset = ci.codeOffset;
|
||||
|
||||
if (ps.count) memset(&ps, 0, sizeof(ps));
|
||||
|
||||
/**** INSTRUCTION DECODING NEXT: ****/
|
||||
|
||||
/* Make sure we didn't run out of output entries. */
|
||||
if (pdi >= maxResultAddr) {
|
||||
ret = DECRES_MEMORYERR;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = decode_inst(&ci, &ps, code, pdi);
|
||||
/* decode_inst keeps track (only if successful!) for code and codeLen but ignores codeOffset, fix it here. */
|
||||
ci.codeOffset += pdi->size;
|
||||
|
||||
if (ret == DECRES_SUCCESS) {
|
||||
|
||||
if (features & (DF_SINGLE_BYTE_STEP | DF_RETURN_FC_ONLY | DF_STOP_ON_PRIVILEGED | DF_STOP_ON_FLOW_CONTROL)) {
|
||||
|
||||
/* Sync codeinfo, remember that currently it points to beginning of the instruction and prefixes if any. */
|
||||
if (features & DF_SINGLE_BYTE_STEP) {
|
||||
ci.code = code + 1;
|
||||
ci.codeLen = codeLen - 1;
|
||||
ci.codeOffset = codeOffset + 1;
|
||||
}
|
||||
|
||||
/* See if we need to filter this instruction. */
|
||||
if ((features & DF_RETURN_FC_ONLY) && (META_GET_FC(pdi->meta) == FC_NONE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check whether we need to stop on any feature. */
|
||||
if ((features & DF_STOP_ON_PRIVILEGED) && (FLAG_GET_PRIVILEGED(pdi->flags))) {
|
||||
pdi = (_DInst*)((char*)pdi + diStructSize);
|
||||
break; /* ret = DECRES_SUCCESS; */
|
||||
}
|
||||
|
||||
if (features & DF_STOP_ON_FLOW_CONTROL) {
|
||||
unsigned int mfc = META_GET_FC(pdi->meta);
|
||||
if (mfc && (((features & DF_STOP_ON_CALL) && (mfc == FC_CALL)) ||
|
||||
((features & DF_STOP_ON_RET) && (mfc == FC_RET)) ||
|
||||
((features & DF_STOP_ON_SYS) && (mfc == FC_SYS)) ||
|
||||
((features & DF_STOP_ON_UNC_BRANCH) && (mfc == FC_UNC_BRANCH)) ||
|
||||
((features & DF_STOP_ON_CND_BRANCH) && (mfc == FC_CND_BRANCH)) ||
|
||||
((features & DF_STOP_ON_INT) && (mfc == FC_INT)) ||
|
||||
((features & DF_STOP_ON_CMOV) && (mfc == FC_CMOV)) ||
|
||||
((features & DF_STOP_ON_HLT) && (mfc == FC_HLT)))) {
|
||||
pdi = (_DInst*)((char*)pdi + diStructSize);
|
||||
break; /* ret = DECRES_SUCCESS; */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate at least one more entry to use, for the next instruction. */
|
||||
pdi = (_DInst*)((char*)pdi + diStructSize);
|
||||
}
|
||||
else { /* ret == DECRES_INPUTERR */
|
||||
|
||||
/* Handle failure of decoding last instruction. */
|
||||
if ((!(features & DF_RETURN_FC_ONLY))) {
|
||||
memset(pdi, 0, sizeof(_DInst));
|
||||
pdi->flags = FLAG_NOT_DECODABLE;
|
||||
pdi->imm.byte = *code;
|
||||
pdi->size = 1;
|
||||
pdi->addr = codeOffset & ci.addrMask;
|
||||
pdi = (_DInst*)((char*)pdi + diStructSize);
|
||||
|
||||
/* If an instruction wasn't decoded then stop on undecodeable if set. */
|
||||
if (features & DF_STOP_ON_UNDECODEABLE) {
|
||||
ret = DECRES_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip a single byte in case of a failure and retry instruction. */
|
||||
ci.code = code + 1;
|
||||
ci.codeLen = codeLen - 1;
|
||||
ci.codeOffset = codeOffset + 1;
|
||||
|
||||
/* Reset return value. */
|
||||
ret = DECRES_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set OUT params. */
|
||||
*usedInstructionsCount = (unsigned int)(((size_t)pdi - (size_t)result) / (size_t)diStructSize);
|
||||
_ci->nextOffset = ci.codeOffset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
decoder.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DECODER_H
|
||||
#define DECODER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef unsigned int _iflags;
|
||||
|
||||
_DecodeResult decode_internal(_CodeInfo* _ci, int supportOldIntr, _DInst result[], unsigned int maxResultCount, unsigned int* usedInstructionsCount);
|
||||
|
||||
#endif /* DECODER_H */
|
||||
@@ -0,0 +1,117 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DISASM_H
|
||||
#define DISASM_H 1
|
||||
|
||||
#ifdef DISASM_DISTORM
|
||||
#include <distorm.h>
|
||||
#include <mnemonics.h>
|
||||
|
||||
typedef struct funchook_disasm {
|
||||
funchook_t *funchook;
|
||||
_CodeInfo ci;
|
||||
unsigned int idx;
|
||||
unsigned int cnt;
|
||||
_DInst dis[MAX_INSN_CHECK_SIZE];
|
||||
} funchook_disasm_t;
|
||||
typedef _DInst funchook_insn_t;
|
||||
|
||||
#define funchook_insn_size(insn) ((insn)->size)
|
||||
#define funchook_insn_address(insn) ((size_t)(insn)->addr)
|
||||
#define funchook_insn_branch_address(insn) ((size_t)INSTRUCTION_GET_TARGET(insn))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DISASM_CAPSTONE
|
||||
#include <capstone/capstone.h>
|
||||
|
||||
typedef struct funchook_disasm {
|
||||
funchook_t *funchook;
|
||||
csh handle;
|
||||
cs_insn *insns;
|
||||
size_t index;
|
||||
size_t count;
|
||||
} funchook_disasm_t;
|
||||
|
||||
typedef cs_insn funchook_insn_t;
|
||||
|
||||
#define funchook_insn_size(insn) ((insn)->size / sizeof(insn_t))
|
||||
#define funchook_insn_address(insn) ((size_t)(insn)->address)
|
||||
#define funchook_insn_branch_address(insn) ((size_t)(insn)->detail->x86.operands[0].imm)
|
||||
#endif
|
||||
|
||||
#ifdef DISASM_ZYDIS
|
||||
#include <Zydis/Zydis.h>
|
||||
|
||||
typedef struct {
|
||||
ZydisDecodedInstruction insn;
|
||||
size_t next_address;
|
||||
} funchook_insn_t;
|
||||
|
||||
typedef struct funchook_disasm {
|
||||
funchook_t *funchook;
|
||||
ZydisDecoder decoder;
|
||||
ZydisFormatter formatter;
|
||||
funchook_insn_t insn;
|
||||
const uint8_t *code;
|
||||
const uint8_t *code_end;
|
||||
} funchook_disasm_t;
|
||||
|
||||
#define funchook_insn_size(insn) ((insn)->insn.length)
|
||||
#define funchook_insn_address(insn) ((insn)->next_address - (insn)->insn.length)
|
||||
#define funchook_insn_branch_address(insn) ((insn)->next_address + (intptr_t)(insn)->insn.raw.imm[0].value.s)
|
||||
|
||||
#endif
|
||||
|
||||
#define FUNCHOOK_ERROR_END_OF_INSTRUCTION -2
|
||||
|
||||
int funchook_disasm_init(funchook_disasm_t *disasm, funchook_t *funchook, const insn_t *code, size_t code_size, size_t address);
|
||||
void funchook_disasm_cleanup(funchook_disasm_t *disasm);
|
||||
int funchook_disasm_next(funchook_disasm_t *disasm, const funchook_insn_t **next_insn);
|
||||
void funchook_disasm_log_instruction(funchook_disasm_t *disasm, const funchook_insn_t *insn);
|
||||
|
||||
#if defined(CPU_ARM64)
|
||||
funchook_insn_info_t funchook_disasm_arm64_insn_info(funchook_disasm_t *disasm, const funchook_insn_t *insn);
|
||||
#endif
|
||||
|
||||
#if defined(CPU_X86) || defined(CPU_X86_64)
|
||||
/* RIP-relative address information */
|
||||
typedef struct {
|
||||
insn_t *addr; /* absolute address */
|
||||
intptr_t raddr; /* relative address */
|
||||
int offset;
|
||||
int size;
|
||||
} rip_relative_t;
|
||||
|
||||
void funchook_disasm_x86_rip_relative(funchook_disasm_t *disasm, const funchook_insn_t *insn, rip_relative_t *rel_disp, rip_relative_t *rel_imm);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,310 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "funchook_internal.h"
|
||||
#include "disasm.h"
|
||||
|
||||
int funchook_disasm_init(funchook_disasm_t *disasm, funchook_t *funchook, const uint8_t *code, size_t code_size, size_t address)
|
||||
{
|
||||
_DecodeResult decres;
|
||||
|
||||
disasm->funchook = funchook;
|
||||
disasm->ci.codeOffset = address;
|
||||
disasm->ci.code = code;
|
||||
disasm->ci.codeLen = (int)code_size;
|
||||
#ifdef CPU_X86_64
|
||||
disasm->ci.dt = Decode64Bits;
|
||||
#else
|
||||
disasm->ci.dt = Decode32Bits;
|
||||
#endif
|
||||
disasm->ci.features = DF_STOP_ON_RET;
|
||||
disasm->idx = 0;
|
||||
decres = distorm_decompose64(&disasm->ci, disasm->dis, MAX_INSN_CHECK_SIZE, &disasm->cnt);
|
||||
if (decres != DECRES_SUCCESS) {
|
||||
funchook_set_error_message(funchook, "Disassemble Error: %d", decres);
|
||||
return FUNCHOOK_ERROR_DISASSEMBLY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void funchook_disasm_cleanup(funchook_disasm_t *disasm)
|
||||
{
|
||||
/* no need to free resources */
|
||||
}
|
||||
|
||||
int funchook_disasm_next(funchook_disasm_t *disasm, const funchook_insn_t **next_insn)
|
||||
{
|
||||
if (disasm->idx < disasm->cnt) {
|
||||
*next_insn = &disasm->dis[disasm->idx++];
|
||||
return 0;
|
||||
} else {
|
||||
return FUNCHOOK_ERROR_END_OF_INSTRUCTION;
|
||||
}
|
||||
}
|
||||
|
||||
void funchook_disasm_log_instruction(funchook_disasm_t *disasm, const funchook_insn_t *insn)
|
||||
{
|
||||
_DecodedInst dec;
|
||||
distorm_format64(&disasm->ci, insn, &dec);
|
||||
funchook_log(disasm->funchook, " "ADDR_FMT" (%02d) %-24s %s%s%s\n",
|
||||
(size_t)dec.offset, dec.size, (char*)dec.instructionHex.p,
|
||||
(char*)dec.mnemonic.p, dec.operands.length != 0 ? " " : "", (char*)dec.operands.p);
|
||||
}
|
||||
|
||||
void funchook_disasm_x86_rip_relative(funchook_disasm_t *disasm, const funchook_insn_t *insn, rip_relative_t *rel_disp, rip_relative_t *rel_imm)
|
||||
{
|
||||
int opsiz = 0;
|
||||
int disp_offset = 0;
|
||||
int imm_offset = 0;
|
||||
int i;
|
||||
|
||||
memset(rel_disp, 0, sizeof(rip_relative_t));
|
||||
memset(rel_imm, 0, sizeof(rip_relative_t));
|
||||
|
||||
/*
|
||||
* Estimate total operand size and RIP-relative address offsets.
|
||||
*/
|
||||
for (i = 0; i < OPERANDS_NO && insn->ops[i].type != O_NONE; i++) {
|
||||
const _Operand *op = &insn->ops[i];
|
||||
switch (op->type) {
|
||||
case O_IMM:
|
||||
opsiz += op->size / 8;
|
||||
break;
|
||||
case O_PC:
|
||||
rel_imm->addr = (uint8_t*)(size_t)(insn->addr + insn->size + insn->imm.addr);
|
||||
rel_imm->raddr = (intptr_t)insn->imm.addr;
|
||||
rel_imm->size = op->size;
|
||||
imm_offset = opsiz;
|
||||
opsiz += op->size / 8;
|
||||
break;
|
||||
case O_SMEM:
|
||||
if (insn->dispSize != 0 && op->index == R_RIP) {
|
||||
rel_disp->addr = (uint8_t*)(size_t)(insn->addr + insn->size + insn->disp);
|
||||
rel_disp->raddr = (intptr_t)insn->disp;
|
||||
rel_disp->size = insn->dispSize;
|
||||
disp_offset = opsiz;
|
||||
}
|
||||
opsiz += insn->dispSize / 8;
|
||||
break;
|
||||
case O_MEM:
|
||||
case O_DISP:
|
||||
opsiz += insn->dispSize / 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (insn->opcode) {
|
||||
/* CMPSD */
|
||||
case I_CMPEQSD:
|
||||
case I_CMPLTSD:
|
||||
case I_CMPLESD:
|
||||
case I_CMPUNORDSD:
|
||||
case I_CMPNEQSD:
|
||||
case I_CMPNLTSD:
|
||||
case I_CMPNLESD:
|
||||
case I_CMPORDSD:
|
||||
case I_VCMPEQSD:
|
||||
case I_VCMPLTSD:
|
||||
case I_VCMPLESD:
|
||||
case I_VCMPUNORDSD:
|
||||
case I_VCMPNEQSD:
|
||||
case I_VCMPNLTSD:
|
||||
case I_VCMPNLESD:
|
||||
case I_VCMPORDSD:
|
||||
case I_VCMPEQ_UQSD:
|
||||
case I_VCMPNGESD:
|
||||
case I_VCMPNGTSD:
|
||||
case I_VCMPFALSESD:
|
||||
case I_VCMPNEQ_OQSD:
|
||||
case I_VCMPGESD:
|
||||
case I_VCMPGTSD:
|
||||
case I_VCMPTRUESD:
|
||||
case I_VCMPEQ_OSSD:
|
||||
case I_VCMPLT_OQSD:
|
||||
case I_VCMPLE_OQSD:
|
||||
case I_VCMPUNORD_SSD:
|
||||
case I_VCMPNEQ_USSD:
|
||||
case I_VCMPNLT_UQSD:
|
||||
case I_VCMPNLE_UQSD:
|
||||
case I_VCMPORD_SSD:
|
||||
case I_VCMPEQ_USSD:
|
||||
case I_VCMPNGE_UQSD:
|
||||
case I_VCMPNGT_UQSD:
|
||||
case I_VCMPFALSE_OSSD:
|
||||
case I_VCMPNEQ_OSSD:
|
||||
case I_VCMPGE_OQSD:
|
||||
case I_VCMPGT_OQSD:
|
||||
/* CMPSS */
|
||||
case I_CMPEQSS:
|
||||
case I_CMPLTSS:
|
||||
case I_CMPLESS:
|
||||
case I_CMPUNORDSS:
|
||||
case I_CMPNEQSS:
|
||||
case I_CMPNLTSS:
|
||||
case I_CMPNLESS:
|
||||
case I_CMPORDSS:
|
||||
case I_VCMPEQSS:
|
||||
case I_VCMPLTSS:
|
||||
case I_VCMPLESS:
|
||||
case I_VCMPUNORDSS:
|
||||
case I_VCMPNEQSS:
|
||||
case I_VCMPNLTSS:
|
||||
case I_VCMPNLESS:
|
||||
case I_VCMPORDSS:
|
||||
case I_VCMPEQ_UQSS:
|
||||
case I_VCMPNGESS:
|
||||
case I_VCMPNGTSS:
|
||||
case I_VCMPFALSESS:
|
||||
case I_VCMPNEQ_OQSS:
|
||||
case I_VCMPGESS:
|
||||
case I_VCMPGTSS:
|
||||
case I_VCMPTRUESS:
|
||||
case I_VCMPEQ_OSSS:
|
||||
case I_VCMPLT_OQSS:
|
||||
case I_VCMPLE_OQSS:
|
||||
case I_VCMPUNORD_SSS:
|
||||
case I_VCMPNEQ_USSS:
|
||||
case I_VCMPNLT_UQSS:
|
||||
case I_VCMPNLE_UQSS:
|
||||
case I_VCMPORD_SSS:
|
||||
case I_VCMPEQ_USSS:
|
||||
case I_VCMPNGE_UQSS:
|
||||
case I_VCMPNGT_UQSS:
|
||||
case I_VCMPFALSE_OSSS:
|
||||
case I_VCMPNEQ_OSSS:
|
||||
case I_VCMPGE_OQSS:
|
||||
case I_VCMPGT_OQSS:
|
||||
/* CMPPD */
|
||||
case I_CMPEQPD:
|
||||
case I_CMPLTPD:
|
||||
case I_CMPLEPD:
|
||||
case I_CMPUNORDPD:
|
||||
case I_CMPNEQPD:
|
||||
case I_CMPNLTPD:
|
||||
case I_CMPNLEPD:
|
||||
case I_CMPORDPD:
|
||||
case I_VCMPEQPD:
|
||||
case I_VCMPLTPD:
|
||||
case I_VCMPLEPD:
|
||||
case I_VCMPUNORDPD:
|
||||
case I_VCMPNEQPD:
|
||||
case I_VCMPNLTPD:
|
||||
case I_VCMPNLEPD:
|
||||
case I_VCMPORDPD:
|
||||
case I_VCMPEQ_UQPD:
|
||||
case I_VCMPNGEPD:
|
||||
case I_VCMPNGTPD:
|
||||
case I_VCMPFALSEPD:
|
||||
case I_VCMPNEQ_OQPD:
|
||||
case I_VCMPGEPD:
|
||||
case I_VCMPGTPD:
|
||||
case I_VCMPTRUEPD:
|
||||
case I_VCMPEQ_OSPD:
|
||||
case I_VCMPLT_OQPD:
|
||||
case I_VCMPLE_OQPD:
|
||||
case I_VCMPUNORD_SPD:
|
||||
case I_VCMPNEQ_USPD:
|
||||
case I_VCMPNLT_UQPD:
|
||||
case I_VCMPNLE_UQPD:
|
||||
case I_VCMPORD_SPD:
|
||||
case I_VCMPEQ_USPD:
|
||||
case I_VCMPNGE_UQPD:
|
||||
case I_VCMPNGT_UQPD:
|
||||
case I_VCMPFALSE_OSPD:
|
||||
case I_VCMPNEQ_OSPD:
|
||||
case I_VCMPGE_OQPD:
|
||||
case I_VCMPGT_OQPD:
|
||||
case I_VCMPTRUE_USPD:
|
||||
/* CMPPS */
|
||||
case I_CMPEQPS:
|
||||
case I_CMPLTPS:
|
||||
case I_CMPLEPS:
|
||||
case I_CMPUNORDPS:
|
||||
case I_CMPNEQPS:
|
||||
case I_CMPNLTPS:
|
||||
case I_CMPNLEPS:
|
||||
case I_CMPORDPS:
|
||||
case I_VCMPEQPS:
|
||||
case I_VCMPLTPS:
|
||||
case I_VCMPLEPS:
|
||||
case I_VCMPUNORDPS:
|
||||
case I_VCMPNEQPS:
|
||||
case I_VCMPNLTPS:
|
||||
case I_VCMPNLEPS:
|
||||
case I_VCMPORDPS:
|
||||
case I_VCMPEQ_UQPS:
|
||||
case I_VCMPNGEPS:
|
||||
case I_VCMPNGTPS:
|
||||
case I_VCMPFALSEPS:
|
||||
case I_VCMPNEQ_OQPS:
|
||||
case I_VCMPGEPS:
|
||||
case I_VCMPGTPS:
|
||||
case I_VCMPTRUEPS:
|
||||
case I_VCMPEQ_OSPS:
|
||||
case I_VCMPLT_OQPS:
|
||||
case I_VCMPLE_OQPS:
|
||||
case I_VCMPUNORD_SPS:
|
||||
case I_VCMPNEQ_USPS:
|
||||
case I_VCMPNLT_UQPS:
|
||||
case I_VCMPNLE_UQPS:
|
||||
case I_VCMPORD_SPS:
|
||||
case I_VCMPEQ_USPS:
|
||||
case I_VCMPNGE_UQPS:
|
||||
case I_VCMPNGT_UQPS:
|
||||
case I_VCMPFALSE_OSPS:
|
||||
case I_VCMPNEQ_OSPS:
|
||||
case I_VCMPGE_OQPS:
|
||||
case I_VCMPGT_OQPS:
|
||||
case I_VCMPTRUE_USPS:
|
||||
/* ohters */
|
||||
case I_PI2FD:
|
||||
case I_PI2FW:
|
||||
case I_PF2IW:
|
||||
case I_PF2ID:
|
||||
case I_PSWAPD:
|
||||
case I_VPBLENDVB:
|
||||
case I_PFNACC:
|
||||
opsiz++;
|
||||
}
|
||||
|
||||
if (rel_disp->size > 0) {
|
||||
rel_disp->offset = insn->size - opsiz + disp_offset;
|
||||
funchook_log(disasm->funchook, " ip-relative %08x, absolute address= "ADDR_FMT", offset=%d, size=%d\n",
|
||||
(uint32_t)rel_disp->raddr, (size_t)rel_disp->addr, rel_disp->offset, rel_disp->size);
|
||||
}
|
||||
if (rel_imm->size > 0) {
|
||||
rel_imm->offset = insn->size - opsiz + imm_offset;
|
||||
funchook_log(disasm->funchook, " ip-relative %08x, absolute address= "ADDR_FMT", offset=%d, size=%d\n",
|
||||
(uint32_t)rel_imm->raddr, (size_t)rel_imm->addr, rel_imm->offset, rel_imm->size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
distorm.c
|
||||
|
||||
diStorm3 C Library Interface
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "../include/distorm.h"
|
||||
#include "config.h"
|
||||
#include "decoder.h"
|
||||
#include "x86defs.h"
|
||||
#include "textdefs.h"
|
||||
#include "wstring.h"
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
/* C DLL EXPORTS */
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
_DLLEXPORT_ _DecodeResult distorm_decompose64(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount)
|
||||
#else
|
||||
_DLLEXPORT_ _DecodeResult distorm_decompose32(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount)
|
||||
#endif
|
||||
{
|
||||
if (usedInstructionsCount == NULL) {
|
||||
return DECRES_SUCCESS;
|
||||
}
|
||||
|
||||
if ((ci == NULL) ||
|
||||
(ci->codeLen < 0) ||
|
||||
((unsigned)ci->dt > (unsigned)Decode64Bits) ||
|
||||
(ci->code == NULL) ||
|
||||
(result == NULL) ||
|
||||
(maxInstructions == 0) ||
|
||||
((ci->features & (DF_MAXIMUM_ADDR16 | DF_MAXIMUM_ADDR32)) == (DF_MAXIMUM_ADDR16 | DF_MAXIMUM_ADDR32)))
|
||||
{
|
||||
return DECRES_INPUTERR;
|
||||
}
|
||||
|
||||
return decode_internal(ci, FALSE, result, maxInstructions, usedInstructionsCount);
|
||||
}
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
/* Helper function to concatenate an explicit size when it's unknown from the operands. */
|
||||
static void distorm_format_size(unsigned char** str, const _DInst* di, int opNum)
|
||||
{
|
||||
int isSizingRequired = 0;
|
||||
/*
|
||||
* We only have to output the size explicitly if it's not clear from the operands.
|
||||
* For example:
|
||||
* mov al, [0x1234] -> The size is 8, we know it from the AL register operand.
|
||||
* mov [0x1234], 0x11 -> Now we don't know the size. Pam pam pam
|
||||
*
|
||||
* If given operand number is higher than 2, then output the size anyways.
|
||||
*/
|
||||
isSizingRequired = ((opNum >= 2) || ((opNum == 0) && (di->ops[0].type != O_REG) && (di->ops[1].type != O_REG)));
|
||||
|
||||
/* Still not sure? Try some special instructions. */
|
||||
if (!isSizingRequired) {
|
||||
/*
|
||||
* INS/OUTS are exception, because DX is a port specifier and not a real src/dst register.
|
||||
* A few exceptions that always requires sizing:
|
||||
* MOVZX, MOVSX, MOVSXD.
|
||||
* ROL, ROR, RCL, RCR, SHL, SHR, SAL, SAR.
|
||||
* SHLD, SHRD.
|
||||
* CVTSI2SS is also an exception.
|
||||
*/
|
||||
switch (di->opcode)
|
||||
{
|
||||
case I_INS:
|
||||
case I_OUTS:
|
||||
case I_MOVZX:
|
||||
case I_MOVSX:
|
||||
case I_MOVSXD:
|
||||
case I_ROL:
|
||||
case I_ROR:
|
||||
case I_RCL:
|
||||
case I_RCR:
|
||||
case I_SHL:
|
||||
case I_SHR:
|
||||
case I_SAL:
|
||||
case I_SAR:
|
||||
case I_SHLD:
|
||||
case I_SHRD:
|
||||
case I_CVTSI2SS:
|
||||
isSizingRequired = 1;
|
||||
break;
|
||||
default: /* Instruction doesn't require sizing. */ break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSizingRequired)
|
||||
{
|
||||
/*case 0: break; OT_MEM's unknown size. */
|
||||
switch (di->ops[opNum].size / 8)
|
||||
{
|
||||
case 1: strcat_WS(*str, "BYTE ", 8, 5); break;
|
||||
case 2: strcat_WS(*str, "WORD ", 8, 5); break;
|
||||
case 4: strcat_WS(*str, "DWORD ", 8, 6); break;
|
||||
case 8: strcat_WS(*str, "QWORD ", 8, 6); break;
|
||||
case 10: strcat_WS(*str, "TBYTE ", 8, 6); break;
|
||||
case 16: strcat_WS(*str, "DQWORD ", 8, 7); break;
|
||||
case 32: strcat_WS(*str, "YWORD ", 8, 6); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void distorm_format_signed_disp(unsigned char** str, const _DInst* di, uint64_t addrMask)
|
||||
{
|
||||
int64_t tmpDisp64;
|
||||
|
||||
if (di->dispSize) {
|
||||
if (((int64_t)di->disp < 0)) {
|
||||
chrcat_WS(*str, MINUS_DISP_CHR);
|
||||
tmpDisp64 = -(int64_t)di->disp;
|
||||
tmpDisp64 &= addrMask; /* Verify only for neg numbers. */
|
||||
}
|
||||
else {
|
||||
chrcat_WS(*str, PLUS_DISP_CHR);
|
||||
tmpDisp64 = di->disp;
|
||||
}
|
||||
str_int(str, tmpDisp64);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t prefixTable[6][8] = { "", "LOCK ", "REPNZ ", "REPNZ ", "REP ", "REPZ " };
|
||||
static unsigned int prefixSizesTable[6] = { 0, 5, 6, 6, 4, 5 };
|
||||
static uint8_t suffixTable[10] = { 0, 'B', 'W', 0, 'D', 0, 0, 0, 'Q' };
|
||||
|
||||
/* WARNING: This function is written carefully to be able to work with same input and output buffer in-place! */
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
_DLLEXPORT_ void distorm_format64(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result)
|
||||
#else
|
||||
_DLLEXPORT_ void distorm_format32(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result)
|
||||
#endif
|
||||
{
|
||||
unsigned char* str;
|
||||
int64_t tmpDisp64;
|
||||
uint64_t addrMask = (uint64_t)-1;
|
||||
const _WMnemonic* mnemonic;
|
||||
int suffixSize = -1;
|
||||
unsigned int i;
|
||||
|
||||
/* Set address mask, when default is for 64bits addresses. */
|
||||
if (ci->features & DF_USE_ADDR_MASK) addrMask = ci->addrMask;
|
||||
else {
|
||||
if (ci->features & DF_MAXIMUM_ADDR32) addrMask = 0xffffffff;
|
||||
else if (ci->features & DF_MAXIMUM_ADDR16) addrMask = 0xffff;
|
||||
}
|
||||
|
||||
/* Gotta have full address for (di->addr - ci->codeOffset) to work in all modes. */
|
||||
str_hex(&result->instructionHex, (const uint8_t*)&ci->code[(unsigned int)(di->addr - ci->codeOffset)], di->size);
|
||||
|
||||
if ((int)((int16_t)di->flags) == -1) {
|
||||
/* In-place considerations: DI is RESULT. Deref fields first. */
|
||||
unsigned int size = di->size;
|
||||
unsigned int byte = di->imm.byte;
|
||||
_OffsetType offset = di->addr & addrMask;
|
||||
|
||||
result->offset = offset;
|
||||
result->size = size;
|
||||
str = (unsigned char*)&result->mnemonic.p;
|
||||
strcat_WS(str, "DB ", 4, 3);
|
||||
str_int(&str, byte);
|
||||
strfinalize_WS(result->mnemonic, str);
|
||||
*(uint64_t*)&result->operands = 0; /* Clears length and the string at once. */
|
||||
return; /* Skip to next instruction. */
|
||||
}
|
||||
|
||||
str = (unsigned char*)&result->operands.p;
|
||||
|
||||
/* Special treatment for String (movs, cmps, stos, lods, scas) instructions. */
|
||||
if ((di->opcode >= I_MOVS) && (di->opcode <= I_SCAS)) {
|
||||
/*
|
||||
* No operands are needed if the address size is the default one,
|
||||
* and no segment is overridden, so add the suffix letter,
|
||||
* to indicate size of operation and continue to next instruction.
|
||||
*/
|
||||
if ((SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) && (FLAG_GET_ADDRSIZE(di->flags) == ci->dt)) {
|
||||
suffixSize = di->ops[0].size / 8;
|
||||
goto skipOperands;
|
||||
}
|
||||
suffixSize = 0; /* Marks it's a string instruction. */
|
||||
}
|
||||
|
||||
for (i = 0; i < di->opsNo; i++) {
|
||||
unsigned int type = di->ops[i].type;
|
||||
if (i > 0) strcat_WS(str, ", ", 2, 2);
|
||||
if (type == O_REG) {
|
||||
strcat_WSR(&str, &_REGISTERS[di->ops[i].index]);
|
||||
}
|
||||
else if (type == O_IMM) {
|
||||
/* If the instruction is 'push', show explicit size (except byte imm). */
|
||||
if ((di->opcode == I_PUSH) && (di->ops[i].size != 8)) distorm_format_size(&str, di, i);
|
||||
/* Special fix for negative sign extended immediates. */
|
||||
if ((di->flags & FLAG_IMM_SIGNED) && (di->ops[i].size == 8) && (di->imm.sbyte < 0)) {
|
||||
chrcat_WS(str, MINUS_DISP_CHR);
|
||||
tmpDisp64 = -di->imm.sbyte;
|
||||
str_int(&str, tmpDisp64);
|
||||
}
|
||||
else {
|
||||
/* Notice signedness and size of the immediate. */
|
||||
if (di->ops[i].size == 0x20) str_int(&str, di->imm.dword);
|
||||
else str_int(&str, di->imm.qword);
|
||||
}
|
||||
}
|
||||
else if (type == O_PC) {
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
str_int(&str, (di->size + di->imm.sqword + di->addr) & addrMask);
|
||||
#else
|
||||
tmpDisp64 = ((_OffsetType)di->imm.sdword + di->addr + di->size) & (uint32_t)addrMask;
|
||||
str_int(&str, tmpDisp64);
|
||||
#endif
|
||||
}
|
||||
else if (type == O_DISP) {
|
||||
distorm_format_size(&str, di, i);
|
||||
chrcat_WS(str, OPEN_CHR);
|
||||
if (!SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) {
|
||||
strcat_WSR(&str, &_REGISTERS[SEGMENT_GET_UNSAFE(di->segment)]);
|
||||
chrcat_WS(str, SEG_OFF_CHR);
|
||||
}
|
||||
tmpDisp64 = di->disp & addrMask;
|
||||
str_int(&str, tmpDisp64);
|
||||
chrcat_WS(str, CLOSE_CHR);
|
||||
}
|
||||
else if (type == O_SMEM) {
|
||||
int isDefault;
|
||||
int segment;
|
||||
distorm_format_size(&str, di, i);
|
||||
chrcat_WS(str, OPEN_CHR);
|
||||
|
||||
segment = SEGMENT_GET(di->segment);
|
||||
isDefault = SEGMENT_IS_DEFAULT(di->segment);
|
||||
|
||||
/*
|
||||
* This is where we need to take special care for String instructions.
|
||||
* If we got here, it means we need to explicitly show their operands.
|
||||
* The problem with CMPS and MOVS is that they have two(!) memory operands.
|
||||
* So we have to complement(!) them ourselves, since the isntruction structure supplies only the segment that can be overridden.
|
||||
* And make the rest of the String operations explicit.
|
||||
* We ignore default ES/DS in 64 bits.
|
||||
* ["MOVS"], [OPT.REGI_EDI, OPT.REGI_ESI] -- DS can be overridden.
|
||||
* ["CMPS"], [OPT.REGI_ESI, OPT.REGI_EDI] -- DS can be overriden.
|
||||
*
|
||||
* suffixSize == 0 was set above for string opcode already.
|
||||
*/
|
||||
if (suffixSize == 0) {
|
||||
if (((di->opcode == I_MOVS) && (i == 0)) || ((di->opcode == I_CMPS) && (i == 1))) {
|
||||
if (ci->dt != Decode64Bits) {
|
||||
segment = R_ES;
|
||||
isDefault = FALSE;
|
||||
}
|
||||
else isDefault = TRUE;
|
||||
}
|
||||
else if (isDefault && ((di->opcode == I_MOVS) || (di->opcode == I_CMPS))) {
|
||||
if (ci->dt != Decode64Bits) {
|
||||
segment = R_DS;
|
||||
isDefault = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isDefault && (segment != R_NONE)) {
|
||||
strcat_WSR(&str, &_REGISTERS[segment]);
|
||||
chrcat_WS(str, SEG_OFF_CHR);
|
||||
}
|
||||
|
||||
strcat_WSR(&str, &_REGISTERS[di->ops[i].index]);
|
||||
|
||||
distorm_format_signed_disp(&str, di, addrMask);
|
||||
chrcat_WS(str, CLOSE_CHR);
|
||||
}
|
||||
else if (type == O_MEM) {
|
||||
distorm_format_size(&str, di, i);
|
||||
chrcat_WS(str, OPEN_CHR);
|
||||
if (!SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) {
|
||||
strcat_WSR(&str, &_REGISTERS[SEGMENT_GET_UNSAFE(di->segment)]);
|
||||
chrcat_WS(str, SEG_OFF_CHR);
|
||||
}
|
||||
if (di->base != R_NONE) {
|
||||
strcat_WSR(&str, &_REGISTERS[di->base]);
|
||||
chrcat_WS(str, PLUS_DISP_CHR);
|
||||
}
|
||||
strcat_WSR(&str, &_REGISTERS[di->ops[i].index]);
|
||||
if (di->scale != 0) {
|
||||
switch (di->scale)
|
||||
{
|
||||
case 2: strcat_WS(str, "*2", 2, 2); break;
|
||||
case 4: strcat_WS(str, "*4", 2, 2); break;
|
||||
case 8: strcat_WS(str, "*8", 2, 2); break;
|
||||
}
|
||||
}
|
||||
distorm_format_signed_disp(&str, di, addrMask);
|
||||
chrcat_WS(str, CLOSE_CHR);
|
||||
}
|
||||
else if (type == O_PTR) {
|
||||
str_int(&str, di->imm.ptr.seg);
|
||||
chrcat_WS(str, SEG_OFF_CHR);
|
||||
str_int(&str, di->imm.ptr.off);
|
||||
}
|
||||
else if (type == O_IMM1) {
|
||||
str_int(&str, di->imm.ex.i1);
|
||||
}
|
||||
else if (type == O_IMM2) {
|
||||
str_int(&str, di->imm.ex.i2);
|
||||
}
|
||||
}
|
||||
|
||||
skipOperands:
|
||||
|
||||
/* Finalize the operands string. */
|
||||
strfinalize_WS(result->operands, str);
|
||||
|
||||
/* Not used anymore.
|
||||
if (di->flags & FLAG_HINT_TAKEN) strcat_WSN(str, " ;TAKEN");
|
||||
else if (di->flags & FLAG_HINT_NOT_TAKEN) strcat_WSN(str, " ;NOT TAKEN");
|
||||
*/
|
||||
{
|
||||
/* In-place considerations: DI is RESULT. Deref fields first. */
|
||||
unsigned int opcode = di->opcode;
|
||||
unsigned int prefix = FLAG_GET_PREFIX(di->flags);
|
||||
unsigned int size = di->size;
|
||||
_OffsetType offset = di->addr & addrMask;
|
||||
str = (unsigned char*)&result->mnemonic.p;
|
||||
mnemonic = (const _WMnemonic*)&_MNEMONICS[opcode];
|
||||
|
||||
if (prefix) {
|
||||
/* REP prefix for CMPS and SCAS is really a REPZ. */
|
||||
prefix += (opcode == I_CMPS);
|
||||
prefix += (opcode == I_SCAS);
|
||||
memcpy(str, &prefixTable[prefix][0], 8);
|
||||
str += prefixSizesTable[prefix];
|
||||
}
|
||||
|
||||
/*
|
||||
* Always copy 16 bytes from the mnemonic, we have a sentinel padding so we can read past.
|
||||
* This helps the compiler to remove the call to memcpy and therefore makes this copying much faster.
|
||||
* The longest instruction is exactly 16 chars long, so we null terminate the string below.
|
||||
*/
|
||||
memcpy((int8_t*)str, mnemonic->p, 16);
|
||||
str += mnemonic->length;
|
||||
|
||||
if (suffixSize > 0) {
|
||||
*str++ = suffixTable[suffixSize];
|
||||
}
|
||||
strfinalize_WS(result->mnemonic, str);
|
||||
|
||||
result->offset = offset;
|
||||
result->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
_DLLEXPORT_ _DecodeResult distorm_decode64(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount)
|
||||
#else
|
||||
_DLLEXPORT_ _DecodeResult distorm_decode32(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount)
|
||||
#endif
|
||||
{
|
||||
_DecodeResult res;
|
||||
_CodeInfo ci;
|
||||
unsigned int i, instsCount;
|
||||
|
||||
*usedInstructionsCount = 0;
|
||||
|
||||
/* I use codeLen as a signed variable in order to ease detection of underflow... and besides - */
|
||||
if (codeLen < 0) {
|
||||
return DECRES_INPUTERR;
|
||||
}
|
||||
|
||||
if ((unsigned)dt > (unsigned)Decode64Bits) {
|
||||
return DECRES_INPUTERR;
|
||||
}
|
||||
|
||||
/* Make sure there's at least one instruction in the result buffer. */
|
||||
if ((code == NULL) || (result == NULL) || (maxInstructions == 0)) {
|
||||
return DECRES_INPUTERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to format the result into text. But the interal decoder works with the new structure of _DInst.
|
||||
* Therefore, we will pass the result array(!) from the caller and the interal decoder will fill it in with _DInst's.
|
||||
* Then we will copy each result to a temporary structure, and use it to reformat that specific result.
|
||||
*
|
||||
* This is all done to save memory allocation and to work on the same result array in-place!!!
|
||||
* It's a bit ugly, I have to admit, but worth it.
|
||||
*/
|
||||
|
||||
ci.codeOffset = codeOffset;
|
||||
ci.code = code;
|
||||
ci.codeLen = codeLen;
|
||||
ci.dt = dt;
|
||||
ci.features = DF_USE_ADDR_MASK;
|
||||
if (dt == Decode16Bits) ci.addrMask = 0xffff;
|
||||
else if (dt == Decode32Bits) ci.addrMask = 0xffffffff;
|
||||
else ci.addrMask = (_OffsetType)-1;
|
||||
|
||||
res = decode_internal(&ci, TRUE, (_DInst*)result, maxInstructions, usedInstructionsCount);
|
||||
instsCount = *usedInstructionsCount;
|
||||
for (i = 0; i < instsCount; i++) {
|
||||
/* distorm_format is optimized and can work with same input/output buffer in-place. */
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
distorm_format64(&ci, (_DInst*)&result[i], &result[i]);
|
||||
#else
|
||||
distorm_format32(&ci, (_DInst*)&result[i], &result[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
|
||||
_DLLEXPORT_ unsigned int distorm_version(void)
|
||||
{
|
||||
return __DISTORMV__;
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
#endif
|
||||
#include "funchook.h"
|
||||
#include "funchook_internal.h"
|
||||
#include "disasm.h"
|
||||
|
||||
#define FUNCHOOK_MAX_ERROR_MESSAGE_LEN 200
|
||||
|
||||
struct funchook {
|
||||
int installed;
|
||||
funchook_page_t *page_list;
|
||||
char error_message[FUNCHOOK_MAX_ERROR_MESSAGE_LEN];
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
char funchook_debug_file[PATH_MAX];
|
||||
|
||||
const size_t funchook_size = sizeof(funchook_t);
|
||||
|
||||
static size_t num_entries_in_page;
|
||||
|
||||
static void funchook_logv(funchook_t *funchook, int set_error, const char *fmt, va_list ap);
|
||||
static void funchook_log_end(funchook_t *funchook, const char *fmt, ...);
|
||||
static funchook_t *funchook_create_internal(void);
|
||||
static int funchook_prepare_internal(funchook_t *funchook, void **target_func, void *hook_func);
|
||||
static void funchook_log_trampoline(funchook_t *funchook, const insn_t *trampoline, size_t trampoline_size);
|
||||
static int funchook_install_internal(funchook_t *funchook, int flags);
|
||||
static int funchook_uninstall_internal(funchook_t *funchook, int flags);
|
||||
static int funchook_destroy_internal(funchook_t *funchook);
|
||||
static int get_page(funchook_t *funchook, funchook_page_t **page_out, uint8_t *addr, ip_displacement_t *disp);
|
||||
|
||||
static void flush_instruction_cache(void *addr, size_t size)
|
||||
{
|
||||
#if defined __GNUC__
|
||||
__builtin___clear_cache((char*)addr, (char*)addr + size);
|
||||
#elif defined WIN32
|
||||
FlushInstructionCache(GetCurrentProcess(), addr, size);
|
||||
#else
|
||||
#error unsupported OS or compiler
|
||||
#endif
|
||||
}
|
||||
|
||||
funchook_t *funchook_create(void)
|
||||
{
|
||||
funchook_t *funchook = NULL;
|
||||
|
||||
funchook_log(funchook, "Enter funchook_create()\n");
|
||||
funchook = funchook_create_internal();
|
||||
funchook_log_end(funchook, "Leave funchook_create() => %p\n", funchook);
|
||||
return funchook;
|
||||
}
|
||||
|
||||
int funchook_prepare(funchook_t *funchook, void **target_func, void *hook_func)
|
||||
{
|
||||
int rv;
|
||||
void *orig_func;
|
||||
|
||||
funchook_log(funchook, "Enter funchook_prepare(%p, %p, %p)\n", funchook, target_func, hook_func);
|
||||
orig_func = *target_func;
|
||||
rv = funchook_prepare_internal(funchook, target_func, hook_func);
|
||||
funchook_log_end(funchook, "Leave funchook_prepare(..., [%p->%p],...) => %d\n", orig_func, *target_func, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int funchook_install(funchook_t *funchook, int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
funchook_log(funchook, "Enter funchook_install(%p, 0x%x)\n", funchook, flags);
|
||||
rv = funchook_install_internal(funchook, flags);
|
||||
funchook_log_end(funchook, "Leave funchook_install() => %d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int funchook_uninstall(funchook_t *funchook, int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
funchook_log(funchook, "Enter funchook_uninstall(%p, 0x%x)\n", funchook, flags);
|
||||
rv = funchook_uninstall_internal(funchook, flags);
|
||||
funchook_log_end(NULL, "Leave funchook_uninstall() => %d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int funchook_destroy(funchook_t *funchook)
|
||||
{
|
||||
int rv;
|
||||
|
||||
funchook_log(funchook, "Enter funchook_destroy(%p)\n", funchook);
|
||||
rv = funchook_destroy_internal(funchook);
|
||||
funchook_log_end(rv == 0 ? NULL : funchook, "Leave funchook_destroy() => %d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
const char *funchook_error_message(const funchook_t *funchook)
|
||||
{
|
||||
return funchook->error_message;
|
||||
}
|
||||
|
||||
int funchook_set_debug_file(const char *name)
|
||||
{
|
||||
if (name != NULL) {
|
||||
strncpy(funchook_debug_file, name, sizeof(funchook_debug_file) - 1);
|
||||
funchook_debug_file[sizeof(funchook_debug_file) - 1] = '\0';
|
||||
} else {
|
||||
funchook_debug_file[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void funchook_log(funchook_t *funchook, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
funchook_logv(funchook, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void funchook_set_error_message(funchook_t *funchook, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(funchook->error_message, FUNCHOOK_MAX_ERROR_MESSAGE_LEN, fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
funchook_logv(funchook, 1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void funchook_logv(funchook_t *funchook, int set_error, const char *fmt, va_list ap)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (*funchook_debug_file == '\0') {
|
||||
return;
|
||||
}
|
||||
if (funchook == NULL) {
|
||||
fp = fopen(funchook_debug_file, "a");
|
||||
} else if (funchook->fp == NULL) {
|
||||
funchook->fp = fopen(funchook_debug_file, "a");
|
||||
fp = funchook->fp;
|
||||
} else {
|
||||
fp = funchook->fp;
|
||||
}
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
if (set_error) {
|
||||
fputs(" ", fp);
|
||||
}
|
||||
vfprintf(fp, fmt, ap);
|
||||
if (set_error) {
|
||||
fputc('\n', fp);
|
||||
}
|
||||
if (funchook == NULL) {
|
||||
fclose(fp);
|
||||
} else {
|
||||
fflush(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void funchook_log_end(funchook_t *funchook, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
funchook_logv(funchook, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
if (funchook != NULL && funchook->fp != NULL) {
|
||||
fclose(funchook->fp);
|
||||
funchook->fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static funchook_t *funchook_create_internal(void)
|
||||
{
|
||||
funchook_t *funchook = funchook_alloc();
|
||||
if (funchook == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (num_entries_in_page == 0) {
|
||||
#ifdef FUNCHOOK_ENTRY_AT_PAGE_BOUNDARY
|
||||
num_entries_in_page = 1;
|
||||
#else
|
||||
num_entries_in_page = (page_size - offsetof(funchook_page_t, entries)) / sizeof(funchook_entry_t);
|
||||
#endif
|
||||
funchook_log(funchook,
|
||||
#ifdef WIN32
|
||||
" allocation_unit=%"PRIuPTR"\n"
|
||||
#endif
|
||||
" page_size=%"PRIuPTR"\n"
|
||||
" num_entries_in_page=%"PRIuPTR"\n",
|
||||
#ifdef WIN32
|
||||
allocation_unit,
|
||||
#endif
|
||||
page_size, num_entries_in_page);
|
||||
}
|
||||
return funchook;
|
||||
}
|
||||
|
||||
static int funchook_prepare_internal(funchook_t *funchook, void **target_func, void *hook_func)
|
||||
{
|
||||
void *func = *target_func;
|
||||
insn_t trampoline[TRAMPOLINE_SIZE];
|
||||
size_t trampoline_size;
|
||||
ip_displacement_t disp;
|
||||
funchook_page_t *page = NULL;
|
||||
funchook_entry_t *entry;
|
||||
int rv;
|
||||
|
||||
if (funchook->installed) {
|
||||
funchook_set_error_message(funchook, "Could not modify already-installed funchook handle.");
|
||||
return FUNCHOOK_ERROR_ALREADY_INSTALLED;
|
||||
}
|
||||
func = funchook_resolve_func(funchook, func);
|
||||
rv = funchook_make_trampoline(funchook, &disp, func, trampoline, &trampoline_size);
|
||||
if (rv != 0) {
|
||||
funchook_log(funchook, " failed to make trampoline\n");
|
||||
return rv;
|
||||
}
|
||||
rv = get_page(funchook, &page, func, &disp);
|
||||
if (rv != 0) {
|
||||
funchook_log(funchook, " failed to get page\n");
|
||||
return rv;
|
||||
}
|
||||
entry = &page->entries[page->used];
|
||||
/* fill members */
|
||||
entry->target_func = func;
|
||||
entry->hook_func = hook_func;
|
||||
memcpy(entry->trampoline, trampoline, TRAMPOLINE_BYTE_SIZE);
|
||||
memcpy(entry->old_code, func, JUMP32_BYTE_SIZE);
|
||||
|
||||
funchook_fix_code(funchook, entry, &disp);
|
||||
funchook_log_trampoline(funchook, entry->trampoline, trampoline_size);
|
||||
#ifdef CPU_ARM64
|
||||
int i;
|
||||
for (i = 0; i < LITERAL_POOL_NUM; i++) {
|
||||
size_t *addr = (size_t*)(entry->trampoline + LITERAL_POOL_OFFSET + i * 2);
|
||||
if (*addr != 0) {
|
||||
funchook_log(funchook, " "ADDR_FMT" : 0x%"PRIxPTR"\n", (size_t)addr, *addr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Just in case though I think this is unnecessary. */
|
||||
flush_instruction_cache(entry->trampoline, sizeof(entry->trampoline));
|
||||
#ifdef CPU_64BIT
|
||||
flush_instruction_cache(entry->transit, sizeof(entry->transit));
|
||||
#endif
|
||||
|
||||
page->used++;
|
||||
*target_func = (void*)entry->trampoline;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void funchook_log_trampoline(funchook_t *funchook, const insn_t *trampoline, size_t trampoline_size)
|
||||
{
|
||||
funchook_disasm_t disasm;
|
||||
const funchook_insn_t *insn;
|
||||
|
||||
if (*funchook_debug_file == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
funchook_log(funchook, " Trampoline Instructions:\n");
|
||||
if (funchook_disasm_init(&disasm, funchook, trampoline, trampoline_size, (size_t)trampoline) != 0) {
|
||||
int i;
|
||||
funchook_log(funchook, " Failed to decode trampoline\n ");
|
||||
for (i = 0; i < TRAMPOLINE_SIZE; i++) {
|
||||
funchook_log(funchook, " %02x", trampoline[i]);
|
||||
}
|
||||
funchook_log(funchook, "\n");
|
||||
return;
|
||||
}
|
||||
while (funchook_disasm_next(&disasm, &insn) == 0) {
|
||||
funchook_disasm_log_instruction(&disasm, insn);
|
||||
}
|
||||
funchook_disasm_cleanup(&disasm);
|
||||
}
|
||||
|
||||
static int funchook_install_internal(funchook_t *funchook, int flags)
|
||||
{
|
||||
funchook_page_t *page;
|
||||
|
||||
if (funchook->installed) {
|
||||
return FUNCHOOK_ERROR_ALREADY_INSTALLED;
|
||||
}
|
||||
|
||||
for (page = funchook->page_list; page != NULL; page = page->next) {
|
||||
int rv = funchook_page_protect(funchook, page);
|
||||
int i;
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (i = 0; i < page->used; i++) {
|
||||
funchook_entry_t *entry = &page->entries[i];
|
||||
mem_state_t mstate;
|
||||
int rv = funchook_unprotect_begin(funchook, &mstate, entry->target_func, JUMP32_BYTE_SIZE);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
memcpy(entry->target_func, entry->new_code, JUMP32_BYTE_SIZE);
|
||||
rv = funchook_unprotect_end(funchook, &mstate);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
flush_instruction_cache(entry->target_func, JUMP32_BYTE_SIZE);
|
||||
}
|
||||
}
|
||||
funchook->installed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int funchook_uninstall_internal(funchook_t *funchook, int flags)
|
||||
{
|
||||
funchook_page_t *page;
|
||||
|
||||
if (!funchook->installed) {
|
||||
return FUNCHOOK_ERROR_NOT_INSTALLED;
|
||||
}
|
||||
|
||||
for (page = funchook->page_list; page != NULL; page = page->next) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < page->used; i++) {
|
||||
funchook_entry_t *entry = &page->entries[i];
|
||||
mem_state_t mstate;
|
||||
int rv = funchook_unprotect_begin(funchook, &mstate, entry->target_func, JUMP32_BYTE_SIZE);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
memcpy(entry->target_func, entry->old_code, JUMP32_BYTE_SIZE);
|
||||
rv = funchook_unprotect_end(funchook, &mstate);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
flush_instruction_cache(entry->target_func, JUMP32_BYTE_SIZE);
|
||||
}
|
||||
funchook_page_unprotect(funchook, page);
|
||||
}
|
||||
funchook->installed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int funchook_destroy_internal(funchook_t *funchook)
|
||||
{
|
||||
funchook_page_t *page, *page_next;
|
||||
|
||||
if (funchook == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (funchook->installed) {
|
||||
return FUNCHOOK_ERROR_ALREADY_INSTALLED;
|
||||
}
|
||||
for (page = funchook->page_list; page != NULL; page = page_next) {
|
||||
page_next = page->next;
|
||||
funchook_page_free(funchook, page);
|
||||
}
|
||||
if (funchook->fp != NULL) {
|
||||
fclose(funchook->fp);
|
||||
}
|
||||
funchook_free(funchook);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_page(funchook_t *funchook, funchook_page_t **page_out, uint8_t *addr, ip_displacement_t *disp)
|
||||
{
|
||||
funchook_page_t *page;
|
||||
int rv;
|
||||
|
||||
for (page = funchook->page_list; page != NULL; page = page->next) {
|
||||
if (page->used < num_entries_in_page && funchook_page_avail(funchook, page, page->used, addr, disp)) {
|
||||
/* Reuse allocated page. */
|
||||
*page_out = page;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rv = funchook_page_alloc(funchook, &page, addr, disp);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
page->used = 0;
|
||||
page->next = funchook->page_list;
|
||||
funchook->page_list = page;
|
||||
*page_out = page;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FUNCHOOK_H
|
||||
#define FUNCHOOK_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Only functions with FUNCHOOK_EXPORT are visible from outside of funchook.dll
|
||||
* or libfunchook.so. Others are invisible.
|
||||
*/
|
||||
#ifdef FUNCHOOK_EXPORTS
|
||||
#if defined(WIN32)
|
||||
#define FUNCHOOK_EXPORT __declspec(dllexport)
|
||||
#elif defined(__GNUC__)
|
||||
#define FUNCHOOK_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif /* FUNCHOOK_EXPORTS */
|
||||
#ifndef FUNCHOOK_EXPORT
|
||||
#define FUNCHOOK_EXPORT
|
||||
#endif
|
||||
|
||||
typedef struct funchook funchook_t;
|
||||
|
||||
#define FUNCHOOK_ERROR_INTERNAL_ERROR -1
|
||||
#define FUNCHOOK_ERROR_SUCCESS 0
|
||||
#define FUNCHOOK_ERROR_OUT_OF_MEMORY 1
|
||||
#define FUNCHOOK_ERROR_ALREADY_INSTALLED 2
|
||||
#define FUNCHOOK_ERROR_DISASSEMBLY 3
|
||||
#define FUNCHOOK_ERROR_IP_RELATIVE_OFFSET 4
|
||||
#define FUNCHOOK_ERROR_CANNOT_FIX_IP_RELATIVE 5
|
||||
#define FUNCHOOK_ERROR_FOUND_BACK_JUMP 6
|
||||
#define FUNCHOOK_ERROR_TOO_SHORT_INSTRUCTIONS 7
|
||||
#define FUNCHOOK_ERROR_MEMORY_ALLOCATION 8 /* memory allocation error */
|
||||
#define FUNCHOOK_ERROR_MEMORY_FUNCTION 9 /* other memory function errors */
|
||||
#define FUNCHOOK_ERROR_NOT_INSTALLED 10
|
||||
#define FUNCHOOK_ERROR_NO_AVAILABLE_REGISTERS 11
|
||||
|
||||
/**
|
||||
* Create a funchook handle
|
||||
*
|
||||
* @return allocated funchook handle. NULL when out-of-memory.
|
||||
*/
|
||||
FUNCHOOK_EXPORT funchook_t *funchook_create(void);
|
||||
|
||||
/**
|
||||
* Prepare hooking
|
||||
*
|
||||
* @param funchook a funchook handle created by funchook_create()
|
||||
* @param target_func function pointer to be intercepted. The pointer to trampoline function is set on success.
|
||||
* @param hook_func function pointer which is called istead of target_func
|
||||
* @return error code. one of FUNCHOOK_ERROR_*.
|
||||
*/
|
||||
FUNCHOOK_EXPORT int funchook_prepare(funchook_t *funchook, void **target_func, void *hook_func);
|
||||
|
||||
/**
|
||||
* Install hooks prepared by funchook_prepare().
|
||||
*
|
||||
* @param funchook a funchook handle created by funchook_create()
|
||||
* @param flags reserved. Set zero.
|
||||
* @return error code. one of FUNCHOOK_ERROR_*.
|
||||
*/
|
||||
FUNCHOOK_EXPORT int funchook_install(funchook_t *funchook, int flags);
|
||||
|
||||
/**
|
||||
* Uninstall hooks installed by funchook_install().
|
||||
*
|
||||
* @param funchook a funchook handle created by funchook_create()
|
||||
* @param flags reserved. Set zero.
|
||||
* @return error code. one of FUNCHOOK_ERROR_*.
|
||||
*/
|
||||
FUNCHOOK_EXPORT int funchook_uninstall(funchook_t *funchook, int flags);
|
||||
|
||||
/**
|
||||
* Destroy a funchook handle
|
||||
*
|
||||
* @param funchook a funchook handle created by funchook_create()
|
||||
* @return error code. one of FUNCHOOK_ERROR_*.
|
||||
*/
|
||||
FUNCHOOK_EXPORT int funchook_destroy(funchook_t *funchook);
|
||||
|
||||
/**
|
||||
* Get error message
|
||||
*
|
||||
* @param funchook a funchook handle created by funchook_create()
|
||||
* @return pointer to buffer containing error message
|
||||
*/
|
||||
FUNCHOOK_EXPORT const char *funchook_error_message(const funchook_t *funchook);
|
||||
|
||||
/**
|
||||
* Set log file name to debug funchook itself.
|
||||
*
|
||||
* @param name log file name
|
||||
* @return error code. one of FUNCHOOK_ERROR_*.
|
||||
*/
|
||||
FUNCHOOK_EXPORT int funchook_set_debug_file(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FUNCHOOK_INTERNAL_H
|
||||
#define FUNCHOOK_INTERNAL_H 1
|
||||
#include "funchook.h"
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||
#ifdef _WIN64
|
||||
#define PRIxPTR "I64"
|
||||
#else
|
||||
#define PRIxPTR ""
|
||||
#endif
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(arg)
|
||||
#endif
|
||||
|
||||
#define ROUND_DOWN(num, unit) ((num) & ~((unit) - 1))
|
||||
#define ROUND_UP(num, unit) (((num) + (unit) - 1) & ~((unit) - 1))
|
||||
|
||||
#if SIZEOF_VOID_P == 8
|
||||
#define ADDR_FMT "%016" PRIxPTR
|
||||
#else
|
||||
#define ADDR_FMT "%08" PRIxPTR
|
||||
#endif
|
||||
|
||||
#if defined _M_ARM64 || defined __aarch64__
|
||||
#define CPU_ARM64
|
||||
#define CPU_64BIT
|
||||
#endif
|
||||
|
||||
#if defined _M_AMD64 || defined __x86_64__
|
||||
#define CPU_X86_64
|
||||
#define CPU_64BIT
|
||||
#endif
|
||||
|
||||
#if defined _M_IX86 || defined __i686__ || defined __i386__
|
||||
#define CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(CPU_ARM64)
|
||||
#include "funchook_arm64.h"
|
||||
#endif
|
||||
#if defined(CPU_X86) || defined(CPU_X86_64)
|
||||
#include "funchook_x86.h"
|
||||
#endif
|
||||
|
||||
#define JUMP32_BYTE_SIZE (JUMP32_SIZE * sizeof(insn_t))
|
||||
#define TRAMPOLINE_BYTE_SIZE (TRAMPOLINE_SIZE * sizeof(insn_t))
|
||||
|
||||
/* This must be same with sysconf(_SC_PAGE_SIZE) on Unix
|
||||
* or the dwPageSize member of the SYSTEM_INFO structure on Windows.
|
||||
*/
|
||||
#undef PAGE_SIZE
|
||||
#define PAGE_SIZE 0x1000 /* 4k */
|
||||
|
||||
/* This must be same with the dwAllocationGranularity
|
||||
* member of the SYSTEM_INFO structure on Windows.
|
||||
*/
|
||||
#define ALLOCATION_UNIT 0x10000 /* 64k */
|
||||
|
||||
typedef struct {
|
||||
void *addr;
|
||||
size_t size;
|
||||
#ifdef WIN32
|
||||
DWORD protect;
|
||||
#endif
|
||||
} mem_state_t;
|
||||
|
||||
typedef struct funchook_page {
|
||||
#ifdef FUNCHOOK_ENTRY_AT_PAGE_BOUNDARY
|
||||
funchook_entry_t entries[1]; /* This contains at most one. */
|
||||
#endif
|
||||
struct funchook_page *next;
|
||||
uint16_t used;
|
||||
#ifndef FUNCHOOK_ENTRY_AT_PAGE_BOUNDARY
|
||||
funchook_entry_t entries[1]; /* This contains zero or more. */
|
||||
#endif
|
||||
} funchook_page_t;
|
||||
|
||||
/* Functions in funchook.c */
|
||||
extern const size_t funchook_size;
|
||||
extern char funchook_debug_file[];
|
||||
void funchook_log(funchook_t *funchook, const char *fmt, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
||||
void funchook_set_error_message(funchook_t *funchook, const char *fmt, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
||||
|
||||
/* Functions in funchook_linux.c & funchook_windows.c */
|
||||
extern const size_t page_size;
|
||||
extern const size_t allocation_unit; /* windows only */
|
||||
|
||||
funchook_t *funchook_alloc(void);
|
||||
int funchook_free(funchook_t *funchook);
|
||||
|
||||
int funchook_page_alloc(funchook_t *funchook, funchook_page_t **page_out, uint8_t *func, ip_displacement_t *disp);
|
||||
int funchook_page_free(funchook_t *funchook, funchook_page_t *page);
|
||||
int funchook_page_protect(funchook_t *funchook, funchook_page_t *page);
|
||||
int funchook_page_unprotect(funchook_t *funchook, funchook_page_t *page);
|
||||
|
||||
int funchook_unprotect_begin(funchook_t *funchook, mem_state_t *mstate, void *addr, size_t len);
|
||||
int funchook_unprotect_end(funchook_t *funchook, const mem_state_t *mstate);
|
||||
|
||||
void *funchook_resolve_func(funchook_t *funchook, void *func);
|
||||
|
||||
/* Functions in funchook_{CPU_NAME}.c */
|
||||
int funchook_make_trampoline(funchook_t *funchook, ip_displacement_t *disp, const insn_t *func, insn_t *trampoline, size_t *trampoline_size);
|
||||
int funchook_fix_code(funchook_t *funchook, funchook_entry_t *entry, const ip_displacement_t *disp);
|
||||
#ifdef CPU_X86_64
|
||||
int funchook_page_avail(funchook_t *funchook, funchook_page_t *page, int idx, uint8_t *addr, ip_displacement_t *disp);
|
||||
#else
|
||||
#define funchook_page_avail(funchook, page, idx, addr, disp) (1)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,424 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define PSAPI_VERSION 1
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include "funchook_internal.h"
|
||||
|
||||
typedef struct page_info {
|
||||
struct page_info *next;
|
||||
struct page_info *prev;
|
||||
int num_used;
|
||||
char used[1];
|
||||
} page_list_t;
|
||||
|
||||
const size_t page_size = PAGE_SIZE; /* 4K */
|
||||
const size_t allocation_unit = ALLOCATION_UNIT; /* 64K */
|
||||
|
||||
static size_t max_num_pages = ALLOCATION_UNIT / PAGE_SIZE - 1; /* 15 */
|
||||
static page_list_t page_list = {
|
||||
&page_list,
|
||||
&page_list,
|
||||
};
|
||||
|
||||
static const char *to_errmsg(DWORD err, char *buf, size_t bufsiz)
|
||||
{
|
||||
size_t len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
buf, (DWORD)bufsiz, NULL);
|
||||
if (len == 0) {
|
||||
return "Unknown Error";
|
||||
}
|
||||
if (len >= bufsiz) {
|
||||
len = bufsiz - 1;
|
||||
}
|
||||
while (len > 0 && (buf[len - 1] == '\r' || buf[len - 1] == '\n')) {
|
||||
len--;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
funchook_t *funchook_alloc(void)
|
||||
{
|
||||
size_t size = ROUND_UP(funchook_size, page_size);
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
int funchook_free(funchook_t *funchook)
|
||||
{
|
||||
VirtualFree(funchook, 0, MEM_RELEASE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reserve 64K bytes (allocation_unit) and use the first
|
||||
* 4K bytes (1 page) as the control page.
|
||||
*/
|
||||
static int alloc_page_info(funchook_t *funchook, page_list_t **pl_out, void *hint)
|
||||
{
|
||||
void *addr;
|
||||
page_list_t *pl;
|
||||
#ifdef CPU_64BIT
|
||||
void *old_hint = hint;
|
||||
while (1) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery(hint, &mbi, sizeof(mbi)) == 0) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to execute VirtualQuery (addr=%p, error=%lu(%s))",
|
||||
hint,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
funchook_log(funchook, " process map: %016I64x-%016I64x %s\n",
|
||||
(size_t)mbi.BaseAddress, (size_t)mbi.BaseAddress + mbi.RegionSize,
|
||||
(mbi.State == MEM_FREE) ? "free" : "used");
|
||||
if (mbi.State == MEM_FREE) {
|
||||
size_t addr = ROUND_UP((size_t)mbi.BaseAddress, allocation_unit);
|
||||
intptr_t diff = addr - (size_t)mbi.BaseAddress;
|
||||
if (diff >= 0) {
|
||||
if (mbi.RegionSize - diff >= allocation_unit) {
|
||||
hint = (void*)addr;
|
||||
funchook_log(funchook, " change hint address from %p to %p\n",
|
||||
old_hint, hint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hint = (void*)((size_t)mbi.BaseAddress + mbi.RegionSize);
|
||||
}
|
||||
#else
|
||||
hint = NULL;
|
||||
#endif
|
||||
pl = VirtualAlloc(hint, allocation_unit, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (pl == NULL) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to reserve memory %p (hint=%p, size=%"PRIuPTR", errro=%lu(%s))",
|
||||
pl, hint, allocation_unit,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_ALLOCATION;
|
||||
}
|
||||
funchook_log(funchook, " reserve memory %p (hint=%p, size=%"PRIuPTR")\n", pl, hint, allocation_unit);
|
||||
addr = VirtualAlloc(pl, page_size, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (addr == NULL) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to commit memory %p for read-write (hint=%p, size=%"PRIuPTR", error=%lu(%s))",
|
||||
addr, pl, page_size,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
VirtualFree(pl, 0, MEM_RELEASE);
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
funchook_log(funchook, " commit memory %p for read-write (hint=%p, size=%"PRIuPTR")\n", addr, pl, page_size);
|
||||
pl->next = page_list.next;
|
||||
pl->prev = &page_list;
|
||||
page_list.next->prev = pl;
|
||||
page_list.next = pl;
|
||||
*pl_out = pl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get one page from page_list, commit it and return it.
|
||||
*/
|
||||
int funchook_page_alloc(funchook_t *funchook, funchook_page_t **page_out, uint8_t *func, ip_displacement_t *disp)
|
||||
{
|
||||
page_list_t *pl;
|
||||
funchook_page_t *page = NULL;
|
||||
size_t i;
|
||||
|
||||
for (pl = page_list.next; pl != &page_list; pl = pl->next) {
|
||||
for (i = 0; i < max_num_pages; i++) {
|
||||
if (!pl->used[i]) {
|
||||
funchook_page_t *p = (funchook_page_t *)((size_t)pl + (i + 1) * page_size);
|
||||
if (funchook_page_avail(funchook, p, 0, func, disp)) {
|
||||
page = p;
|
||||
goto exit_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exit_loop:
|
||||
if (page == NULL) {
|
||||
/* no page_list is available. */
|
||||
int rv = alloc_page_info(funchook, &pl, func);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
i = 0;
|
||||
page = (funchook_page_t *)((size_t)pl + page_size);
|
||||
}
|
||||
if (VirtualAlloc(page, page_size, MEM_COMMIT, PAGE_READWRITE) == NULL) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to commit page %p (base=%p(used=%d), idx=%"PRIuPTR", size=%"PRIuPTR", error=%lu(%s))",
|
||||
page, pl, pl->num_used, i, page_size,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
pl->used[i] = 1;
|
||||
pl->num_used++;
|
||||
funchook_log(funchook, " commit page %p (base=%p(used=%d), idx=%"PRIuPTR", size=%"PRIuPTR")\n",
|
||||
page, pl, pl->num_used, i, page_size);
|
||||
*page_out = page;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Back to one page to page_list.
|
||||
*/
|
||||
int funchook_page_free(funchook_t *funchook, funchook_page_t *page)
|
||||
{
|
||||
page_list_t *pl = (page_list_t *)((size_t)page & ~(allocation_unit - 1));
|
||||
size_t idx = ((size_t)page - (size_t)pl) / page_size - 1;
|
||||
BOOL ok;
|
||||
|
||||
ok = VirtualFree(page, page_size, MEM_DECOMMIT);
|
||||
if (!ok) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to decommit page %p (base=%p(used=%d), idx=%"PRIuPTR", size=%"PRIuPTR", error=%lu(%s))",
|
||||
page, pl, pl->num_used, idx, page_size,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
funchook_log(funchook, " decommit page %p (base=%p(used=%d), idx=%"PRIuPTR", size=%"PRIuPTR")\n",
|
||||
page, pl, pl->num_used, idx, page_size);
|
||||
pl->num_used--;
|
||||
pl->used[idx] = 0;
|
||||
if (pl->num_used != 0) {
|
||||
return 0;
|
||||
}
|
||||
/* all pages in this allocation unit are decommitted. delete this page_list */
|
||||
pl->next->prev = pl->prev;
|
||||
pl->prev->next = pl->next;
|
||||
ok = VirtualFree(pl, 0, MEM_RELEASE);
|
||||
if (!ok) {
|
||||
DWORD err = GetLastError();
|
||||
char errbuf[128];
|
||||
|
||||
funchook_set_error_message(funchook, "Failed to release memory %p (size=%"PRIuPTR", error=%lu(%s))",
|
||||
pl, allocation_unit,
|
||||
err, to_errmsg(err, errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
funchook_log(funchook, " release memory %p (size=%"PRIuPTR")\n",
|
||||
pl, allocation_unit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int funchook_page_protect(funchook_t *funchook, funchook_page_t *page)
|
||||
{
|
||||
char errbuf[128];
|
||||
DWORD oldprot;
|
||||
BOOL ok = VirtualProtect(page, page_size, PAGE_EXECUTE_READ, &oldprot);
|
||||
|
||||
if (ok) {
|
||||
funchook_log(funchook, " protect page %p (size=%"PRIuPTR", prot=read,exec)\n",
|
||||
page, page_size);
|
||||
return 0;
|
||||
}
|
||||
funchook_set_error_message(funchook, "Failed to protect page %p (size=%"PRIuPTR", prot=read,exec, error=%lu(%s))",
|
||||
page, page_size,
|
||||
GetLastError(), to_errmsg(GetLastError(), errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
|
||||
int funchook_page_unprotect(funchook_t *funchook, funchook_page_t *page)
|
||||
{
|
||||
char errbuf[128];
|
||||
DWORD oldprot;
|
||||
BOOL ok = VirtualProtect(page, page_size, PAGE_READWRITE, &oldprot);
|
||||
|
||||
if (ok) {
|
||||
funchook_log(funchook, " unprotect page %p (size=%"PRIuPTR", prot=read,write)\n",
|
||||
page, page_size);
|
||||
return 0;
|
||||
}
|
||||
funchook_set_error_message(funchook, "Failed to unprotect page %p (size=%"PRIuPTR", prot=read,write, error=%lu(%s))",
|
||||
page, page_size,
|
||||
GetLastError(), to_errmsg(GetLastError(), errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
|
||||
int funchook_unprotect_begin(funchook_t *funchook, mem_state_t *mstate, void *start, size_t len)
|
||||
{
|
||||
char errbuf[128];
|
||||
size_t saddr = ROUND_DOWN((size_t)start, page_size);
|
||||
BOOL ok;
|
||||
|
||||
mstate->addr = (void*)saddr;
|
||||
mstate->size = len + (size_t)start - saddr;
|
||||
mstate->size = ROUND_UP(mstate->size, page_size);
|
||||
ok = VirtualProtect(mstate->addr, mstate->size, PAGE_EXECUTE_READWRITE, &mstate->protect);
|
||||
if (ok) {
|
||||
funchook_log(funchook, " unprotect memory %p (size=%"PRIuPTR") <- %p (size=%"PRIuPTR")\n",
|
||||
mstate->addr, mstate->size, start, len);
|
||||
return 0;
|
||||
}
|
||||
funchook_set_error_message(funchook, "Failed to unprotect memory %p (size=%"PRIuPTR") <- %p (size=%"PRIuPTR", error=%lu(%s))",
|
||||
mstate->addr, mstate->size, start, len,
|
||||
GetLastError(), to_errmsg(GetLastError(), errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
|
||||
int funchook_unprotect_end(funchook_t *funchook, const mem_state_t *mstate)
|
||||
{
|
||||
char errbuf[128];
|
||||
DWORD oldprot;
|
||||
BOOL ok = VirtualProtect(mstate->addr, mstate->size, mstate->protect, &oldprot);
|
||||
|
||||
if (ok) {
|
||||
funchook_log(funchook, " protect memory %p (size=%"PRIuPTR")\n",
|
||||
mstate->addr, mstate->size);
|
||||
return 0;
|
||||
}
|
||||
funchook_set_error_message(funchook, "Failed to protect memory %p (size=%"PRIuPTR", error=%lu(%s))",
|
||||
mstate->addr, mstate->size,
|
||||
GetLastError(), to_errmsg(GetLastError(), errbuf, sizeof(errbuf)));
|
||||
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
|
||||
}
|
||||
|
||||
static IMAGE_IMPORT_DESCRIPTOR *get_image_import_descriptor(HMODULE hMod, DWORD *cnt)
|
||||
{
|
||||
IMAGE_DOS_HEADER *doshdr;
|
||||
IMAGE_NT_HEADERS *nthdr;
|
||||
IMAGE_DATA_DIRECTORY *dir;
|
||||
|
||||
if (memcmp(hMod, "MZ", 2) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
doshdr = (IMAGE_DOS_HEADER*)hMod;
|
||||
nthdr = (PIMAGE_NT_HEADERS)((size_t)hMod + doshdr->e_lfanew);
|
||||
dir = &nthdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
if (dir->VirtualAddress == 0) {
|
||||
return NULL;
|
||||
}
|
||||
*cnt = dir->Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
return (IMAGE_IMPORT_DESCRIPTOR*)((size_t)hMod + dir->VirtualAddress);
|
||||
}
|
||||
|
||||
void *funchook_resolve_func(funchook_t *funchook, void *func)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
HMODULE hMod;
|
||||
BOOL ok;
|
||||
IMAGE_IMPORT_DESCRIPTOR *desc_head, *desc;
|
||||
insn_t *fn = (insn_t*)func;
|
||||
size_t pos = 0;
|
||||
DWORD cnt;
|
||||
|
||||
if (*funchook_debug_file != '\0') {
|
||||
DWORD len = GetMappedFileNameA(GetCurrentProcess(), func, path, sizeof(path));
|
||||
if (len > 0) {
|
||||
funchook_log(funchook, " func %p is in %.*s\n", func, (int)len, path);
|
||||
}
|
||||
}
|
||||
#if defined CPU_X86 || defined CPU_X86_64
|
||||
if (fn[0] == 0xe9) {
|
||||
fn = (fn + 5) + *(int*)(fn + 1);
|
||||
funchook_log(funchook, " relative jump to %p\n", fn);
|
||||
}
|
||||
if (fn[0] == 0xff && fn[1] == 0x25) {
|
||||
#ifdef CPU_X86_64
|
||||
pos = (size_t)(fn + 6) + *(int*)(fn + 2);
|
||||
#else
|
||||
pos = *(size_t*)(fn + 2);
|
||||
#endif
|
||||
funchook_log(funchook, " indirect jump to addresss at %p\n", (void*)pos);
|
||||
}
|
||||
#endif
|
||||
#if defined CPU_ARM64
|
||||
#define ADRP_XIP0 0x90000010
|
||||
#define ADRP_XIP0_MASK 0x9F00001F
|
||||
#define ADRP_XIP0_IMMLO 0x60000000
|
||||
#define ADRP_XIP0_IMMHI 0x00FFFFE0
|
||||
#define LDR_XIP0 0xF9400210
|
||||
#define LDR_XIP0_MASK 0xFFC003FF
|
||||
#define LDR_XIP0_IMM12 0x003FFC00
|
||||
#define BR_XIP0 0xD61F0200
|
||||
if ((fn[0] & ADRP_XIP0_MASK) == ADRP_XIP0 &&
|
||||
(fn[1] & LDR_XIP0_MASK) == LDR_XIP0 &&
|
||||
fn[2] == BR_XIP0) {
|
||||
// fn[0]: addrp xip0, immhi&immlo
|
||||
// fn[1]: ldr xip0, [xip0,imm12]
|
||||
// fn[2]: br xip0
|
||||
size_t addr = (size_t)fn & ~((1 << 12) - 1);
|
||||
size_t immhi = ((size_t)(fn[0] & ADRP_XIP0_IMMHI) >> 5) << (12 + 2);
|
||||
size_t immlo = ((size_t)(fn[0] & ADRP_XIP0_IMMLO) >> 29) << 12;
|
||||
size_t imm12 = ((size_t)(fn[1] & LDR_XIP0_IMM12) >> 10) << 3;
|
||||
pos = addr + immhi + immlo + imm12;
|
||||
// fprintf(stderr, "%016I64x: %08x %08x %08x : %I64x %I64x %I64x %I64x\n", (size_t)fn, fn[0], fn[1], fn[2], addr, immhi, immlo, imm12);
|
||||
funchook_log(funchook, " indirect jump to addresss at %p\n", (void*)pos);
|
||||
}
|
||||
#endif
|
||||
if (pos == 0) {
|
||||
return func;
|
||||
}
|
||||
ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, func, &hMod);
|
||||
if (!ok) {
|
||||
return func;
|
||||
}
|
||||
|
||||
desc_head = get_image_import_descriptor(hMod, &cnt);
|
||||
if (desc_head == NULL) {
|
||||
return func;
|
||||
}
|
||||
|
||||
for (desc = desc_head; desc->Name != 0; desc++) {
|
||||
IMAGE_THUNK_DATA *addr_thunk = (IMAGE_THUNK_DATA*)((char*)hMod + desc->FirstThunk);
|
||||
|
||||
while (addr_thunk->u1.Function != 0) {
|
||||
if (pos == (size_t)&addr_thunk->u1.Function) {
|
||||
func = (void*)addr_thunk->u1.Function;
|
||||
if (*funchook_debug_file != '\0') {
|
||||
DWORD len = GetMappedFileNameA(GetCurrentProcess(), func, path, sizeof(path));
|
||||
if (len > 0) {
|
||||
funchook_log(funchook, " -> func %p in %.*s\n", func, (int)len, path);
|
||||
} else {
|
||||
funchook_log(funchook, " -> func %p\n", func);
|
||||
}
|
||||
}
|
||||
return func;
|
||||
}
|
||||
addr_thunk++;
|
||||
}
|
||||
}
|
||||
return func;
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "funchook_internal.h"
|
||||
#include "disasm.h"
|
||||
|
||||
typedef struct {
|
||||
funchook_t *funchook;
|
||||
ip_displacement_t *rip_disp;
|
||||
const uint8_t *src;
|
||||
const uint8_t *dst_base;
|
||||
uint8_t *dst;
|
||||
} make_trampoline_context_t;
|
||||
|
||||
#define NOP_INSTRUCTION 0x90
|
||||
|
||||
#if defined(__i386)
|
||||
static int handle_x86_get_pc_thunk(make_trampoline_context_t *ctx, const funchook_insn_t *di);
|
||||
static int handle_x86_get_pc_by_call_and_pop(make_trampoline_context_t *ctx, const funchook_insn_t *di);
|
||||
#else
|
||||
#define handle_x86_get_pc_thunk(ctx, di) (0)
|
||||
#define handle_x86_get_pc_by_call_and_pop(ctx, di) (0)
|
||||
#endif
|
||||
|
||||
static int handle_rip_relative(make_trampoline_context_t *ctx, const rip_relative_t *rel, size_t insn_size);
|
||||
|
||||
static int funchook_write_jump32(funchook_t *funchook, const uint8_t *src, const uint8_t *dst, uint8_t *out)
|
||||
{
|
||||
out[0] = 0xe9;
|
||||
*(int*)(out + 1) = (int)(dst - (src + 5));
|
||||
funchook_log(funchook, " Write jump32 0x"ADDR_FMT" -> 0x"ADDR_FMT"\n",
|
||||
(size_t)src, (size_t)dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CPU_X86_64
|
||||
|
||||
static int funchook_write_jump64(funchook_t *funchook, uint8_t *src, const uint8_t *dst)
|
||||
{
|
||||
src[0] = 0xFF;
|
||||
src[1] = 0x25;
|
||||
src[2] = 0x00;
|
||||
src[3] = 0x00;
|
||||
src[4] = 0x00;
|
||||
src[5] = 0x00;
|
||||
*(const uint8_t**)(src + 6) = dst;
|
||||
funchook_log(funchook, " Write jump64 0x"ADDR_FMT" -> 0x"ADDR_FMT"\n",
|
||||
(size_t)src, (size_t)dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int funchook_within_32bit_relative(const uint8_t *src, const uint8_t *dst)
|
||||
{
|
||||
int64_t diff = (int64_t)(dst - src);
|
||||
return (INT32_MIN <= diff && diff <= INT32_MAX);
|
||||
}
|
||||
|
||||
static int funchook_jump32_avail(const uint8_t *src, const uint8_t *dst)
|
||||
{
|
||||
return funchook_within_32bit_relative(src + 5, dst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int funchook_make_trampoline(funchook_t *funchook, ip_displacement_t *disp, const uint8_t *func, uint8_t *trampoline, size_t *trampoline_size)
|
||||
{
|
||||
make_trampoline_context_t ctx;
|
||||
funchook_disasm_t disasm;
|
||||
int rv;
|
||||
const funchook_insn_t *insn;
|
||||
|
||||
memset(disp, 0, sizeof(*disp));
|
||||
memset(trampoline, NOP_INSTRUCTION, TRAMPOLINE_SIZE);
|
||||
*trampoline_size = 0;
|
||||
ctx.funchook = funchook;
|
||||
ctx.rip_disp = disp;
|
||||
ctx.src = func;
|
||||
ctx.dst_base = ctx.dst = trampoline;
|
||||
|
||||
rv = funchook_disasm_init(&disasm, funchook, func, MAX_INSN_CHECK_SIZE, (size_t)func);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
funchook_log(funchook, " Original Instructions:\n");
|
||||
while ((rv = funchook_disasm_next(&disasm, &insn)) == 0) {
|
||||
rip_relative_t rel_disp;
|
||||
rip_relative_t rel_imm;
|
||||
|
||||
funchook_disasm_log_instruction(&disasm, insn);
|
||||
|
||||
if (handle_x86_get_pc_thunk(&ctx, insn)) {
|
||||
;
|
||||
} else if (handle_x86_get_pc_by_call_and_pop(&ctx, insn)) {
|
||||
if ((rv = funchook_disasm_next(&disasm, &insn)) == 0) {
|
||||
funchook_disasm_log_instruction(&disasm, insn);
|
||||
}
|
||||
} else {
|
||||
size_t insn_size = funchook_insn_size(insn);
|
||||
memcpy(ctx.dst, ctx.src, insn_size);
|
||||
funchook_disasm_x86_rip_relative(&disasm, insn, &rel_disp, &rel_imm);
|
||||
rv = handle_rip_relative(&ctx, &rel_disp, insn_size);
|
||||
if (rv != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
rv = handle_rip_relative(&ctx, &rel_imm, insn_size);
|
||||
if (rv != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
ctx.src += insn_size;
|
||||
ctx.dst += insn_size;
|
||||
}
|
||||
if (ctx.src - func >= JUMP32_SIZE) {
|
||||
ctx.dst[0] = 0xe9; /* unconditional jump */
|
||||
disp->disp[0].dst_addr = ctx.src;
|
||||
disp->disp[0].src_addr_offset = (ctx.dst - ctx.dst_base) + 5;
|
||||
disp->disp[0].pos_offset = (ctx.dst - ctx.dst_base) + 1;
|
||||
*trampoline_size = (ctx.dst - ctx.dst_base) + 5;
|
||||
while ((rv = funchook_disasm_next(&disasm, &insn)) == 0) {
|
||||
funchook_disasm_log_instruction(&disasm, insn);
|
||||
funchook_disasm_x86_rip_relative(&disasm, insn, &rel_disp, &rel_imm);
|
||||
if (func < rel_imm.addr && rel_imm.addr < func + JUMP32_SIZE) {
|
||||
/* jump to the hot-patched region. */
|
||||
funchook_set_error_message(funchook, "instruction jumping back to the hot-patched region was found");
|
||||
rv = FUNCHOOK_ERROR_FOUND_BACK_JUMP;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rv != FUNCHOOK_ERROR_END_OF_INSTRUCTION) {
|
||||
goto cleanup;
|
||||
}
|
||||
rv = 0;
|
||||
/* too short function. Check whether NOP instructions continue. */
|
||||
while (ctx.src - func < JUMP32_SIZE) {
|
||||
if (*ctx.src != NOP_INSTRUCTION) {
|
||||
funchook_set_error_message(funchook, "Too short instructions");
|
||||
rv = FUNCHOOK_ERROR_TOO_SHORT_INSTRUCTIONS;
|
||||
goto cleanup;
|
||||
}
|
||||
ctx.src++;
|
||||
}
|
||||
cleanup:
|
||||
funchook_disasm_cleanup(&disasm);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifndef handle_x86_get_pc_thunk
|
||||
/* special cases to handle "call __x86.get_pc_thunk.??"
|
||||
* If the target instructions are "movl (%esp), %???; ret",
|
||||
* use "movl addr + 5, %???" instead.
|
||||
*/
|
||||
static int handle_x86_get_pc_thunk(make_trampoline_context_t *ctx, const funchook_insn_t *insn)
|
||||
{
|
||||
uint32_t eip = 0;
|
||||
const char *reg_name = NULL;
|
||||
|
||||
if (*ctx->src == 0xe8) {
|
||||
uint32_t first_4_bytes = *(uint32_t*)funchook_insn_branch_address(insn);
|
||||
|
||||
eip = funchook_insn_address(insn) + 5;
|
||||
switch (first_4_bytes) {
|
||||
case 0xc324048b: /* 8b 04 24 c3: movl (%esp), %eax; ret */
|
||||
reg_name = "ax";
|
||||
*ctx->dst = 0xb8; /* movl addr + 5, %eax */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc3241c8b: /* 8b 1c 24 c3: movl (%esp), %ebx; ret */
|
||||
reg_name = "bx";
|
||||
*ctx->dst = 0xbb; /* movl addr + 5, %ebx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc3240c8b: /* 8b 0c 24 c3: movl (%esp), %ecx; ret */
|
||||
reg_name = "cx";
|
||||
*ctx->dst = 0xb9; /* movl addr + 5, %ecx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc324148b: /* 8b 14 24 c3: movl (%esp), %edx; ret */
|
||||
reg_name = "dx";
|
||||
*ctx->dst = 0xba; /* movl addr + 5, %edx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc324348b: /* 8b 34 24 c3: movl (%esp), %esi; ret */
|
||||
reg_name = "si";
|
||||
*ctx->dst = 0xbe; /* movl addr + 5, %esi */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc3243c8b: /* 8b 3c 24 c3: movl (%esp), %edi; ret */
|
||||
reg_name = "di";
|
||||
*ctx->dst = 0xbf; /* movl addr + 5, %edi */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0xc3242c8b: /* 8b 2c 24 c3: movl (%esp), %ebp; ret */
|
||||
reg_name = "bp";
|
||||
*ctx->dst = 0xbd; /* movl addr + 5, %ebp */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fixed:
|
||||
funchook_log(ctx->funchook, " use 'MOV E%c%c, 0x%x' instead of 'CALL __x86.get_pc_thunk.%s'\n",
|
||||
reg_name[0] + 'A' - 'a',
|
||||
reg_name[1] + 'A' - 'a',
|
||||
eip, reg_name);
|
||||
ctx->dst += 5;
|
||||
ctx->src += 5;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef handle_x86_get_pc_by_call_and_pop
|
||||
static int handle_x86_get_pc_by_call_and_pop(make_trampoline_context_t *ctx, const funchook_insn_t *insn)
|
||||
{
|
||||
uint32_t eip = 0;
|
||||
const char *reg_name = NULL;
|
||||
|
||||
if (*ctx->src == 0xe8 && *(uint32_t*)(ctx->src + 1) == 0) {
|
||||
eip = funchook_insn_address(insn) + 5;
|
||||
switch (*(ctx->src + 5)) {
|
||||
case 0x58: /* pop %eax */
|
||||
reg_name = "EAX";
|
||||
*ctx->dst = 0xb8; /* movl addr + 5, %eax */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x5b: /* pop %ebx */
|
||||
reg_name = "EBX";
|
||||
*ctx->dst = 0xbb; /* movl addr + 5, %ebx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x59: /* pop %ecx */
|
||||
reg_name = "ECX";
|
||||
*ctx->dst = 0xb9; /* movl addr + 5, %ecx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x5a: /* pop %edx */
|
||||
reg_name = "EDX";
|
||||
*ctx->dst = 0xba; /* movl addr + 5, %edx */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x5e: /* pop %esi */
|
||||
reg_name = "ESI";
|
||||
*ctx->dst = 0xbe; /* movl addr + 5, %esi */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x5f: /* pop %edi */
|
||||
reg_name = "EDI";
|
||||
*ctx->dst = 0xbf; /* movl addr + 5, %edi */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
case 0x5d: /* pop %ebp */
|
||||
reg_name = "EBP";
|
||||
*ctx->dst = 0xbd; /* movl addr + 5, %ebp */
|
||||
*(uint32_t*)(ctx->dst + 1) = eip;
|
||||
goto fixed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fixed:
|
||||
funchook_log(ctx->funchook, " use 'MOV %s, 0x%x' instead of 'CALL 0x%x; POP %s'\n",
|
||||
reg_name, eip, eip, reg_name);
|
||||
ctx->dst += 5;
|
||||
ctx->src += 6;
|
||||
return 1;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fix RIP-relative address in an instruction
|
||||
*/
|
||||
static int handle_rip_relative(make_trampoline_context_t *ctx, const rip_relative_t *rel, size_t insn_size)
|
||||
{
|
||||
if (rel->size == 32) {
|
||||
if (*(int32_t*)(ctx->dst + rel->offset) != (uint32_t)rel->raddr) {
|
||||
/* sanity check.
|
||||
* reach here if opsiz and/or disp_offset are incorrectly
|
||||
* estimated.
|
||||
*/
|
||||
funchook_set_error_message(ctx->funchook, "Invalid ip-relative offset %d. The value at the offset should be %08x but %08x",
|
||||
rel->offset, (uint32_t)rel->raddr, *(int32_t*)(ctx->dst + rel->offset));
|
||||
return FUNCHOOK_ERROR_IP_RELATIVE_OFFSET;
|
||||
}
|
||||
ctx->rip_disp->disp[1].dst_addr = rel->addr;
|
||||
ctx->rip_disp->disp[1].src_addr_offset = (ctx->dst - ctx->dst_base) + insn_size;
|
||||
ctx->rip_disp->disp[1].pos_offset = (ctx->dst - ctx->dst_base) + rel->offset;
|
||||
} else if (rel->size != 0) {
|
||||
funchook_set_error_message(ctx->funchook, "Could not fix ip-relative address. The size is not 32.");
|
||||
return FUNCHOOK_ERROR_CANNOT_FIX_IP_RELATIVE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int funchook_fix_code(funchook_t *funchook, funchook_entry_t *entry, const ip_displacement_t *disp)
|
||||
{
|
||||
insn_t *src_addr;
|
||||
uint32_t *offset_addr;
|
||||
|
||||
#ifdef CPU_X86_64
|
||||
if (funchook_jump32_avail(entry->target_func, entry->hook_func)) {
|
||||
funchook_write_jump32(funchook, entry->target_func, entry->hook_func, entry->new_code);
|
||||
entry->transit[0] = 0;
|
||||
} else {
|
||||
funchook_write_jump32(funchook, entry->target_func, entry->transit, entry->new_code);
|
||||
funchook_write_jump64(funchook, entry->transit, entry->hook_func);
|
||||
}
|
||||
#else
|
||||
funchook_write_jump32(funchook, entry->target_func, entry->hook_func, entry->new_code);
|
||||
#endif
|
||||
/* fix rip-relative offsets */
|
||||
src_addr = entry->trampoline + disp->disp[0].src_addr_offset;
|
||||
offset_addr = (uint32_t*)(entry->trampoline + disp->disp[0].pos_offset);
|
||||
*offset_addr = (uint32_t)(disp->disp[0].dst_addr - src_addr);
|
||||
if (disp->disp[1].dst_addr != 0) {
|
||||
src_addr = entry->trampoline + disp->disp[1].src_addr_offset;
|
||||
offset_addr = (uint32_t*)(entry->trampoline + disp->disp[1].pos_offset);
|
||||
*offset_addr = (uint32_t)(disp->disp[1].dst_addr - src_addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CPU_X86_64
|
||||
int funchook_page_avail(funchook_t *funchook, funchook_page_t *page, int idx, uint8_t *addr, ip_displacement_t *disp)
|
||||
{
|
||||
funchook_entry_t *entry = &page->entries[idx];
|
||||
const uint8_t *src;
|
||||
const uint8_t *dst;
|
||||
|
||||
if (!funchook_jump32_avail(addr, entry->trampoline)) {
|
||||
funchook_log(funchook, " could not jump function %p to trampoline %p\n", addr, entry->trampoline);
|
||||
return 0;
|
||||
}
|
||||
src = entry->trampoline + disp->disp[0].src_addr_offset;
|
||||
dst = disp->disp[0].dst_addr;
|
||||
if (!funchook_within_32bit_relative(src, dst)) {
|
||||
funchook_log(funchook, " could not jump trampoline %p to function %p\n",
|
||||
src, dst);
|
||||
return 0;
|
||||
}
|
||||
src = entry->trampoline + disp->disp[1].src_addr_offset;
|
||||
dst = disp->disp[1].dst_addr;
|
||||
if (dst != 0 && !funchook_within_32bit_relative(src, dst)) {
|
||||
funchook_log(funchook, " could not make 32-bit relative address from %p to %p\n",
|
||||
src, dst);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- indent-tabs-mode: nil -*-
|
||||
*
|
||||
* This file is part of Funchook.
|
||||
* https://github.com/kubo/funchook
|
||||
*
|
||||
* Funchook is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give you
|
||||
* permission to link this library with independent modules to produce an
|
||||
* executable, regardless of the license terms of these independent
|
||||
* modules, and to copy and distribute the resulting executable under
|
||||
* terms of your choice, provided that you also meet, for each linked
|
||||
* independent module, the terms and conditions of the license of that
|
||||
* module. An independent module is a module which is not derived from or
|
||||
* based on this library. If you modify this library, you may extend this
|
||||
* exception to your version of the library, but you are not obliged to
|
||||
* do so. If you do not wish to do so, delete this exception statement
|
||||
* from your version.
|
||||
*
|
||||
* Funchook is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Funchook. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FUNCHOOK_X86_H
|
||||
#define FUNCHOOK_X86_H 1
|
||||
|
||||
#define MAX_INSN_LEN 16
|
||||
#define MAX_INSN_CHECK_SIZE 256
|
||||
|
||||
#define JUMP32_SIZE 5
|
||||
#ifdef CPU_X86_64
|
||||
#define JUMP64_SIZE 14
|
||||
#endif
|
||||
|
||||
#define TRAMPOLINE_SIZE (JUMP32_SIZE + (MAX_INSN_LEN - 1) + JUMP32_SIZE)
|
||||
|
||||
typedef uint8_t insn_t;
|
||||
|
||||
typedef struct funchook_entry {
|
||||
void *target_func;
|
||||
void *hook_func;
|
||||
uint8_t trampoline[TRAMPOLINE_SIZE];
|
||||
uint8_t old_code[JUMP32_SIZE];
|
||||
uint8_t new_code[JUMP32_SIZE];
|
||||
#ifdef CPU_X86_64
|
||||
uint8_t transit[JUMP64_SIZE];
|
||||
#endif
|
||||
} funchook_entry_t;
|
||||
|
||||
typedef struct {
|
||||
const insn_t *dst_addr;
|
||||
intptr_t src_addr_offset;
|
||||
intptr_t pos_offset;
|
||||
} ip_displacement_entry_t;
|
||||
|
||||
typedef struct {
|
||||
ip_displacement_entry_t disp[2];
|
||||
} ip_displacement_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
instructions.c
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "instructions.h"
|
||||
|
||||
#include "insts.h"
|
||||
#include "prefix.h"
|
||||
#include "x86defs.h"
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
|
||||
/* Helper macros to extract the type or index from an inst-node value. */
|
||||
#define INST_NODE_INDEX(n) ((n) & 0x1fff)
|
||||
#define INST_NODE_TYPE(n) ((n) >> 13)
|
||||
|
||||
/* Helper macro to read the actual flags that are associated with an inst-info. */
|
||||
#define INST_INFO_FLAGS(ii) (FlagsTable[InstSharedInfoTable[(ii)->sharedIndex].flagsIndex])
|
||||
|
||||
/*
|
||||
I use the trie data structure as I found it most fitting to a disassembler mechanism.
|
||||
When you read a byte and have to decide if it's enough or you should read more bytes, 'till you get to the instruction information.
|
||||
It's really fast because you POP the instruction info in top 3 iterates on the DB, because an instruction can be formed from two bytes + 3 bits reg from the ModR/M byte.
|
||||
For a simple explanation, check this out:
|
||||
http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Tree/Trie/
|
||||
Further reading: http://en.wikipedia.org/wiki/Trie
|
||||
|
||||
The first GATE (array you read off a trie data structure), as I call them, is statically allocated by the compiler.
|
||||
The second and third gates if used are being allocated dynamically by the instructions-insertion functionality.
|
||||
|
||||
How would such a thing look in memory, say we support 4 instructions with 3 bytes top (means 2 dynamically allocated gates).
|
||||
|
||||
->
|
||||
|-------| 0,
|
||||
|0| -------------------------------> |-------|
|
||||
|1|RET | 1, |0|AND |
|
||||
|2| -----> |-------| |1|XOR |
|
||||
|3|INT3 | |0|PUSH | |2|OR | 0,3,
|
||||
|-------| |1|POP | |3| --------->|-------|
|
||||
|2|PUSHF| |-------| |0|ROR |
|
||||
|3|POPF | |1|ROL |
|
||||
|-------| |2|SHR |
|
||||
|3|SHL |
|
||||
|-------|
|
||||
|
||||
Of course, this is NOT how Intel instructions set looks!!!
|
||||
but I just wanted to give a small demonstration.
|
||||
Now the instructions you get from such a trie DB goes like this:
|
||||
|
||||
0, 0 - AND
|
||||
0, 1 - XOR
|
||||
0, 2 - OR
|
||||
0, 3, 0, ROR
|
||||
0, 3, 1, ROL
|
||||
0, 3, 2, SHR
|
||||
0, 3, 3, SHL
|
||||
1 - RET
|
||||
2, 0 - PUSH
|
||||
2, 1 - POP
|
||||
2, 2 - PUSHF
|
||||
2, 3 - POPF
|
||||
3 - INT3
|
||||
|
||||
I guess it's clear by now.
|
||||
So now, if you read 0, you know that you have to enter the second gate(list) with the second byte specifying the index.
|
||||
But if you read 1, you know that you go to an instruction (in this case, a RET).
|
||||
That's why there's an Instruction-Node structure, it tells you whether you got to an instruction or another list
|
||||
so you should keep on reading byte).
|
||||
|
||||
In Intel, you could go through 4 gates at top, because there are instructions which are built from 2 bytes and another smaller list
|
||||
for the REG part, or newest SSE4 instructions which use 4 bytes for opcode.
|
||||
Therefore, Intel's first gate is 256 long, and other gates are 256 (/72) or 8 long, yes, it costs pretty much a lot of memory
|
||||
for non-used defined instructions, but I think that it still rocks.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A helper function to look up the correct inst-info structure.
|
||||
* It does one fetch from the index-table, and then another to get the inst-info.
|
||||
* Note that it takes care about basic inst-info or inst-info-ex.
|
||||
* The caller should worry about boundary checks and whether it accesses a last-level table.
|
||||
*/
|
||||
static _InstInfo* inst_get_info(_InstNode in, int index)
|
||||
{
|
||||
int instIndex = 0;
|
||||
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + index];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
|
||||
instIndex = INST_NODE_INDEX(in);
|
||||
return INST_NODE_TYPE(in) == INT_INFO ? &InstInfos[instIndex] : (_InstInfo*)&InstInfosEx[instIndex];
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is responsible to return the instruction information of the first found in code.
|
||||
* It returns the _InstInfo of the found instruction, otherwise NULL.
|
||||
* code should point to the ModR/M byte upon exit (if used), or after the instruction binary code itself.
|
||||
* This function is NOT decoding-type dependant, it is up to the caller to see whether the instruction is valid.
|
||||
* Get the instruction info, using a Trie data structure.
|
||||
*
|
||||
* Sometimes normal prefixes become mandatory prefixes, which means they are now part of the instruction opcode bytes.
|
||||
|
||||
* This is a bit tricky now,
|
||||
* if the first byte is a REP (F3) prefix, we will have to give a chance to an SSE instruction.
|
||||
* If an instruction doesn't exist, we will make it as a prefix and re-locateinst.
|
||||
* A case such that a REP prefix is being changed into an instruction byte and also an SSE instruction will not be found can't happen,
|
||||
* simply because there are no collisions between string instruction and SSE instructions (they are escaped).
|
||||
|
||||
* As for S/SSE2/3, check for F2 and 66 as well.
|
||||
|
||||
* In 64 bits, we have to make sure that we will skip the REX prefix, if it exists.
|
||||
* There's a specific case, where a 66 is mandatory but it was dropped because REG.W was used,
|
||||
* but it doesn't behave as an operand size prefix but as a mandatory, so we will have to take it into account.
|
||||
|
||||
* For example (64 bits decoding mode):
|
||||
* 66 98 CBW
|
||||
* 48 98 CDQE
|
||||
* 66 48 98: db 0x66; CDQE
|
||||
* Shows that operand size is dropped.
|
||||
|
||||
* Now, it's a mandatory prefix and NOT an operand size one.
|
||||
* 66480f2dc0 db 0x48; CVTPD2PI XMM0, XMM0
|
||||
* Although this instruction doesn't require a REX.W, it just shows, that even if it did - it doesn't matter.
|
||||
* REX.W is dropped because it's not required, but the decode function disabled the operand size even so.
|
||||
*/
|
||||
static _InstInfo* inst_lookup_prefixed(_InstNode in, _PrefixState* ps)
|
||||
{
|
||||
int checkOpSize = FALSE;
|
||||
int index = 0;
|
||||
_InstInfo* ii = NULL;
|
||||
|
||||
/* Check prefixes of current decoded instruction (None, 0x66, 0xf3, 0xf2). */
|
||||
switch (ps->decodedPrefixes & (INST_PRE_OP_SIZE | INST_PRE_REPS))
|
||||
{
|
||||
case 0:
|
||||
/* Non-prefixed, index = 0. */
|
||||
index = 0;
|
||||
break;
|
||||
case INST_PRE_OP_SIZE:
|
||||
/* 0x66, index = 1. */
|
||||
index = 1;
|
||||
/* Mark that we used it as a mandatory prefix. */
|
||||
ps->isOpSizeMandatory = TRUE;
|
||||
ps->decodedPrefixes &= ~INST_PRE_OP_SIZE;
|
||||
break;
|
||||
case INST_PRE_REP:
|
||||
/* 0xf3, index = 2. */
|
||||
index = 2;
|
||||
ps->decodedPrefixes &= ~INST_PRE_REP;
|
||||
break;
|
||||
case INST_PRE_REPNZ:
|
||||
/* 0xf2, index = 3. */
|
||||
index = 3;
|
||||
ps->decodedPrefixes &= ~INST_PRE_REPNZ;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Now we got a problem, since there are a few mandatory prefixes at once.
|
||||
* There is only one case when it's ok, when the operand size prefix is for real (not mandatory).
|
||||
* Otherwise we will have to return NULL, since the instruction is illegal.
|
||||
* Therefore we will start with REPNZ and REP prefixes,
|
||||
* try to get the instruction and only then check for the operand size prefix.
|
||||
*/
|
||||
|
||||
/* If both REPNZ and REP are together, it's illegal for sure. */
|
||||
if ((ps->decodedPrefixes & INST_PRE_REPS) == INST_PRE_REPS) return NULL;
|
||||
|
||||
/* Now we know it's either REPNZ+OPSIZE or REP+OPSIZE, so examine the instruction. */
|
||||
if (ps->decodedPrefixes & INST_PRE_REPNZ) {
|
||||
index = 3;
|
||||
ps->decodedPrefixes &= ~INST_PRE_REPNZ;
|
||||
}
|
||||
else if (ps->decodedPrefixes & INST_PRE_REP) {
|
||||
index = 2;
|
||||
ps->decodedPrefixes &= ~INST_PRE_REP;
|
||||
}
|
||||
/* Mark to verify the operand-size prefix of the fetched instruction below. */
|
||||
checkOpSize = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fetch the inst-info from the index. */
|
||||
ii = inst_get_info(in, index);
|
||||
|
||||
if (checkOpSize) {
|
||||
/* If the instruction doesn't support operand size prefix, then it's illegal. */
|
||||
if ((ii == NULL) || (~INST_INFO_FLAGS(ii) & INST_PRE_OP_SIZE)) return NULL;
|
||||
}
|
||||
|
||||
/* If there was a prefix, but the instruction wasn't found. Try to fall back to use the normal instruction. */
|
||||
if (ii == NULL) ii = inst_get_info(in, 0);
|
||||
return ii;
|
||||
}
|
||||
|
||||
/* A helper function to look up special VEX instructions.
|
||||
* See if it's a MOD based instruction and fix index if required.
|
||||
* Only after a first lookup (that was done by caller), we can tell if we need to fix the index.
|
||||
* Because these are coupled instructions
|
||||
* (which means that the base instruction hints about the other instruction).
|
||||
* Note that caller should check if it's a MOD dependent instruction before getting in here.
|
||||
*/
|
||||
static _InstInfo* inst_vex_mod_lookup(_CodeInfo* ci, _InstNode in, _InstInfo* ii, unsigned int index)
|
||||
{
|
||||
/* Advance to read the MOD from ModRM byte. */
|
||||
ci->code += 1;
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL;
|
||||
if (*ci->code < INST_DIVIDED_MODRM) {
|
||||
/* MOD is not 11, therefore change the index to 8 - 12 range in the prefixed table. */
|
||||
index += 4;
|
||||
/* Make a second lookup for this special instruction. */
|
||||
return inst_get_info(in, index);
|
||||
}
|
||||
/* Return the original one, in case we didn't find a suited instruction. */
|
||||
return ii;
|
||||
}
|
||||
|
||||
static _InstInfo* inst_vex_lookup(_CodeInfo* ci, _PrefixState* ps)
|
||||
{
|
||||
_InstNode in = 0;
|
||||
unsigned int pp = 0, start = 0;
|
||||
unsigned int index = 4; /* VEX instructions start at index 4 in the Prefixed table. */
|
||||
uint8_t vex = *ps->vexPos, vex2 = 0, v = 0;
|
||||
int instType = 0, instIndex = 0;
|
||||
|
||||
/* The VEX instruction will #ud if any of 66, f0, f2, f3, REX prefixes precede. */
|
||||
_iflags illegal = (INST_PRE_OP_SIZE | INST_PRE_LOCK | INST_PRE_REP | INST_PRE_REPNZ | INST_PRE_REX);
|
||||
if ((ps->decodedPrefixes & illegal) != 0) return NULL;
|
||||
|
||||
/* Read the some fields from the VEX prefix we need to extract the instruction. */
|
||||
if (ps->prefixExtType == PET_VEX2BYTES) {
|
||||
ps->vexV = v = (~vex >> 3) & 0xf;
|
||||
pp = vex & 3;
|
||||
/* Implied leading 0x0f byte by default for 2 bytes VEX prefix. */
|
||||
start = 1;
|
||||
}
|
||||
else { /* PET_VEX3BYTES */
|
||||
start = vex & 0x1f;
|
||||
vex2 = *(ps->vexPos + 1);
|
||||
ps->vexV = v = (~vex2 >> 3) & 0xf;
|
||||
pp = vex2 & 3;
|
||||
}
|
||||
|
||||
/* start can be either 1 (0x0f), 2 (0x0f, 0x038) or 3 (0x0f, 0x3a), otherwise it's illegal. */
|
||||
switch (start)
|
||||
{
|
||||
case 1: in = Table_0F; break;
|
||||
case 2: in = Table_0F_38; break;
|
||||
case 3: in = Table_0F_3A; break;
|
||||
default: return NULL;
|
||||
}
|
||||
|
||||
/* pp is actually the implied mandatory prefix, apply it to the index. */
|
||||
index += pp; /* (None, 0x66, 0xf3, 0xf2) */
|
||||
|
||||
/* Read a byte from the stream. */
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL;
|
||||
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + *ci->code];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
|
||||
instType = INST_NODE_TYPE(in);
|
||||
instIndex = INST_NODE_INDEX(in);
|
||||
|
||||
/*
|
||||
* If we started with 0f38 or 0f3a so it's a prefixed table,
|
||||
* therefore it's surely a VEXed instruction (because of a high index).
|
||||
* However, starting with 0f, could also lead immediately to a prefixed table for some bytes.
|
||||
* it might return NULL, if the index is invalid.
|
||||
*/
|
||||
if (instType == INT_LIST_PREFIXED) {
|
||||
_InstInfo* ii = inst_get_info(in, index);
|
||||
/* See if the instruction is dependent on MOD. */
|
||||
if ((ii != NULL) && (((_InstInfoEx*)ii)->flagsEx & INST_MODRR_BASED)) {
|
||||
ii = inst_vex_mod_lookup(ci, in, ii, index);
|
||||
}
|
||||
return ii;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached here, obviously we started with 0f. VEXed instructions must be nodes of a prefixed table.
|
||||
* But since we found an instruction (or divided one), just return NULL.
|
||||
* They cannot lead to a VEXed instruction.
|
||||
*/
|
||||
if ((instType == INT_INFO) || (instType == INT_INFOEX) || (instType == INT_LIST_DIVIDED)) return NULL;
|
||||
|
||||
/* Now we are left with handling either GROUP or FULL tables, therefore we will read another byte from the stream. */
|
||||
ci->code += 1;
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL;
|
||||
|
||||
if (instType == INT_LIST_GROUP) {
|
||||
in = InstructionsTree[instIndex + ((*ci->code >> 3) & 7)];
|
||||
/* Continue below to check prefixed table. */
|
||||
}
|
||||
else if (instType == INT_LIST_FULL) {
|
||||
in = InstructionsTree[instIndex + *ci->code];
|
||||
/* Continue below to check prefixed table. */
|
||||
}
|
||||
|
||||
/* Now that we got to the last table in the trie, check for a prefixed table. */
|
||||
if (INST_NODE_TYPE(in) == INT_LIST_PREFIXED) {
|
||||
_InstInfo* ii = inst_get_info(in, index);
|
||||
/* See if the instruction is dependent on MOD. */
|
||||
if ((ii != NULL) && (((_InstInfoEx*)ii)->flagsEx & INST_MODRR_BASED)) {
|
||||
ii = inst_vex_mod_lookup(ci, in, ii, index);
|
||||
}
|
||||
return ii;
|
||||
}
|
||||
|
||||
/* No VEXed instruction was found. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_InstInfo* inst_lookup(_CodeInfo* ci, _PrefixState* ps, int* isPrefixed)
|
||||
{
|
||||
unsigned int tmpIndex0, tmpIndex1, tmpIndex2;
|
||||
int instType;
|
||||
_InstNode in;
|
||||
_InstInfo* ii = NULL;
|
||||
int isWaitIncluded = FALSE;
|
||||
|
||||
/* Always safe to read first byte codeLen > 0. */
|
||||
tmpIndex0 = *ci->code;
|
||||
|
||||
if (prefixes_is_valid((unsigned char)tmpIndex0, ci->dt)) {
|
||||
*isPrefixed = TRUE;
|
||||
prefixes_decode(ci, ps);
|
||||
if (ci->codeLen < 1) return NULL; /* No more bytes for opcode, halt. */
|
||||
tmpIndex0 = *ci->code; /* Reload. */
|
||||
|
||||
/* If there are too many prefixes, it will be checked later in decode_inst. */
|
||||
|
||||
/* See whether we have to handle a VEX prefixed instruction. */
|
||||
if (ps->decodedPrefixes & INST_PRE_VEX) {
|
||||
ii = inst_vex_lookup(ci, ps);
|
||||
if (ii != NULL) {
|
||||
/* Make sure that VEX.L exists when forced. */
|
||||
if ((((_InstInfoEx*)ii)->flagsEx & INST_FORCE_VEXL) && (~ps->vrex & PREFIX_EX_L)) return NULL;
|
||||
/* If the instruction doesn't use VEX.vvvv it must be zero. */
|
||||
if ((((_InstInfoEx*)ii)->flagsEx & INST_VEX_V_UNUSED) && ps->vexV) return NULL;
|
||||
}
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
|
||||
/* Account first byte, we know it's safe to read. */
|
||||
ci->codeLen -= 1;
|
||||
|
||||
/* Check for special 0x9b, WAIT instruction, which can be part of some instructions(x87). */
|
||||
if (tmpIndex0 == INST_WAIT_INDEX) {
|
||||
/* Only OCST_1dBYTES get a chance to include this byte as part of the opcode. */
|
||||
isWaitIncluded = TRUE;
|
||||
|
||||
/* Ignore all prefixes, since they are useless and operate on the WAIT instruction itself. */
|
||||
prefixes_ignore_all(ps);
|
||||
|
||||
/* Move to next code byte as a new whole instruction. */
|
||||
ci->code += 1;
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL; /* Faster to return NULL, it will be detected as WAIT later anyway. */
|
||||
/* Since we got a WAIT prefix, we re-read the first byte. */
|
||||
tmpIndex0 = *ci->code;
|
||||
}
|
||||
|
||||
/* Walk first byte in InstructionsTree root. */
|
||||
in = InstructionsTree[tmpIndex0];
|
||||
if ((uint32_t)in == INT_NOTEXISTS) return NULL;
|
||||
instType = INST_NODE_TYPE(in);
|
||||
|
||||
/* Single byte instruction (OCST_1BYTE). */
|
||||
if ((instType < INT_INFOS) && (!isWaitIncluded)) {
|
||||
/* Some single byte instructions need extra treatment. */
|
||||
if (instType == INT_INFO_TREAT) {
|
||||
if (tmpIndex0 == INST_NOP_INDEX) { /* Nopnopnop */
|
||||
/* Check for Pause, since it's prefixed with 0xf3, which is not a real mandatory prefix. */
|
||||
if (ps->decodedPrefixes & INST_PRE_REP) {
|
||||
/* Flag this prefix as used. */
|
||||
ps->usedPrefixes |= INST_PRE_REP;
|
||||
return &II_PAUSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Treat NOP/XCHG specially.
|
||||
* If we're not in 64bits restore XCHG to NOP, since in the DB it's XCHG.
|
||||
* Else if we're in 64bits examine REX, if exists, and decide which instruction should go to output.
|
||||
* 48 90 XCHG RAX, RAX is a true NOP (eat REX in this case because it's valid).
|
||||
* 90 XCHG EAX, EAX is a true NOP (and not high dword of RAX = 0 although it should be a 32 bits operation).
|
||||
* Note that if the REX.B is used, then the register is not RAX anymore but R8, which means it's not a NOP.
|
||||
*/
|
||||
if (ps->vrex & PREFIX_EX_W) ps->usedPrefixes |= INST_PRE_REX;
|
||||
if ((ci->dt != Decode64Bits) || (~ps->vrex & PREFIX_EX_B)) return &II_NOP;
|
||||
}
|
||||
else if (tmpIndex0 == INST_LEA_INDEX) {
|
||||
/* Ignore segment override prefixes for LEA instruction. */
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
/* Update unused mask for ignoring segment prefix. */
|
||||
prefixes_ignore(ps, PFXIDX_SEG);
|
||||
}
|
||||
else if (tmpIndex0 == INST_ARPL_INDEX) {
|
||||
/*
|
||||
* ARPL/MOVSXD share the same opcode, and both have different operands and mnemonics, of course.
|
||||
* Practically, I couldn't come up with a comfortable way to merge the operands' types of ARPL/MOVSXD.
|
||||
* And since the DB can't be patched dynamically, because the DB has to be multi-threaded compliant,
|
||||
* I have no choice but to check for ARPL/MOVSXD right here - "right about now, the funk soul brother, check it out now, the funk soul brother...", fatboy slim
|
||||
*/
|
||||
if (ci->dt == Decode64Bits) {
|
||||
return &II_MOVSXD;
|
||||
} /* else ARPL will be returned because its defined in the DB already. */
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Return the 1 byte instruction we found.
|
||||
* We can have three node types here: infoex, info_treat and info.
|
||||
* The latter two are really the same basic structure.
|
||||
*/
|
||||
return instType == INT_INFOEX ? (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in)] : &InstInfos[INST_NODE_INDEX(in)];
|
||||
}
|
||||
|
||||
/* Read second byte, still doesn't mean all of its bits are used (I.E: ModRM). */
|
||||
ci->code += 1;
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL;
|
||||
tmpIndex1 = *ci->code;
|
||||
|
||||
/* Try single byte instruction + reg bits (OCST_13BYTES). */
|
||||
if ((instType == INT_LIST_GROUP) && (!isWaitIncluded)) return inst_get_info(in, (tmpIndex1 >> 3) & 7);
|
||||
|
||||
/* Try single byte instruction + reg byte OR one whole byte (OCST_1dBYTES). */
|
||||
if (instType == INT_LIST_DIVIDED) {
|
||||
|
||||
/* Checking for inst by REG bits is higher priority if it's found not to be divided instruction. */
|
||||
{
|
||||
_InstNode in2 = InstructionsTree[INST_NODE_INDEX(in) + ((tmpIndex1 >> 3) & 7)];
|
||||
/*
|
||||
* Do NOT check for NULL here, since we do a bit of a guess work,
|
||||
* hence we don't override 'in', cause we might still need it.
|
||||
*/
|
||||
instType = INST_NODE_TYPE(in2);
|
||||
|
||||
if (instType == INT_INFO) ii = &InstInfos[INST_NODE_INDEX(in2)];
|
||||
else if (instType == INT_INFOEX) ii = (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in2)];
|
||||
if ((ii != NULL) && (INST_INFO_FLAGS(ii) & INST_NOT_DIVIDED)) return ii;
|
||||
/* ii is reset below. */
|
||||
}
|
||||
|
||||
/* Continue normally because of wait prefix. */
|
||||
if (tmpIndex1 < INST_DIVIDED_MODRM) {
|
||||
/* An instruction which requires a ModR/M byte. Thus it's 1.3 bytes long instruction. */
|
||||
tmpIndex1 = (tmpIndex1 >> 3) & 7; /* Isolate the 3 REG/OPCODE bits. */
|
||||
}
|
||||
else { /* Normal 2 bytes instruction. */
|
||||
/*
|
||||
* Divided instructions can't be in the range of 0x8-0xc0.
|
||||
* That's because 0-8 are used for 3 bits group.
|
||||
* And 0xc0-0xff are used for not-divided instruction.
|
||||
* So the in between range is omitted, thus saving some more place in the tables.
|
||||
*/
|
||||
tmpIndex1 -= INST_DIVIDED_MODRM - 8;
|
||||
}
|
||||
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + tmpIndex1];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
instType = INST_NODE_TYPE(in);
|
||||
|
||||
if (instType < INT_INFOS) {
|
||||
/* If the instruction doesn't support the wait (marked as opsize) as part of the opcode, it's illegal. */
|
||||
ii = instType == INT_INFO ? &InstInfos[INST_NODE_INDEX(in)] : (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in)];
|
||||
if ((~INST_INFO_FLAGS(ii) & INST_PRE_OP_SIZE) && (isWaitIncluded)) return NULL;
|
||||
return ii;
|
||||
}
|
||||
/*
|
||||
* If we got here the instruction can support the wait prefix, so see if it was part of the stream.
|
||||
* Examine prefixed table, specially used for 0x9b, since it's optional.
|
||||
* No Wait: index = 0.
|
||||
* Wait Exists, index = 1.
|
||||
*/
|
||||
return inst_get_info(in, isWaitIncluded);
|
||||
}
|
||||
|
||||
/* Don't allow to continue if WAIT is part of the opcode, because there are no instructions that include it. */
|
||||
if (isWaitIncluded) return NULL;
|
||||
|
||||
/* Try 2 bytes long instruction (doesn't include ModRM byte). */
|
||||
if (instType == INT_LIST_FULL) {
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + tmpIndex1];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
instType = INST_NODE_TYPE(in);
|
||||
|
||||
/* This is where we check if we just read two escape bytes in a row, which means it is a 3DNow! instruction. */
|
||||
if ((tmpIndex0 == _3DNOW_ESCAPE_BYTE) && (tmpIndex1 == _3DNOW_ESCAPE_BYTE)) return &II_3DNOW;
|
||||
|
||||
/* 2 bytes instruction (OCST_2BYTES). */
|
||||
if (instType < INT_INFOS)
|
||||
return instType == INT_INFO ? &InstInfos[INST_NODE_INDEX(in)] : (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in)];
|
||||
|
||||
/*
|
||||
* 2 bytes + mandatory prefix.
|
||||
* Mandatory prefixes can be anywhere in the prefixes.
|
||||
* There cannot be more than one mandatory prefix, unless it's a normal operand size prefix.
|
||||
*/
|
||||
if (instType == INT_LIST_PREFIXED) return inst_lookup_prefixed(in, ps);
|
||||
}
|
||||
|
||||
/* Read third byte, still doesn't mean all of its bits are used (I.E: ModRM). */
|
||||
ci->code += 1;
|
||||
ci->codeLen -= 1;
|
||||
if (ci->codeLen < 0) return NULL;
|
||||
tmpIndex2 = *ci->code;
|
||||
|
||||
/* Try 2 bytes + reg instruction (OCST_23BYTES). */
|
||||
if (instType == INT_LIST_GROUP) {
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + ((tmpIndex2 >> 3) & 7)];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
instType = INST_NODE_TYPE(in);
|
||||
|
||||
if (instType < INT_INFOS)
|
||||
return instType == INT_INFO ? &InstInfos[INST_NODE_INDEX(in)] : (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in)];
|
||||
|
||||
/* It has to be a prefixed table then. */
|
||||
ii = inst_lookup_prefixed(in, ps);
|
||||
/* RDRAND and VMPTRLD share same 2.3 bytes opcode, and alternate on the MOD bits. See insts.h for more info. */
|
||||
if ((ii != NULL) && (ii->opcodeId == I_VMPTRLD) && (tmpIndex1 >= INST_DIVIDED_MODRM)) return &II_RDRAND;
|
||||
return ii;
|
||||
}
|
||||
|
||||
/* Try 2 bytes + divided range (OCST_2dBYTES). */
|
||||
if (instType == INT_LIST_DIVIDED) {
|
||||
_InstNode in2 = InstructionsTree[INST_NODE_INDEX(in) + ((tmpIndex2 >> 3) & 7)];
|
||||
/*
|
||||
* Do NOT check for NULL here, since we do a bit of a guess work,
|
||||
* hence we don't override 'in', cause we might still need it.
|
||||
*/
|
||||
instType = INST_NODE_TYPE(in2);
|
||||
|
||||
if (instType == INT_INFO) ii = &InstInfos[INST_NODE_INDEX(in2)];
|
||||
else if (instType == INT_INFOEX) ii = (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in2)];
|
||||
|
||||
/*
|
||||
* OCST_2dBYTES is complex, because there are a few instructions which are not divided in some special cases.
|
||||
* If the instruction wasn't divided (but still it must be a 2.3 because we are in divided category)
|
||||
* or it was an official 2.3 (because its index was less than 0xc0) -
|
||||
* Then it means the instruction should be using the REG bits, otherwise give a chance to range 0xc0-0xff.
|
||||
*/
|
||||
/* If we found an instruction only by its REG bits, AND it is not divided, then return it. */
|
||||
if ((ii != NULL) && (INST_INFO_FLAGS(ii) & INST_NOT_DIVIDED)) return ii;
|
||||
/* Otherwise, if the range is above 0xc0, try the special divided range (range 0x8-0xc0 is omitted). */
|
||||
if (tmpIndex2 >= INST_DIVIDED_MODRM) return inst_get_info(in, tmpIndex2 - INST_DIVIDED_MODRM + 8);
|
||||
|
||||
/* It might be that we got here without touching ii in the above if statements, then it becomes an invalid instruction prolly. */
|
||||
return ii;
|
||||
}
|
||||
|
||||
/* Try 3 full bytes (OCST_3BYTES - no ModRM byte). */
|
||||
if (instType == INT_LIST_FULL) {
|
||||
/* OCST_3BYTES. */
|
||||
in = InstructionsTree[INST_NODE_INDEX(in) + tmpIndex2];
|
||||
if (in == INT_NOTEXISTS) return NULL;
|
||||
instType = INST_NODE_TYPE(in);
|
||||
|
||||
if (instType < INT_INFOS)
|
||||
return instType == INT_INFO ? &InstInfos[INST_NODE_INDEX(in)] : (_InstInfo*)&InstInfosEx[INST_NODE_INDEX(in)];
|
||||
|
||||
if (instType == INT_LIST_PREFIXED) return inst_lookup_prefixed(in, ps);
|
||||
}
|
||||
|
||||
/* Kahtchinggg, damn. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3DNow! instruction handling:
|
||||
|
||||
* This is used when we encounter a 3DNow! instruction.
|
||||
* We can't really locate a 3DNow! instruction before we see two escaped bytes,
|
||||
* 0x0f, 0x0f. Then we have to extract operands which are, dest=mmx register, src=mmx register or quadword indirection.
|
||||
* When we are finished with the extraction of operands we can resume to locate the instruction by reading another byte
|
||||
* which tells us which 3DNow instruction we really tracked down...
|
||||
* So in order to tell the extract operands function which operands the 3DNow! instruction require, we need to set up some
|
||||
* generic instruction info for 3DNow! instructions.
|
||||
|
||||
* In the inst_lookup itself, when we read an OCST_3BYTES which the two first bytes are 0x0f and 0x0f.
|
||||
* we will return this special generic II for the specific operands we are interested in (MM, MM64).
|
||||
* Then after extracting the operand, we'll call a completion routine for locating the instruction
|
||||
* which will be called only for 3DNow! instructions, distinguished by a flag, and it will read the last byte of the 3 bytes.
|
||||
*
|
||||
* The id of this opcode should not be used, the following function should change it anyway.
|
||||
*/
|
||||
_InstInfo* inst_lookup_3dnow(_CodeInfo* ci)
|
||||
{
|
||||
/* Start off from the two escape bytes gates... which is 3DNow! table.*/
|
||||
_InstNode in = Table_0F_0F;
|
||||
|
||||
int index;
|
||||
|
||||
/* Make sure we can read a byte off the stream. */
|
||||
if (ci->codeLen < 1) return NULL;
|
||||
|
||||
index = *ci->code;
|
||||
|
||||
ci->codeLen -= 1;
|
||||
ci->code += 1;
|
||||
return inst_get_info(in, index);
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
instructions.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INSTRUCTIONS_H
|
||||
#define INSTRUCTIONS_H
|
||||
|
||||
#include "config.h"
|
||||
#include "prefix.h"
|
||||
|
||||
|
||||
/*
|
||||
* Operand type possibilities:
|
||||
* Note "_FULL" suffix indicates to decode the operand as 16 bits or 32 bits depends on DecodeType -
|
||||
* actually, it depends on the decoding mode, unless there's an operand/address size prefix.
|
||||
* For example, the code: 33 c0 could be decoded/executed as XOR AX, AX or XOR EAX, EAX.
|
||||
*/
|
||||
|
||||
typedef enum OpType {
|
||||
/* No operand is set */
|
||||
OT_NONE = 0,
|
||||
|
||||
/* Read a byte(8 bits) immediate */
|
||||
OT_IMM8,
|
||||
/* Force a read of a word(16 bits) immediate, used by ret only */
|
||||
OT_IMM16,
|
||||
/* Read a word/dword immediate */
|
||||
OT_IMM_FULL,
|
||||
/* Read a double-word(32 bits) immediate */
|
||||
OT_IMM32,
|
||||
|
||||
/* Read a signed extended byte(8 bits) immediate */
|
||||
OT_SEIMM8,
|
||||
|
||||
/* Use a 8bit register */
|
||||
OT_REG8,
|
||||
/* Use a 16bit register */
|
||||
OT_REG16,
|
||||
/* Use a 16/32/64bit register */
|
||||
OT_REG_FULL,
|
||||
/* Use a 32bit register */
|
||||
OT_REG32,
|
||||
/*
|
||||
* If used with REX the reg operand size becomes 64 bits, otherwise 32 bits.
|
||||
* VMX instructions are promoted automatically without a REX prefix.
|
||||
*/
|
||||
OT_REG32_64,
|
||||
|
||||
/* Use AL */
|
||||
OT_ACC8,
|
||||
/* Use AX (FSTSW) */
|
||||
OT_ACC16,
|
||||
/* Use AX/EAX/RAX */
|
||||
OT_ACC_FULL,
|
||||
/* Use AX/EAX, no REX is possible for RAX, used only with IN/OUT which don't support 64 bit registers */
|
||||
OT_ACC_FULL_NOT64,
|
||||
|
||||
/* Read a byte(8 bits) immediate and calculate it relatively to the current offset of the instruction being decoded */
|
||||
OT_RELCB,
|
||||
/* Read a word/dword immediate and calculate it relatively to the current offset of the instruction being decoded */
|
||||
OT_RELC_FULL,
|
||||
|
||||
/*
|
||||
* Instruction-Block for one byte long instructions, used by INC/DEC/PUSH/POP/XCHG,
|
||||
* REG is extracted from the value of opcode
|
||||
* Use a 8bit register
|
||||
*/
|
||||
OT_IB_RB,
|
||||
/* Use a 16/32/64bit register */
|
||||
OT_IB_R_FULL,
|
||||
|
||||
/* Read an immediate as an absolute address, size is known by instruction, used by MOV (memory offset) only */
|
||||
OT_MOFFS8,
|
||||
OT_MOFFS_FULL,
|
||||
/* Use [(r)SI] as INDIRECTION, for repeatable instructions */
|
||||
OT_REGI_ESI,
|
||||
/* Use [(r)DI] as INDIRECTION, for repeatable instructions */
|
||||
OT_REGI_EDI,
|
||||
/* Use [(r)BX + AL] as INDIRECTIOM, used by XLAT only */
|
||||
OT_REGI_EBXAL,
|
||||
/* Use [(r)AX] as INDIRECTION, used by AMD's SVM instructions */
|
||||
OT_REGI_EAX,
|
||||
/* Use DX, as for OUTS DX, BYTE [SI] */
|
||||
OT_REGDX,
|
||||
/* Use ECX in INVLPGA instruction */
|
||||
OT_REGECX,
|
||||
|
||||
/* FPU registers: */
|
||||
OT_FPU_SI, /* ST(i) */
|
||||
OT_FPU_SSI, /* ST(0), ST(i) */
|
||||
OT_FPU_SIS, /* ST(i), ST(0) */
|
||||
|
||||
/* SSE registers: */
|
||||
OT_XMM,
|
||||
/* Extract the SSE register from the RM bits this time (used when the REG bits are used for opcode extension) */
|
||||
OT_XMM_RM,
|
||||
/* Implied XMM0 register as operand, used in SSE4. */
|
||||
OT_REGXMM0,
|
||||
/* Reg32/Reg 64 depends on prefix width only. */
|
||||
OT_WREG32_64,
|
||||
|
||||
/* XMM is encoded in VEX.VVVV. */
|
||||
OT_VXMM,
|
||||
/* XMM is encoded in the high nibble of an immediate byte. */
|
||||
OT_XMM_IMM,
|
||||
/* YMM/XMM is dependent on VEX.L. */
|
||||
OT_YXMM,
|
||||
/* YMM/XMM (depends on prefix length) is encoded in the high nibble of an immediate byte. */
|
||||
OT_YXMM_IMM,
|
||||
/* YMM is encoded in reg. */
|
||||
OT_YMM,
|
||||
/* YMM is encoded in VEX.VVVV. */
|
||||
OT_VYMM,
|
||||
/* YMM/XMM is dependent on VEX.L, and encoded in VEX.VVVV. */
|
||||
OT_VYXMM,
|
||||
|
||||
/* Use an immediate of 1, as for SHR R/M, 1 */
|
||||
OT_CONST1,
|
||||
/* Use CL, as for SHR R/M, CL */
|
||||
OT_REGCL,
|
||||
|
||||
/* Use a control register */
|
||||
OT_CREG,
|
||||
/* Use a debug register */
|
||||
OT_DREG,
|
||||
/* Use a segment register */
|
||||
OT_SREG,
|
||||
/*
|
||||
* SEG is encoded in the flags of the opcode itself!
|
||||
* This is used for specific "push SS" where SS is a segment where
|
||||
* each "push SS" has an absolutely different opcode byte.
|
||||
* We need this to detect whether an operand size prefix is used.
|
||||
*/
|
||||
OT_SEG,
|
||||
|
||||
/*
|
||||
* Special immediates for instructions which have more than one immediate,
|
||||
* which is an exception from standard instruction format.
|
||||
* As to version v1.0: ENTER, INSERTQ, EXTRQ are the only problematic ones.
|
||||
*/
|
||||
/* 16 bits immediate using the first imm-slot */
|
||||
OT_IMM16_1,
|
||||
/* 8 bits immediate using the first imm-slot */
|
||||
OT_IMM8_1,
|
||||
/* 8 bits immediate using the second imm-slot */
|
||||
OT_IMM8_2,
|
||||
|
||||
/* Read one word (seg) and a word/dword/qword (depends on operand size), usually SEG:OFF, JMP 1234:1234 */
|
||||
OT_PTR16_FULL,
|
||||
|
||||
/* Used only by MOV CR/DR(n). Promoted with REX onlly. */
|
||||
OT_FREG32_64_RM,
|
||||
|
||||
/* MMX registers: */
|
||||
OT_MM,
|
||||
/* Extract the MMX register from the RM bits this time (used when the REG bits are used for opcode extension) */
|
||||
OT_MM_RM,
|
||||
|
||||
|
||||
/**** MEMORY only operands: ****/
|
||||
|
||||
/* Use general memory indirection, with varying sizes: */
|
||||
OT_MEM,
|
||||
OT_MEM32,
|
||||
/* Memory dereference for MOVNTI, either 32 or 64 bits (with REX). */
|
||||
OT_MEM32_64,
|
||||
OT_MEM64,
|
||||
/* Used for cmpxchg8b/16b. */
|
||||
OT_MEM64_128,
|
||||
OT_MEM128,
|
||||
/*
|
||||
* Read one word (seg), and a word/dword/qword (depends on operand size) from memory.
|
||||
* JMP FAR [EBX] means EBX point to 16:32 ptr.
|
||||
*/
|
||||
OT_MEM16_FULL,
|
||||
/* Read one word (limit) and a dword/qword (limit) (depends on operand size), used by SGDT, SIDT, LGDT, LIDT. */
|
||||
OT_MEM16_3264,
|
||||
/* Used when a memory indirection is required, but if the mod field is 11, this operand will be ignored. */
|
||||
OT_MEM_OPT,
|
||||
|
||||
/* Same as OT_RMXX but POINTS to 16 bits [cannot use GENERAL-PURPOSE REG!] */
|
||||
OT_FPUM16,
|
||||
/* Same as OT_RMXX but POINTS to 32 bits (single precision) [cannot use GENERAL-PURPOSE REG!] */
|
||||
OT_FPUM32,
|
||||
/* Same as OT_RMXX but POINTS to 64 bits (double precision) [cannot use GENERAL-PURPOSE REG!] */
|
||||
OT_FPUM64,
|
||||
/* Same as OT_RMXX but POINTS to 80 bits (extended precision) [cannot use GENERAL-PURPOSE REG!] */
|
||||
OT_FPUM80,
|
||||
|
||||
/* Mem128/Mem256 is dependent on VEX.L. */
|
||||
OT_LMEM128_256,
|
||||
|
||||
|
||||
/**** MEMORY & REGISTER only operands: ****/
|
||||
|
||||
/* Use or read (indirection) a 8bit register or immediate byte */
|
||||
OT_RM8,
|
||||
/* Some instructions force 16 bits (mov sreg, rm16) */
|
||||
OT_RM16,
|
||||
/* ModR/M for 32 bits. */
|
||||
OT_RM32,
|
||||
/*
|
||||
* Special operand type for MOV reg16/32/64/mem16, segReg 8C /r. and SMSW.
|
||||
* It supports all decoding modes, but if used as a memory indirection it's a 16 bit ModR/M indirection.
|
||||
*/
|
||||
OT_RFULL_M16,
|
||||
/* Use or read a 16/32/64bit register or immediate word/dword/qword */
|
||||
OT_RM_FULL,
|
||||
|
||||
/* RM32/RM64 depends on prefix width only. */
|
||||
OT_WRM32_64,
|
||||
/*
|
||||
* Special type for SSE4, ModR/M might be a 32 bits or 64 bits (with REX) register or
|
||||
* a 8 bits memory indirection operand.
|
||||
*/
|
||||
OT_R32_64_M8,
|
||||
/*
|
||||
* Special type for SSE4, ModR/M might be a 32 bits or 64 bits (with REX) register or
|
||||
* a 16 bits memory indirection operand.
|
||||
*/
|
||||
OT_R32_64_M16,
|
||||
|
||||
/*
|
||||
* 32 or 64 bits (with REX) operand size indirection memory operand.
|
||||
* Some instructions are promoted automatically without a REX prefix.
|
||||
*/
|
||||
OT_RM32_64,
|
||||
/* 16 or 32 bits RM. This is used only with MOVZXD instruction in 64bits. */
|
||||
OT_RM16_32,
|
||||
|
||||
/*
|
||||
* Special operand type for SSE4 where the ModR/M might
|
||||
* be a 32 bits register or 8 bits memory indirection operand.
|
||||
*/
|
||||
OT_R32_M8,
|
||||
/*
|
||||
* Special ModR/M for PINSRW, which need a 16 bits memory operand or 32 bits register.
|
||||
* In 16 bits decoding mode R32 becomes R16, operand size cannot affect this.
|
||||
*/
|
||||
OT_R32_M16,
|
||||
/* Reg32/Reg64 (prefix width) or Mem8. */
|
||||
OT_REG32_64_M8,
|
||||
/* Reg32/Reg64 (prefix width) or Mem16. */
|
||||
OT_REG32_64_M16,
|
||||
|
||||
/* ModR/M points to 32 bits MMX variable */
|
||||
OT_MM32,
|
||||
/* ModR/M points to 32 bits MMX variable */
|
||||
OT_MM64,
|
||||
|
||||
/* ModR/M points to 16 bits SSE variable */
|
||||
OT_XMM16,
|
||||
/* ModR/M points to 32 bits SSE variable */
|
||||
OT_XMM32,
|
||||
/* ModR/M points to 64 bits SSE variable */
|
||||
OT_XMM64,
|
||||
/* ModR/M points to 128 bits SSE variable */
|
||||
OT_XMM128,
|
||||
|
||||
/* AVX operands: */
|
||||
/* XMM or Mem32/Mem64 depends on perfix width only. */
|
||||
OT_WXMM32_64,
|
||||
/* YMM or Mem256. */
|
||||
OT_YMM256,
|
||||
/* YMM/XMM or Mem64/Mem256 is dependent on VEX.L. */
|
||||
OT_YXMM64_256,
|
||||
/* YMM/XMM or Mem128/Mem256 is dependent on VEX.L. */
|
||||
OT_YXMM128_256,
|
||||
/* XMM or Mem64/Mem256 is dependent on VEX.L. */
|
||||
OT_LXMM64_128
|
||||
} _OpType;
|
||||
|
||||
/* Flags for instruction: */
|
||||
|
||||
/* Empty flags indicator: */
|
||||
#define INST_FLAGS_NONE (0)
|
||||
/* The instruction we are going to decode requires ModR/M encoding. */
|
||||
#define INST_MODRM_REQUIRED (1)
|
||||
/* Special treatment for instructions which are in the divided-category but still needs the whole byte for ModR/M... */
|
||||
#define INST_NOT_DIVIDED (1 << 1)
|
||||
/*
|
||||
* Used explicitly in repeatable instructions,
|
||||
* which needs a suffix letter in their mnemonic to specify operation-size (depend on operands).
|
||||
*/
|
||||
#define INST_16BITS (1 << 2)
|
||||
/* If the opcode is supported by 80286 and upper models (16/32 bits). */
|
||||
#define INST_32BITS (1 << 3)
|
||||
/*
|
||||
* Prefix flags (6 types: lock/rep, seg override, addr-size, oper-size, REX, VEX)
|
||||
* There are several specific instructions that can follow LOCK prefix,
|
||||
* note that they must be using a memory operand form, otherwise they generate an exception.
|
||||
*/
|
||||
#define INST_PRE_LOCK (1 << 4)
|
||||
/* REPNZ prefix for string instructions only - means an instruction can follow it. */
|
||||
#define INST_PRE_REPNZ (1 << 5)
|
||||
/* REP prefix for string instructions only - means an instruction can follow it. */
|
||||
#define INST_PRE_REP (1 << 6)
|
||||
/* CS override prefix. */
|
||||
#define INST_PRE_CS (1 << 7)
|
||||
/* SS override prefix. */
|
||||
#define INST_PRE_SS (1 << 8)
|
||||
/* DS override prefix. */
|
||||
#define INST_PRE_DS (1 << 9)
|
||||
/* ES override prefix. */
|
||||
#define INST_PRE_ES (1 << 10)
|
||||
/* FS override prefix. Funky Segment :) */
|
||||
#define INST_PRE_FS (1 << 11)
|
||||
/* GS override prefix. Groovy Segment, of course not, duh ! */
|
||||
#define INST_PRE_GS (1 << 12)
|
||||
/* Switch operand size from 32 to 16 and vice versa. */
|
||||
#define INST_PRE_OP_SIZE (1 << 13)
|
||||
/* Switch address size from 32 to 16 and vice versa. */
|
||||
#define INST_PRE_ADDR_SIZE (1 << 14)
|
||||
/* Native instructions which needs suffix letter to indicate their operation-size (and don't depend on operands). */
|
||||
#define INST_NATIVE (1 << 15)
|
||||
/* Use extended mnemonic, means it's an _InstInfoEx structure, which contains another mnemonic for 32 bits specifically. */
|
||||
#define INST_USE_EXMNEMONIC (1 << 16)
|
||||
/* Use third operand, means it's an _InstInfoEx structure, which contains another operand for special instructions. */
|
||||
#define INST_USE_OP3 (1 << 17)
|
||||
/* Use fourth operand, means it's an _InstInfoEx structure, which contains another operand for special instructions. */
|
||||
#define INST_USE_OP4 (1 << 18)
|
||||
/* The instruction's mnemonic depends on the mod value of the ModR/M byte (mod=11, mod!=11). */
|
||||
#define INST_MNEMONIC_MODRM_BASED (1 << 19)
|
||||
/* The instruction uses a ModR/M byte which the MOD must be 11 (for registers operands only). */
|
||||
#define INST_MODRR_REQUIRED (1 << 20)
|
||||
/* The way of 3DNow! instructions are built, we have to handle their locating specially. Suffix imm8 tells which instruction it is. */
|
||||
#define INST_3DNOW_FETCH (1 << 21)
|
||||
/* The instruction needs two suffixes, one for the comparison type (imm8) and the second for its operation size indication (second mnemonic). */
|
||||
#define INST_PSEUDO_OPCODE (1 << 22)
|
||||
/* Invalid instruction at 64 bits decoding mode. */
|
||||
#define INST_INVALID_64BITS (1 << 23)
|
||||
/* Specific instruction can be promoted to 64 bits (without REX, it is promoted automatically). */
|
||||
#define INST_64BITS (1 << 24)
|
||||
/* Indicates the instruction must be REX prefixed in order to use 64 bits operands. */
|
||||
#define INST_PRE_REX (1 << 25)
|
||||
/* Third mnemonic is set. */
|
||||
#define INST_USE_EXMNEMONIC2 (1 << 26)
|
||||
/* Instruction is only valid in 64 bits decoding mode. */
|
||||
#define INST_64BITS_FETCH (1 << 27)
|
||||
/* Forces that the ModRM-REG/Opcode field will be 0. (For EXTRQ). */
|
||||
#define INST_FORCE_REG0 (1 << 28)
|
||||
/* Indicates that instruction is encoded with a VEX prefix. */
|
||||
#define INST_PRE_VEX (1 << 29)
|
||||
/* Indicates that the instruction is encoded with a ModRM byte (REG field specifically). */
|
||||
#define INST_MODRM_INCLUDED (1 << 30)
|
||||
/* Indicates that the first (/destination) operand of the instruction is writable. */
|
||||
#define INST_DST_WR (1 << 31)
|
||||
|
||||
#define INST_PRE_REPS (INST_PRE_REPNZ | INST_PRE_REP)
|
||||
#define INST_PRE_LOKREP_MASK (INST_PRE_LOCK | INST_PRE_REPNZ | INST_PRE_REP)
|
||||
#define INST_PRE_SEGOVRD_MASK32 (INST_PRE_CS | INST_PRE_SS | INST_PRE_DS | INST_PRE_ES)
|
||||
#define INST_PRE_SEGOVRD_MASK64 (INST_PRE_FS | INST_PRE_GS)
|
||||
#define INST_PRE_SEGOVRD_MASK (INST_PRE_SEGOVRD_MASK32 | INST_PRE_SEGOVRD_MASK64)
|
||||
|
||||
/* Extended flags for VEX: */
|
||||
/* Indicates that the instruction might have VEX.L encoded. */
|
||||
#define INST_VEX_L (1)
|
||||
/* Indicates that the instruction might have VEX.W encoded. */
|
||||
#define INST_VEX_W (1 << 1)
|
||||
/* Indicates that the mnemonic of the instruction is based on the VEX.W bit. */
|
||||
#define INST_MNEMONIC_VEXW_BASED (1 << 2)
|
||||
/* Indicates that the mnemonic of the instruction is based on the VEX.L bit. */
|
||||
#define INST_MNEMONIC_VEXL_BASED (1 << 3)
|
||||
/* Forces the instruction to be encoded with VEX.L, otherwise it's undefined. */
|
||||
#define INST_FORCE_VEXL (1 << 4)
|
||||
/*
|
||||
* Indicates that the instruction is based on the MOD field of the ModRM byte.
|
||||
* (MOD==11: got the right instruction, else skip +4 in prefixed table for the correct instruction).
|
||||
*/
|
||||
#define INST_MODRR_BASED (1 << 5)
|
||||
/* Indicates that the instruction doesn't use the VVVV field of the VEX prefix, if it does then it's undecodable. */
|
||||
#define INST_VEX_V_UNUSED (1 << 6)
|
||||
|
||||
/* Indication that the instruction is privileged (Ring 0), this should be checked on the opcodeId field. */
|
||||
#define META_INST_PRIVILEGED ((uint16_t)0x8000)
|
||||
|
||||
/*
|
||||
* Indicates which operand is being decoded.
|
||||
* Destination (1st), Source (2nd), op3 (3rd), op4 (4th).
|
||||
* Used to set the operands' fields in the _DInst structure!
|
||||
*/
|
||||
typedef enum {ONT_NONE = -1, ONT_1 = 0, ONT_2 = 1, ONT_3 = 2, ONT_4 = 3} _OperandNumberType;
|
||||
|
||||
/* CPU Flags that instructions modify, test or undefine, in compacted form (CF,PF,AF,ZF,SF are 1:1 map to EFLAGS). */
|
||||
#define D_COMPACT_CF 1 /* Carry */
|
||||
#define D_COMPACT_PF 4 /* Parity */
|
||||
#define D_COMPACT_AF 0x10 /* Auxiliary */
|
||||
#define D_COMPACT_ZF 0x40 /* Zero */
|
||||
#define D_COMPACT_SF 0x80 /* Sign */
|
||||
/* The following flags have to be translated to EFLAGS. */
|
||||
#define D_COMPACT_IF 2 /* Interrupt */
|
||||
#define D_COMPACT_DF 8 /* Direction */
|
||||
#define D_COMPACT_OF 0x20 /* Overflow */
|
||||
|
||||
/* The mask of flags that are already compatible with EFLAGS. */
|
||||
#define D_COMPACT_SAME_FLAGS (D_COMPACT_CF | D_COMPACT_PF | D_COMPACT_AF | D_COMPACT_ZF | D_COMPACT_SF)
|
||||
|
||||
/*
|
||||
* In order to save more space for storing the DB statically,
|
||||
* I came up with another level of shared info.
|
||||
* Because I saw that most of the information that instructions use repeats itself.
|
||||
*
|
||||
* Info about the instruction, source/dest types, meta and flags.
|
||||
* _InstInfo points to a table of _InstSharedInfo.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t flagsIndex; /* An index into FlagsTables */
|
||||
uint8_t s, d; /* OpType. */
|
||||
/*
|
||||
* The following are CPU flag masks that the instruction changes.
|
||||
* The flags are compacted so 8 bits representation is enough.
|
||||
* They will be expanded in runtime to be compatible to EFLAGS.
|
||||
*/
|
||||
uint8_t modifiedFlagsMask;
|
||||
uint8_t testedFlagsMask;
|
||||
uint8_t undefinedFlagsMask;
|
||||
uint16_t meta; /* High byte = Instruction set class | Low byte = flow control flags. */
|
||||
} _InstSharedInfo;
|
||||
|
||||
/*
|
||||
* This structure is used for the instructions DB and NOT for the disassembled result code!
|
||||
* This is the BASE structure, there are extensions to this structure below.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t sharedIndex; /* An index into the SharedInfoTable. */
|
||||
uint16_t opcodeId; /* The opcodeId is really a byte-offset into the mnemonics table. MSB is a privileged indication. */
|
||||
} _InstInfo;
|
||||
|
||||
/*
|
||||
* There are merely few instructions which need a second mnemonic for 32 bits.
|
||||
* Or a third for 64 bits. Therefore sometimes the second mnemonic is empty but not the third.
|
||||
* In all decoding modes the first mnemonic is the default.
|
||||
* A flag will indicate it uses another mnemonic.
|
||||
*
|
||||
* There are a couple of (SSE4) instructions in the whole DB which need both op3 and 3rd mnemonic for 64bits,
|
||||
* therefore, I decided to make the extended structure contain all extra info in the same structure.
|
||||
* There are a few instructions (SHLD/SHRD/IMUL and SSE too) which use third operand (or a fourth).
|
||||
* A flag will indicate it uses a third/fourth operand.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Base structure (doesn't get accessed directly from code). */
|
||||
_InstInfo BASE;
|
||||
|
||||
/* Extended starts here. */
|
||||
uint8_t flagsEx; /* 8 bits are enough, in the future we might make it a bigger integer. */
|
||||
uint8_t op3, op4; /* OpType. */
|
||||
uint16_t opcodeId2, opcodeId3;
|
||||
} _InstInfoEx;
|
||||
|
||||
/* Trie data structure node type: */
|
||||
typedef enum {
|
||||
INT_NOTEXISTS = 0, /* Not exists. */
|
||||
INT_INFO = 1, /* It's an instruction info. */
|
||||
INT_INFOEX,
|
||||
INT_INFO_TREAT, /* Extra intervention is required by inst_lookup. */
|
||||
INT_LIST_GROUP,
|
||||
INT_LIST_FULL,
|
||||
INT_LIST_DIVIDED,
|
||||
INT_LIST_PREFIXED
|
||||
} _InstNodeType;
|
||||
|
||||
/* Used to check instType < INT_INFOS, means we got an inst-info. Cause it has to be only one of them. */
|
||||
#define INT_INFOS (INT_LIST_GROUP)
|
||||
|
||||
/* Instruction node is treated as { int index:13; int type:3; } */
|
||||
typedef uint16_t _InstNode;
|
||||
|
||||
_InstInfo* inst_lookup(_CodeInfo* ci, _PrefixState* ps, int* isPrefixed);
|
||||
_InstInfo* inst_lookup_3dnow(_CodeInfo* ci);
|
||||
|
||||
#endif /* INSTRUCTIONS_H */
|
||||
|
||||
7943
examples/raze-internal-cs2-main/dependencies/funchook/src/insts.c
Normal file
7943
examples/raze-internal-cs2-main/dependencies/funchook/src/insts.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
insts.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INSTS_H
|
||||
#define INSTS_H
|
||||
|
||||
#include "instructions.h"
|
||||
|
||||
|
||||
/* Flags Table */
|
||||
extern _iflags FlagsTable[];
|
||||
|
||||
/* Root Trie DB */
|
||||
extern _InstSharedInfo InstSharedInfoTable[];
|
||||
extern _InstInfo InstInfos[];
|
||||
extern _InstInfoEx InstInfosEx[];
|
||||
extern _InstNode InstructionsTree[];
|
||||
|
||||
/* 3DNow! Trie DB */
|
||||
extern _InstNode Table_0F_0F;
|
||||
/* AVX related: */
|
||||
extern _InstNode Table_0F, Table_0F_38, Table_0F_3A;
|
||||
|
||||
/*
|
||||
* The inst_lookup will return on of these two instructions according to the specified decoding mode.
|
||||
* ARPL or MOVSXD on 64 bits is one byte instruction at index 0x63.
|
||||
*/
|
||||
extern _InstInfo II_MOVSXD;
|
||||
|
||||
/*
|
||||
* The NOP instruction can be prefixed by REX in 64bits, therefore we have to decide in runtime whether it's an XCHG or NOP instruction.
|
||||
* If 0x90 is prefixed by a usable REX it will become XCHG, otherwise it will become a NOP.
|
||||
* Also note that if it's prefixed by 0xf3, it becomes a Pause.
|
||||
*/
|
||||
extern _InstInfo II_NOP;
|
||||
extern _InstInfo II_PAUSE;
|
||||
|
||||
/*
|
||||
* RDRAND and VMPTRLD share same 2.3 bytes opcode, and then alternates on the MOD bits,
|
||||
* RDRAND is OT_FULL_REG while VMPTRLD is OT_MEM, and there's no such mixed type.
|
||||
* So a hack into the inst_lookup was added for this decision, the DB isn't flexible enough. :(
|
||||
*/
|
||||
extern _InstInfo II_RDRAND;
|
||||
|
||||
/*
|
||||
* Used for letting the extract operand know the type of operands without knowing the
|
||||
* instruction itself yet, because of the way those instructions work.
|
||||
* See function instructions.c!inst_lookup_3dnow.
|
||||
*/
|
||||
extern _InstInfo II_3DNOW;
|
||||
|
||||
/* Helper tables for pseudo compare mnemonics. */
|
||||
extern uint16_t CmpMnemonicOffsets[8]; /* SSE */
|
||||
extern uint16_t VCmpMnemonicOffsets[32]; /* AVX */
|
||||
|
||||
#endif /* INSTS_H */
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
mnemonics.c
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
const unsigned char _MNEMONICS[] =
|
||||
"\x09" "UNDEFINED\0" "\x03" "ADD\0" "\x04" "PUSH\0" "\x03" "POP\0" \
|
||||
"\x02" "OR\0" "\x03" "ADC\0" "\x03" "SBB\0" "\x03" "AND\0" "\x03" "DAA\0" \
|
||||
"\x03" "SUB\0" "\x03" "DAS\0" "\x03" "XOR\0" "\x03" "AAA\0" "\x03" "CMP\0" \
|
||||
"\x03" "AAS\0" "\x03" "INC\0" "\x03" "DEC\0" "\x05" "PUSHA\0" "\x04" "POPA\0" \
|
||||
"\x05" "BOUND\0" "\x04" "ARPL\0" "\x04" "IMUL\0" "\x03" "INS\0" "\x04" "OUTS\0" \
|
||||
"\x02" "JO\0" "\x03" "JNO\0" "\x02" "JB\0" "\x03" "JAE\0" "\x02" "JZ\0" \
|
||||
"\x03" "JNZ\0" "\x03" "JBE\0" "\x02" "JA\0" "\x02" "JS\0" "\x03" "JNS\0" \
|
||||
"\x02" "JP\0" "\x03" "JNP\0" "\x02" "JL\0" "\x03" "JGE\0" "\x03" "JLE\0" \
|
||||
"\x02" "JG\0" "\x04" "TEST\0" "\x04" "XCHG\0" "\x03" "MOV\0" "\x03" "LEA\0" \
|
||||
"\x03" "CBW\0" "\x04" "CWDE\0" "\x04" "CDQE\0" "\x03" "CWD\0" "\x03" "CDQ\0" \
|
||||
"\x03" "CQO\0" "\x08" "CALL FAR\0" "\x05" "PUSHF\0" "\x04" "POPF\0" \
|
||||
"\x04" "SAHF\0" "\x04" "LAHF\0" "\x04" "MOVS\0" "\x04" "CMPS\0" "\x04" "STOS\0" \
|
||||
"\x04" "LODS\0" "\x04" "SCAS\0" "\x03" "RET\0" "\x03" "LES\0" "\x03" "LDS\0" \
|
||||
"\x05" "ENTER\0" "\x05" "LEAVE\0" "\x04" "RETF\0" "\x05" "INT 3\0" \
|
||||
"\x03" "INT\0" "\x04" "INTO\0" "\x04" "IRET\0" "\x03" "AAM\0" "\x03" "AAD\0" \
|
||||
"\x04" "SALC\0" "\x04" "XLAT\0" "\x06" "LOOPNZ\0" "\x05" "LOOPZ\0" \
|
||||
"\x04" "LOOP\0" "\x04" "JCXZ\0" "\x05" "JECXZ\0" "\x05" "JRCXZ\0" "\x02" "IN\0" \
|
||||
"\x03" "OUT\0" "\x04" "CALL\0" "\x03" "JMP\0" "\x07" "JMP FAR\0" "\x04" "INT1\0" \
|
||||
"\x03" "HLT\0" "\x03" "CMC\0" "\x03" "CLC\0" "\x03" "STC\0" "\x03" "CLI\0" \
|
||||
"\x03" "STI\0" "\x03" "CLD\0" "\x03" "STD\0" "\x03" "LAR\0" "\x03" "LSL\0" \
|
||||
"\x07" "SYSCALL\0" "\x04" "CLTS\0" "\x06" "SYSRET\0" "\x04" "INVD\0" \
|
||||
"\x06" "WBINVD\0" "\x03" "UD2\0" "\x05" "FEMMS\0" "\x03" "NOP\0" "\x05" "WRMSR\0" \
|
||||
"\x05" "RDTSC\0" "\x05" "RDMSR\0" "\x05" "RDPMC\0" "\x08" "SYSENTER\0" \
|
||||
"\x07" "SYSEXIT\0" "\x06" "GETSEC\0" "\x05" "CMOVO\0" "\x06" "CMOVNO\0" \
|
||||
"\x05" "CMOVB\0" "\x06" "CMOVAE\0" "\x05" "CMOVZ\0" "\x06" "CMOVNZ\0" \
|
||||
"\x06" "CMOVBE\0" "\x05" "CMOVA\0" "\x05" "CMOVS\0" "\x06" "CMOVNS\0" \
|
||||
"\x05" "CMOVP\0" "\x06" "CMOVNP\0" "\x05" "CMOVL\0" "\x06" "CMOVGE\0" \
|
||||
"\x06" "CMOVLE\0" "\x05" "CMOVG\0" "\x04" "SETO\0" "\x05" "SETNO\0" \
|
||||
"\x04" "SETB\0" "\x05" "SETAE\0" "\x04" "SETZ\0" "\x05" "SETNZ\0" "\x05" "SETBE\0" \
|
||||
"\x04" "SETA\0" "\x04" "SETS\0" "\x05" "SETNS\0" "\x04" "SETP\0" "\x05" "SETNP\0" \
|
||||
"\x04" "SETL\0" "\x05" "SETGE\0" "\x05" "SETLE\0" "\x04" "SETG\0" "\x05" "CPUID\0" \
|
||||
"\x02" "BT\0" "\x04" "SHLD\0" "\x03" "RSM\0" "\x03" "BTS\0" "\x04" "SHRD\0" \
|
||||
"\x07" "CMPXCHG\0" "\x03" "LSS\0" "\x03" "BTR\0" "\x03" "LFS\0" "\x03" "LGS\0" \
|
||||
"\x05" "MOVZX\0" "\x03" "BTC\0" "\x05" "MOVSX\0" "\x04" "XADD\0" "\x06" "MOVNTI\0" \
|
||||
"\x05" "BSWAP\0" "\x03" "ROL\0" "\x03" "ROR\0" "\x03" "RCL\0" "\x03" "RCR\0" \
|
||||
"\x03" "SHL\0" "\x03" "SHR\0" "\x03" "SAL\0" "\x03" "SAR\0" "\x06" "XABORT\0" \
|
||||
"\x06" "XBEGIN\0" "\x04" "FADD\0" "\x04" "FMUL\0" "\x04" "FCOM\0" "\x05" "FCOMP\0" \
|
||||
"\x04" "FSUB\0" "\x05" "FSUBR\0" "\x04" "FDIV\0" "\x05" "FDIVR\0" "\x03" "FLD\0" \
|
||||
"\x03" "FST\0" "\x04" "FSTP\0" "\x06" "FLDENV\0" "\x05" "FLDCW\0" "\x04" "FXCH\0" \
|
||||
"\x04" "FNOP\0" "\x04" "FCHS\0" "\x04" "FABS\0" "\x04" "FTST\0" "\x04" "FXAM\0" \
|
||||
"\x04" "FLD1\0" "\x06" "FLDL2T\0" "\x06" "FLDL2E\0" "\x05" "FLDPI\0" \
|
||||
"\x06" "FLDLG2\0" "\x06" "FLDLN2\0" "\x04" "FLDZ\0" "\x05" "F2XM1\0" \
|
||||
"\x05" "FYL2X\0" "\x05" "FPTAN\0" "\x06" "FPATAN\0" "\x07" "FXTRACT\0" \
|
||||
"\x06" "FPREM1\0" "\x07" "FDECSTP\0" "\x07" "FINCSTP\0" "\x05" "FPREM\0" \
|
||||
"\x07" "FYL2XP1\0" "\x05" "FSQRT\0" "\x07" "FSINCOS\0" "\x07" "FRNDINT\0" \
|
||||
"\x06" "FSCALE\0" "\x04" "FSIN\0" "\x04" "FCOS\0" "\x05" "FIADD\0" \
|
||||
"\x05" "FIMUL\0" "\x05" "FICOM\0" "\x06" "FICOMP\0" "\x05" "FISUB\0" \
|
||||
"\x06" "FISUBR\0" "\x05" "FIDIV\0" "\x06" "FIDIVR\0" "\x06" "FCMOVB\0" \
|
||||
"\x06" "FCMOVE\0" "\x07" "FCMOVBE\0" "\x06" "FCMOVU\0" "\x07" "FUCOMPP\0" \
|
||||
"\x04" "FILD\0" "\x06" "FISTTP\0" "\x04" "FIST\0" "\x05" "FISTP\0" \
|
||||
"\x07" "FCMOVNB\0" "\x07" "FCMOVNE\0" "\x08" "FCMOVNBE\0" "\x07" "FCMOVNU\0" \
|
||||
"\x04" "FENI\0" "\x06" "FEDISI\0" "\x06" "FSETPM\0" "\x06" "FUCOMI\0" \
|
||||
"\x05" "FCOMI\0" "\x06" "FRSTOR\0" "\x05" "FFREE\0" "\x05" "FUCOM\0" \
|
||||
"\x06" "FUCOMP\0" "\x05" "FADDP\0" "\x05" "FMULP\0" "\x06" "FCOMPP\0" \
|
||||
"\x06" "FSUBRP\0" "\x05" "FSUBP\0" "\x06" "FDIVRP\0" "\x05" "FDIVP\0" \
|
||||
"\x04" "FBLD\0" "\x05" "FBSTP\0" "\x07" "FUCOMIP\0" "\x06" "FCOMIP\0" \
|
||||
"\x03" "NOT\0" "\x03" "NEG\0" "\x03" "MUL\0" "\x03" "DIV\0" "\x04" "IDIV\0" \
|
||||
"\x04" "SLDT\0" "\x03" "STR\0" "\x04" "LLDT\0" "\x03" "LTR\0" "\x04" "VERR\0" \
|
||||
"\x04" "VERW\0" "\x04" "SGDT\0" "\x04" "SIDT\0" "\x04" "LGDT\0" "\x04" "LIDT\0" \
|
||||
"\x04" "SMSW\0" "\x04" "LMSW\0" "\x06" "INVLPG\0" "\x06" "VMCALL\0" \
|
||||
"\x08" "VMLAUNCH\0" "\x08" "VMRESUME\0" "\x06" "VMXOFF\0" "\x07" "MONITOR\0" \
|
||||
"\x05" "MWAIT\0" "\x06" "XGETBV\0" "\x06" "XSETBV\0" "\x06" "VMFUNC\0" \
|
||||
"\x04" "XEND\0" "\x05" "VMRUN\0" "\x07" "VMMCALL\0" "\x06" "VMLOAD\0" \
|
||||
"\x06" "VMSAVE\0" "\x04" "STGI\0" "\x04" "CLGI\0" "\x06" "SKINIT\0" \
|
||||
"\x07" "INVLPGA\0" "\x06" "SWAPGS\0" "\x06" "RDTSCP\0" "\x08" "PREFETCH\0" \
|
||||
"\x09" "PREFETCHW\0" "\x05" "PI2FW\0" "\x05" "PI2FD\0" "\x05" "PF2IW\0" \
|
||||
"\x05" "PF2ID\0" "\x06" "PFNACC\0" "\x07" "PFPNACC\0" "\x07" "PFCMPGE\0" \
|
||||
"\x05" "PFMIN\0" "\x05" "PFRCP\0" "\x07" "PFRSQRT\0" "\x05" "PFSUB\0" \
|
||||
"\x05" "PFADD\0" "\x07" "PFCMPGT\0" "\x05" "PFMAX\0" "\x08" "PFRCPIT1\0" \
|
||||
"\x08" "PFRSQIT1\0" "\x06" "PFSUBR\0" "\x05" "PFACC\0" "\x07" "PFCMPEQ\0" \
|
||||
"\x05" "PFMUL\0" "\x08" "PFRCPIT2\0" "\x07" "PMULHRW\0" "\x06" "PSWAPD\0" \
|
||||
"\x07" "PAVGUSB\0" "\x06" "MOVUPS\0" "\x06" "MOVUPD\0" "\x05" "MOVSS\0" \
|
||||
"\x05" "MOVSD\0" "\x07" "VMOVUPS\0" "\x07" "VMOVUPD\0" "\x06" "VMOVSS\0" \
|
||||
"\x06" "VMOVSD\0" "\x07" "MOVHLPS\0" "\x06" "MOVLPS\0" "\x06" "MOVLPD\0" \
|
||||
"\x08" "MOVSLDUP\0" "\x07" "MOVDDUP\0" "\x08" "VMOVHLPS\0" "\x07" "VMOVLPS\0" \
|
||||
"\x07" "VMOVLPD\0" "\x09" "VMOVSLDUP\0" "\x08" "VMOVDDUP\0" "\x08" "UNPCKLPS\0" \
|
||||
"\x08" "UNPCKLPD\0" "\x09" "VUNPCKLPS\0" "\x09" "VUNPCKLPD\0" "\x08" "UNPCKHPS\0" \
|
||||
"\x08" "UNPCKHPD\0" "\x09" "VUNPCKHPS\0" "\x09" "VUNPCKHPD\0" "\x07" "MOVLHPS\0" \
|
||||
"\x06" "MOVHPS\0" "\x06" "MOVHPD\0" "\x08" "MOVSHDUP\0" "\x08" "VMOVLHPS\0" \
|
||||
"\x07" "VMOVHPS\0" "\x07" "VMOVHPD\0" "\x09" "VMOVSHDUP\0" "\x0b" "PREFETCHNTA\0" \
|
||||
"\x0a" "PREFETCHT0\0" "\x0a" "PREFETCHT1\0" "\x0a" "PREFETCHT2\0" "\x06" "MOVAPS\0" \
|
||||
"\x06" "MOVAPD\0" "\x07" "VMOVAPS\0" "\x07" "VMOVAPD\0" "\x08" "CVTPI2PS\0" \
|
||||
"\x08" "CVTPI2PD\0" "\x08" "CVTSI2SS\0" "\x08" "CVTSI2SD\0" "\x09" "VCVTSI2SS\0" \
|
||||
"\x09" "VCVTSI2SD\0" "\x07" "MOVNTPS\0" "\x07" "MOVNTPD\0" "\x07" "MOVNTSS\0" \
|
||||
"\x07" "MOVNTSD\0" "\x08" "VMOVNTPS\0" "\x08" "VMOVNTPD\0" "\x09" "CVTTPS2PI\0" \
|
||||
"\x09" "CVTTPD2PI\0" "\x09" "CVTTSS2SI\0" "\x09" "CVTTSD2SI\0" "\x0a" "VCVTTSS2SI\0" \
|
||||
"\x0a" "VCVTTSD2SI\0" "\x08" "CVTPS2PI\0" "\x08" "CVTPD2PI\0" "\x08" "CVTSS2SI\0" \
|
||||
"\x08" "CVTSD2SI\0" "\x09" "VCVTSS2SI\0" "\x09" "VCVTSD2SI\0" "\x07" "UCOMISS\0" \
|
||||
"\x07" "UCOMISD\0" "\x08" "VUCOMISS\0" "\x08" "VUCOMISD\0" "\x06" "COMISS\0" \
|
||||
"\x06" "COMISD\0" "\x07" "VCOMISS\0" "\x07" "VCOMISD\0" "\x08" "MOVMSKPS\0" \
|
||||
"\x08" "MOVMSKPD\0" "\x09" "VMOVMSKPS\0" "\x09" "VMOVMSKPD\0" "\x06" "SQRTPS\0" \
|
||||
"\x06" "SQRTPD\0" "\x06" "SQRTSS\0" "\x06" "SQRTSD\0" "\x07" "VSQRTPS\0" \
|
||||
"\x07" "VSQRTPD\0" "\x07" "VSQRTSS\0" "\x07" "VSQRTSD\0" "\x07" "RSQRTPS\0" \
|
||||
"\x07" "RSQRTSS\0" "\x08" "VRSQRTPS\0" "\x08" "VRSQRTSS\0" "\x05" "RCPPS\0" \
|
||||
"\x05" "RCPSS\0" "\x06" "VRCPPS\0" "\x06" "VRCPSS\0" "\x05" "ANDPS\0" \
|
||||
"\x05" "ANDPD\0" "\x06" "VANDPS\0" "\x06" "VANDPD\0" "\x06" "ANDNPS\0" \
|
||||
"\x06" "ANDNPD\0" "\x07" "VANDNPS\0" "\x07" "VANDNPD\0" "\x04" "ORPS\0" \
|
||||
"\x04" "ORPD\0" "\x05" "VORPS\0" "\x05" "VORPD\0" "\x05" "XORPS\0" \
|
||||
"\x05" "XORPD\0" "\x06" "VXORPS\0" "\x06" "VXORPD\0" "\x05" "ADDPS\0" \
|
||||
"\x05" "ADDPD\0" "\x05" "ADDSS\0" "\x05" "ADDSD\0" "\x06" "VADDPS\0" \
|
||||
"\x06" "VADDPD\0" "\x06" "VADDSS\0" "\x06" "VADDSD\0" "\x05" "MULPS\0" \
|
||||
"\x05" "MULPD\0" "\x05" "MULSS\0" "\x05" "MULSD\0" "\x06" "VMULPS\0" \
|
||||
"\x06" "VMULPD\0" "\x06" "VMULSS\0" "\x06" "VMULSD\0" "\x08" "CVTPS2PD\0" \
|
||||
"\x08" "CVTPD2PS\0" "\x08" "CVTSS2SD\0" "\x08" "CVTSD2SS\0" "\x09" "VCVTPS2PD\0" \
|
||||
"\x09" "VCVTPD2PS\0" "\x09" "VCVTSS2SD\0" "\x09" "VCVTSD2SS\0" "\x08" "CVTDQ2PS\0" \
|
||||
"\x08" "CVTPS2DQ\0" "\x09" "CVTTPS2DQ\0" "\x09" "VCVTDQ2PS\0" "\x09" "VCVTPS2DQ\0" \
|
||||
"\x0a" "VCVTTPS2DQ\0" "\x05" "SUBPS\0" "\x05" "SUBPD\0" "\x05" "SUBSS\0" \
|
||||
"\x05" "SUBSD\0" "\x06" "VSUBPS\0" "\x06" "VSUBPD\0" "\x06" "VSUBSS\0" \
|
||||
"\x06" "VSUBSD\0" "\x05" "MINPS\0" "\x05" "MINPD\0" "\x05" "MINSS\0" \
|
||||
"\x05" "MINSD\0" "\x06" "VMINPS\0" "\x06" "VMINPD\0" "\x06" "VMINSS\0" \
|
||||
"\x06" "VMINSD\0" "\x05" "DIVPS\0" "\x05" "DIVPD\0" "\x05" "DIVSS\0" \
|
||||
"\x05" "DIVSD\0" "\x06" "VDIVPS\0" "\x06" "VDIVPD\0" "\x06" "VDIVSS\0" \
|
||||
"\x06" "VDIVSD\0" "\x05" "MAXPS\0" "\x05" "MAXPD\0" "\x05" "MAXSS\0" \
|
||||
"\x05" "MAXSD\0" "\x06" "VMAXPS\0" "\x06" "VMAXPD\0" "\x06" "VMAXSS\0" \
|
||||
"\x06" "VMAXSD\0" "\x09" "PUNPCKLBW\0" "\x0a" "VPUNPCKLBW\0" "\x09" "PUNPCKLWD\0" \
|
||||
"\x0a" "VPUNPCKLWD\0" "\x09" "PUNPCKLDQ\0" "\x0a" "VPUNPCKLDQ\0" "\x08" "PACKSSWB\0" \
|
||||
"\x09" "VPACKSSWB\0" "\x07" "PCMPGTB\0" "\x08" "VPCMPGTB\0" "\x07" "PCMPGTW\0" \
|
||||
"\x08" "VPCMPGTW\0" "\x07" "PCMPGTD\0" "\x08" "VPCMPGTD\0" "\x08" "PACKUSWB\0" \
|
||||
"\x09" "VPACKUSWB\0" "\x09" "PUNPCKHBW\0" "\x0a" "VPUNPCKHBW\0" "\x09" "PUNPCKHWD\0" \
|
||||
"\x0a" "VPUNPCKHWD\0" "\x09" "PUNPCKHDQ\0" "\x0a" "VPUNPCKHDQ\0" "\x08" "PACKSSDW\0" \
|
||||
"\x09" "VPACKSSDW\0" "\x0a" "PUNPCKLQDQ\0" "\x0b" "VPUNPCKLQDQ\0" "\x0a" "PUNPCKHQDQ\0" \
|
||||
"\x0b" "VPUNPCKHQDQ\0" "\x04" "MOVD\0" "\x04" "MOVQ\0" "\x05" "VMOVD\0" \
|
||||
"\x05" "VMOVQ\0" "\x06" "MOVDQA\0" "\x06" "MOVDQU\0" "\x07" "VMOVDQA\0" \
|
||||
"\x07" "VMOVDQU\0" "\x06" "PSHUFW\0" "\x06" "PSHUFD\0" "\x07" "PSHUFHW\0" \
|
||||
"\x07" "PSHUFLW\0" "\x07" "VPSHUFD\0" "\x08" "VPSHUFHW\0" "\x08" "VPSHUFLW\0" \
|
||||
"\x07" "PCMPEQB\0" "\x08" "VPCMPEQB\0" "\x07" "PCMPEQW\0" "\x08" "VPCMPEQW\0" \
|
||||
"\x07" "PCMPEQD\0" "\x08" "VPCMPEQD\0" "\x04" "EMMS\0" "\x0a" "VZEROUPPER\0" \
|
||||
"\x08" "VZEROALL\0" "\x06" "VMREAD\0" "\x05" "EXTRQ\0" "\x07" "INSERTQ\0" \
|
||||
"\x07" "VMWRITE\0" "\x08" "CVTPH2PS\0" "\x08" "CVTPS2PH\0" "\x06" "HADDPD\0" \
|
||||
"\x06" "HADDPS\0" "\x07" "VHADDPD\0" "\x07" "VHADDPS\0" "\x06" "HSUBPD\0" \
|
||||
"\x06" "HSUBPS\0" "\x07" "VHSUBPD\0" "\x07" "VHSUBPS\0" "\x05" "XSAVE\0" \
|
||||
"\x07" "XSAVE64\0" "\x06" "LFENCE\0" "\x06" "XRSTOR\0" "\x08" "XRSTOR64\0" \
|
||||
"\x06" "MFENCE\0" "\x08" "XSAVEOPT\0" "\x0a" "XSAVEOPT64\0" "\x06" "SFENCE\0" \
|
||||
"\x07" "CLFLUSH\0" "\x06" "POPCNT\0" "\x03" "BSF\0" "\x05" "TZCNT\0" \
|
||||
"\x03" "BSR\0" "\x05" "LZCNT\0" "\x07" "CMPEQPS\0" "\x07" "CMPLTPS\0" \
|
||||
"\x07" "CMPLEPS\0" "\x0a" "CMPUNORDPS\0" "\x08" "CMPNEQPS\0" "\x08" "CMPNLTPS\0" \
|
||||
"\x08" "CMPNLEPS\0" "\x08" "CMPORDPS\0" "\x07" "CMPEQPD\0" "\x07" "CMPLTPD\0" \
|
||||
"\x07" "CMPLEPD\0" "\x0a" "CMPUNORDPD\0" "\x08" "CMPNEQPD\0" "\x08" "CMPNLTPD\0" \
|
||||
"\x08" "CMPNLEPD\0" "\x08" "CMPORDPD\0" "\x07" "CMPEQSS\0" "\x07" "CMPLTSS\0" \
|
||||
"\x07" "CMPLESS\0" "\x0a" "CMPUNORDSS\0" "\x08" "CMPNEQSS\0" "\x08" "CMPNLTSS\0" \
|
||||
"\x08" "CMPNLESS\0" "\x08" "CMPORDSS\0" "\x07" "CMPEQSD\0" "\x07" "CMPLTSD\0" \
|
||||
"\x07" "CMPLESD\0" "\x0a" "CMPUNORDSD\0" "\x08" "CMPNEQSD\0" "\x08" "CMPNLTSD\0" \
|
||||
"\x08" "CMPNLESD\0" "\x08" "CMPORDSD\0" "\x08" "VCMPEQPS\0" "\x08" "VCMPLTPS\0" \
|
||||
"\x08" "VCMPLEPS\0" "\x0b" "VCMPUNORDPS\0" "\x09" "VCMPNEQPS\0" "\x09" "VCMPNLTPS\0" \
|
||||
"\x09" "VCMPNLEPS\0" "\x09" "VCMPORDPS\0" "\x0b" "VCMPEQ_UQPS\0" "\x09" "VCMPNGEPS\0" \
|
||||
"\x09" "VCMPNGTPS\0" "\x0b" "VCMPFALSEPS\0" "\x0c" "VCMPNEQ_OQPS\0" "\x08" "VCMPGEPS\0" \
|
||||
"\x08" "VCMPGTPS\0" "\x0a" "VCMPTRUEPS\0" "\x0b" "VCMPEQ_OSPS\0" "\x0b" "VCMPLT_OQPS\0" \
|
||||
"\x0b" "VCMPLE_OQPS\0" "\x0d" "VCMPUNORD_SPS\0" "\x0c" "VCMPNEQ_USPS\0" \
|
||||
"\x0c" "VCMPNLT_UQPS\0" "\x0c" "VCMPNLE_UQPS\0" "\x0b" "VCMPORD_SPS\0" \
|
||||
"\x0b" "VCMPEQ_USPS\0" "\x0c" "VCMPNGE_UQPS\0" "\x0c" "VCMPNGT_UQPS\0" \
|
||||
"\x0e" "VCMPFALSE_OSPS\0" "\x0c" "VCMPNEQ_OSPS\0" "\x0b" "VCMPGE_OQPS\0" \
|
||||
"\x0b" "VCMPGT_OQPS\0" "\x0d" "VCMPTRUE_USPS\0" "\x08" "VCMPEQPD\0" "\x08" "VCMPLTPD\0" \
|
||||
"\x08" "VCMPLEPD\0" "\x0b" "VCMPUNORDPD\0" "\x09" "VCMPNEQPD\0" "\x09" "VCMPNLTPD\0" \
|
||||
"\x09" "VCMPNLEPD\0" "\x09" "VCMPORDPD\0" "\x0b" "VCMPEQ_UQPD\0" "\x09" "VCMPNGEPD\0" \
|
||||
"\x09" "VCMPNGTPD\0" "\x0b" "VCMPFALSEPD\0" "\x0c" "VCMPNEQ_OQPD\0" "\x08" "VCMPGEPD\0" \
|
||||
"\x08" "VCMPGTPD\0" "\x0a" "VCMPTRUEPD\0" "\x0b" "VCMPEQ_OSPD\0" "\x0b" "VCMPLT_OQPD\0" \
|
||||
"\x0b" "VCMPLE_OQPD\0" "\x0d" "VCMPUNORD_SPD\0" "\x0c" "VCMPNEQ_USPD\0" \
|
||||
"\x0c" "VCMPNLT_UQPD\0" "\x0c" "VCMPNLE_UQPD\0" "\x0b" "VCMPORD_SPD\0" \
|
||||
"\x0b" "VCMPEQ_USPD\0" "\x0c" "VCMPNGE_UQPD\0" "\x0c" "VCMPNGT_UQPD\0" \
|
||||
"\x0e" "VCMPFALSE_OSPD\0" "\x0c" "VCMPNEQ_OSPD\0" "\x0b" "VCMPGE_OQPD\0" \
|
||||
"\x0b" "VCMPGT_OQPD\0" "\x0d" "VCMPTRUE_USPD\0" "\x08" "VCMPEQSS\0" "\x08" "VCMPLTSS\0" \
|
||||
"\x08" "VCMPLESS\0" "\x0b" "VCMPUNORDSS\0" "\x09" "VCMPNEQSS\0" "\x09" "VCMPNLTSS\0" \
|
||||
"\x09" "VCMPNLESS\0" "\x09" "VCMPORDSS\0" "\x0b" "VCMPEQ_UQSS\0" "\x09" "VCMPNGESS\0" \
|
||||
"\x09" "VCMPNGTSS\0" "\x0b" "VCMPFALSESS\0" "\x0c" "VCMPNEQ_OQSS\0" "\x08" "VCMPGESS\0" \
|
||||
"\x08" "VCMPGTSS\0" "\x0a" "VCMPTRUESS\0" "\x0b" "VCMPEQ_OSSS\0" "\x0b" "VCMPLT_OQSS\0" \
|
||||
"\x0b" "VCMPLE_OQSS\0" "\x0d" "VCMPUNORD_SSS\0" "\x0c" "VCMPNEQ_USSS\0" \
|
||||
"\x0c" "VCMPNLT_UQSS\0" "\x0c" "VCMPNLE_UQSS\0" "\x0b" "VCMPORD_SSS\0" \
|
||||
"\x0b" "VCMPEQ_USSS\0" "\x0c" "VCMPNGE_UQSS\0" "\x0c" "VCMPNGT_UQSS\0" \
|
||||
"\x0e" "VCMPFALSE_OSSS\0" "\x0c" "VCMPNEQ_OSSS\0" "\x0b" "VCMPGE_OQSS\0" \
|
||||
"\x0b" "VCMPGT_OQSS\0" "\x0d" "VCMPTRUE_USSS\0" "\x08" "VCMPEQSD\0" "\x08" "VCMPLTSD\0" \
|
||||
"\x08" "VCMPLESD\0" "\x0b" "VCMPUNORDSD\0" "\x09" "VCMPNEQSD\0" "\x09" "VCMPNLTSD\0" \
|
||||
"\x09" "VCMPNLESD\0" "\x09" "VCMPORDSD\0" "\x0b" "VCMPEQ_UQSD\0" "\x09" "VCMPNGESD\0" \
|
||||
"\x09" "VCMPNGTSD\0" "\x0b" "VCMPFALSESD\0" "\x0c" "VCMPNEQ_OQSD\0" "\x08" "VCMPGESD\0" \
|
||||
"\x08" "VCMPGTSD\0" "\x0a" "VCMPTRUESD\0" "\x0b" "VCMPEQ_OSSD\0" "\x0b" "VCMPLT_OQSD\0" \
|
||||
"\x0b" "VCMPLE_OQSD\0" "\x0d" "VCMPUNORD_SSD\0" "\x0c" "VCMPNEQ_USSD\0" \
|
||||
"\x0c" "VCMPNLT_UQSD\0" "\x0c" "VCMPNLE_UQSD\0" "\x0b" "VCMPORD_SSD\0" \
|
||||
"\x0b" "VCMPEQ_USSD\0" "\x0c" "VCMPNGE_UQSD\0" "\x0c" "VCMPNGT_UQSD\0" \
|
||||
"\x0e" "VCMPFALSE_OSSD\0" "\x0c" "VCMPNEQ_OSSD\0" "\x0b" "VCMPGE_OQSD\0" \
|
||||
"\x0b" "VCMPGT_OQSD\0" "\x0d" "VCMPTRUE_USSD\0" "\x06" "PINSRW\0" "\x07" "VPINSRW\0" \
|
||||
"\x06" "PEXTRW\0" "\x07" "VPEXTRW\0" "\x06" "SHUFPS\0" "\x06" "SHUFPD\0" \
|
||||
"\x07" "VSHUFPS\0" "\x07" "VSHUFPD\0" "\x09" "CMPXCHG8B\0" "\x0a" "CMPXCHG16B\0" \
|
||||
"\x07" "VMPTRST\0" "\x08" "ADDSUBPD\0" "\x08" "ADDSUBPS\0" "\x09" "VADDSUBPD\0" \
|
||||
"\x09" "VADDSUBPS\0" "\x05" "PSRLW\0" "\x06" "VPSRLW\0" "\x05" "PSRLD\0" \
|
||||
"\x06" "VPSRLD\0" "\x05" "PSRLQ\0" "\x06" "VPSRLQ\0" "\x05" "PADDQ\0" \
|
||||
"\x06" "VPADDQ\0" "\x06" "PMULLW\0" "\x07" "VPMULLW\0" "\x07" "MOVQ2DQ\0" \
|
||||
"\x07" "MOVDQ2Q\0" "\x08" "PMOVMSKB\0" "\x09" "VPMOVMSKB\0" "\x07" "PSUBUSB\0" \
|
||||
"\x08" "VPSUBUSB\0" "\x07" "PSUBUSW\0" "\x08" "VPSUBUSW\0" "\x06" "PMINUB\0" \
|
||||
"\x07" "VPMINUB\0" "\x04" "PAND\0" "\x05" "VPAND\0" "\x07" "PADDUSB\0" \
|
||||
"\x08" "VPADDUSW\0" "\x07" "PADDUSW\0" "\x06" "PMAXUB\0" "\x07" "VPMAXUB\0" \
|
||||
"\x05" "PANDN\0" "\x06" "VPANDN\0" "\x05" "PAVGB\0" "\x06" "VPAVGB\0" \
|
||||
"\x05" "PSRAW\0" "\x06" "VPSRAW\0" "\x05" "PSRAD\0" "\x06" "VPSRAD\0" \
|
||||
"\x05" "PAVGW\0" "\x06" "VPAVGW\0" "\x07" "PMULHUW\0" "\x08" "VPMULHUW\0" \
|
||||
"\x06" "PMULHW\0" "\x07" "VPMULHW\0" "\x09" "CVTTPD2DQ\0" "\x08" "CVTDQ2PD\0" \
|
||||
"\x08" "CVTPD2DQ\0" "\x0a" "VCVTTPD2DQ\0" "\x09" "VCVTDQ2PD\0" "\x09" "VCVTPD2DQ\0" \
|
||||
"\x06" "MOVNTQ\0" "\x07" "MOVNTDQ\0" "\x08" "VMOVNTDQ\0" "\x06" "PSUBSB\0" \
|
||||
"\x07" "VPSUBSB\0" "\x06" "PSUBSW\0" "\x07" "VPSUBSW\0" "\x06" "PMINSW\0" \
|
||||
"\x07" "VPMINSW\0" "\x03" "POR\0" "\x04" "VPOR\0" "\x06" "PADDSB\0" \
|
||||
"\x07" "VPADDSB\0" "\x06" "PADDSW\0" "\x07" "VPADDSW\0" "\x06" "PMAXSW\0" \
|
||||
"\x07" "VPMAXSW\0" "\x04" "PXOR\0" "\x05" "VPXOR\0" "\x05" "LDDQU\0" \
|
||||
"\x06" "VLDDQU\0" "\x05" "PSLLW\0" "\x06" "VPSLLW\0" "\x05" "PSLLD\0" \
|
||||
"\x06" "VPSLLD\0" "\x05" "PSLLQ\0" "\x06" "VPSLLQ\0" "\x07" "PMULUDQ\0" \
|
||||
"\x08" "VPMULUDQ\0" "\x07" "PMADDWD\0" "\x08" "VPMADDWD\0" "\x06" "PSADBW\0" \
|
||||
"\x07" "VPSADBW\0" "\x08" "MASKMOVQ\0" "\x0a" "MASKMOVDQU\0" "\x0b" "VMASKMOVDQU\0" \
|
||||
"\x05" "PSUBB\0" "\x06" "VPSUBB\0" "\x05" "PSUBW\0" "\x06" "VPSUBW\0" \
|
||||
"\x05" "PSUBD\0" "\x06" "VPSUBD\0" "\x05" "PSUBQ\0" "\x06" "VPSUBQ\0" \
|
||||
"\x05" "PADDB\0" "\x06" "VPADDB\0" "\x05" "PADDW\0" "\x06" "VPADDW\0" \
|
||||
"\x05" "PADDD\0" "\x06" "VPADDD\0" "\x07" "FNSTENV\0" "\x06" "FSTENV\0" \
|
||||
"\x06" "FNSTCW\0" "\x05" "FSTCW\0" "\x06" "FNCLEX\0" "\x05" "FCLEX\0" \
|
||||
"\x06" "FNINIT\0" "\x05" "FINIT\0" "\x06" "FNSAVE\0" "\x05" "FSAVE\0" \
|
||||
"\x06" "FNSTSW\0" "\x05" "FSTSW\0" "\x06" "PSHUFB\0" "\x07" "VPSHUFB\0" \
|
||||
"\x06" "PHADDW\0" "\x07" "VPHADDW\0" "\x06" "PHADDD\0" "\x07" "VPHADDD\0" \
|
||||
"\x07" "PHADDSW\0" "\x08" "VPHADDSW\0" "\x09" "PMADDUBSW\0" "\x0a" "VPMADDUBSW\0" \
|
||||
"\x06" "PHSUBW\0" "\x07" "VPHSUBW\0" "\x06" "PHSUBD\0" "\x07" "VPHSUBD\0" \
|
||||
"\x07" "PHSUBSW\0" "\x08" "VPHSUBSW\0" "\x06" "PSIGNB\0" "\x07" "VPSIGNB\0" \
|
||||
"\x06" "PSIGNW\0" "\x07" "VPSIGNW\0" "\x06" "PSIGND\0" "\x07" "VPSIGND\0" \
|
||||
"\x08" "PMULHRSW\0" "\x09" "VPMULHRSW\0" "\x09" "VPERMILPS\0" "\x09" "VPERMILPD\0" \
|
||||
"\x07" "VTESTPS\0" "\x07" "VTESTPD\0" "\x08" "PBLENDVB\0" "\x08" "BLENDVPS\0" \
|
||||
"\x08" "BLENDVPD\0" "\x05" "PTEST\0" "\x06" "VPTEST\0" "\x0c" "VBROADCASTSS\0" \
|
||||
"\x0c" "VBROADCASTSD\0" "\x0e" "VBROADCASTF128\0" "\x05" "PABSB\0" "\x06" "VPABSB\0" \
|
||||
"\x05" "PABSW\0" "\x06" "VPABSW\0" "\x05" "PABSD\0" "\x06" "VPABSD\0" \
|
||||
"\x08" "PMOVSXBW\0" "\x09" "VPMOVSXBW\0" "\x08" "PMOVSXBD\0" "\x09" "VPMOVSXBD\0" \
|
||||
"\x08" "PMOVSXBQ\0" "\x09" "VPMOVSXBQ\0" "\x08" "PMOVSXWD\0" "\x09" "VPMOVSXWD\0" \
|
||||
"\x08" "PMOVSXWQ\0" "\x09" "VPMOVSXWQ\0" "\x08" "PMOVSXDQ\0" "\x09" "VPMOVSXDQ\0" \
|
||||
"\x06" "PMULDQ\0" "\x07" "VPMULDQ\0" "\x07" "PCMPEQQ\0" "\x08" "VPCMPEQQ\0" \
|
||||
"\x08" "MOVNTDQA\0" "\x09" "VMOVNTDQA\0" "\x08" "PACKUSDW\0" "\x09" "VPACKUSDW\0" \
|
||||
"\x0a" "VMASKMOVPS\0" "\x0a" "VMASKMOVPD\0" "\x08" "PMOVZXBW\0" "\x09" "VPMOVZXBW\0" \
|
||||
"\x08" "PMOVZXBD\0" "\x09" "VPMOVZXBD\0" "\x08" "PMOVZXBQ\0" "\x09" "VPMOVZXBQ\0" \
|
||||
"\x08" "PMOVZXWD\0" "\x09" "VPMOVZXWD\0" "\x08" "PMOVZXWQ\0" "\x09" "VPMOVZXWQ\0" \
|
||||
"\x08" "PMOVZXDQ\0" "\x09" "VPMOVZXDQ\0" "\x07" "PCMPGTQ\0" "\x08" "VPCMPGTQ\0" \
|
||||
"\x06" "PMINSB\0" "\x07" "VPMINSB\0" "\x06" "PMINSD\0" "\x07" "VPMINSD\0" \
|
||||
"\x06" "PMINUW\0" "\x07" "VPMINUW\0" "\x06" "PMINUD\0" "\x07" "VPMINUD\0" \
|
||||
"\x06" "PMAXSB\0" "\x07" "VPMAXSB\0" "\x06" "PMAXSD\0" "\x07" "VPMAXSD\0" \
|
||||
"\x06" "PMAXUW\0" "\x07" "VPMAXUW\0" "\x06" "PMAXUD\0" "\x07" "VPMAXUD\0" \
|
||||
"\x06" "PMULLD\0" "\x07" "VPMULLD\0" "\x0a" "PHMINPOSUW\0" "\x0b" "VPHMINPOSUW\0" \
|
||||
"\x06" "INVEPT\0" "\x07" "INVVPID\0" "\x07" "INVPCID\0" "\x0e" "VFMADDSUB132PS\0" \
|
||||
"\x0e" "VFMADDSUB132PD\0" "\x0e" "VFMSUBADD132PS\0" "\x0e" "VFMSUBADD132PD\0" \
|
||||
"\x0b" "VFMADD132PS\0" "\x0b" "VFMADD132PD\0" "\x0b" "VFMADD132SS\0" \
|
||||
"\x0b" "VFMADD132SD\0" "\x0b" "VFMSUB132PS\0" "\x0b" "VFMSUB132PD\0" \
|
||||
"\x0b" "VFMSUB132SS\0" "\x0b" "VFMSUB132SD\0" "\x0c" "VFNMADD132PS\0" \
|
||||
"\x0c" "VFNMADD132PD\0" "\x0c" "VFNMADD132SS\0" "\x0c" "VFNMADD132SD\0" \
|
||||
"\x0c" "VFNMSUB132PS\0" "\x0c" "VFNMSUB132PD\0" "\x0c" "VFNMSUB132SS\0" \
|
||||
"\x0c" "VFNMSUB132SD\0" "\x0e" "VFMADDSUB213PS\0" "\x0e" "VFMADDSUB213PD\0" \
|
||||
"\x0e" "VFMSUBADD213PS\0" "\x0e" "VFMSUBADD213PD\0" "\x0b" "VFMADD213PS\0" \
|
||||
"\x0b" "VFMADD213PD\0" "\x0b" "VFMADD213SS\0" "\x0b" "VFMADD213SD\0" \
|
||||
"\x0b" "VFMSUB213PS\0" "\x0b" "VFMSUB213PD\0" "\x0b" "VFMSUB213SS\0" \
|
||||
"\x0b" "VFMSUB213SD\0" "\x0c" "VFNMADD213PS\0" "\x0c" "VFNMADD213PD\0" \
|
||||
"\x0c" "VFNMADD213SS\0" "\x0c" "VFNMADD213SD\0" "\x0c" "VFNMSUB213PS\0" \
|
||||
"\x0c" "VFNMSUB213PD\0" "\x0c" "VFNMSUB213SS\0" "\x0c" "VFNMSUB213SD\0" \
|
||||
"\x0e" "VFMADDSUB231PS\0" "\x0e" "VFMADDSUB231PD\0" "\x0e" "VFMSUBADD231PS\0" \
|
||||
"\x0e" "VFMSUBADD231PD\0" "\x0b" "VFMADD231PS\0" "\x0b" "VFMADD231PD\0" \
|
||||
"\x0b" "VFMADD231SS\0" "\x0b" "VFMADD231SD\0" "\x0b" "VFMSUB231PS\0" \
|
||||
"\x0b" "VFMSUB231PD\0" "\x0b" "VFMSUB231SS\0" "\x0b" "VFMSUB231SD\0" \
|
||||
"\x0c" "VFNMADD231PS\0" "\x0c" "VFNMADD231PD\0" "\x0c" "VFNMADD231SS\0" \
|
||||
"\x0c" "VFNMADD231SD\0" "\x0c" "VFNMSUB231PS\0" "\x0c" "VFNMSUB231PD\0" \
|
||||
"\x0c" "VFNMSUB231SS\0" "\x0c" "VFNMSUB231SD\0" "\x06" "AESIMC\0" "\x07" "VAESIMC\0" \
|
||||
"\x06" "AESENC\0" "\x07" "VAESENC\0" "\x0a" "AESENCLAST\0" "\x0b" "VAESENCLAST\0" \
|
||||
"\x06" "AESDEC\0" "\x07" "VAESDEC\0" "\x0a" "AESDECLAST\0" "\x0b" "VAESDECLAST\0" \
|
||||
"\x05" "MOVBE\0" "\x05" "CRC32\0" "\x0a" "VPERM2F128\0" "\x07" "ROUNDPS\0" \
|
||||
"\x08" "VROUNDPS\0" "\x07" "ROUNDPD\0" "\x08" "VROUNDPD\0" "\x07" "ROUNDSS\0" \
|
||||
"\x08" "VROUNDSS\0" "\x07" "ROUNDSD\0" "\x08" "VROUNDSD\0" "\x07" "BLENDPS\0" \
|
||||
"\x08" "VBLENDPS\0" "\x07" "BLENDPD\0" "\x08" "VBLENDPD\0" "\x07" "PBLENDW\0" \
|
||||
"\x08" "VPBLENDW\0" "\x07" "PALIGNR\0" "\x08" "VPALIGNR\0" "\x06" "PEXTRB\0" \
|
||||
"\x07" "VPEXTRB\0" "\x06" "PEXTRD\0" "\x06" "PEXTRQ\0" "\x07" "VPEXTRD\0" \
|
||||
"\x07" "VPEXTRQ\0" "\x09" "EXTRACTPS\0" "\x0a" "VEXTRACTPS\0" "\x0b" "VINSERTF128\0" \
|
||||
"\x0c" "VEXTRACTF128\0" "\x06" "PINSRB\0" "\x07" "VPINSRB\0" "\x08" "INSERTPS\0" \
|
||||
"\x09" "VINSERTPS\0" "\x06" "PINSRD\0" "\x06" "PINSRQ\0" "\x07" "VPINSRD\0" \
|
||||
"\x07" "VPINSRQ\0" "\x04" "DPPS\0" "\x05" "VDPPS\0" "\x04" "DPPD\0" \
|
||||
"\x05" "VDPPD\0" "\x07" "MPSADBW\0" "\x08" "VMPSADBW\0" "\x09" "PCLMULQDQ\0" \
|
||||
"\x0a" "VPCLMULQDQ\0" "\x09" "VBLENDVPS\0" "\x09" "VBLENDVPD\0" "\x09" "VPBLENDVB\0" \
|
||||
"\x09" "PCMPESTRM\0" "\x0a" "VPCMPESTRM\0" "\x09" "PCMPESTRI\0" "\x0a" "VPCMPESTRI\0" \
|
||||
"\x09" "PCMPISTRM\0" "\x0a" "VPCMPISTRM\0" "\x09" "PCMPISTRI\0" "\x0a" "VPCMPISTRI\0" \
|
||||
"\x0f" "AESKEYGENASSIST\0" "\x10" "VAESKEYGENASSIST\0" "\x06" "PSRLDQ\0" \
|
||||
"\x07" "VPSRLDQ\0" "\x06" "PSLLDQ\0" "\x07" "VPSLLDQ\0" "\x06" "FXSAVE\0" \
|
||||
"\x08" "FXSAVE64\0" "\x08" "RDFSBASE\0" "\x07" "FXRSTOR\0" "\x09" "FXRSTOR64\0" \
|
||||
"\x08" "RDGSBASE\0" "\x07" "LDMXCSR\0" "\x08" "WRFSBASE\0" "\x08" "VLDMXCSR\0" \
|
||||
"\x07" "STMXCSR\0" "\x08" "WRGSBASE\0" "\x08" "VSTMXCSR\0" "\x07" "VMPTRLD\0" \
|
||||
"\x07" "VMCLEAR\0" "\x05" "VMXON\0" "\x06" "MOVSXD\0" "\x05" "PAUSE\0" \
|
||||
"\x04" "WAIT\0" "\x06" "RDRAND\0" "\x06" "_3DNOW\0" \
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; /* Sentinel mnemonic. */
|
||||
|
||||
const _WRegister _REGISTERS[] = {
|
||||
{3, "RAX"}, {3, "RCX"}, {3, "RDX"}, {3, "RBX"}, {3, "RSP"}, {3, "RBP"}, {3, "RSI"}, {3, "RDI"}, {2, "R8"}, {2, "R9"}, {3, "R10"}, {3, "R11"}, {3, "R12"}, {3, "R13"}, {3, "R14"}, {3, "R15"},
|
||||
{3, "EAX"}, {3, "ECX"}, {3, "EDX"}, {3, "EBX"}, {3, "ESP"}, {3, "EBP"}, {3, "ESI"}, {3, "EDI"}, {3, "R8D"}, {3, "R9D"}, {4, "R10D"}, {4, "R11D"}, {4, "R12D"}, {4, "R13D"}, {4, "R14D"}, {4, "R15D"},
|
||||
{2, "AX"}, {2, "CX"}, {2, "DX"}, {2, "BX"}, {2, "SP"}, {2, "BP"}, {2, "SI"}, {2, "DI"}, {3, "R8W"}, {3, "R9W"}, {4, "R10W"}, {4, "R11W"}, {4, "R12W"}, {4, "R13W"}, {4, "R14W"}, {4, "R15W"},
|
||||
{2, "AL"}, {2, "CL"}, {2, "DL"}, {2, "BL"}, {2, "AH"}, {2, "CH"}, {2, "DH"}, {2, "BH"}, {3, "R8B"}, {3, "R9B"}, {4, "R10B"}, {4, "R11B"}, {4, "R12B"}, {4, "R13B"}, {4, "R14B"}, {4, "R15B"},
|
||||
{3, "SPL"}, {3, "BPL"}, {3, "SIL"}, {3, "DIL"},
|
||||
{2, "ES"}, {2, "CS"}, {2, "SS"}, {2, "DS"}, {2, "FS"}, {2, "GS"},
|
||||
{3, "RIP"},
|
||||
{3, "ST0"}, {3, "ST1"}, {3, "ST2"}, {3, "ST3"}, {3, "ST4"}, {3, "ST5"}, {3, "ST6"}, {3, "ST7"},
|
||||
{3, "MM0"}, {3, "MM1"}, {3, "MM2"}, {3, "MM3"}, {3, "MM4"}, {3, "MM5"}, {3, "MM6"}, {3, "MM7"},
|
||||
{4, "XMM0"}, {4, "XMM1"}, {4, "XMM2"}, {4, "XMM3"}, {4, "XMM4"}, {4, "XMM5"}, {4, "XMM6"}, {4, "XMM7"}, {4, "XMM8"}, {4, "XMM9"}, {5, "XMM10"}, {5, "XMM11"}, {5, "XMM12"}, {5, "XMM13"}, {5, "XMM14"}, {5, "XMM15"},
|
||||
{4, "YMM0"}, {4, "YMM1"}, {4, "YMM2"}, {4, "YMM3"}, {4, "YMM4"}, {4, "YMM5"}, {4, "YMM6"}, {4, "YMM7"}, {4, "YMM8"}, {4, "YMM9"}, {5, "YMM10"}, {5, "YMM11"}, {5, "YMM12"}, {5, "YMM13"}, {5, "YMM14"}, {5, "YMM15"},
|
||||
{3, "CR0"}, {0, ""}, {3, "CR2"}, {3, "CR3"}, {3, "CR4"}, {0, ""}, {0, ""}, {0, ""}, {3, "CR8"},
|
||||
{3, "DR0"}, {3, "DR1"}, {3, "DR2"}, {3, "DR3"}, {0, ""}, {0, ""}, {3, "DR6"}, {3, "DR7"},
|
||||
{0, ""} /* There must be an empty last reg, see strcat_WSR. */
|
||||
};
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
1365
examples/raze-internal-cs2-main/dependencies/funchook/src/operands.c
Normal file
1365
examples/raze-internal-cs2-main/dependencies/funchook/src/operands.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
operands.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OPERANDS_H
|
||||
#define OPERANDS_H
|
||||
|
||||
#include "config.h"
|
||||
#include "decoder.h"
|
||||
#include "prefix.h"
|
||||
#include "instructions.h"
|
||||
|
||||
int operands_extract(_CodeInfo* ci, _DInst* di, _InstInfo* ii,
|
||||
_iflags instFlags, _OpType type,
|
||||
unsigned int modrm, _PrefixState* ps, _DecodeType effOpSz,
|
||||
_DecodeType effAdrSz, _Operand* op);
|
||||
|
||||
#endif /* OPERANDS_H */
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
prefix.c
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "prefix.h"
|
||||
|
||||
#include "x86defs.h"
|
||||
#include "instructions.h"
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
|
||||
/*
|
||||
* The main purpose of this module is to keep track of all kind of prefixes a single instruction may have.
|
||||
* The problem is that a single instruction may have up to six different prefix-types.
|
||||
* That's why I have to detect such cases and drop those excess prefixes.
|
||||
*/
|
||||
|
||||
|
||||
int PrefixTables[256 * 2] = {
|
||||
/* Decode 16/32 Bits */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* ES (0x26) CS (0x2e) */
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* DS (0x3e) SS (0x36) */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* FS(0x64) GS(0x65) OP_SIZE(0x66) ADDR_SIZE(0x67) */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* VEX2b (0xc5) VEX3b (0xc4) */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* LOCK (0xf0) REPNZ (0xf2) REP (0xf3) */
|
||||
/* Decode64Bits */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* REX: 0x40 - 0x4f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* Ignore all prefix. */
|
||||
void prefixes_ignore_all(_PrefixState* ps)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PFXIDX_MAX; i++)
|
||||
prefixes_ignore(ps, i);
|
||||
}
|
||||
|
||||
/* Calculates which prefixes weren't used and accordingly sets the bits in the unusedPrefixesMask. */
|
||||
uint16_t prefixes_set_unused_mask(_PrefixState* ps)
|
||||
{
|
||||
/*
|
||||
* The decodedPrefixes represents the prefixes that were *read* from the binary stream for the instruction.
|
||||
* The usedPrefixes represents the prefixes that were actually used by the instruction in the *decode* phase.
|
||||
* Xoring between the two will result in a 'diff' which returns the prefixes that were read
|
||||
* from the stream *and* that were never used in the actual decoding.
|
||||
*
|
||||
* Only one prefix per type can be set in decodedPrefixes from the stream.
|
||||
* Therefore it's enough to check each type once and set the flag accordingly.
|
||||
* That's why we had to book-keep each prefix type and its position.
|
||||
* So now we know which bits we need to set exactly in the mask.
|
||||
*/
|
||||
_iflags unusedPrefixesDiff = ps->decodedPrefixes ^ ps->usedPrefixes;
|
||||
uint16_t unusedPrefixesMask = ps->unusedPrefixesMask;
|
||||
|
||||
/* Examine unused prefixes by type: */
|
||||
/*
|
||||
* About REX: it might be set in the diff although it was never in the stream itself.
|
||||
* This is because the vrex is shared between VEX and REX and some places flag it as REX usage, while
|
||||
* we were really decoding an AVX instruction.
|
||||
* It's not a big problem, because the prefixes_ignore func will ignore it anyway,
|
||||
* since it wasn't seen earlier. But it's important to know this.
|
||||
*/
|
||||
if (unusedPrefixesDiff) {
|
||||
if (unusedPrefixesDiff & INST_PRE_REX) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_REX];
|
||||
if (unusedPrefixesDiff & INST_PRE_SEGOVRD_MASK) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_SEG];
|
||||
if (unusedPrefixesDiff & INST_PRE_LOKREP_MASK) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_LOREP];
|
||||
if (unusedPrefixesDiff & INST_PRE_OP_SIZE) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_OP_SIZE];
|
||||
if (unusedPrefixesDiff & INST_PRE_ADDR_SIZE) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_ADRS];
|
||||
/* If a VEX instruction was found, its prefix is considered as used, therefore no point for checking for it. */
|
||||
}
|
||||
|
||||
return unusedPrefixesMask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark a prefix as unused, and bookkeep where we last saw this same type,
|
||||
* because in the future we might want to disable it too.
|
||||
*/
|
||||
_INLINE_ void prefixes_track_unused(_PrefixState* ps, int index, _PrefixIndexer pi)
|
||||
{
|
||||
/* Mark the previously used prefix (if exists) in the unused mask. */
|
||||
prefixes_ignore(ps, pi);
|
||||
/* Book-keep the current index for this type. */
|
||||
ps->pfxIndexer[pi] = 1 << index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read as many prefixes as possible, up to 15 bytes, and halt when we encounter non-prefix byte.
|
||||
* This algorithm tries to imitate a real processor, where the same prefix can appear a few times, etc.
|
||||
* The tiny complexity is that we want to know when a prefix was superfluous and mark any copy of it as unused.
|
||||
* Note that the last prefix of its type will be considered as used, and all the others (of same type) before it as unused.
|
||||
*/
|
||||
void prefixes_decode(_CodeInfo* ci, _PrefixState* ps)
|
||||
{
|
||||
const uint8_t* rexPos = NULL;
|
||||
const uint8_t* start = ci->code;
|
||||
uint8_t byte, vex;
|
||||
unsigned int index;
|
||||
/*
|
||||
* First thing to do, scan for prefixes, there are six types of prefixes.
|
||||
* There may be up to six prefixes before a single instruction, not the same type, no special order,
|
||||
* except REX/VEX must precede immediately the first opcode byte.
|
||||
* BTW - This is the reason why I didn't make the REP prefixes part of the instructions (STOS/SCAS/etc).
|
||||
*
|
||||
* Another thing, the instruction maximum size is 15 bytes, thus if we read more than 15 bytes, we will halt.
|
||||
*
|
||||
* We attach all prefixes to the next instruction, there might be two or more occurrences from the same prefix.
|
||||
* Also, since VEX can be allowed only once we will test it separately.
|
||||
*/
|
||||
for (index = 0;
|
||||
(ci->codeLen > 0) && (index < INST_MAXIMUM_SIZE);
|
||||
ci->code++, ci->codeLen--, index++) {
|
||||
/*
|
||||
NOTE: AMD treat lock/rep as two different groups... But I am based on Intel.
|
||||
|
||||
- Lock and Repeat:
|
||||
- 0xF0 — LOCK
|
||||
- 0xF2 — REPNE/REPNZ
|
||||
- 0xF3 - REP/REPE/REPZ
|
||||
- Segment Override:
|
||||
- 0x2E - CS
|
||||
- 0x36 - SS
|
||||
- 0x3E - DS
|
||||
- 0x26 - ES
|
||||
- 0x64 - FS
|
||||
- 0x65 - GS
|
||||
- Operand-Size Override: 0x66, switching default size.
|
||||
- Address-Size Override: 0x67, switching default size.
|
||||
|
||||
64 Bits:
|
||||
- REX: 0x40 - 0x4f, extends register access.
|
||||
- 2 Bytes VEX: 0xc4
|
||||
- 3 Bytes VEX: 0xc5
|
||||
32 Bits:
|
||||
- 2 Bytes VEX: 0xc4 11xx-xxxx
|
||||
- 3 Bytes VEX: 0xc5 11xx-xxxx
|
||||
*/
|
||||
|
||||
/* Examine what type of prefix we got. */
|
||||
byte = *ci->code;
|
||||
switch (byte)
|
||||
{
|
||||
case PREFIX_OP_SIZE: {/* Op Size type: */
|
||||
ps->decodedPrefixes |= INST_PRE_OP_SIZE;
|
||||
prefixes_track_unused(ps, index, PFXIDX_OP_SIZE);
|
||||
} break;
|
||||
/* Look for both common arch prefixes. */
|
||||
case PREFIX_LOCK: {
|
||||
/* LOCK and REPx type: */
|
||||
ps->decodedPrefixes |= INST_PRE_LOCK;
|
||||
prefixes_track_unused(ps, index, PFXIDX_LOREP);
|
||||
} break;
|
||||
case PREFIX_REPNZ: {
|
||||
ps->decodedPrefixes |= INST_PRE_REPNZ;
|
||||
prefixes_track_unused(ps, index, PFXIDX_LOREP);
|
||||
} break;
|
||||
case PREFIX_REP: {
|
||||
ps->decodedPrefixes |= INST_PRE_REP;
|
||||
prefixes_track_unused(ps, index, PFXIDX_LOREP);
|
||||
} break;
|
||||
case PREFIX_CS: {
|
||||
/* Seg Overide type: */
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_CS;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_SS: {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_SS;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_DS: {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_DS;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_ES: {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_ES;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_FS: {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_FS;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_GS: {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK;
|
||||
ps->decodedPrefixes |= INST_PRE_GS;
|
||||
prefixes_track_unused(ps, index, PFXIDX_SEG);
|
||||
} break;
|
||||
case PREFIX_ADDR_SIZE: {
|
||||
/* Addr Size type: */
|
||||
ps->decodedPrefixes |= INST_PRE_ADDR_SIZE;
|
||||
prefixes_track_unused(ps, index, PFXIDX_ADRS);
|
||||
} break;
|
||||
default:
|
||||
if (ci->dt == Decode64Bits) {
|
||||
/* REX type, 64 bits decoding mode only: */
|
||||
if ((byte & 0xf0) == 0x40) {
|
||||
ps->decodedPrefixes |= INST_PRE_REX;
|
||||
rexPos = ci->code;
|
||||
ps->vrex = byte & 0xf; /* Keep only BXRW. */
|
||||
ps->prefixExtType = PET_REX;
|
||||
prefixes_track_unused(ps, index, PFXIDX_REX);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto _Break2;
|
||||
}
|
||||
}
|
||||
_Break2:
|
||||
|
||||
/* 2 Bytes VEX: */
|
||||
if ((ci->codeLen >= 2) &&
|
||||
(*ci->code == PREFIX_VEX2b) &&
|
||||
((ci->code - start) <= INST_MAXIMUM_SIZE - 2)) {
|
||||
/*
|
||||
* In 32 bits the second byte has to be in the special range of Mod=11.
|
||||
* Otherwise it might be a normal LDS instruction.
|
||||
*/
|
||||
if ((ci->dt == Decode64Bits) || (*(ci->code + 1) >= INST_DIVIDED_MODRM)) {
|
||||
ps->vexPos = ci->code + 1;
|
||||
ps->decodedPrefixes |= INST_PRE_VEX;
|
||||
ps->prefixExtType = PET_VEX2BYTES;
|
||||
|
||||
/*
|
||||
* VEX 1 byte bits:
|
||||
* |7-6--3-2-10|
|
||||
* |R|vvvv|L|pp|
|
||||
* |-----------|
|
||||
*/
|
||||
|
||||
/* -- Convert from VEX prefix to VREX flags -- */
|
||||
vex = *ps->vexPos;
|
||||
if (!(vex & 0x80) && (ci->dt == Decode64Bits)) ps->vrex |= PREFIX_EX_R; /* Convert VEX.R. */
|
||||
if (vex & 4) ps->vrex |= PREFIX_EX_L; /* Convert VEX.L. */
|
||||
|
||||
ci->code += 2;
|
||||
ci->codeLen -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3 Bytes VEX: */
|
||||
if ((ci->codeLen >= 3) &&
|
||||
(*ci->code == PREFIX_VEX3b) &&
|
||||
((ci->code - start) <= INST_MAXIMUM_SIZE - 3) &&
|
||||
(!(ps->decodedPrefixes & INST_PRE_VEX))) {
|
||||
/*
|
||||
* In 32 bits the second byte has to be in the special range of Mod=11.
|
||||
* Otherwise it might be a normal LES instruction.
|
||||
* And we don't care now about the 3rd byte.
|
||||
*/
|
||||
if ((ci->dt == Decode64Bits) || (*(ci->code + 1) >= INST_DIVIDED_MODRM)) {
|
||||
ps->vexPos = ci->code + 1;
|
||||
ps->decodedPrefixes |= INST_PRE_VEX;
|
||||
ps->prefixExtType = PET_VEX3BYTES;
|
||||
|
||||
/*
|
||||
* VEX first and second bytes:
|
||||
* |7-6-5-4----0| |7-6--3-2-10|
|
||||
* |R|X|B|m-mmmm| |W|vvvv|L|pp|
|
||||
* |------------| |-----------|
|
||||
*/
|
||||
|
||||
/* -- Convert from VEX prefix to VREX flags -- */
|
||||
vex = *ps->vexPos;
|
||||
ps->vrex |= ((~vex >> 5) & 0x7); /* Shift and invert VEX.R/X/B to their place */
|
||||
vex = *(ps->vexPos + 1);
|
||||
if (vex & 4) ps->vrex |= PREFIX_EX_L; /* Convert VEX.L. */
|
||||
if (vex & 0x80) ps->vrex |= PREFIX_EX_W; /* Convert VEX.W. */
|
||||
|
||||
/* Clear some flags if the mode isn't 64 bits. */
|
||||
if (ci->dt != Decode64Bits) ps->vrex &= ~(PREFIX_EX_B | PREFIX_EX_X | PREFIX_EX_R | PREFIX_EX_W);
|
||||
|
||||
ci->code += 3;
|
||||
ci->codeLen -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (ci->dt == Decode64Bits) {
|
||||
if (ps->decodedPrefixes & INST_PRE_REX) {
|
||||
/* REX prefix must precede first byte of instruction. */
|
||||
if (rexPos != (ci->code - 1)) {
|
||||
ps->decodedPrefixes &= ~INST_PRE_REX;
|
||||
if (ps->prefixExtType == PET_REX) ps->prefixExtType = PET_NONE; /* It might be a VEX by now, keep it that way. */
|
||||
prefixes_ignore(ps, PFXIDX_REX);
|
||||
}
|
||||
/*
|
||||
* We will disable operand size prefix,
|
||||
* if it exists only after decoding the instruction, since it might be a mandatory prefix.
|
||||
* This will be done after calling inst_lookup in decode_inst.
|
||||
*/
|
||||
}
|
||||
/* In 64 bits, segment overrides of CS, DS, ES and SS are ignored. So don't take'em into account. */
|
||||
if (ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK32) {
|
||||
ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK32;
|
||||
prefixes_ignore(ps, PFXIDX_SEG);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store number of prefixes scanned. */
|
||||
ps->count = (uint8_t)(ci->code - start);
|
||||
}
|
||||
|
||||
/*
|
||||
* For every memory-indirection operand we want to set a used segment.
|
||||
* If the segment is being overrided with a prefix, we will need to check if it's a default.
|
||||
* Defaults don't use their prefix, e.g "mov [rsp]" can ignore a given SS: prefix,
|
||||
* but still set the used segment as SS.
|
||||
* This function is called only with SS and DS as defaults.
|
||||
* If there's a segment prefix used, it will override the default one.
|
||||
* And If the prefix is a default seg in 64 bits, it will be ignored.
|
||||
*/
|
||||
void prefixes_use_segment(_iflags defaultSeg, _PrefixState* ps, _DecodeType dt, _DInst* di)
|
||||
{
|
||||
/* Extract given segment prefix from the decoded prefixes. */
|
||||
_iflags flags;
|
||||
|
||||
if (dt == Decode64Bits) {
|
||||
if (ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK64) { /* Either GS or FS. */
|
||||
di->segment = ps->decodedPrefixes & INST_PRE_GS ? R_GS : R_FS;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
flags = ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK;
|
||||
|
||||
/* Use the given prefix only if it's not the default. */
|
||||
if (flags && (flags != defaultSeg)) {
|
||||
ps->usedPrefixes |= flags;
|
||||
|
||||
switch (flags >> 7) /* INST_PRE_CS is 1 << 7. And the rest of the prefixes follow as bit fields. */
|
||||
{
|
||||
case 1: di->segment = R_CS; break;
|
||||
case 2: di->segment = R_SS; break;
|
||||
case 4: di->segment = R_DS; break;
|
||||
case 8: di->segment = R_ES; break;
|
||||
case 0x10: di->segment = R_FS; break;
|
||||
case 0x20: di->segment = R_GS; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (defaultSeg == INST_PRE_SS) di->segment = SEGMENT_DEFAULT | R_SS;
|
||||
else di->segment = SEGMENT_DEFAULT | R_DS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
prefix.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PREFIX_H
|
||||
#define PREFIX_H
|
||||
|
||||
#include "config.h"
|
||||
#include "decoder.h"
|
||||
|
||||
|
||||
/* Specifies the type of the extension prefix, such as: REX, 2 bytes VEX, 3 bytes VEX. */
|
||||
typedef enum {PET_NONE = 0, PET_REX, PET_VEX2BYTES, PET_VEX3BYTES} _PrefixExtType;
|
||||
|
||||
/* Specifies an index into a table of prefixes by their type. */
|
||||
typedef enum {PFXIDX_NONE = -1, PFXIDX_REX, PFXIDX_LOREP, PFXIDX_SEG, PFXIDX_OP_SIZE, PFXIDX_ADRS, PFXIDX_MAX} _PrefixIndexer;
|
||||
|
||||
/*
|
||||
* This holds the prefixes state for the current instruction we decode.
|
||||
* decodedPrefixes includes all specific prefixes that the instruction got.
|
||||
* start is a pointer to the first prefix to take into account.
|
||||
* last is a pointer to the last byte we scanned.
|
||||
* Other pointers are used to keep track of prefixes positions and help us know if they appeared already and where.
|
||||
*/
|
||||
typedef struct {
|
||||
_iflags decodedPrefixes, usedPrefixes;
|
||||
/* Number of prefixes scanned for current instruction, including VEX! */
|
||||
unsigned int count;
|
||||
uint16_t unusedPrefixesMask;
|
||||
/* Holds the offset to the prefix byte by its type. */
|
||||
uint16_t pfxIndexer[PFXIDX_MAX];
|
||||
_PrefixExtType prefixExtType;
|
||||
/* Indicates whether the operand size prefix (0x66) was used as a mandatory prefix. */
|
||||
int isOpSizeMandatory;
|
||||
/* If VEX prefix is used, store the VEX.vvvv field. */
|
||||
unsigned int vexV;
|
||||
/* The fields B/X/R/W/L of REX and VEX are stored together in this byte. */
|
||||
unsigned int vrex;
|
||||
const uint8_t* vexPos;
|
||||
} _PrefixState;
|
||||
|
||||
/*
|
||||
* Intel supports 6 types of prefixes, whereas AMD supports 5 types (lock is seperated from rep/nz).
|
||||
* REX is the fifth prefix type, this time I'm based on AMD64.
|
||||
* VEX is the 6th, though it can't be repeated.
|
||||
*/
|
||||
#define MAX_PREFIXES (5)
|
||||
|
||||
extern int PrefixTables[256 * 2];
|
||||
|
||||
_INLINE_ int prefixes_is_valid(unsigned char ch, _DecodeType dt)
|
||||
{
|
||||
/* The predicate selects (branchlessly) second half table for 64 bits otherwise selects first half. */
|
||||
return PrefixTables[ch + ((dt >> 1) << 8)];
|
||||
}
|
||||
|
||||
/* Ignore a specific prefix type. */
|
||||
_INLINE_ void prefixes_ignore(_PrefixState* ps, _PrefixIndexer pi)
|
||||
{
|
||||
/*
|
||||
* If that type of prefix appeared already, set the bit of that *former* prefix.
|
||||
* Anyway, set the new index of that prefix type to the current index, so next time we know its position.
|
||||
*/
|
||||
ps->unusedPrefixesMask |= ps->pfxIndexer[pi];
|
||||
}
|
||||
|
||||
void prefixes_ignore_all(_PrefixState* ps);
|
||||
uint16_t prefixes_set_unused_mask(_PrefixState* ps);
|
||||
void prefixes_decode(_CodeInfo* ci, _PrefixState* ps);
|
||||
void prefixes_use_segment(_iflags defaultSeg, _PrefixState* ps, _DecodeType dt, _DInst* di);
|
||||
|
||||
#endif /* PREFIX_H */
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
textdefs.c
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "textdefs.h"
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
static uint8_t Nibble2ChrTable[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
#define NIBBLE_TO_CHR Nibble2ChrTable[t]
|
||||
|
||||
void str_hex(_WString* s, const uint8_t* buf, unsigned int len)
|
||||
{
|
||||
/* 256 * 2 : 2 chars per byte value. */
|
||||
static const char* TextBTable =
|
||||
"000102030405060708090a0b0c0d0e0f" \
|
||||
"101112131415161718191a1b1c1d1e1f" \
|
||||
"202122232425262728292a2b2c2d2e2f" \
|
||||
"303132333435363738393a3b3c3d3e3f" \
|
||||
"404142434445464748494a4b4c4d4e4f" \
|
||||
"505152535455565758595a5b5c5d5e5f" \
|
||||
"606162636465666768696a6b6c6d6e6f" \
|
||||
"707172737475767778797a7b7c7d7e7f" \
|
||||
"808182838485868788898a8b8c8d8e8f" \
|
||||
"909192939495969798999a9b9c9d9e9f" \
|
||||
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" \
|
||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \
|
||||
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \
|
||||
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \
|
||||
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \
|
||||
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
|
||||
|
||||
unsigned int i = 0;
|
||||
/* Length is at least 1, enter loop. */
|
||||
s->length = len * 2;
|
||||
s->p[len * 2] = 0;
|
||||
do {
|
||||
RSHORT(&s->p[i]) = RSHORT(&TextBTable[(*buf) * 2]);
|
||||
buf++;
|
||||
i += 2;
|
||||
} while (i < len * 2);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
|
||||
void str_int_impl(unsigned char** s, uint64_t x)
|
||||
{
|
||||
int8_t* buf;
|
||||
int shift = 0;
|
||||
OFFSET_INTEGER t = x;
|
||||
|
||||
buf = (int8_t*)*s;
|
||||
|
||||
*buf++ = '0';
|
||||
*buf++ = 'x';
|
||||
|
||||
if (x == 0) {
|
||||
*buf = '0';
|
||||
*s += 3;
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
t >>= 4;
|
||||
shift += 4;
|
||||
} while (t);
|
||||
|
||||
do {
|
||||
shift -= 4;
|
||||
t = (x >> shift) & 0xf;
|
||||
*buf++ = NIBBLE_TO_CHR;
|
||||
} while (shift > 0);
|
||||
|
||||
*s = (unsigned char*)buf;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void str_int_impl(unsigned char** s, uint8_t src[8])
|
||||
{
|
||||
int8_t* buf;
|
||||
int i = 0, shift = 0;
|
||||
uint32_t x = RULONG(&src[sizeof(int32_t)]);
|
||||
int t;
|
||||
|
||||
buf = (int8_t*)*s;
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
buf += 2;
|
||||
|
||||
for (shift = 28; shift != -4; shift -= 4) {
|
||||
t = (x >> shift) & 0xf;
|
||||
if (i | t) buf[i++] = NIBBLE_TO_CHR;
|
||||
}
|
||||
|
||||
x = RULONG(src);
|
||||
for (shift = 28; shift != 0; shift -= 4) {
|
||||
t = (x >> shift) & 0xf;
|
||||
if (i | t) buf[i++] = NIBBLE_TO_CHR;
|
||||
}
|
||||
t = x & 0xf;
|
||||
buf[i++] = NIBBLE_TO_CHR;
|
||||
|
||||
*s += (size_t)(i + 2);
|
||||
}
|
||||
|
||||
#endif /* SUPPORT_64BIT_OFFSET */
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
textdefs.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TEXTDEFS_H
|
||||
#define TEXTDEFS_H
|
||||
|
||||
#include "config.h"
|
||||
#include "wstring.h"
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
#define PLUS_DISP_CHR '+'
|
||||
#define MINUS_DISP_CHR '-'
|
||||
#define OPEN_CHR '['
|
||||
#define CLOSE_CHR ']'
|
||||
#define SP_CHR ' '
|
||||
#define SEG_OFF_CHR ':'
|
||||
|
||||
/*
|
||||
Naming Convention:
|
||||
|
||||
* get - returns a pointer to a string.
|
||||
* str - concatenates to string.
|
||||
|
||||
* hex - means the function is used for hex dump (number is padded to required size) - Little Endian output.
|
||||
* code - means the function is used for disassembled instruction - Big Endian output.
|
||||
* off - means the function is used for 64bit offset - Big Endian output.
|
||||
|
||||
* h - '0x' in front of the string.
|
||||
|
||||
* b - byte
|
||||
* dw - double word (can be used for word also)
|
||||
* qw - quad word
|
||||
|
||||
* all numbers are in HEX.
|
||||
*/
|
||||
|
||||
void str_hex(_WString* s, const uint8_t* buf, unsigned int len);
|
||||
|
||||
#ifdef SUPPORT_64BIT_OFFSET
|
||||
#define str_int(s, x) str_int_impl((s), (x))
|
||||
void str_int_impl(unsigned char** s, uint64_t x);
|
||||
#else
|
||||
#define str_int(s, x) str_int_impl((s), (uint8_t*)&(x))
|
||||
void str_int_impl(unsigned char** s, uint8_t src[8]);
|
||||
#endif
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
|
||||
#endif /* TEXTDEFS_H */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
wstring.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WSTRING_H
|
||||
#define WSTRING_H
|
||||
|
||||
#include "config.h"
|
||||
#include "../include/mnemonics.h"
|
||||
|
||||
#ifndef DISTORM_LIGHT
|
||||
|
||||
_INLINE_ void strcat_WSR(unsigned char** str, const _WRegister* reg)
|
||||
{
|
||||
/*
|
||||
* Longest register name is YMM15 - 5 characters,
|
||||
* Copy 8 so compiler can do a QWORD move.
|
||||
* We copy nul termination and fix the length, so it's okay to copy more to the output buffer.
|
||||
* There's a sentinel register to make sure we don't read past the end of the registers table.
|
||||
*/
|
||||
memcpy((int8_t*)*str, (const int8_t*)reg->p, 8);
|
||||
*str += reg->length;
|
||||
}
|
||||
|
||||
#define strfinalize_WS(s, end) do { *end = 0; s.length = (unsigned int)((size_t)end - (size_t)s.p); } while (0)
|
||||
#define chrcat_WS(s, ch) do { *s = ch; s += 1; } while (0)
|
||||
#define strcat_WS(s, buf, copylen, advancelen) do { memcpy((int8_t*)s, buf, copylen); s += advancelen; } while(0)
|
||||
|
||||
#endif /* DISTORM_LIGHT */
|
||||
|
||||
#endif /* WSTRING_H */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
x86defs.h
|
||||
|
||||
diStorm3 - Powerful disassembler for X86/AMD64
|
||||
http://ragestorm.net/distorm/
|
||||
distorm at gmail dot com
|
||||
Copyright (C) 2003-2021 Gil Dabah
|
||||
This library is licensed under the BSD license. See the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef X86DEFS_H
|
||||
#define X86DEFS_H
|
||||
|
||||
|
||||
#define SEG_REGS_MAX (6)
|
||||
#define CREGS_MAX (9)
|
||||
#define DREGS_MAX (8)
|
||||
|
||||
/* Maximum instruction size, including prefixes */
|
||||
#define INST_MAXIMUM_SIZE (15)
|
||||
|
||||
/* Maximum range of imm8 (comparison type) of special SSE CMP instructions. */
|
||||
#define INST_CMP_MAX_RANGE (8)
|
||||
|
||||
/* Maximum range of imm8 (comparison type) of special AVX VCMP instructions. */
|
||||
#define INST_VCMP_MAX_RANGE (32)
|
||||
|
||||
/* Wait instruction byte code. */
|
||||
#define INST_WAIT_INDEX (0x9b)
|
||||
|
||||
/* Lea instruction byte code. */
|
||||
#define INST_LEA_INDEX (0x8d)
|
||||
|
||||
/* NOP/XCHG instruction byte code. */
|
||||
#define INST_NOP_INDEX (0x90)
|
||||
|
||||
/* ARPL/MOVSXD instruction byte code. */
|
||||
#define INST_ARPL_INDEX (0x63)
|
||||
|
||||
/*
|
||||
* Minimal MODR/M value of divided instructions.
|
||||
* It's 0xc0, two MSBs set, which indicates a general purpose register is used too.
|
||||
*/
|
||||
#define INST_DIVIDED_MODRM (0xc0)
|
||||
|
||||
/* This is the escape byte value used for 3DNow! instructions. */
|
||||
#define _3DNOW_ESCAPE_BYTE (0x0f)
|
||||
|
||||
#define PREFIX_LOCK (0xf0)
|
||||
#define PREFIX_REPNZ (0xf2)
|
||||
#define PREFIX_REP (0xf3)
|
||||
#define PREFIX_CS (0x2e)
|
||||
#define PREFIX_SS (0x36)
|
||||
#define PREFIX_DS (0x3e)
|
||||
#define PREFIX_ES (0x26)
|
||||
#define PREFIX_FS (0x64)
|
||||
#define PREFIX_GS (0x65)
|
||||
#define PREFIX_OP_SIZE (0x66)
|
||||
#define PREFIX_ADDR_SIZE (0x67)
|
||||
#define PREFIX_VEX2b (0xc5)
|
||||
#define PREFIX_VEX3b (0xc4)
|
||||
|
||||
/* REX prefix value range, 64 bits mode decoding only. */
|
||||
#define PREFIX_REX_LOW (0x40)
|
||||
#define PREFIX_REX_HI (0x4f)
|
||||
/* In order to use the extended GPR's we have to add 8 to the Modr/M info values. */
|
||||
#define EX_GPR_BASE (8)
|
||||
|
||||
/* Mask for REX and VEX features: */
|
||||
/* Base */
|
||||
#define PREFIX_EX_B (1)
|
||||
/* Index */
|
||||
#define PREFIX_EX_X (2)
|
||||
/* Register */
|
||||
#define PREFIX_EX_R (4)
|
||||
/* Operand Width */
|
||||
#define PREFIX_EX_W (8)
|
||||
/* Vector Lengh */
|
||||
#define PREFIX_EX_L (0x10)
|
||||
|
||||
#endif /* X86DEFS_H */
|
||||
Reference in New Issue
Block a user