private static void CopyOpcode(ldasm_data *pLdasmData, void *pCode, byte[] opcodes, uint offset) { for (byte i = 0; i < pLdasmData->opcd_size; i++) { opcodes[offset + pLdasmData->opcd_offset + i] = ((byte *)pCode)[pLdasmData->opcd_offset + i]; } }
/// <summary> /// Disassemble one instruction /// </summary> /// <param name="code">pointer to the code for disassemble</param> /// <param name="ld">pointer to structure ldasm_data</param> /// <param name="is64">set this flag for 64-bit code, and clear for 32-bit</param> /// <returns>length of instruction</returns> public static uint ldasm(void *code, ldasm_data *ld, bool is64) { byte *p = (byte *)code; byte s, op, f; byte rexw, pr_66, pr_67; s = rexw = pr_66 = pr_67 = 0; /* dummy check */ if (code == null || ld == null) { return(0); } /* init output data */ *ld = new ldasm_data(); /* phase 1: parse prefixies */ while ((cflags(*p) & OP_PREFIX) != 0) { if (*p == 0x66) { pr_66 = 1; } if (*p == 0x67) { pr_67 = 1; } p++; s++; ld->flags |= F_PREFIX; if (s == 15) { ld->flags |= F_INVALID; return(s); } } /* parse REX prefix */ if (is64 && *p >> 4 == 4) { ld->rex = *p; rexw = (byte)((ld->rex >> 3) & 1); ld->flags |= F_REX; p++; s++; } /* can be only one REX prefix */ if (is64 && *p >> 4 == 4) { ld->flags |= F_INVALID; s++; return(s); } /* phase 2: parse opcode */ ld->opcd_offset = (byte)(p - (byte *)code); ld->opcd_size = 1; op = *p++; s++; /* is 2 byte opcode? */ if (op == 0x0F) { op = *p++; s++; ld->opcd_size++; f = cflags_ex(op); if ((f & OP_INVALID) != 0) { ld->flags |= F_INVALID; return(s); } /* for SSE instructions */ if ((f & OP_EXTENDED) != 0) { op = *p++; s++; ld->opcd_size++; } } else { f = cflags(op); /* pr_66 = pr_67 for opcodes A0-A3 */ if (op >= 0xA0 && op <= 0xA3) { pr_66 = pr_67; } } /* phase 3: parse ModR/M, SIB and DISP */ if ((f & OP_MODRM) != 0) { byte mod = (byte)(*p >> 6); byte ro = (byte)((*p & 0x38) >> 3); byte rm = (byte)(*p & 7); ld->modrm = *p++; s++; ld->flags |= F_MODRM; /* in F6,F7 opcodes immediate data present if R/O == 0 */ if (op == 0xF6 && (ro == 0 || ro == 1)) { f |= OP_DATA_I8; } if (op == 0xF7 && (ro == 0 || ro == 1)) { f |= OP_DATA_I16_I32_I64; } /* is SIB byte exist? */ if (mod != 3 && rm == 4 && !(!is64 && pr_67 != 0)) { ld->sib = *p++; s++; ld->flags |= F_SIB; /* if base == 5 and mod == 0 */ if ((ld->sib & 7) == 5 && mod == 0) { ld->disp_size = 4; } } switch (mod) { case 0: if (is64) { if (rm == 5) { ld->disp_size = 4; if (is64) { ld->flags |= F_RELATIVE; } } } else if (pr_67 != 0) { if (rm == 6) { ld->disp_size = 2; } } else { if (rm == 5) { ld->disp_size = 4; } } break; case 1: ld->disp_size = 1; break; case 2: if (is64) { ld->disp_size = 4; } else if (pr_67 != 0) { ld->disp_size = 2; } else { ld->disp_size = 4; } break; } if (ld->disp_size != 0) { ld->disp_offset = (byte)(p - (byte *)code); p += ld->disp_size; s += ld->disp_size; ld->flags |= F_DISP; } } /* phase 4: parse immediate data */ if (rexw != 0 && (f & OP_DATA_I16_I32_I64) != 0) { ld->imm_size = 8; } else if ((f & OP_DATA_I16_I32) != 0 || (f & OP_DATA_I16_I32_I64) != 0) { ld->imm_size = (byte)(4 - (pr_66 << 1)); } /* if exist, add OP_DATA_I16 and OP_DATA_I8 size */ ld->imm_size += (byte)(f & 3); if (ld->imm_size != 0) { s += ld->imm_size; ld->imm_offset = (byte)(p - (byte *)code); ld->flags |= F_IMM; if ((f & OP_RELATIVE) != 0) { ld->flags |= F_RELATIVE; } } /* instruction is too long */ if (s > 15) { ld->flags |= F_INVALID; } return(s); }