I64 InstEntriesCompare(CInst *tmpins1, CInst *tmpins2) { I64 i1, i2, j = 0, res = 0, oc_count1 = tmpins1->opcode_count, oc_count2 = tmpins2->opcode_count; if (tmpins1->flags & IEF_STI_LIKE) oc_count1--; if (tmpins2->flags & IEF_STI_LIKE) oc_count2--; while (TRUE) { if (j < oc_count1 && j < oc_count2) { if (res = tmpins1->opcode[j] - tmpins2->opcode[j]) return res; j++; } else { if (res = oc_count1 - oc_count2) return res; if (tmpins1->flags & IEF_STI_LIKE && tmpins2->flags & IEF_STI_LIKE) return tmpins1->opcode[j] - tmpins2->opcode[j]; if (res = tmpins1->flags & IEF_STI_LIKE - tmpins2->flags & IEF_STI_LIKE) return res; if (res = tmpins1->slash_val - tmpins2->slash_val) return res; if (res = tmpins1->flags & IEF_OP_SIZE32 - tmpins2->flags & IEF_OP_SIZE32) return res; i1 = Bt(&uasm.ins64_arg_mask, tmpins1->arg1) || Bt(&uasm.ins64_arg_mask, tmpins1->arg2); i2 = Bt(&uasm.ins64_arg_mask, tmpins2->arg1) || Bt(&uasm.ins64_arg_mask, tmpins2->arg2); if (res = i1 - i2) return res; if (res = tmpins1->flags & IEF_48_REX - tmpins2->flags & IEF_48_REX) return res; i1 = tmpins1->arg2 == ARGT_IMM64 || tmpins1->arg2 == ARGT_UIMM64; i2 = tmpins2->arg2 == ARGT_IMM64 || tmpins2->arg2 == ARGT_UIMM64; return i1 - i2; } } } /* U0 DumpUAsmIns(CInst *tmpins) { CHashOpcode *tmpo = tmpins(U8 *) - tmpins->ins_entry_num * sizeof(CInst) - offset(CHashOpcode.ins); "%10s:%02d,%02d SV:%02d\n", tmpo->str, tmpins->arg1, tmpins->arg2, tmpins->slash_val; } U0 DumpUAsmTables() { I64 k; "16/32 Bit Table\n"; for (k = 0; k < uasm.table_16_32_entries; k++) DumpUAsmIns(uasm.table_16_32[k]); "\n\n\n\n64 Bit Table\n"; for (k = 0; k < uasm.table_64_entries; k++) DumpUAsmIns(uasm.table_64[k]); } */ CInst *InstEntryFind(U8 *rip, I64 opsize, I64 seg_size) {//Binary Search I64 i, j, n, m, k, arg1, arg2, o1, o2, oc_count; CInst *tmpins, **table; i = 0; if (seg_size == 64) { table = uasm.table_64; j = uasm.table_64_entries - 1; } else { table = uasm.table_16_32; j = uasm.table_16_32_entries - 1; } while (TRUE) { k = (i + j) >> 1; //binary search tmpins = table[k]; //DumpUAsmIns(tmpins); m = 0; n = 0; while (TRUE) { //ief_compare_start arg1 = tmpins->arg1; arg2 = tmpins->arg2; oc_count = tmpins->opcode_count; if (tmpins->flags & IEF_STI_LIKE) oc_count--; if (n < oc_count) { o1 = rip[n]; if (n == tmpins->opcode_count - 1 && tmpins->flags & IEF_PLUS_OPCODE) o1 &= -8; o2 = tmpins->opcode[n++]; if (m = o1 - o2) goto ief_compare_done; } else switch [tmpins->uasm_slash_val] { case 0...7: if (!(m = rip[n] >> 3 & 7 - tmpins->slash_val)) { if ((Bt(&uasm.mem_arg_mask, arg1) || Bt(&uasm.mem_arg_mask, arg2)) && rip[n] & 0xC0 == 0xC0) { m = 1; goto ief_compare_done; } if (opsize == 16) { if (tmpins->flags & IEF_OP_SIZE32) { m = -1; goto ief_compare_done; } } else { if (tmpins->flags & IEF_OP_SIZE16) { m = 1; goto ief_compare_done; } } if (opsize == 64 || arg1 == ARGT_M64 || arg2 == ARGT_M64) { if (!Bt(&uasm.ins64_arg_mask, arg1) && !Bt(&uasm.ins64_arg_mask, arg2) && !(tmpins->flags & IEF_48_REX)) m = 1; } else { if (Bt(&uasm.ins64_arg_mask, arg1) || Bt(&uasm.ins64_arg_mask, arg2) || tmpins->flags & IEF_48_REX) m = -1; } } else if ((Bt(&uasm.mem_arg_mask, arg1) || Bt(&uasm.mem_arg_mask, arg2)) && rip[n] & 0xC0 == 0xC0) m = 1; goto ief_compare_done; case SV_I_REG: m = rip[n] >> 3 - tmpins->opcode[tmpins->opcode_count - 1] >> 3; goto ief_compare_done; case SV_STI_LIKE: if (!(m = rip[n] >> 3 - tmpins->opcode[tmpins->opcode_count - 1] >> 3)) m = rip[n] - tmpins->opcode[tmpins->opcode_count - 1]; goto ief_compare_done; case SV_R_REG: case SV_NONE: m = 0; if (opsize == 16) { if (tmpins->flags & IEF_OP_SIZE32) { m = -1; goto ief_compare_done; } } else { if (tmpins->flags & IEF_OP_SIZE16) { m = 1; goto ief_compare_done; } } if (opsize == 64 || arg1 == ARGT_M64 || arg2 == ARGT_M64) { if (!Bt(&uasm.ins64_arg_mask, arg1) && !Bt(&uasm.ins64_arg_mask, arg2) && !(tmpins->flags & IEF_48_REX) && !(arg2 == ARGT_NONE && (ARGT_UIMM8 <= arg1 <= ARGT_UIMM64 || ARGT_IMM8 <= arg1 <= ARGT_IMM64))) m = 1; else if (tmpins->arg2 == ARGT_IMM64 || tmpins->arg2 == ARGT_UIMM64) { if (arg2 != ARGT_IMM64 && arg2 != ARGT_UIMM64) m = 1; } else if (arg2 == ARGT_IMM64 || arg2 == ARGT_UIMM64) m = -1; } else { if (Bt(&uasm.ins64_arg_mask, arg1) || Bt(&uasm.ins64_arg_mask, arg2) || tmpins->flags & IEF_48_REX) m = -1; } goto ief_compare_done; } } ief_compare_done: if (m > 0) { if (k == i) { k = j; break; } else i = k; } else if (m < 0) { if (k - i <= 1) { k = i; break; } else j = k; } else break; } return table[k]; } U0 UAsmHashLoad() { CHashOpcode *tmph; CInst *tmpins; I64 i, j1, j2, k; uasm.ins64_arg_mask = 0x0880888880 + 1 << ARGT_ST0 + 1 << ARGT_STI; uasm.signed_arg_mask = 1 << ARGT_REL8 + 1 << ARGT_REL16 + 1 << ARGT_REL32+ 1 << ARGT_IMM8 + 1 << ARGT_IMM16 + 1 << ARGT_IMM32 + 1 << ARGT_IMM64; uasm.mem_arg_mask = 1 << ARGT_M8 + 1 << ARGT_M16 + 1 << ARGT_M32 + 1 << ARGT_M64; uasm.table_16_32_entries = uasm.table_64_entries = 0; for (i = 0; i <= cmp.asm_hash->mask; i++) { tmph = cmp.asm_hash->body[i]; while (tmph) { if (tmph->type == HTT_OPCODE && !(tmph->oc_flags & OCF_ALIAS)) { tmpins = &tmph->ins; for (k = 0; k < tmph->inst_entry_count; k++) { uasm.table_16_32_entries++; if (!(tmpins->flags & IEF_NOT_IN_64_BIT)) uasm.table_64_entries++; tmpins++; } } tmph = tmph->next; } } j1 = j2 = 0; uasm.table_16_32 = MAlloc(uasm.table_16_32_entries * sizeof(U8 *)); uasm.table_64 = MAlloc(uasm.table_64_entries * sizeof(U8 *)); for (i = 0; i <= cmp.asm_hash->mask; i++) { tmph = cmp.asm_hash->body[i]; while (tmph) { if (tmph->type == HTT_OPCODE && !(tmph->oc_flags & OCF_ALIAS)) { tmpins = &tmph->ins; for (k = 0; k < tmph->inst_entry_count; k++) { uasm.table_16_32[j1++] = tmpins; if (!(tmpins->flags & IEF_NOT_IN_64_BIT)) uasm.table_64[j2++] = tmpins; tmpins++; } } tmph = tmph->next; } } QuickSortI64(uasm.table_16_32, uasm.table_16_32_entries, &InstEntriesCompare); QuickSortI64(uasm.table_64 , uasm.table_64_entries , &InstEntriesCompare); } U0 Ui(U8 *buf, U8 **_rip, I64 seg_size=64, I64 *_jmp_dst=NULL, Bool just_ins=FALSE) {//Unassembles one instruction I64 i, disp, imm, opsize, opadd, arg1, arg2, reloced_arg1, reloced_arg2, arg1_size = 0, arg2_size = 0, reloced_arg1_size, reloced_arg2_size, ModrM = -1, SIB = -1, scale, r1, r2, Mod = -1, RM1 = -1, RM2 = -1, REX = -1, REX_r = 0, REX_x = 0, REX_b = 0; Bool cont; CInst *tmpins, *tmpins2; CHashOpcode *tmpo; U8 *rip = *_rip, *ptr, *reloced_arg1_st, *reloced_arg2_st, *bin_data_area1, *bin_data_area2, line1[512], line2[512], buf2[512], arg1_st[512], arg2_st[512], seg_overrides[32]; if (_jmp_dst) *_jmp_dst = -1; if (seg_size == 16) { opsize = 16; opadd = 16; } else if (seg_size == 32) { opsize = 32; opadd = 32; } else { opsize = 32; opadd = 64; } *arg1_st = 0; *arg2_st = 0; if (!IsRaw && PutSrcLink(rip, 1, line1)) CatPrint(line1, "\n"); else *line1 = 0; StrPrint(line1 + StrLen(line1), "%24tp 0x", rip); bin_data_area1 = line1 + StrLen(line1); for (i = 0; i < 6; i++) CatPrint(line1, "%02X", rip[i]); CatPrint(line1, " "); StrPrint(line2, "%24tp 0x", rip + 6); bin_data_area2 = line2 + StrLen(line2); for (i = 6; i < 12; i++) CatPrint(line2, "%02X", rip[i]); *seg_overrides = 0; cont = TRUE; while (TRUE) { switch (*rip) { case 0x2E: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "CS:"); break; case 0x36: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "SS:"); break; case 0x3E: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "DS:"); break; case 0x26: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "ES:"); break; case 0x64: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "FS:"); break; case 0x65: if (StrLen(seg_overrides) < 24) CatPrint(seg_overrides, "GS:"); break; case OC_OP_SIZE_PREFIX: if (opsize == 16) opsize = 32; else opsize = 16; break; case OC_ADDR_SIZE_PREFIX: if (opadd == 16) opadd = 32; else opadd = 16; break; case 0x40...0x4F: if (seg_size == 64) { REX = *rip; if (REX >= 0x48) opsize = 64; REX_b = Bt(&REX, 0) << 3; REX_x = Bt(&REX, 1) << 3; REX_r = Bt(&REX, 2) << 3; break; } //Fall thru if !64 default: cont = FALSE; } if (cont) rip++; else break; } tmpins = InstEntryFind(rip, opsize, seg_size); if (opsize == 32 && seg_size == 64) { tmpins2 = InstEntryFind(rip, 64, seg_size); if (tmpins2 != tmpins && tmpins2->flags & IEF_REX_ONLY_R8_R15 || tmpins2->flags & IEF_REX_XOR_LIKE && rip[1] >> 3 & 7 == rip[1] & 7) tmpins = tmpins2; } rip += tmpins->opcode_count; tmpo = tmpins(U8 *) - tmpins->ins_entry_num * sizeof(CInst) - offset(CHashOpcode.ins); if (just_ins) *line1 = 0; CatPrint(line1, tmpo->str); arg1 = tmpins->arg1; arg2 = tmpins->arg2; if (arg1_size = tmpins->size1) { if (Bt(&uasm.signed_arg_mask, arg1)) CatPrint(arg1_st, "I%d ", arg1_size); else CatPrint(arg1_st, "U%d ", arg1_size); } if (arg2_size = tmpins->size2) { if (Bt(&uasm.signed_arg_mask, arg2)) CatPrint(arg2_st, "I%d ", arg2_size); else CatPrint(arg2_st, "U%d ", arg2_size); } if (tmpins->flags & IEF_PLUS_OPCODE) { rip--; RM1 = *rip++ - tmpins->opcode[tmpins->opcode_count - 1] + REX_b; ptr = NULL; if (ARGT_R8 <= arg1 <= ARGT_R64) { if (arg1_size == 8) { if (REX != -1) ptr = "ST_U8_REX_REGS"; else ptr = "ST_U8_REGS"; } else if (arg1_size == 16) ptr = "ST_U16_REGS"; else if (arg1_size == 32) ptr="ST_U32_REGS"; else if (arg1_size == 64) ptr = "ST_U64_REGS"; if (ptr) CatPrint(arg1_st, "%Z", RM1, ptr); } else { if (arg2_size == 8) { if (REX != -1) ptr = "ST_U8_REX_REGS"; else ptr = "ST_U8_REGS"; } else if (arg2_size == 16) ptr = "ST_U16_REGS"; else if (arg2_size == 32) ptr = "ST_U32_REGS"; else if (arg2_size == 64) ptr = "ST_U64_REGS"; if (ptr) CatPrint(arg2_st, "%Z", RM1, ptr); } } if (ARGT_RM8 <= arg1 <= ARGT_RM64 || ARGT_M8 <= arg1 <= ARGT_M64 || ARGT_RM8 <= arg2 <= ARGT_RM64 || ARGT_M8 <= arg2 <= ARGT_M64) { if (ARGT_RM8 <= arg2 <= ARGT_RM64 || ARGT_M8 <= arg2 <= ARGT_M64) { reloced_arg1 = arg2; reloced_arg2 = arg1; reloced_arg1_size = arg2_size; reloced_arg2_size = arg1_size; reloced_arg1_st = arg2_st; reloced_arg2_st = arg1_st; } else { reloced_arg1 = arg1; reloced_arg2 = arg2; reloced_arg1_size = arg1_size; reloced_arg2_size = arg2_size; reloced_arg1_st = arg1_st; reloced_arg2_st = arg2_st; } CatPrint(reloced_arg1_st, seg_overrides); ModrM = *rip++; Mod = ModrM >> 6 & 3; RM1 = ModrM & 7 + REX_b; RM2 = ModrM >> 3 & 7 + REX_r; if (Mod < 3 && RM1 & 7 == 4) SIB = *rip++; if (Mod == 1) { disp = *rip(U8 *)++; CatPrint(reloced_arg1_st, "0x%02X", disp); } else if (Mod == 2) { disp = *rip(U32 *)++; CatPrint(reloced_arg1_st, "0x%08X", disp); } if (tmpins->slash_val < 8) RM2 = -1; else { ptr = NULL; if (reloced_arg2 == ARGT_SREG) { if (RM2 <= 5) ptr = "ST_SEG_REGS"; } else if (!(ARGT_IMM8 <= reloced_arg2 <= ARGT_IMM64) && !(ARGT_UIMM8 <= reloced_arg2 <= ARGT_UIMM64)) { if (reloced_arg2_size == 8) { if (REX != -1) ptr = "ST_U8_REX_REGS"; else ptr = "ST_U8_REGS"; } else if (reloced_arg2_size == 16) ptr = "ST_U16_REGS"; else if (reloced_arg2_size == 32) ptr = "ST_U32_REGS"; else if (reloced_arg2_size == 64) ptr = "ST_U64_REGS"; } if (ptr) CatPrint(reloced_arg2_st, "%Z", RM2, ptr); } if (RM1 & 7 == 5 && !Mod) { disp = *rip(I32 *)++; if (seg_size == 64) { disp += rip; if (reloced_arg2 == ARGT_IMM8 || reloced_arg2 == ARGT_UIMM8) disp++; else if (reloced_arg2 == ARGT_IMM16 || reloced_arg2 == ARGT_UIMM16) disp += 2; else if (reloced_arg2 == ARGT_IMM32 || reloced_arg2 == ARGT_UIMM32) disp += 4; else if (reloced_arg2 == ARGT_IMM64 || reloced_arg2 == ARGT_UIMM64) disp += 8; } CatPrint(reloced_arg1_st, "[%X]", disp); RM1 = -1; } else { if (Mod < 3) { if (RM1 & 7 == 4) { RM1 = -1; r1 = SIB & 7 + REX_b; r2 = SIB >> 3 & 7 + REX_x; scale = SIB >> 6 & 3; if (scale == 3) scale = 8; else if (scale == 2) scale = 4; else if (scale == 1) scale = 2; else scale = 1; if (seg_size == 64) ptr = "ST_U64_REGS"; else ptr = "ST_U32_REGS"; if (r1 == REG_RBP && !Mod) { disp = *rip(U32 *)++; CatPrint(reloced_arg1_st, "0x%08X[%Z*%d]", disp, r2, ptr, scale); } else if (r2 == 4) CatPrint(reloced_arg1_st, "[%Z]", r1, ptr); else CatPrint(reloced_arg1_st, "[%Z+%Z*%d]", r1, ptr, r2, ptr, scale); } else { if (opadd == 16) ptr = "ST_U16_REGS"; else if (opadd == 32) ptr = "ST_U32_REGS"; else ptr = "ST_U64_REGS"; CatPrint(reloced_arg1_st, "[%Z]", RM1, ptr); } } else { ptr = NULL; if (reloced_arg1_size == 8) { if (REX != -1) ptr = "ST_U8_REX_REGS"; else ptr = "ST_U8_REGS"; } else if (reloced_arg1_size == 16) ptr = "ST_U16_REGS"; else if (reloced_arg1_size == 32) ptr = "ST_U32_REGS"; else if (reloced_arg1_size == 64) ptr = "ST_U64_REGS"; if (ptr) CatPrint(reloced_arg1_st, DefineSub(RM1, ptr)); } } } switch (arg1) { case ARGT_IMM8: case ARGT_UIMM8: imm = *rip(U8 *)++; CatPrint(arg1_st, "0x%02X", imm); if (tmpins->opcode[0] == 0xCD && (ptr = DefineSub(imm, "ST_INT_NAMES"))) CatPrint(arg1_st, " %s", ptr); break; case ARGT_IMM16: case ARGT_UIMM16: CatPrint(arg1_st, "0x%04X", *rip(U16 *)++); break; case ARGT_IMM32: case ARGT_UIMM32: CatPrint(arg1_st, "0x%08X", *rip(U32 *)++); break; case ARGT_IMM64: case ARGT_UIMM64: CatPrint(arg1_st, "0x%016X", *rip(I64 *)++); break; start: case ARGT_REL8: disp = *rip(I8 *)++; break; case ARGT_REL16: disp = *rip(I16 *)++; break; case ARGT_REL32: disp = *rip(I32 *)++; break; end: disp += rip; if (IsDebugMode) CatPrint(arg1_st, "%p ", disp); else if (PutSrcLink(disp, 512, buf2)) CatPrint(arg1_st, "%s ", buf2); else CatPrint(arg1_st, "%P ", disp); if (_jmp_dst) *_jmp_dst = disp; break; case ARGT_MOFFS8...ARGT_MOFFS64: CatPrint(arg1_st, seg_overrides); if (arg1_size == 8) disp = *rip(U8 *)++; else if (opadd == 16) disp = *rip(U16 *)++; else disp = *rip(U32 *)++; CatPrint(arg1_st, "[0x%X]",disp); break; case ARGT_AL ... ARGT_DX: case ARGT_SS ... ARGT_ST0: CatPrint(arg1_st, "%z", arg1 - ARGT_AL, "AL\0AX\0EAX\0RAX\0CL\0DX\0 \0 \0SS\0DS\0ES\0FS\0GS\0CS\0ST0\0"); break; case ARGT_STI: rip--; CatPrint(arg1_st, "%Z", *rip++ - tmpins->opcode[tmpins->opcode_count - 1], "ST_FSTACK_REGS"); break; } switch (arg2) { case ARGT_IMM8: case ARGT_UIMM8: CatPrint(arg2_st, "0x%02X", *rip(U8 *)++); break; case ARGT_IMM16: case ARGT_UIMM16: CatPrint(arg2_st, "0x%04X", *rip(U16 *)++); break; case ARGT_IMM32: case ARGT_UIMM32: CatPrint(arg2_st, "0x%08X", *rip(U32 *)++); break; case ARGT_IMM64: case ARGT_UIMM64: CatPrint(arg2_st, "0x%016X", *rip(I64 *)++); break; case ARGT_MOFFS8...ARGT_MOFFS64: CatPrint(arg2_st, seg_overrides); if (arg2_size == 8) disp = *rip(U8 *)++; else if (opadd == 16) disp = *rip(U16 *)++; else disp = *rip(U32 *)++; CatPrint(arg2_st, "[0x%X]", disp); break; case ARGT_AL ... ARGT_DX: case ARGT_SS ... ARGT_ST0: CatPrint(arg2_st, "%z",arg2 - ARGT_AL, "AL\0AX\0EAX\0RAX\0CL\0DX\0 \0 \0SS\0DS\0ES\0FS\0GS\0CS\0ST0\0"); break; case ARGT_STI: rip--; CatPrint(arg2_st, "%Z", *rip++ - tmpins->opcode[tmpins->opcode_count - 1], "ST_FSTACK_REGS"); break; } if (tmpins->flags & IEF_ENDING_ZERO) rip++; if (*arg1_st) CatPrint(line1, "\t%s", arg1_st); if (*arg2_st) CatPrint(line1, ", %s", arg2_st); CatPrint(line1, "\n"); CatPrint(line2, "\n"); if (!just_ins) { for (i = rip - (*_rip)(I64); i < 6; i++) { bin_data_area1[i << 1] = CH_SPACE; bin_data_area1[i << 1 + 1] = CH_SPACE; } for (i = rip - (*_rip)(I64); i < 12; i++) { bin_data_area2[(i - 6) << 1] = CH_SPACE; bin_data_area2[(i - 6) << 1 + 1] = CH_SPACE; } } StrCopy(buf, line1); if (!just_ins && rip - (*_rip)(I64) > 6) CatPrint(buf, line2); *_rip = rip; } U8 *U(U8 *rip, I64 count=20, I64 seg_size=64) {//Unassembles a num of insts. I64 i; U8 buf[1024]; if (seg_size == 16) PrintWarn("16-bit unassembly is not well supported.\n"); "$HL,1$\n"; for (i = 0; i < count; i++) { Ui(buf, &rip, seg_size); "%s", buf; } "$HL,0$\n"; return rip; } I64 Un(U8 *rip, I64 count=0x80, I64 seg_size=64) {//Unassembles a num of bytes I64 i = 0; U8 buf[1024], *end_rip = rip(I64) + count; if (seg_size == 16) PrintWarn("16-bit unassembly is not well supported.\n"); "$HL,1$\n"; while (rip < end_rip) { Ui(buf, &rip, seg_size); "%s", buf; i++; } "$HL,0$\n"; return i; }