diff options
| -rw-r--r-- | src/disasm.c | 174 |
1 files changed, 135 insertions, 39 deletions
diff --git a/src/disasm.c b/src/disasm.c index c9b839d..e38a6db 100644 --- a/src/disasm.c +++ b/src/disasm.c @@ -68,12 +68,14 @@ // ====== !windows.h ====== // ======================== +const u8 x64_max_inst_size = 16U; const u8 MAX_LEGACY_PREFIXES = 4U; const u8 legacy_prefixes[] = { // Operand-size override 0x66, - 0x67, // Address-size override + 0x67, + // Segment override 0x2E, 0x3E, 0x26, @@ -106,6 +108,26 @@ const u8 REX_prefixes[] = { 0x4F, }; +const char* registers[] = { + "RAX", + "RBX", + "RCX", + "RDX", + "RSI", + "RDI", + "RBP", + "RSP", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + "RIP", +}; + const char* ModRM_registers[8U][5U] = { { "YMM0", "XMM0", "MMX0", "RAX" }, { "YMM1", "XMM1", "MMX1", "RCX" }, @@ -154,19 +176,42 @@ struct operand { Vector_REG, // L DS_rSI, // X ES_rSI, // Y + Reg, } src; // Handle eventual SIB byte following ModRM byte - enum DATA_TYPE { - TYPE_BYTE = 0x1, // b - TYPE_WORD = 0x2, - TYPE_DWORD = 0x4, - TYPE_QWORD = 0x8, - TYPE_FP = 0x10, - TYPE_v = 0x1f, // v - TYPE_p = 0x20, // 32 or 48 bit depending on 16 or 32 bit operand size - TYPE_z = 0x1000, // z - TYPE_1 = 0x2000, // Hardcoded 1 - } type; + union { + enum DATA_TYPE { + TYPE_NONE = 0x0, + TYPE_BYTE = 0x1, // b + TYPE_WORD = 0x2, + TYPE_DWORD = 0x4, + TYPE_QWORD = 0x8, + TYPE_FP = 0x10, + TYPE_v = 0x1f, // v + TYPE_p = 0x20, // 32 or 48 bit depending on 16 or 32 bit operand size + TYPE_z = 0x1000, // z + TYPE_1 = 0x2000, // Hardcoded 1 + } type; + enum REGISTER { + RAX, + RBX, + RCX, + RDX, + RSI, + RDI, + RBP, + RSP, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, + RIP, + } reg; + }; // SSE stuff }; @@ -261,14 +306,14 @@ const struct opcode primary_opcode_map[256U] = { { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "PUSH", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO - { "PUSH", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSH", { .src = Reg, .reg = RAX }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RCX }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RDX }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RBX }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RSP }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RBP }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RSI }, { .src = None, .type = TYPE_NONE }}, + { "PUSH", { .src = Reg, .reg = RDI }, { .src = None, .type = TYPE_NONE }}, { "POP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO { "POP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO { "POP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO @@ -611,6 +656,34 @@ u8 is_REX_prefix(u8 byte) { return FALSE; } +u8 has_ModRM_byte(const enum OPERAND_TYPE op_type) { + switch (op_type) { + case None: + return FALSE; + case Inst_FAR: + return FALSE; + case TYPE_E: + return TRUE; + case ModRM_Reg: + return TRUE; + case Imm: + return FALSE; + case ModRM_MEM: + return TRUE; + case Vector_REG: + return FALSE; + case DS_rSI: + return FALSE; + case ES_rSI: + return FALSE; + case Reg: + return FALSE; + } + + assert(FALSE); + return FALSE; +} + const struct opcode* primary_map_group(u8 opcode, u8 ModRM) { const u8 reg_size = 0x8; const u8 reg_byte_mask = 0b111; @@ -653,10 +726,13 @@ u64 get_immediate(u8** bytes, enum DATA_TYPE type, u8 operand_effective_size) { } else if (type == TYPE_v) { if (operand_effective_size == 16U) { imm = (u16)**bytes; + *bytes += 2U; } else if (operand_effective_size == 32U) { imm = (u32)**bytes; + *bytes += 4U; } else if (operand_effective_size == 64U) { imm = (u64)**bytes; + *bytes += 8U; } else { print("ERROR: Unhandled operand type\n"); } @@ -668,7 +744,7 @@ u64 get_immediate(u8** bytes, enum DATA_TYPE type, u8 operand_effective_size) { *bytes += 2U; } else { imm = (u32)**bytes; - *bytes += 2U; + *bytes += 4U; } } else { print("ERROR: Unhandled operand type\n"); @@ -720,15 +796,13 @@ void unassemble(u8* start, u64 size) { u8 legacy_prefixes_count = 0U; u8 effective_operand_size = 32U; // 32 by default in 64bit mode i32 effective_address = -1; - (void)effective_address; // Not used yet - u8 operand_size_override_66 = FALSE; + (void)effective_address; // Not used yet u8 operand_size_override_REX = FALSE; (void)operand_size_override_REX; // Not used yet u8 REX = 0U; while (is_legacy_prefix(*current_byte) && legacy_prefixes_count < MAX_LEGACY_PREFIXES) { if (*current_byte == 0x66) { // Override effective operand size effective_operand_size = 16U; - operand_size_override_66 = TRUE; } legacy_prefixes_count++; current_byte++; @@ -737,7 +811,7 @@ void unassemble(u8* start, u64 size) { if (is_REX_prefix(*current_byte)) { REX = *current_byte; - if (REXW(REX) && operand_size_override_66 == FALSE) { + if (REXW(REX)) { effective_operand_size = 64U; operand_size_override_REX = TRUE; } @@ -745,23 +819,43 @@ void unassemble(u8* start, u64 size) { current_byte++; } - // TODO: VEX, XOP prefixes + // TODO: VEX, XOP prefixes and there escape sequences - u8 op_byte = *current_byte; - current_byte++; - u8 ModRM = *current_byte; + u8 has_ModRM = FALSE; + u8 ModRM = 0U; const struct opcode* op = NULL; - if (op_byte == 0x0F) { // Secondary op code map needed + if (current_byte[0U] == 0x0F && current_byte[1U] == 0x0F) { // 3DNow! + assert(FALSE); + current_byte += 2U; + } else if (current_byte[0U] == 0x0F && (current_byte[1U] == 0x38 || current_byte[1U] == 0x3A)) { // SSE + assert(FALSE); + current_byte += 2U; + } else if (current_byte[0U] == 0x0F) { // Secondary op code map needed + assert(FALSE); current_byte++; - } else if ((op = primary_map_group(op_byte, ModRM)) != NULL) { - } else { - op = &primary_opcode_map[op_byte]; + } else { // Primary op code map + if ((op = primary_map_group(current_byte[0U], current_byte[1U])) != NULL) { + has_ModRM = TRUE; + ModRM = current_byte[1U]; + current_byte += 2U; + } else { + op = &primary_opcode_map[current_byte[0U]]; + current_byte++; + + has_ModRM = has_ModRM_byte(op->dst_operand.src) || has_ModRM_byte(op->src_operand.src); + if (has_ModRM) { + ModRM = *current_byte; + current_byte++; + } + } } + u8 disp_bytes_count = 0U; u8 has_src_SIB = FALSE; u8 has_dst_SIB = FALSE; - if (op->src_operand.src & (TYPE_E | ModRM_Reg) || op->dst_operand.src & (TYPE_E | ModRM_Reg)) { + // NOTE: could we test has_ModRM instead ? + if (op->src_operand.src == TYPE_E || op->src_operand.src == ModRM_Reg || op->dst_operand.src == TYPE_E || op->dst_operand.src == ModRM_Reg) { u8 Mod = MODRM_MOD(ModRM); u8 RM = MODRM_RM(ModRM); @@ -769,7 +863,7 @@ void unassemble(u8* start, u64 size) { // Displacement detection if (Mod == 0b00 && RM == 0b101) { disp_bytes_count = mod_to_disp_size[Mod]; - } else if (Mod != 0b11) { + } else if (Mod == 0b01 || Mod == 0b10) { disp_bytes_count = mod_to_disp_size[Mod]; } @@ -784,15 +878,13 @@ void unassemble(u8* start, u64 size) { // NOTE: We probably can't have both operand needing an SIB byte assert(!(has_src_SIB == has_dst_SIB == TRUE)); } - - current_byte++; } // SIB u8 SIB = *current_byte; if (has_src_SIB || has_dst_SIB) { u8 Mod = MODRM_MOD(ModRM); - if (SIB_BASE(SIB)) { + if (SIB_BASE(SIB) == 0b101) { disp_bytes_count = mod_to_disp_size[Mod]; } current_byte++; @@ -823,7 +915,7 @@ void unassemble(u8* start, u64 size) { u8 inst_size = (u8)(current_byte - inst_start); - for (u8 index = 0U; index < 6U; index++) { + for (u8 index = 0U; index < x64_max_inst_size; index++) { if (index < inst_size) { print("%.2x ", inst_start[index]); } else { @@ -845,6 +937,8 @@ void unassemble(u8* start, u64 size) { if (Mod == 0b11) { print(" %s", ModRM_registers[RM][3U]); } + } else if (op->src_operand.src == Reg) { + print(" %s", registers[op->src_operand.reg]); } if (has_src_SIB) { @@ -861,6 +955,8 @@ void unassemble(u8* start, u64 size) { { if (op->dst_operand.src == Imm) { print(" %x", dst_imm); + } else if (op->dst_operand.src == Reg) { + print(", %s", registers[op->dst_operand.reg]); } if (has_dst_SIB) { |
