/* ----------------------------------------------------------------------------- * decode_operands() - Disassembles Operands. * ----------------------------------------------------------------------------- */ static int decode_operand(struct ud *u, struct ud_operand *operand, enum ud_operand_code type, unsigned int size) { operand->_oprcode = type; switch (type) { case OP_A : decode_a(u, operand); break; case OP_MR: decode_modrm_rm(u, operand, REGCLASS_GPR, MODRM_MOD(modrm(u)) == 3 ? Mx_reg_size(size) : Mx_mem_size(size)); break; case OP_F: u->br_far = 1; /* intended fall through */ case OP_M: if (MODRM_MOD(modrm(u)) == 3) { UDERR(u, "expected modrm.mod != 3\n"); } /* intended fall through */ case OP_E: decode_modrm_rm(u, operand, REGCLASS_GPR, size); break; case OP_G: decode_modrm_reg(u, operand, REGCLASS_GPR, size); break; case OP_sI: case OP_I: decode_imm(u, size, operand); break; case OP_I1: operand->type = UD_OP_CONST; operand->lval.udword = 1; break; case OP_N: if (MODRM_MOD(modrm(u)) != 3) { UDERR(u, "expected modrm.mod == 3\n"); } /* intended fall through */ case OP_Q: decode_modrm_rm(u, operand, REGCLASS_MMX, size); break; case OP_P: decode_modrm_reg(u, operand, REGCLASS_MMX, size); break; case OP_U: if (MODRM_MOD(modrm(u)) != 3) { UDERR(u, "expected modrm.mod == 3\n"); } /* intended fall through */ case OP_W: decode_modrm_rm(u, operand, REGCLASS_XMM, size); break; case OP_V: decode_modrm_reg(u, operand, REGCLASS_XMM, size); break; case OP_MU: decode_modrm_rm(u, operand, REGCLASS_XMM, MODRM_MOD(modrm(u)) == 3 ? Mx_reg_size(size) : Mx_mem_size(size)); break; case OP_S: decode_modrm_reg(u, operand, REGCLASS_SEG, size); break; case OP_O: decode_moffset(u, size, operand); break; case OP_R0: case OP_R1: case OP_R2: case OP_R3: case OP_R4: case OP_R5: case OP_R6: case OP_R7: decode_reg(u, operand, REGCLASS_GPR, (REX_B(u->pfx_rex) << 3) | (type - OP_R0), size); break; case OP_AL: case OP_AX: case OP_eAX: case OP_rAX: decode_reg(u, operand, REGCLASS_GPR, 0, size); break; case OP_CL: case OP_CX: case OP_eCX: decode_reg(u, operand, REGCLASS_GPR, 1, size); break; case OP_DL: case OP_DX: case OP_eDX: decode_reg(u, operand, REGCLASS_GPR, 2, size); break; case OP_ES: case OP_CS: case OP_DS: case OP_SS: case OP_FS: case OP_GS: /* in 64bits mode, only fs and gs are allowed */ if (u->dis_mode == 64) { if (type != OP_FS && type != OP_GS) { UDERR(u, "invalid segment register in 64bits\n"); } } operand->type = UD_OP_REG; operand->base = (type - OP_ES) + UD_R_ES; operand->size = 16; break; case OP_J : decode_imm(u, size, operand); operand->type = UD_OP_JIMM; break ; case OP_R : if (MODRM_MOD(modrm(u)) != 3) { UDERR(u, "expected modrm.mod == 3\n"); } decode_modrm_rm(u, operand, REGCLASS_GPR, size); break; case OP_C: decode_modrm_reg(u, operand, REGCLASS_CR, size); break; case OP_D: decode_modrm_reg(u, operand, REGCLASS_DB, size); break; case OP_I3 : operand->type = UD_OP_CONST; operand->lval.sbyte = 3; break; case OP_ST0: case OP_ST1: case OP_ST2: case OP_ST3: case OP_ST4: case OP_ST5: case OP_ST6: case OP_ST7: operand->type = UD_OP_REG; operand->base = (type - OP_ST0) + UD_R_ST0; operand->size = 80; break; default : break; } return 0; }
/* ----------------------------------------------------------------------------- * decode_operands() - Disassembles Operands. * ----------------------------------------------------------------------------- */ static int decode_operand(struct ud *u, struct ud_operand *operand, enum ud_operand_code type, unsigned int size) { switch (type) { case OP_A : decode_a(u, operand); break; case OP_MR: if (MODRM_MOD(modrm(u)) == 3) { decode_modrm_rm(u, operand, T_GPR, size == SZ_DY ? SZ_MDQ : SZ_V); } else if (size == SZ_WV) { decode_modrm_rm( u, operand, T_GPR, SZ_W); } else if (size == SZ_BV) { decode_modrm_rm( u, operand, T_GPR, SZ_B); } else if (size == SZ_DY) { decode_modrm_rm( u, operand, T_GPR, SZ_D); } else { assert(!"unexpected size"); } break; case OP_M: if (MODRM_MOD(modrm(u)) == 3) { u->error = 1; } /* intended fall through */ case OP_E: decode_modrm_rm(u, operand, T_GPR, size); break; break; case OP_G: decode_modrm_reg(u, operand, T_GPR, size); break; case OP_I: decode_imm(u, size, operand); break; case OP_I1: operand->type = UD_OP_CONST; operand->lval.udword = 1; break; case OP_PR: if (MODRM_MOD(modrm(u)) != 3) { u->error = 1; } decode_modrm_rm(u, operand, T_MMX, size); break; case OP_P: decode_modrm_reg(u, operand, T_MMX, size); break; case OP_VR: if (MODRM_MOD(modrm(u)) != 3) { u->error = 1; } /* intended fall through */ case OP_W: decode_modrm_rm(u, operand, T_XMM, size); break; case OP_V: decode_modrm_reg(u, operand, T_XMM, size); break; case OP_S: decode_modrm_reg(u, operand, T_SEG, size); break; case OP_AL: case OP_CL: case OP_DL: case OP_BL: case OP_AH: case OP_CH: case OP_DH: case OP_BH: operand->type = UD_OP_REG; operand->base = UD_R_AL + (type - OP_AL); operand->size = 8; break; case OP_DX: operand->type = UD_OP_REG; operand->base = UD_R_DX; operand->size = 16; break; case OP_O: decode_o(u, size, operand); break; case OP_rAXr8: case OP_rCXr9: case OP_rDXr10: case OP_rBXr11: case OP_rSPr12: case OP_rBPr13: case OP_rSIr14: case OP_rDIr15: case OP_rAX: case OP_rCX: case OP_rDX: case OP_rBX: case OP_rSP: case OP_rBP: case OP_rSI: case OP_rDI: operand->type = UD_OP_REG; operand->base = resolve_gpr64(u, type, &operand->size); break; case OP_ALr8b: case OP_CLr9b: case OP_DLr10b: case OP_BLr11b: case OP_AHr12b: case OP_CHr13b: case OP_DHr14b: case OP_BHr15b: { ud_type_t gpr = (type - OP_ALr8b) + UD_R_AL + (REX_B(u->pfx_rex) << 3); if (UD_R_AH <= gpr && u->pfx_rex) { gpr = gpr + 4; } operand->type = UD_OP_REG; operand->base = gpr; break; } case OP_eAX: case OP_eCX: case OP_eDX: case OP_eBX: case OP_eSP: case OP_eBP: case OP_eSI: case OP_eDI: operand->type = UD_OP_REG; operand->base = resolve_gpr32(u, type); operand->size = u->opr_mode == 16 ? 16 : 32; break; case OP_ES: case OP_CS: case OP_DS: case OP_SS: case OP_FS: case OP_GS: /* in 64bits mode, only fs and gs are allowed */ if (u->dis_mode == 64) { if (type != OP_FS && type != OP_GS) { u->error= 1; } } operand->type = UD_OP_REG; operand->base = (type - OP_ES) + UD_R_ES; operand->size = 16; break; case OP_J : decode_imm(u, size, operand); operand->type = UD_OP_JIMM; break ; case OP_Q: decode_modrm_rm(u, operand, T_MMX, size); break; case OP_R : decode_modrm_rm(u, operand, T_GPR, size); break; case OP_C: decode_modrm_reg(u, operand, T_CRG, size); break; case OP_D: decode_modrm_reg(u, operand, T_DBG, size); break; case OP_I3 : operand->type = UD_OP_CONST; operand->lval.sbyte = 3; break; case OP_ST0: case OP_ST1: case OP_ST2: case OP_ST3: case OP_ST4: case OP_ST5: case OP_ST6: case OP_ST7: operand->type = UD_OP_REG; operand->base = (type - OP_ST0) + UD_R_ST0; operand->size = 0; break; case OP_AX: operand->type = UD_OP_REG; operand->base = UD_R_AX; operand->size = 16; break; default : operand->type = UD_NONE; break; } return 0; }
virtual void handle_mov(UByte opcode, size_t word_size) { switch (opcode) { case 0x88: case 0x8A: case 0x89: case 0x8E: { // // Modify R/M and REG fields in the MOD R/M byte // UByte fault; UByte modrm; _scanner.get(&modrm); switch (decode_modrm_mod(modrm)) { case 0: if (word_size == 4 && decode_modrm_rm(modrm) == 4) { fault = modify_reg(modrm); } else if (decode_modrm_rm(modrm) == 5) { fault = modify_reg(modrm); } else { fault = modify_rm_reg(modrm); } break; case 1: if (word_size == 4 && decode_modrm_rm(modrm) == 4) { fault = modify_reg(modrm); } else { fault = modify_rm_reg(modrm); } break; case 2: if (word_size == 4 && decode_modrm_rm(modrm) == 4) { fault = modify_reg(modrm); } else { fault = modify_rm_reg(modrm); } break; case 3: fault = modify_rm_reg(modrm); break; default: System.Print(System.WARN, "Unknown modrm"); return; } // Inject a fault _scanner.seek(-1, scanner::SEEK_CUR); _scanner.put(fault); // OK. Let's work on the next instruction. skip_modrm(fault, word_size); break; } // [SKIP] Segment registers case 0x8B: case 0x8C: { UByte next; _scanner.get(&next); skip_modrm(next, word_size); break; } // [SKIP] Immediate case 0xC6: { UByte next; _scanner.get(&next); skip_modrm(next, word_size); skip_one(); break; } // [SKIP] Immediate case 0xC7: { UByte next; _scanner.get(&next); skip_modrm(next, word_size); skip_word(word_size); break; } // [SKIP] 'A' register (i.e. al, ax, eax) case 0xA0: case 0xA1: case 0xA2: case 0xA3: { skip_word(word_size); break; } default: { // Move imm8 to r8 if (0xB0 <= opcode && opcode <= 0xB7) { UByte fault = opcode; while (fault == opcode) { fault = 0xB0 | (static_cast<UByte>(rand()) & 0xF); } // Inject a fault _scanner.seek(-1, scanner::SEEK_CUR); _scanner.put(fault); // OK. Work on the next instruction. skip_one(); System.Print("FI: MOV(%.2X): Change opcode %.2X\n", opcode, fault); } // Move imm16/32 to r16/32 else if (0xB8 <= opcode && opcode <= 0xBF) { UByte fault = opcode; while (fault == opcode) { fault = 0xB8 | (static_cast<UByte>(rand()) & 0xF); } // Inject a fault _scanner.seek(-1, scanner::SEEK_CUR); _scanner.put(fault); // OK. Work on the next instruction. skip_word(word_size); System.Print("FI: MOV(%.2X): Change opcode %.2X\n", opcode, fault); } } } // switch }