diff options
Diffstat (limited to 'thirdparty/mhook/disasm-lib/disasm.h')
-rw-r--r-- | thirdparty/mhook/disasm-lib/disasm.h | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/thirdparty/mhook/disasm-lib/disasm.h b/thirdparty/mhook/disasm-lib/disasm.h new file mode 100644 index 00000000..6e35ab72 --- /dev/null +++ b/thirdparty/mhook/disasm-lib/disasm.h @@ -0,0 +1,578 @@ +// Copyright (C) 2004, Matt Conover (mconover@gmail.com) +// +// WARNING: +// I wouldn't recommend changing any flags like OP_*, ITYPE_*, or *_MASK +// aside from those marked as UNUSED. This is because the flags parts of +// the flags are architecture independent and other are left to specific +// architectures to define, so unless you understand the relationships +// between them, I would leave them as is. + +#ifndef DISASM_H +#define DISASM_H +#ifdef __cplusplus +extern "C" { +#endif +#include <windows.h> +#include <stdio.h> +#include "misc.h" + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; +typedef signed long S32; +typedef unsigned long U32; +typedef LONG64 S64; +typedef ULONG64 U64; + +#ifdef SPEEDY +// On Visual Studio 6, making the internal functions inline makes compiling take forever +#define INTERNAL static _inline +#define INLINE _inline +#else +#define INTERNAL static +#define INLINE +#endif + +#define VALID_INSTRUCTION(i) ((i) && !((i)->ErrorOccurred)) +#define NEXT_INSTRUCTION(i) ((i)->Address + (i)->Length) +#define DISASM_ARCH_TYPE(dis) ((dis)->ArchType) +#define INS_ARCH_TYPE(ins) DISASM_ARCH_TYPE((ins)->Disassembler) + +// NOTE: these should be as big set to the maximum of the supported architectures +#define MAX_PREFIX_LENGTH 15 +#define MAX_OPERAND_COUNT 3 +#define MAX_INSTRUCTION_LENGTH 25 +#define MAX_OPCODE_LENGTH 3 +#define MAX_OPCODE_DESCRIPTION 256 + +///////////////////////////////////////////////////////////////////// +// Code branch +///////////////////////////////////////////////////////////////////// + +#define MAX_CODE_REFERENCE_COUNT 3 + +typedef struct _CODE_BRANCH +{ + U64 Addresses[MAX_CODE_REFERENCE_COUNT]; // NULL if multiple to addresses + U32 Count; + U8 IsLoop : 1; + U8 IsCall : 1; // branch if false + U8 IsIndirect : 1; // call/jmp [Address] + U8 AddressOffset: 5; + struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address +} CODE_BRANCH; + +///////////////////////////////////////////////////////////////////// +// Data references +///////////////////////////////////////////////////////////////////// + +#define MAX_DATA_REFERENCE_COUNT 3 + +typedef struct _DATA_REFERENCE +{ + U64 Addresses[MAX_DATA_REFERENCE_COUNT]; // NULL if multiple to addresses + U32 Count; + ULONG_PTR DataSize; + struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address +} DATA_REFERENCE; + +//////////////////////////////////////////////////////////////////// +// Instruction +///////////////////////////////////////////////////////////////////// + +// +// Instruction types (bits 0-7) +// Instruction groups (bits 8-26) +// +#define ITYPE_EXEC_OFFSET (1<<8) +#define ITYPE_ARITH_OFFSET (1<<9) +#define ITYPE_LOGIC_OFFSET (1<<10) +#define ITYPE_STACK_OFFSET (1<<11) +#define ITYPE_TESTCOND_OFFSET (1<<12) +#define ITYPE_LOAD_OFFSET (1<<13) +#define ITYPE_ARRAY_OFFSET (1<<14) +#define ITYPE_BIT_OFFSET (1<<15) +#define ITYPE_FLAG_OFFSET (1<<16) +#define ITYPE_FPU_OFFSET (1<<17) +#define ITYPE_TRAPS_OFFSET (1<<18) +#define ITYPE_SYSTEM_OFFSET (1<<19) +#define ITYPE_OTHER_OFFSET (1<<20) +#define ITYPE_UNUSED1_OFFSET (1<<21) +#define ITYPE_UNUSED2_OFFSET (1<<22) +#define ITYPE_UNUSED3_OFFSET (1<<23) +#define ITYPE_UNUSED4_OFFSET (1<<24) +#define ITYPE_UNUSED5_OFFSET (1<<25) +#define ITYPE_UNUSED6_OFFSET (1<<26) +#define ITYPE_EXT_UNUSED1 (1<<27) +#define ITYPE_EXT_UNUSED2 (1<<28) +#define ITYPE_EXT_UNUSED3 (1<<29) +#define ITYPE_EXT_UNUSED4 (1<<30) +#define ITYPE_EXT_UNUSED5 (1<<31) + +// +// X86-specific flags (bits 27-31) +// + +#define ITYPE_EXT_64 ITYPE_EXT_UNUSED1 // Use index 1 if in 64-bit mode and 0 otherwise +#define ITYPE_EXT_MODRM ITYPE_EXT_UNUSED2 // ModRM byte may extend the opcode +#define ITYPE_EXT_SUFFIX ITYPE_EXT_UNUSED3 // byte after ModRM/SIB/displacement is the third opcode +#define ITYPE_EXT_PREFIX ITYPE_EXT_UNUSED4 // prefix +#define ITYPE_EXT_FPU ITYPE_EXT_UNUSED5 // FPU instructions require special handling + +#define ITYPE_3DNOW_OFFSET ITYPE_UNUSED1_OFFSET +#define ITYPE_MMX_OFFSET ITYPE_UNUSED2_OFFSET +#define ITYPE_SSE_OFFSET ITYPE_UNUSED3_OFFSET +#define ITYPE_SSE2_OFFSET ITYPE_UNUSED4_OFFSET +#define ITYPE_SSE3_OFFSET ITYPE_UNUSED5_OFFSET + +// +// Instruction types +// + +#define ITYPE_TYPE_MASK 0x7FFFFFFF +#define ITYPE_GROUP_MASK 0x7FFFFF00 + +typedef enum _INSTRUCTION_TYPE +{ + // ITYPE_EXEC group + ITYPE_EXEC = ITYPE_EXEC_OFFSET, + ITYPE_BRANCH, + ITYPE_BRANCHCC, // conditional (not necessarily just flags) + ITYPE_CALL, + ITYPE_CALLCC, // conditional (not necessarily just flags) + ITYPE_RET, + ITYPE_LOOPCC, + + // ITYPE_ARITH group + ITYPE_ARITH = ITYPE_ARITH_OFFSET, + ITYPE_XCHGADD, + ITYPE_ADD, + ITYPE_SUB, + ITYPE_MUL, + ITYPE_DIV, + ITYPE_INC, + ITYPE_DEC, + ITYPE_SHL, + ITYPE_SHR, + ITYPE_ROL, + ITYPE_ROR, + + // ITYPE_LOGIC group + ITYPE_LOGIC=ITYPE_LOGIC_OFFSET, + ITYPE_AND, + ITYPE_OR, + ITYPE_XOR, + ITYPE_NOT, + ITYPE_NEG, + + // ITYPE_STACK group + ITYPE_STACK=ITYPE_STACK_OFFSET, + ITYPE_PUSH, + ITYPE_POP, + ITYPE_PUSHA, + ITYPE_POPA, + ITYPE_PUSHF, + ITYPE_POPF, + ITYPE_ENTER, + ITYPE_LEAVE, + + // ITYPE_TESTCOND group + ITYPE_TESTCOND=ITYPE_TESTCOND_OFFSET, + ITYPE_TEST, + ITYPE_CMP, + + // ITYPE_LOAD group + ITYPE_LOAD=ITYPE_LOAD_OFFSET, + ITYPE_MOV, + ITYPE_MOVCC, // conditional + ITYPE_LEA, + ITYPE_XCHG, + ITYPE_XCHGCC, // conditional + + // ITYPE_ARRAY group + ITYPE_ARRAY=ITYPE_ARRAY_OFFSET, + ITYPE_STRCMP, + ITYPE_STRLOAD, + ITYPE_STRMOV, + ITYPE_STRSTOR, + ITYPE_XLAT, + + // ITYPE_BIT group + ITYPE_BIT=ITYPE_BIT_OFFSET, + ITYPE_BITTEST, + ITYPE_BITSET, + ITYPE_BITCLR, + + // ITYPE_FLAG group + // PF = parify flag + // ZF = zero flag + // OF = overflow flag + // DF = direction flag + // SF = sign flag + ITYPE_FLAG=ITYPE_FLAG_OFFSET, + // clear + ITYPE_CLEARCF, + ITYPE_CLEARZF, + ITYPE_CLEAROF, + ITYPE_CLEARDF, + ITYPE_CLEARSF, + ITYPE_CLEARPF, + // set + ITYPE_SETCF, + ITYPE_SETZF, + ITYPE_SETOF, + ITYPE_SETDF, + ITYPE_SETSF, + ITYPE_SETPF, + // toggle + ITYPE_TOGCF, + ITYPE_TOGZF, + ITYPE_TOGOF, + ITYPE_TOGDF, + ITYPE_TOGSF, + ITYPE_TOGPF, + + // ITYPE_FPU group + ITYPE_FPU=ITYPE_FPU_OFFSET, + ITYPE_FADD, + ITYPE_FSUB, + ITYPE_FMUL, + ITYPE_FDIV, + ITYPE_FCOMP, + ITYPE_FEXCH, + ITYPE_FLOAD, + ITYPE_FLOADENV, + ITYPE_FSTORE, + ITYPE_FSTOREENV, + ITYPE_FSAVE, + ITYPE_FRESTORE, + ITYPE_FMOVCC, + + ITYPE_UNUSED1=ITYPE_UNUSED1_OFFSET, + ITYPE_UNUSED2=ITYPE_UNUSED2_OFFSET, + ITYPE_UNUSED3=ITYPE_UNUSED3_OFFSET, + + // ITYPE_MMX group + ITYPE_MMX=ITYPE_MMX_OFFSET, + ITYPE_MMX_MOV, + ITYPE_MMX_ADD, + ITYPE_MMX_SUB, + ITYPE_MMX_MUL, + ITYPE_MMX_DIV, + ITYPE_MMX_AND, + ITYPE_MMX_OR, + ITYPE_MMX_XOR, + ITYPE_MMX_CMP, + + // ITYPE_SSE group + ITYPE_SSE=ITYPE_SSE_OFFSET, + ITYPE_SSE_MOV, + ITYPE_SSE_ADD, + ITYPE_SSE_SUB, + ITYPE_SSE_MUL, + ITYPE_SSE_DIV, + ITYPE_SSE_AND, + ITYPE_SSE_OR, + ITYPE_SSE_XOR, + ITYPE_SSE_CMP, + + // ITYPE_SSE2 group + ITYPE_SSE2=ITYPE_SSE2_OFFSET, + ITYPE_SSE2_MOV, + ITYPE_SSE2_ADD, + ITYPE_SSE2_SUB, + ITYPE_SSE2_MUL, + ITYPE_SSE2_DIV, + ITYPE_SSE2_AND, + ITYPE_SSE2_OR, + ITYPE_SSE2_XOR, + ITYPE_SSE2_CMP, + + // ITYPE_SSE3 group + ITYPE_SSE3=ITYPE_SSE3_OFFSET, + ITYPE_SSE3_MOV, + ITYPE_SSE3_ADD, + ITYPE_SSE3_SUB, + ITYPE_SSE3_MUL, + ITYPE_SSE3_DIV, + ITYPE_SSE3_AND, + ITYPE_SSE3_OR, + ITYPE_SSE3_XOR, + ITYPE_SSE3_CMP, + + // ITYPE_3DNOW group + ITYPE_3DNOW=ITYPE_3DNOW_OFFSET, + ITYPE_3DNOW_ADD, + ITYPE_3DNOW_SUB, + ITYPE_3DNOW_MUL, + ITYPE_3DNOW_DIV, + ITYPE_3DNOW_CMP, + ITYPE_3DNOW_XCHG, + + // ITYPE_TRAP + ITYPE_TRAPS=ITYPE_TRAPS_OFFSET, + ITYPE_TRAP, // generate trap + ITYPE_TRAPCC, // conditional trap gen + ITYPE_TRAPRET, // return from trap + ITYPE_BOUNDS, // gen bounds trap + ITYPE_DEBUG, // gen breakpoint trap + ITYPE_TRACE, // gen single step trap + ITYPE_INVALID, // gen invalid instruction + ITYPE_OFLOW, // gen overflow trap + + // ITYPE_SYSTEM group + ITYPE_SYSTEM=ITYPE_SYSTEM_OFFSET, + ITYPE_HALT, // halt machine + ITYPE_IN, // input form port + ITYPE_OUT, // output to port + ITYPE_CPUID, // identify cpu + ITYPE_SETIF, // allow interrupts + ITYPE_CLEARIF, // block interrupts + ITYPE_SYSCALL, + ITYPE_SYSCALLRET, + + // ITYPE_OTHER group + ITYPE_OTHER = ITYPE_OTHER_OFFSET, + ITYPE_NOP, + ITYPE_BCDCONV, // convert to/from BCD + ITYPE_SZCONV // convert size of operand +} INSTRUCTION_TYPE; + +// +// Operand flags +// + +// Type = bits 0-6 (these are mutually exclusive -- bits 0-6 will always be a power of 2)) +#define OPTYPE_NONE 0x00 +#define OPTYPE_IMM 0x01 // immediate value +#define OPTYPE_OFFSET 0x02 // relative offset +#define OPTYPE_FLOAT 0x03 // floating point +#define OPTYPE_BCD 0x04 +#define OPTYPE_STRING 0x05 +#define OPTYPE_SPECIAL 0x06 +#define OPTYPE_MASK 0x7F + +// Flags = bits 7-23 (these can be combinations) +// These are used in the X86 opcode table +#define OP_REG (1<<7) // 0x80 +#define OP_SIGNED (1<<8) +#define OP_SYS (1<<9) // parameter is an index into some system structure +#define OP_CONDR (1<<10) +#define OP_CONDW (1<<11) +#define OP_UNUSED (1<<12) +#define OP_SRC (1<<13) // operand is source operand +#define OP_DST (1<<14) // operand is destination operand +#define OP_EXEC (1<<15) // operand is executed + +#define OP_CONDE OP_CONDR +#define OP_COND_EXEC (OP_CONDE|OP_EXEC) // executed only if the pre-conditions are met +#define OP_COND_SRC (OP_CONDR|OP_SRC) // set only if pre-conditions are met +#define OP_COND_DST (OP_CONDW|OP_DST) // set only if pre-conditions are met +#define OP_COND (OP_CONDR|OP_CONDW) + +// Bits 16-31 are available for use outside of the opcode table, but they can only +// be used in INSTRUCTION_OPERAND.Flags, they may conflit with the architecture specific +// operands. For example, bits 16-31 are used in X86 for AMODE_* and OPTYPE_* +#define OP_ADDRESS (1<<16) +#define OP_LOCAL (1<<17) +#define OP_PARAM (1<<18) +#define OP_GLOBAL (1<<19) +#define OP_FAR (1<<20) +#define OP_IPREL (1<<21) + +// +// X86-specific flags (bits 27-31) +// +#define OP_MSR (OP_SYS|OP_UNUSED) + +// +// Other architecture flags +// +#define OP_DELAY OP_UNUSED // delayed instruction (e.g., delayed branch that executes after the next instruction) + +///////////////////////////////////////////////////////////////////// +// Architectures +///////////////////////////////////////////////////////////////////// + +typedef enum _ARCHITECTURE_TYPE +{ + ARCH_UNKNOWN=0, + + // x86-based + ARCH_X86, // 32-bit x86 + ARCH_X86_16, // 16-bit x86 + ARCH_X64, // AMD64 and Intel EMD64 + + // everything else + ARCH_ALPHA, + ARCH_ARM, + ARCH_DOTNET, + ARCH_EFI, + ARCH_IA64, + ARCH_M68K, + ARCH_MIPS, + ARCH_PPC, + ARCH_SH3, + ARCH_SH4, + ARCH_SPARC, + ARCH_THUMB + +} ARCHITECTURE_TYPE; + +typedef BOOL (*INIT_INSTRUCTION)(struct _INSTRUCTION *Instruction); +typedef void (*DUMP_INSTRUCTION)(struct _INSTRUCTION *Instruction, BOOL ShowBytes, BOOL Verbose); +typedef BOOL (*GET_INSTRUCTION)(struct _INSTRUCTION *Instruction, U8 *Address, U32 Flags); +typedef U8 *(*FIND_FUNCTION_BY_PROLOGUE)(struct _INSTRUCTION *Instruction, U8 *StartAddress, U8 *EndAddress, U32 Flags); + +typedef struct _ARCHITECTURE_FORMAT_FUNCTIONS +{ + INIT_INSTRUCTION InitInstruction; + DUMP_INSTRUCTION DumpInstruction; + GET_INSTRUCTION GetInstruction; + FIND_FUNCTION_BY_PROLOGUE FindFunctionByPrologue; +} ARCHITECTURE_FORMAT_FUNCTIONS; + +typedef struct _ARCHITECTURE_FORMAT +{ + ARCHITECTURE_TYPE Type; + ARCHITECTURE_FORMAT_FUNCTIONS *Functions; +} ARCHITECTURE_FORMAT; + +#define DISASSEMBLER_INITIALIZED 0x1234566F +#define INSTRUCTION_INITIALIZED 0x1234567F + +#include "disasm_x86.h" + +typedef struct DECLSPEC_ALIGN(16) _S128 +{ + U64 Low; + S64 High; +} S128; +typedef struct DECLSPEC_ALIGN(16) _U128 +{ + U64 Low; + U64 High; +} U128; + +typedef struct _INSTRUCTION_OPERAND +{ + U32 Flags; + U8 Type : 6; + U8 Unused : 2; + U16 Length; + + + // If non-NULL, this indicates the target address of the instruction (e.g., a branch or + // a displacement with no base register). However, this address is only reliable if the + // image is mapped correctly (e.g., the executable is mapped as an image and fixups have + // been applied if it is not at its preferred image base). + // + // If disassembling a 16-bit DOS application, TargetAddress is in the context of + // X86Instruction->Segment. For example, if TargetAddress is the address of a code branch, + // it is in the CS segment (unless X86Instruction->HasSegmentOverridePrefix is set). If + // TargetAddress is a data pointer, it is in the DS segment (unless + // X86Instruction->HasSegmentOverridePrefix is set) + U64 TargetAddress; + U32 Register; + + union + { + // All 8/16/32-bit operands are extended to 64-bits automatically + // If you want to downcast, check whether Flags & OP_SIGNED is set + // Like this: + // U32 GetOperand32(OPERAND *Operand) + // { + // if (Operand->Flags & OP_SIGNED) return (S32)Operand->Value_S64; + // else return (U32)Operand->Value_U64; + //} + U64 Value_U64; + S64 Value_S64; + U128 Value_U128; + U128 Float128; + U8 Float80[80]; + U8 BCD[10]; + }; +} INSTRUCTION_OPERAND; + +typedef struct _INSTRUCTION +{ + U32 Initialized; + struct _DISASSEMBLER *Disassembler; + + char String[MAX_OPCODE_DESCRIPTION]; + U8 StringIndex; + U64 VirtualAddressDelta; + + U32 Groups; // ITYPE_EXEC, ITYPE_ARITH, etc. -- NOTE groups can be OR'd together + INSTRUCTION_TYPE Type; // ITYPE_ADD, ITYPE_RET, etc. -- NOTE there is only one possible type + + U8 *Address; + U8 *OpcodeAddress; + U32 Length; + + U8 Prefixes[MAX_PREFIX_LENGTH]; + U32 PrefixCount; + + U8 LastOpcode; // last byte of opcode + U8 OpcodeBytes[MAX_OPCODE_LENGTH]; + U32 OpcodeLength; // excludes any operands and prefixes + + INSTRUCTION_OPERAND Operands[MAX_OPERAND_COUNT]; + U32 OperandCount; + + X86_INSTRUCTION X86; + + DATA_REFERENCE DataSrc; + DATA_REFERENCE DataDst; + CODE_BRANCH CodeBranch; + + // Direction depends on which direction the stack grows + // For example, on x86 a push results in StackChange < 0 since the stack grows down + // This is only relevant if (Group & ITYPE_STACK) is true + // + // If Groups & ITYPE_STACK is set but StackChange = 0, it means that the change + // couldn't be determined (non-constant) + LONG StackChange; + + // Used to assist in debugging + // If set, the current instruction is doing something that requires special handling + // For example, popf can cause tracing to be disabled + + U8 StringAligned : 1; // internal only + U8 NeedsEmulation : 1; // instruction does something that re + U8 Repeat : 1; // instruction repeats until some condition is met (e.g., REP prefix on X86) + U8 ErrorOccurred : 1; // set if instruction is invalid + U8 AnomalyOccurred : 1; // set if instruction is anomalous + U8 LastInstruction : 1; // tells the iterator callback it is the last instruction + U8 CodeBlockFirst: 1; + U8 CodeBlockLast : 1; +} INSTRUCTION; + +typedef struct _DISASSEMBLER +{ + U32 Initialized; + ARCHITECTURE_TYPE ArchType; + ARCHITECTURE_FORMAT_FUNCTIONS *Functions; + INSTRUCTION Instruction; + U32 Stage1Count; // GetInstruction called + U32 Stage2Count; // Opcode fully decoded + U32 Stage3CountNoDecode; // made it through all checks when DISASM_DECODE is not set + U32 Stage3CountWithDecode; // made it through all checks when DISASM_DECODE is set +} DISASSEMBLER; + +#define DISASM_DISASSEMBLE (1<<1) +#define DISASM_DECODE (1<<2) +#define DISASM_SUPPRESSERRORS (1<<3) +#define DISASM_SHOWFLAGS (1<<4) +#define DISASM_ALIGNOUTPUT (1<<5) +#define DISASM_DISASSEMBLE_MASK (DISASM_ALIGNOUTPUT|DISASM_SHOWBYTES|DISASM_DISASSEMBLE) + +BOOL InitDisassembler(DISASSEMBLER *Disassembler, ARCHITECTURE_TYPE Architecture); +void CloseDisassembler(DISASSEMBLER *Disassembler); +INSTRUCTION *GetInstruction(DISASSEMBLER *Disassembler, U64 VirtualAddress, U8 *Address, U32 Flags); + +#ifdef __cplusplus +} +#endif +#endif // DISASM_H |