Hacker Disassembler Engine 64 C 0.04 FINAL ========================================== 1. What is it? 2. How to use? 3. Invalid instructions 4. Contacts My english is bad, I hope that you understand me ;) If you can translate the russian documentation, email me, please :) 1. What is it? ============== HDE64C is a small disassembler engine, intended for analysis of x86-64 code. It gets information about instruction (length, prefixes, opcode, ModR/M, SIB,..) and also detects invalid instructions. You can use the engine, for example, when working with executables, writing viruses, because most disassemblers too get only assembler mnemonic and aren't intended for analysis of code, but most simple length disassemblers get too little info. HDE64C gets enough info for analysis, but it has very small size. + support General-Purpose, FPU, MMX, SSE-SSE3, 3DNow! instructions + high-speed and small size (~ 2.5 kb) + operating system independent code 2. How to use? ============== To disassemble instruction should call "hde64_disasm" function. First argument is pointer to code, second - pointer to "hde64s" structure: unsigned int hde64_disasm(const void *code, hde64s *hs); You should follow C convention of arguments passing. The function returns length of the instruction and fill "hde64s" structure: typedef struct { uint8_t len; // length of command uint8_t p_rep; // rep/repz (0xf3) & repnz (0xf2) prefix uint8_t p_lock; // lock prefix: 0xf0 uint8_t p_seg; // segment prefix: 0x26,0x2e,0x36,0x3e,0x64,0x65 uint8_t p_66; // operand-size override prefix: 0x66 uint8_t p_67; // address-size override prefix: 0x67 uint8_t rex; // REX prefix uint8_t rex_w; // REX.W uint8_t rex_r; // REX.R uint8_t rex_x; // REX.X uint8_t rex_b; // REX.B uint8_t opcode; // opcode uint8_t opcode2; // second opcode (if first opcode is 0x0f) uint8_t modrm; // ModR/M byte uint8_t modrm_mod; // ModR/M.mod uint8_t modrm_reg; // ModR/M.reg uint8_t modrm_rm; // ModR/M.r/m uint8_t sib; // SIB byte uint8_t sib_scale; // SIB.scale uint8_t sib_index; // SIB.index uint8_t sib_base; // SIB.base union { uint8_t imm8; // immediate value imm8 uint16_t imm16; // immediate value imm16 uint32_t imm32; // immediate value imm32 uint64_t imm64; // immediate value imm64 } imm; union { uint8_t disp8; // displacement disp8 uint16_t disp16; // displacement disp16 uint32_t disp32; // displacement disp32 } disp; uint32_t flags; // flags } hde64s; Special cases of immediate values are relative addresses. In previous versions of the engine this values stores to hde32s.rel* fields. But now it stored to hde32s.imm* as all others immediates. You can detect relative address by flag F_RELATIVE, which setted with one of F_IMM* flags (see below). Alignment of structure "hde64s" is 1 byte (no alignment). Be careful, check settings of your compiler or use headers from this package. Fields "hde64s.opcode" and "hde64s.len" will be always. Presence of other fields you can get with following flags in field "hde64s.flags": #define F_MODRM 0x00000001 // ModR/M exists #define F_SIB 0x00000002 // SIB exists #define F_IMM8 0x00000004 // immediate value imm8 exists #define F_IMM16 0x00000008 // immediate value imm16 exists #define F_IMM32 0x00000010 // immediate value imm32 exists #define F_IMM64 0x00000020 // immediate value imm64 exists #define F_DISP8 0x00000040 // displacement disp8 exists #define F_DISP16 0x00000080 // displacement disp16 exists #define F_DISP32 0x00000100 // displacement disp32 exists #define F_RELATIVE 0x00000200 // relative address rel8 exists #define F_PREFIX_REPNZ 0x01000000 // repnz prefix exists #define F_PREFIX_REPX 0x02000000 // rep(z) prefix exists #define F_PREFIX_REP 0x03000000 // rep(z) or repnz prefix exists #define F_PREFIX_66 0x04000000 // 0x66 prefix exists #define F_PREFIX_67 0x08000000 // 0x67 prefix exists #define F_PREFIX_LOCK 0x10000000 // lock prefix exists #define F_PREFIX_SEG 0x20000000 // segment prefix exists #define F_PREFIX_REX 0x40000000 // REX prefix exists #define F_PREFIX_ANY 0x7f000000 // any prefix esists HDE64C guaranteed that it read from "const void *code" no more than 26 bytes, if instruction is valid, than HDE64C read no more than "hde64s.len" bytes and "hde64s.len" always no more than 15. 3. Invalid instructions ======================= HDE64C analyses instruction for invalid, and do it thoroughly (more than half of the size of engine is code and tables for detecting invalid instructions). If HDE64C think, that instruction is invalid, it set flag "F_ERROR": #define F_ERROR 0x00001000 // invalid instruction Besides, HDE64C set flags to explain type of error: #define F_ERROR_OPCODE 0x00002000 // invalid opcode #define F_ERROR_LENGTH 0x00004000 // length of command more than 15 #define F_ERROR_LOCK 0x00008000 // prefix lock isn't allowed #define F_ERROR_OPERAND 0x00010000 // operand isn't allowed On case of "F_ERROR_OPCODE" flag, under notion opcode is understood not only "hde64s.opcode(2)" byte, but besides opcode's extension in ModR/M.reg, ModR/M or prefix (when two-byte opcode). So, HDE64C detects commands like "c6 c8 00" as invalid, because opcode "c6 /1" is invalid. If HDE64C setted flag "F_ERROR_LENGTH", then field "hde64s.len" is 15, so maximal value of "hde64s.len" is 15. If engine detect instruction as invalid, it doesn't stop disassembling and continue disassembling in general rules, but error flag (F_ERROR) and flag of error's type (F_ERROR_*) will be setted. 4. Contacts =========== Author: Vyacheslav Patkov E-mail: patkov-mail at mail.ru WWW: http://hde32.narod.ru/ Please, mail me on russian or english language. Use text format of email, don't send me beautiful HTML or (oh my god) DOC messages. P. S. I'm boring with HDE64. So, the version is final. And maybe there are bugs (but I have no bug reports yet, and the engine succesfully passed my own tests). If YOU want continute HDE64 history -- fork it.