public static UInt32 tq_I(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { instr.ops[op_index].flags |= (byte)OP_TYPE.OPERAND_TYPE_IMM; instr.ops[op_index].size = (ushort)opsize.size; instr.ops[op_index].value.imm.size = (byte)opsize.size_in_stream; instr.ops[op_index].value.imm .offset = (byte)(offset - origin_offset); //instr.ops[op_index].value.imm.immab = assembly.Image.ReadBytes(offset, opsize.size_in_stream); byte[] bt = assembly.ReadBytes(offset, (int)opsize.size_in_stream); instr.ops[op_index].value.imm.imm64 = 0; foreach (byte bb in bt.Reverse()) { instr.ops[op_index].value.imm.imm64 <<= 8; instr.ops[op_index].value.imm.imm64 += bb; } //!!!memcpy(&(instr.ops[op_index].value.imm.imm8), offset, opsize.size_in_stream); //movsx(ref instr.ops[op_index].value.imm.immab, opsize.size_in_stream, 0x8); return (byte)opsize.size_in_stream; }
static UInt32 post_proc_cmpxchg8b(ulong origin_offset, ulong offset, ref INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { if ((idata.prefixes[PREF_REX_INDEX] != 0xFF) && ((instr.rex & PREFIX_REX_W)!=0)) { idata.is_rex_used = 1; instr.mnemonic = "cmpxchg16b"; instr.ops[0].size = (ushort)OP_SIZE.OPERAND_SIZE_128; } return 0; }
static UInt32 post_proc_nop_pause(ulong origin_offset, ulong offset, ref INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { if (idata.prefixes[PREF_REP_INDEX] == PREF_REPNZ_ID) { instr.id = ID_PAUSE; instr.groups = GRP_CACHECT | GRP_SSE2; idata.prefixes[PREF_REP_INDEX] = 0xFF; instr.mnemonic ="pause"; } return 0; }
//Parses instruction's mnemonic. If mnemonic is simple, it is just copied to // struct INSTRUCTION. If mnemonic contains has multi mnemonic indicator (MM_INDICATOR) // at first character then it depends on implicit operand's size. In this case the function // calls get_instruction_opsize and builds choses mnemonic basing on result. static void parse_mnemonic(OPCODE_DESCRIPTOR opcode, INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { if ((opcode.mnemonic.value.Length>0) && (opcode.mnemonic.value[0] != MM_INDICATOR)) { instr.mnemonic = opcode.mnemonic.value; } else { get_instruction_opsize(opcode.mnemonic, instr, idata, mode); instr.mnemonic = opcode.mnemonic.values[bsr(instr.opsize) - 1]; } }
//Parses operand accordingly to MODRM value. static UInt32 parse_rm_operand(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, ref INTERNAL_DATA idata, DISMODE mode) { UInt32 len = 0; if ((instr.modrm & 0xC0) == 0xC0) { create_genreg_operand(ref instr, op_index, (byte)(instr.modrm & 0x7), opsize.size, PREFIX_REX_B, ref idata, mode); } else { len = parse_mem_operand(origin_offset, offset, ref instr, op_index, opsize, idata, mode); } return len; }
//Calculates segment for memory addressing operands accordingly to //mode, segment override prefixes and address base register. static void get_seg(ref INSTRUCTION instr, int op_index, byte[] prefixes, DISMODE mode) { if (prefixes[PREF_SEG_INDEX] == 0xFF) { if (mode == DISMODE.DISASSEMBLE_MODE_64) { instr.ops[op_index].value.addr.seg = SREG_CODE_CS; } else { if ( (instr.ops[op_index].value.addr.mod & ADDR_MOD_BASE)==0 ) { instr.ops[op_index].value.addr.seg = SREG_CODE_DS; } else { if ((instr.ops[op_index].value.addr.bas != REG_CODE_BP) && (instr.ops[op_index].value.addr.bas != REG_CODE_SP)) { instr.ops[op_index].value.addr.seg = SREG_CODE_DS; } else { instr .ops[op_index].value.addr.seg = SREG_CODE_SS; } } } } else { if (mode != DISMODE.DISASSEMBLE_MODE_64) { instr.ops[op_index].value.addr.seg = sregs[prefixes[PREF_SEG_INDEX]]; } else { if (prefixes[PREF_SEG_INDEX] == PREF_FS_ID || prefixes[PREF_SEG_INDEX] == PREF_GS_ID) { instr.ops[op_index].value.addr.seg = sregs[prefixes[PREF_SEG_INDEX]]; } else { instr.ops[op_index].value.addr.seg = SREG_CODE_CS; } } } }
//Parses 16bit memory address operand. static UInt32 parse_mem_operand_16(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, DISMODE mode) { byte len; int index; instr.ops[op_index].value.addr.mod = (byte)(instr.modrm >> 0x6); len = get_disp(origin_offset, offset, ref instr, op_index, mode); index = (instr.modrm >> 0x3 & 0x18) | (instr.modrm & 0x7); instr.ops[op_index].value.addr.seg = addrs_16bit[index].seg; instr.ops[op_index].value.addr.mod = addrs_16bit[index].mod; instr.ops[op_index].value.addr.bas = addrs_16bit[index].bas; instr.ops[op_index].value.addr.index = addrs_16bit[index].index; instr.ops[op_index].value.addr.scale = addrs_16bit[index].scale; return len; }
public static UInt32 tq_T(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { create_reg_operand(ref instr, op_index, REG_TYPE.REG_TYPE_TR, (byte)((instr.modrm >> 0x3) & 0x7), opsize.size); return 0x0; }
public static UInt32 tq_V(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { create_xmmreg_operand(ref instr, op_index, (byte)((instr.modrm >> 0x3) & 0x7), opsize.size, PREFIX_REX_R, ref idata, mode); return 0; }
public static UInt32 tq_rSP(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { create_genreg_operand(ref instr, op_index, REG_CODE_SP, opsize.size, PREFIX_REX_B, ref idata, mode); return 0x0; }
public static UInt32 tq_SS(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { create_reg_operand(ref instr, op_index, REG_TYPE.REG_TYPE_SEG, SREG_CODE_SS, opsize.size); return 0; }
public static UInt32 tq_R(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 res = parse_rm_operand(origin_offset, offset, ref instr, op_index, opsize, ref idata, mode); if ((instr.modrm & 0xC0) != 0xC0) { idata.err = ERRS.ERR_RM_MEM;//error: rm encodes memory. } return res; }
public static UInt32 tq_O(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 res; res = instr.addrsize; instr.ops[op_index].flags |= (byte) OP_TYPE.OPERAND_TYPE_MEM; instr.ops[op_index].size = (ushort)opsize.size; instr.ops[op_index].value.addr.mod = ADDR_MOD_DISP; //instr.disp.value.ab = assembly.Image.ReadBytes(offset, instr.addrsize); byte[] bt = assembly.ReadBytes(offset, instr.addrsize); instr.disp.value.d64 = 0; foreach (byte bb in bt.Reverse()) { instr.disp.value.d64 <<= 8; instr.disp.value.d64 += bb; } get_seg(ref instr, op_index, idata.prefixes, mode); return res; }
public static UInt32 tq_J(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { instr.ops[op_index].flags |= OPERAND_FLAG_REL; return tq_I(origin_offset, offset, ref instr, op_index, opsize, idata, mode); }
//Calculates displacement's size and copies it to struct DISPLACEMENT. static byte get_disp(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, DISMODE mode) { byte len = 0; switch(instr.ops[op_index].value.addr.mod) { case 0x0: if (instr.ops[op_index].value.addr.bas == REG_CODE_BP) len = instr.addrsize; else len = 0x0; break; case 0x1: len = 0x1; break; case 0x2: len = instr.addrsize; break; } if (len == 8) len = 4; instr.disp.size = len; if (len!=0) { //instr.disp.value.ab = assembly.Image.ReadBytes(offset, len); byte[] bt = assembly.ReadBytes(offset, len); instr.disp.value.d64 = 0; foreach (byte bb in bt.Reverse()) { instr.disp.value.d64 <<= 8; instr.disp.value.d64 += bb; } movsx(ref instr.disp.value.d64, len, 0x8); instr.disp.offset = (byte)(offset - origin_offset); } return len; }
public static UInt32 tq_W(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 res; if ((instr.modrm & 0xC0) == 0xC0) { create_xmmreg_operand(ref instr, op_index, (byte)(instr.modrm & 0x7), opsize.size, PREFIX_REX_B, ref idata, mode); res = 0; } else { res = parse_mem_operand(origin_offset, offset, ref instr, op_index, opsize, idata, mode); } return res; }
//Get instruction's size. Well, really this is size of implicit operand // that influences on instruction's mnemonic. static void get_instruction_opsize(MULTI_MNEMONIC multi_mnemonic, INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { OPERAND_SIZE opsize = new OPERAND_SIZE(); if (multi_mnemonic.size >= sq_handlers.Count()) { idata.severe_err = ERRS.ERR_INTERNAL; } else { sq_handlers[multi_mnemonic.size](ref opsize, ref instr, idata, mode); } instr.opsize = (byte)opsize.size; //Possible sizes are 2/4/8. }
public static UInt32 tq_X(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 res; res = 0; instr.ops[op_index].flags |= (byte)OP_TYPE.OPERAND_TYPE_MEM; instr.ops[op_index].size = (ushort)opsize.size; instr.ops[op_index].value.addr.mod = ADDR_MOD_BASE; instr.ops[op_index].value.addr.bas = REG_CODE_SI; get_seg(ref instr, op_index, idata.prefixes, mode); return 0x0; }
//Parses memory address operand. static UInt32 parse_mem_operand(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 len; instr.ops[op_index].flags |= (byte)OP_TYPE.OPERAND_TYPE_MEM; instr.ops[op_index].size = (ushort)opsize.size; if (instr.addrsize == ADDR_SIZE_16) { len = parse_mem_operand_16(origin_offset, offset, ref instr, op_index, mode); } else { len = parse_mem_operand_32_64(origin_offset, offset, ref instr, op_index, idata, mode); } idata.is_addrsize_used = 1; return len; }
public static UInt32 tq_Y(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { instr.ops[op_index].flags |= (byte)OP_TYPE.OPERAND_TYPE_MEM; instr.ops[op_index].size = (ushort)opsize.size; if (mode == DISMODE.DISASSEMBLE_MODE_64) instr.ops[op_index].value.addr.seg = SREG_CODE_CS; else instr.ops[op_index].value.addr.seg = SREG_CODE_ES; instr.ops[op_index].value.addr.mod = ADDR_MOD_BASE; instr.ops[op_index].value.addr.bas = REG_CODE_DI; return 0x0; }
//Parses 32/64bit memory address operand. static UInt32 parse_mem_operand_32_64(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, INTERNAL_DATA idata, DISMODE mode) { UInt32 len = 0; if ((instr.flags & INSTR_FLAG_SIB)!=0) { instr.ops[op_index].value.addr.mod = (byte)(instr.modrm >> 0x6); instr.ops[op_index].value.addr.bas = (byte)(instr.sib & 0x7); instr.ops[op_index].value.addr.index = (byte)((instr.sib >> 3) & 0x7); instr.ops[op_index].value.addr.scale = (byte)(1 << (instr.sib >> 0x6)); if (mode == DISMODE.DISASSEMBLE_MODE_64 && idata.prefixes[PREF_REX_INDEX] != 0xFF) { if ((instr.rex & PREFIX_REX_B)!=0) { instr.ops[op_index].value.addr.bas |= REG_CODE_64; idata.is_rex_used = 1; } if ((instr.rex & PREFIX_REX_X)!=0) { instr.ops[op_index].value.addr.index |= REG_CODE_64; idata.is_rex_used = 1; } } len = get_disp(origin_offset, offset, ref instr, op_index, mode); get_mod_type_sib(ref instr, op_index); } else { instr.ops[op_index].value.addr.mod = (byte)(instr.modrm >> 0x6); instr.ops[op_index].value.addr.bas = (byte)(instr.modrm & 0x7); if (mode == DISMODE.DISASSEMBLE_MODE_64) { if ((idata.prefixes[PREF_REX_INDEX] != 0xFF) && ((instr.rex & PREFIX_REX_B)!=0)) { instr.ops[op_index].value.addr.bas |= REG_CODE_64; idata.is_rex_used = 1; } if ( (instr.ops[op_index].value.addr.mod == 0x0) && ((instr.ops[op_index].value.addr.bas == REG_CODE_BP) || (instr.ops[op_index].value.addr.bas == REG_CODE_R13)) ) { instr.ops[op_index].value.addr.bas = REG_CODE_IP; } } len = get_disp(origin_offset, offset, ref instr, op_index, mode); get_mod_type_modrm(ref instr, op_index); } get_seg(ref instr, op_index, idata.prefixes, mode); return len; }
public static UInt32 tq_Z(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { byte[] bt = assembly.ReadBytes(offset - 1, 1); //We already consumed opcode, hence we need to look backward. create_genreg_operand(ref instr, op_index, (byte)(bt[0] & 0x7), opsize.size, PREFIX_REX_B, ref idata, mode); return 0x0; }
static UInt32 parse_operand(ulong origin_offset, ulong offset, INTERNAL_OPERAND iop, INSTRUCTION instr, int op_index, INTERNAL_DATA idata, DISMODE mode) { UInt32 res = 0; OPERAND_SIZE opsize = new OPERAND_SIZE(); if (iop.type != TQ_NULL) { instr.ops[op_index].flags |= OPERAND_FLAG_PRESENT; if (iop.size >= sq_handlers.Count()) { idata.severe_err = ERRS.ERR_INTERNAL; } else { sq_handlers[iop.size](ref opsize, ref instr, idata, mode); } if (iop.size >= tq_handlers.Count()) { idata.severe_err = ERRS.ERR_INTERNAL; } else { res = tq_handlers[iop.type](origin_offset, offset, ref instr, op_index, opsize, idata, mode); } } return res; }
static void create_genreg_operand(ref INSTRUCTION instr, int op_index, byte code, OP_SIZE size, byte rex, ref INTERNAL_DATA idata, DISMODE mode) { if (mode == DISMODE.DISASSEMBLE_MODE_64 && idata.prefixes[PREF_REX_INDEX] != 0xFF) { if (code > REG_CODE_BX && size == OP_SIZE.OPERAND_SIZE_8) { code |= REG_CODE_64; code += 0x4; idata.is_rex_used = 1; } if ((instr.rex & rex)!=0) { code |= REG_CODE_64; idata.is_rex_used = 1; } } create_reg_operand(ref instr, op_index, REG_TYPE.REG_TYPE_GEN, code, size); }
/************************* * Postprocessing routines. ************************** */ static UInt32 post_proc_arpl_movsxd(ulong origin_offset, ulong offset, ref INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { UInt32 res; res = 0; if (mode == DISMODE.DISASSEMBLE_MODE_64) { OPERAND_SIZE opsize = new OPERAND_SIZE(); instr.id = ID_MOVSXD; instr.groups = GRP_GEN | GRP_CONVER; instr.tested_flags = 0; instr.modified_flags = 0; instr.set_flags = 0; instr.cleared_flags = 0; instr.flags &= (ushort)(INSTR_FLAG_MODRM | INSTR_FLAG_SIB); instr.mnemonic = "movsxd"; byte[] bt = assembly.ReadBytes((ulong)instr.opcode_offset + 1, 4); res = (UInt32)( bt[0] + bt[1]*256 + bt[2]*256*256 + bt[3]*256*256*256); offset += res; if ((instr.flags & INSTR_FLAG_MODRM)!=0) { res++; offset++; } if ((instr.flags & INSTR_FLAG_SIB)!=0) { res++; offset++; } instr.ops[0].value.imm.imm64 = 0; instr.ops[1].value.imm.imm64 = 0; instr.ops[0].flags = OPERAND_FLAG_PRESENT; instr.ops[1].flags = OPERAND_FLAG_PRESENT; sq_dqp(ref opsize, ref instr, idata, mode); res += tq_G(origin_offset, offset, ref instr, 0, opsize, idata, mode); sq_d(ref opsize, ref instr, idata, mode); res += tq_E(origin_offset, offset, ref instr, 1, opsize, idata, mode); } return res; }
static void create_xmmreg_operand(ref INSTRUCTION instr, int op_index, byte code, OP_SIZE size, byte rex, ref INTERNAL_DATA idata, DISMODE mode) { if ((mode == DISMODE.DISASSEMBLE_MODE_64) && (idata.prefixes[PREF_REX_INDEX] != 0xFF)) { if ((instr.rex & rex)!=0) { code |= REG_CODE_64; idata.is_rex_used = 1; } } create_reg_operand(ref instr, op_index, REG_TYPE.REG_TYPE_XMM, code, size); }
static UInt32 post_proc_multinop(ulong origin_offset, ulong offset, ref INSTRUCTION instr, INTERNAL_DATA idata, DISMODE mode) { instr.ops[0].flags &= (byte)~OPERAND_FLAG_PRESENT; instr.ops[1].flags &= (byte)~OPERAND_FLAG_PRESENT; instr.ops[2].flags &= (byte)~OPERAND_FLAG_PRESENT; return 0; }
//Returns address size. Address size is common for all operands. static void get_address_size(ref INSTRUCTION instr, byte[] prefixes, DISMODE mode) { if (mode == DISMODE.DISASSEMBLE_MODE_64) { if (prefixes[PREF_ADDRSIZE_INDEX] != 0xFF) instr.addrsize = ADDR_SIZE_32; else instr.addrsize = ADDR_SIZE_64; } else { if (prefixes[PREF_ADDRSIZE_INDEX] != 0xFF) mode ^= (DISMODE.DISASSEMBLE_MODE_16 | DISMODE.DISASSEMBLE_MODE_32); if (mode == DISMODE.DISASSEMBLE_MODE_16) instr.addrsize = ADDR_SIZE_16; else instr.addrsize = ADDR_SIZE_32; } }
static UInt32 tq_1(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { instr.ops[op_index].flags |= (byte)OP_TYPE.OPERAND_TYPE_IMM; instr.ops[op_index].size = (ushort)OP_SIZE.OPERAND_SIZE_8; instr.ops[op_index].value.imm.imm8 = 0x1; return 0x0; }
public static UInt32 tq_fES(ulong origin_offset, ulong offset, ref INSTRUCTION instr, int op_index, OPERAND_SIZE opsize, INTERNAL_DATA idata, DISMODE mode) { UInt32 res; if ((instr.modrm & 0xC0) == 0xC0) res = tq_fEST(origin_offset, offset, ref instr, op_index, opsize, idata, mode); else res = tq_M(origin_offset, offset, ref instr, op_index, opsize, idata, mode); return res; }