int helper_pemu_trace(target_ulong pc) { target_ulong target; xed_error_enum_t xed_error = disas_one_inst(pc); if(xed_error != XED_ERROR_NONE){ return -1; } const xed_inst_t * xi = xed_decoded_inst_inst(&xedd_g); xed_iclass_enum_t opcode = xed_decoded_inst_get_iclass(&xedd_g); // char inst_str[512]; // xed_decoded_inst_dump_intel_format(&xedd_g, inst_str, // sizeof(inst_str), 0); switch(opcode){ case XED_ICLASS_JMP: target = Instrument_JMP(xi, pc); break; case XED_ICLASS_CALL_NEAR: target = Instrument_CALL_NEAR(xi,pc); break; case XED_ICLASS_RET_NEAR: target = Instrument_RET(xi); break; default: break; } PEMU_add_trace(target); return 0; }
static void add_write_operands(xed_dot_graph_supp_t* gg, xed_decoded_inst_t* xedd, xed_dot_node_t* n) { xed_uint_t i, noperands; xed_reg_enum_t r, r_enclosing; const xed_inst_t* xi = 0; xi = xed_decoded_inst_inst(xedd); noperands = xed_inst_noperands(xi); for( i=0; i < noperands ; i++) { const xed_operand_t* op = xed_inst_operand(xi,i); xed_operand_enum_t opname = xed_operand_name(op); if (xed_operand_is_register(opname) || xed_operand_is_memory_addressing_register(opname)) { if (xed_operand_written(op)) { /* set n as the source of the value. */ /* ignoring partial writes */ r = xed_decoded_inst_get_reg(xedd, opname); r_enclosing = xed_get_largest_enclosing_register(r); gg->xed_reg_to_node[r_enclosing] = n; } } } /* for */ }
unsigned int disas_get_target(unsigned int start_pc, struct PEMU_INST *inst) { PEMU_read_mem(start_pc, 15, inst->PEMU_inst_buf); xed_decoded_inst_zero_set_mode(&inst->PEMU_xedd_g, &inst->PEMU_dstate); xed_error_enum_t xed_error = xed_decode(&inst->PEMU_xedd_g, XED_STATIC_CAST(const xed_uint8_t *, inst->PEMU_inst_buf), 15); if (xed_error != XED_ERROR_NONE) { fprintf(stderr, "error in disas_get_target\n"); exit(0); } const xed_inst_t *xi = xed_decoded_inst_inst(&inst->PEMU_xedd_g); if(xed_decoded_inst_get_iclass(&inst->PEMU_xedd_g) != XED_ICLASS_CALL_NEAR) { return 0; } const xed_operand_t *op = xed_inst_operand(xi, 0); xed_reg_enum_t reg_id; xed_operand_enum_t op_name = xed_operand_name(op); unsigned int dest, tmp; if(operand_is_relbr(op_name, &dest)){ dest += (start_pc + xed_decoded_inst_get_length(&inst->PEMU_xedd_g)); }else if(operand_is_reg(op_name, ®_id)){ dest = PEMU_get_reg(reg_id); }else if(operand_is_mem4(op_name, &dest,0)){ PEMU_read_mem(dest, 4, &tmp); dest = tmp; } return dest; }
static target_ulong Instrument_CALL_NEAR(target_ulong pc) { uint32_t mem_addr; xed_reg_enum_t reg_id; target_ulong target; PEMU_read_mem(pc, 15, pemu_inst.PEMU_inst_buf); xed_decoded_inst_zero_set_mode(&pemu_inst.PEMU_xedd_g, &pemu_inst.PEMU_dstate); xed_error_enum_t xed_error = xed_decode(&pemu_inst.PEMU_xedd_g, XED_STATIC_CAST(const xed_uint8_t *, pemu_inst.PEMU_inst_buf), 15); const xed_inst_t * ins = xed_decoded_inst_inst(&pemu_inst.PEMU_xedd_g); const xed_operand_t *op = xed_inst_operand(ins, 0); xed_operand_enum_t op_name = xed_operand_name(op); if (operand_is_mem(op_name, &mem_addr, 0)) { PEMU_read_mem(mem_addr,sizeof(target) , &target); } else if (operand_is_reg(op_name, ®_id)){ target = PEMU_get_reg(reg_id); } else{ int len = xed_decoded_inst_get_length(&pemu_inst.PEMU_xedd_g); target = xed_decoded_inst_get_branch_displacement(&pemu_inst.PEMU_xedd_g) + pc + len; } return target; }
bool IsRegisterOperand(xed_decoded_inst_t &xedd, int index) { const xed_inst_t* inst = xed_decoded_inst_inst(&xedd); const xed_operand_t* operand = xed_inst_operand(inst, index); //the first operand is the destination. xed_operand_enum_t oper_type = xed_operand_name(operand); switch(oper_type) { case XED_OPERAND_REG0: case XED_OPERAND_REG1: case XED_OPERAND_REG2: case XED_OPERAND_REG3: case XED_OPERAND_REG4: case XED_OPERAND_REG5: case XED_OPERAND_REG6: case XED_OPERAND_REG7: case XED_OPERAND_REG8: case XED_OPERAND_REG9: case XED_OPERAND_REG10: case XED_OPERAND_REG11: case XED_OPERAND_REG12: case XED_OPERAND_REG13: case XED_OPERAND_REG14: case XED_OPERAND_REG15: return true; break; default: break; } return false; }
int RegisterOperandSize(xed_decoded_inst_t &xedd, int index) { ASSERT(IsRegisterOperand(xedd, index)); const xed_inst_t* inst = xed_decoded_inst_inst(&xedd); const xed_operand_t* operand = xed_inst_operand(inst, index); //the first operand is the destination. xed_operand_enum_t oper_type = xed_operand_name(operand); xed_reg_enum_t reg = xed_decoded_inst_get_reg(&xedd, oper_type); int size = 0; switch(reg) { case XED_REG_AH: case XED_REG_AL: case XED_REG_BH: case XED_REG_BL: case XED_REG_CH: case XED_REG_CL: case XED_REG_DH: case XED_REG_DL: size = 8; break; case XED_REG_AX: case XED_REG_BX: case XED_REG_CX: case XED_REG_DX: size = 16; break; default: size = 32; break; } ASSERT(size != 0); return size; }
void check_for_mov_to_cr3(xed_decoded_inst_t* xedd) { if (xed_decoded_inst_get_iclass(xedd) == XED_ICLASS_MOV_CR) { // we know mov_cr has 2 operands so we do not check // xed_inst_noperands. // get the skeleton (static info) const xed_inst_t* xi = xed_decoded_inst_inst(xedd); // get the dest operand (operand 0) const xed_operand_t* op = xed_inst_operand(xi,0); xed_operand_enum_t op_name = xed_operand_name(op); if (op_name == XED_OPERAND_REG0) { xed_reg_enum_t r = xed_decoded_inst_get_reg(xedd, op_name); if (r == XED_REG_CR3) { printf("Found a mov to CR3\n"); } } } }
// Return the destination register of one instruction xed_reg_enum_t DestRegister(xed_decoded_inst_t &xedd) { const xed_inst_t* inst = xed_decoded_inst_inst(&xedd); unsigned int operandNum = xed_inst_noperands(inst); // get the number of the operands // if the instruction has no operands, return invalid if(operandNum == 0) return XED_REG_INVALID; const xed_operand_t* operand = xed_inst_operand(inst, 0); //the first operand is the destination. xed_operand_enum_t oper_type = xed_operand_name(operand); xed_uint_t mark = xed_operand_is_register(oper_type); // check whether the operand is a register operand if(mark == 1) { xed_reg_enum_t reg = xed_decoded_inst_get_reg(&xedd, oper_type); ASSERT(reg != XED_REG_INVALID); return reg; } return XED_REG_INVALID; }
/* Allocate and initialize a new `Instruction' object given the associated * `xed_decoded_inst_t' structure. */ instruction_t *new_instruction(xed_decoded_inst_t *decoded_inst, xed_uint64_t runtime_address) { instruction_t *instruction; instruction = (instruction_t *)PyType_GenericNew(&type, NULL, NULL); instruction->decoded_inst = decoded_inst; instruction->inst = xed_decoded_inst_inst(decoded_inst); instruction->runtime_address = runtime_address; return instruction; }
static void add_read_operands(xed_dot_graph_supp_t* gg, xed_decoded_inst_t* xedd, xed_dot_node_t* n) { xed_uint_t i, noperands; xed_reg_enum_t r; const xed_inst_t* xi = 0; xed_bool_t found = 0; xi = xed_decoded_inst_inst(xedd); noperands = xed_inst_noperands(xi); for( i=0; i < noperands ; i++) { int memop = -1; const xed_operand_t* op = xed_inst_operand(xi,i); xed_operand_enum_t opname = xed_operand_name(op); if (xed_operand_is_register(opname) || xed_operand_is_memory_addressing_register(opname)) { if (xed_operand_read(op)) { /* add edge to n */ r = xed_decoded_inst_get_reg(xedd, opname); found |= add_edge(gg, n, r); } continue; } if (opname == XED_OPERAND_MEM0) memop = 0; else if (opname == XED_OPERAND_MEM1 ) memop = 1; if (memop != -1) { /* get reads of base/index regs, if any */ xed_reg_enum_t base, indx; base = xed_decoded_inst_get_base_reg(xedd,memop); indx = xed_decoded_inst_get_index_reg(xedd,memop); if (base != XED_REG_INVALID) found |= add_edge(gg, n, base); indx = xed_decoded_inst_get_index_reg(xedd,memop); if (indx != XED_REG_INVALID) found |= add_edge(gg, n, indx); } } /* for */ if (!found) { /* add an edge from start */ xed_dot_edge(gg->g, gg->start, n); } }
bool IsImmediateOperand(xed_decoded_inst_t &xedd, int index) { const xed_inst_t* inst = xed_decoded_inst_inst(&xedd); const xed_operand_t* operand = xed_inst_operand(inst, index); //the first operand is the destination. xed_operand_enum_t oper_type = xed_operand_name(operand); switch(oper_type) { case XED_OPERAND_IMM0: return true; default: break; } return false; }
void print_operands(xed_decoded_inst_t* xedd) { unsigned int i = 0; xed_inst_t const* const xi = xed_decoded_inst_inst(xedd); const unsigned int noperands = xed_inst_noperands(xi); for( i=0; i < noperands ; i++) { xed_operand_t const* op = xed_inst_operand(xi,i); xed_operand_enum_t op_name = xed_operand_name(op); if (xed_operand_is_register(op_name)) { xed_reg_enum_t reg = xed_decoded_inst_get_reg(xedd,op_name); xed_operand_action_enum_t rw = xed_operand_rw(op); printf("%2d: %5s %5s\n", i, xed_reg_enum_t2str(reg), xed_operand_action_enum_t2str(rw)); } } }
int PEMU_disas_handle_branch(target_ulong pc) { xed_error_enum_t xed_error = disas_one_inst(pc); if(xed_error != XED_ERROR_NONE){ return 0; } xed_iclass_enum_t opcode = xed_decoded_inst_get_iclass(&xedd_g); switch(opcode){ case XED_ICLASS_JMP: case XED_ICLASS_CALL_NEAR: { const xed_inst_t * ins = xed_decoded_inst_inst(&xedd_g); const xed_operand_t *op = xed_inst_operand(ins, 0); xed_operand_enum_t op_name = xed_operand_name(op); int len = xed_decoded_inst_get_length(&xedd_g); unsigned int rel; if(operand_is_relbr(op_name, &rel)) { unsigned long target = pc + len + rel; PEMU_add_trace(target); return 0; } return 1; } break; case XED_ICLASS_RET_NEAR: return 1; default: break; } return 0; }
TCA OfflineX86Code::collectJmpTargets(FILE *file, TCA fileStartAddr, TCA codeStartAddr, uint64_t codeLen, vector<TCA> *jmpTargets) { xed_uint8_t* code = (xed_uint8_t*) alloca(codeLen); xed_uint8_t* frontier; TCA ip; if (codeLen == 0) return 0; if (fseek(file, codeStartAddr - fileStartAddr, SEEK_SET)) { error("collectJmpTargets error: seeking file"); } size_t readLen = fread(code, codeLen, 1, file); if (readLen != 1) error("collectJmpTargets error: reading file"); xed_decoded_inst_t xedd; xed_iclass_enum_t iclass = XED_ICLASS_NOP; // Decode each instruction for (frontier = code, ip = codeStartAddr; frontier < code + codeLen; ) { xed_decoded_inst_zero_set_mode(&xedd, &xed_state); xed_decoded_inst_set_input_chip(&xedd, XED_CHIP_INVALID); xed_error_enum_t xed_error = xed_decode(&xedd, frontier, 15); if (xed_error != XED_ERROR_NONE) break; uint32_t instrLen = xed_decoded_inst_get_length(&xedd); iclass = xed_decoded_inst_get_iclass(&xedd); if (iclass >= XED_ICLASS_JB && iclass <= XED_ICLASS_JZ) { const xed_inst_t *xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 1); const xed_operand_t *opnd = xed_inst_operand(xi, 0); xed_operand_enum_t opndName = xed_operand_name(opnd); if (opndName == XED_OPERAND_RELBR) { always_assert(xed_decoded_inst_get_branch_displacement_width(&xedd)); xed_int32_t disp = xed_decoded_inst_get_branch_displacement(&xedd); TCA addr = ip + instrLen + disp; jmpTargets->push_back(addr); } } frontier += instrLen; ip += instrLen; } // If the code sequence falls thru, then add the next instruction as a // possible target bool fallsThru = (iclass != XED_ICLASS_JMP && iclass != XED_ICLASS_JMP_FAR && iclass != XED_ICLASS_RET_NEAR && iclass != XED_ICLASS_RET_FAR); if (fallsThru) { jmpTargets->push_back(ip); return ip; } return 0; }
static void print_inst(INST *inst) { //#if 0 xed_decoded_inst_zero_set_mode(&xedd_g, &dstate); xed_error_enum_t xed_error = xed_decode(&xedd_g, XED_STATIC_CAST(const xed_uint8_t *, inst->inst), 15); #ifdef STATISTICS g_inst_num++; #endif // fprintf(output, "\/\/0x%x\n", g_pc); if (xed_error == XED_ERROR_NONE) { #ifdef WINDOWS_FORMAT xed_decoded_inst_dump_intel_format(&xedd_g, g_inst_str, sizeof(g_inst_str), 0); #else xed_decoded_inst_dump_att_format(&xedd_g, g_inst_str, sizeof(g_inst_str), 0); //xed_decoded_inst_dump_intel_format(&xedd_g, g_inst_str, sizeof(g_inst_str), 0); #endif const xed_inst_t *xi = xed_decoded_inst_inst(&xedd_g); patch_operand(xi); switch(inst->type){ case INCALL: case INJMP: case NORMAL: format_normal(xi); break; case JMP: case TAIL: format_jmp(xi); break; case CALL: format_direct_call(xi); break; case JCC: case LOOP: format_jcc(xi); break; case LEA_8: case LEA_16: case LEA_32: format_lea(xi); default: break; } // fprintf(stdout, "results:\"%s\\n\\t\"\n", inst_buffer); if(get_jmp_dst(g_pc)) #ifdef WINDOWS_FORMAT fprintf(output, "L_0x%x:\n", g_pc); #else fprintf(output, "\"L_0x%x:\"\n", g_pc); #endif #ifdef DEBUG print_debug(); #endif #ifdef WINDOWS_FORMAT fprintf(output, "%s\n", inst_buffer); #else fprintf(output, "\"%s\\n\\t\"\n", inst_buffer); #endif //patch safety guard switch(inst->type){ case INJMP: case JCC: if(safety_guard[0]){ #ifdef WINDOWS_FORMAT fprintf(output, "%s\n", safety_guard); #else fprintf(output, "\"%s\\n\\t\"\n", safety_guard); #endif } break; } } //#endif }
void print_operands(xed_decoded_inst_t* xedd) { unsigned int i, noperands; cout << "Operands" << endl; const xed_inst_t* xi = xed_decoded_inst_inst(xedd); noperands = xed_inst_noperands(xi); for( i=0; i < noperands ; i++) { const xed_operand_t* op = xed_inst_operand(xi,i); xed_operand_enum_t op_name = xed_operand_name(op); cout << i << " " << xed_operand_enum_t2str(op_name) << " "; switch(op_name) { case XED_OPERAND_AGEN: case XED_OPERAND_MEM0: case XED_OPERAND_MEM1: // we print memops in a different function break; case XED_OPERAND_PTR: // pointer (always in conjunction with a IMM0) case XED_OPERAND_RELBR: { // branch displacements xed_uint_t disp_bits = xed_decoded_inst_get_branch_displacement_width(xedd); if (disp_bits) { //cout << "BRANCH_DISPLACEMENT_BYTES= " << disp_bits << " "; xed_int32_t disp = xed_decoded_inst_get_branch_displacement(xedd); //cout << hex << setfill('0') << setw(8) << disp << setfill(' ') << dec; } } break; case XED_OPERAND_IMM0: { // immediates xed_uint_t width = xed_decoded_inst_get_immediate_width(xedd); if (xed_decoded_inst_get_immediate_is_signed(xedd)) { xed_int32_t x =xed_decoded_inst_get_signed_immediate(xedd); //cout << hex << setfill('0') << setw(8) << x << setfill(' ') << dec // << '(' << width << ')'; } else { xed_uint64_t x = xed_decoded_inst_get_unsigned_immediate(xedd); //cout << hex << setfill('0') << setw(16) << x << setfill(' ') << dec // << '(' << width << ')'; } break; } case XED_OPERAND_IMM1: { // immediates xed_uint8_t x = xed_decoded_inst_get_second_immediate(xedd); //cout << hex << setfill('0') << setw(2) << (int)x << setfill(' ') << dec; break; } case XED_OPERAND_REG0: case XED_OPERAND_REG1: case XED_OPERAND_REG2: case XED_OPERAND_REG3: case XED_OPERAND_REG4: case XED_OPERAND_REG5: case XED_OPERAND_REG6: case XED_OPERAND_REG7: case XED_OPERAND_REG8: case XED_OPERAND_REG9: case XED_OPERAND_REG10: case XED_OPERAND_REG11: case XED_OPERAND_REG12: case XED_OPERAND_REG13: case XED_OPERAND_REG14: case XED_OPERAND_REG15: { xed_reg_enum_t r = xed_decoded_inst_get_reg(xedd, op_name); cout << xed_operand_enum_t2str(op_name) << "=" << xed_reg_enum_t2str(r); break; } default: //cout << "[Not currently printing value of field " << xed_operand_enum_t2str(op_name) << ']'; break; } //cout << " " << xed_operand_visibility_enum_t2str(xed_operand_operand_visibility(op)) // << " / " << xed_operand_action_enum_t2str(xed_operand_rw(op)) // << " / " << xed_operand_width_enum_t2str(xed_operand_width(op)); //cout << " bytes=" << xed_decoded_inst_operand_length(xedd,i); //cout << endl; } }
int disas_trace_ex(target_ulong pc_start, TRACE trace) { //#define PEMU_DEBUG #ifdef PEMU_DEBUG printf("New trace %x\n", pc_start); #endif target_ulong pc; char inst_str[256]; int newtrace = 0; pc = pc_start; trace->trace_start = pc_start; BBL bbl= get_BBL(pc); trace->head = bbl; INS ins = NULL; #ifdef PEMU_DEBUG printf("New BBL %x\n", pc_start); #endif while(!newtrace){ xed_error_enum_t xed_error = disas_one_inst(pc); if(xed_error != XED_ERROR_NONE){ return -1; } xed_decoded_inst_dump_intel_format(&xedd_g, inst_str, sizeof(inst_str), 0); xed_iclass_enum_t opcode = xed_decoded_inst_get_iclass(&xedd_g); int len = xed_decoded_inst_get_length(&xedd_g); #ifdef PEMU_DEBUG printf("New INS %x %s\n", pc, inst_str); #endif if(!ins){ ins = get_INS(pc); bbl->head = ins; }else{ ins->next = get_INS(pc); ins = ins->next; } if(pemu_hook_funcs.inst_hook != 0) { pemu_inst.PEMU_inst_pc = pc; pemu_hook_funcs.inst_hook(ins, 0); } bbl->inst_count ++; bbl-> size += len; switch(opcode){ //case XED_ICLASS_CALL_FAR: case XED_ICLASS_CALL_NEAR: case XED_ICLASS_SYSENTER: case XED_ICLASS_INT: case XED_ICLASS_INT1: case XED_ICLASS_INT3: case XED_ICLASS_HLT: case XED_ICLASS_RET_FAR: case XED_ICLASS_RET_NEAR: case XED_ICLASS_JMP: case XED_ICLASS_JMP_FAR: newtrace = 1; break; //case XED_ICLASS_IRET: //case XED_ICLASS_IRETD: //case XED_ICLASS_IRETQ: case XED_ICLASS_JB: case XED_ICLASS_JBE: case XED_ICLASS_JL: case XED_ICLASS_JLE: case XED_ICLASS_JNB: case XED_ICLASS_JNBE: case XED_ICLASS_JNL: case XED_ICLASS_JNLE: case XED_ICLASS_JNO: case XED_ICLASS_JNP: case XED_ICLASS_JNS: case XED_ICLASS_JNZ: case XED_ICLASS_JO: case XED_ICLASS_JP: case XED_ICLASS_JRCXZ: case XED_ICLASS_JS: case XED_ICLASS_JZ: { //add new trace target const xed_inst_t * xi = xed_decoded_inst_inst(&xedd_g); const xed_operand_t *op = xed_inst_operand(xi,0); xed_operand_enum_t opname = xed_operand_name(op); target_ulong rel; target_ulong target; rel = xed_decoded_inst_get_branch_displacement(&xedd_g); target = pc + rel + len; PEMU_add_trace(target); #ifdef PEMU_DEBUG printf("New target %x %d\n", target, bbl->inst_count); #endif bbl->next = get_BBL(pc+len); bbl = bbl->next; ins = NULL; #ifdef PEMU_DEBUG printf("New BBL %x\n", pc + len); #endif break; } default: //TODO: break; //set_code_cache(pc, TAINTED); //printf("pc=%lu\tlen=%x\n", pc, len); } pc = pc + len; } if(pemu_hook_funcs.trace_hook != 0) pemu_hook_funcs.trace_hook(trace, 0); BBL bblnext = trace->head; do{ bbl = bblnext; bblnext = bbl->next; INS ins; INS insnext = bbl->head; do{ ins = insnext; insnext = ins->next; free(ins); }while(insnext!=NULL); free(bbl); }while(bblnext!=NULL); free(trace); }
/* This is the central function Given a memory address, reads a bunch of memory bytes and calls the disassembler to obtain the information Then it stores the information into the eh EntryHeader */ void decode_address(uint32_t address, EntryHeader *eh, int ignore_taint) { unsigned char insn_buf[MAX_INSN_BYTES]; unsigned int is_stackpush = 0, is_stackpop = 0; unsigned int stackpushpop_acc = 0; if (xed2chris_regmapping[XED_REG_EAX][0] == 0) { init_xed2chris(); assert(xed2chris_regmapping[XED_REG_EAX][0] != 0); } /* Read memory from TEMU */ TEMU_read_mem(address, MAX_INSN_BYTES, insn_buf); /* Disassemble instruction buffer */ xed_decoded_inst_zero_set_mode(&xedd, &dstate); xed_error_enum_t xed_error = xed_decode(&xedd, STATIC_CAST(const xed_uint8_t*,insn_buf), MAX_INSN_BYTES); xed_bool_t okay = (xed_error == XED_ERROR_NONE); if (!okay) return; // Increase counters tstats.insn_counter_decoded++; int i; /* Clear out Entry header */ memset(eh, 0, sizeof(EntryHeader)); /* Copy the address and instruction size */ eh->address = address; eh->inst_size = xed_decoded_inst_get_length(&xedd); if (eh->inst_size > MAX_INSN_BYTES) eh->inst_size = MAX_INSN_BYTES; /* Copy instruction rawbytes */ memcpy(eh->rawbytes, insn_buf, eh->inst_size); /* Get the number of XED operands */ const xed_inst_t* xi = xed_decoded_inst_inst(&xedd); int xed_ops = xed_inst_noperands(xi); int op_idx = -1; /* Get the category of the instruction */ xed_category_enum_t category = xed_decoded_inst_get_category(&xedd); /* Iterate over the XED operands */ for(i = 0; i < xed_ops; i++) { if(op_idx >= MAX_NUM_OPERANDS) break; //assert(op_idx < MAX_NUM_OPERANDS); /* Get operand */ const xed_operand_t* op = xed_inst_operand(xi,i); xed_operand_enum_t op_name = xed_operand_name(op); switch(op_name) { /* Register */ case XED_OPERAND_REG0: case XED_OPERAND_REG1: case XED_OPERAND_REG2: case XED_OPERAND_REG3: case XED_OPERAND_REG4: case XED_OPERAND_REG5: case XED_OPERAND_REG6: case XED_OPERAND_REG7: case XED_OPERAND_REG8: case XED_OPERAND_REG9: case XED_OPERAND_REG10: case XED_OPERAND_REG11: case XED_OPERAND_REG12: case XED_OPERAND_REG13: case XED_OPERAND_REG14: case XED_OPERAND_REG15: { xed_reg_enum_t reg_id = xed_decoded_inst_get_reg(&xedd, op_name); int regnum = xed2chris_regmapping[reg_id][1]; // Special handling for Push if (reg_id == XED_REG_STACKPUSH) is_stackpush = 1; else if (reg_id == XED_REG_STACKPOP) is_stackpop = 1; if (-1 == regnum) break; else { op_idx++; eh->num_operands++; eh->operand[op_idx].type = TRegister; eh->operand[op_idx].addr = xed2chris_regmapping[reg_id][0]; eh->operand[op_idx].length = (uint8_t) xed_decoded_inst_operand_length (&xedd, i); eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); eh->operand[op_idx].value = TEMU_cpu_regs[regnum]; switch (eh->operand[op_idx].addr) { case ax_reg: case bx_reg: case cx_reg: case dx_reg: case bp_reg: case sp_reg: case si_reg: case di_reg: eh->operand[op_idx].value &= 0xFFFF; break; case al_reg: case bl_reg: case cl_reg: case dl_reg: eh->operand[op_idx].value &= 0xFF; break; case ah_reg: case bh_reg: case ch_reg: case dh_reg: eh->operand[op_idx].value = (eh->operand[i].value & 0xFF00) >> 8; break; default: break; } } if (ignore_taint == 0) set_operand_data(&(eh->operand[op_idx])); break; } /* Immediate */ case XED_OPERAND_IMM0: { op_idx++; eh->num_operands++; eh->operand[op_idx].type = TImmediate; eh->operand[op_idx].length = (uint8_t) xed_decoded_inst_operand_length (&xedd, i); eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); //xed_uint_t width = xed_decoded_inst_get_immediate_width(&xedd); if (xed_decoded_inst_get_immediate_is_signed(&xedd)) { xed_int32_t signed_imm_val = xed_decoded_inst_get_signed_immediate(&xedd); eh->operand[op_idx].value = (uint32_t) signed_imm_val; } else { xed_uint64_t unsigned_imm_val = xed_decoded_inst_get_unsigned_immediate(&xedd); eh->operand[op_idx].value = (uint32_t) unsigned_imm_val; } break; break; } /* Special immediate only used in ENTER instruction */ case XED_OPERAND_IMM1: { op_idx++; eh->num_operands++; eh->operand[op_idx].type = TImmediate; eh->operand[op_idx].length = (uint8_t) xed_decoded_inst_operand_length (&xedd, i); eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); xed_uint8_t unsigned_imm_val = xed_decoded_inst_get_second_immediate(&xedd); eh->operand[op_idx].value = (uint32_t) unsigned_imm_val; break; } /* Memory */ case XED_OPERAND_AGEN: case XED_OPERAND_MEM0: case XED_OPERAND_MEM1: { unsigned long base = 0; unsigned long index = 0; unsigned long scale = 1; unsigned long segbase = 0; unsigned short segsel = 0; unsigned long displacement = 0; unsigned int j; size_t remaining = 0; /* Set memory index */ int mem_idx = 0; if (op_name == XED_OPERAND_MEM1) mem_idx = 1; unsigned int memlen = xed_decoded_inst_operand_length (&xedd, i); for (j = 0; j < memlen; j+=4) { /* Initialization */ base = 0; index = 0; scale = 1; segbase = 0; segsel = 0; displacement = 0; remaining = memlen - j; op_idx++; if(op_idx >= MAX_NUM_OPERANDS) break; //assert(op_idx < MAX_NUM_OPERANDS); eh->num_operands++; eh->operand[op_idx].type = TMemLoc; eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); eh->operand[op_idx].length = remaining > 4 ? 4 : (uint8_t) remaining; // Get Segment register xed_reg_enum_t seg_regid = xed_decoded_inst_get_seg_reg(&xedd,mem_idx); if (seg_regid != XED_REG_INVALID) { const xed_operand_values_t *xopv = xed_decoded_inst_operands_const(&xedd); xed_bool_t default_segment = xed_operand_values_using_default_segment (xopv,mem_idx); if (!default_segment) { eh->num_operands++; int segmentreg = xed2chris_regmapping[seg_regid][0] - 100; segbase = TEMU_cpu_segs[segmentreg].base; segsel = TEMU_cpu_segs[segmentreg].selector; eh->memregs[op_idx][0].type = TRegister; eh->memregs[op_idx][0].length = 2; eh->memregs[op_idx][0].addr = xed2chris_regmapping[seg_regid][0]; eh->memregs[op_idx][0].access = (uint8_t) XED_OPERAND_ACTION_R; eh->memregs[op_idx][0].value = segsel; eh->memregs[op_idx][0].usage = memsegment; if (ignore_taint == 0) set_operand_data(&(eh->memregs[op_idx][0])); int dt; if (segsel & 0x4) // ldt dt = TEMU_cpu_ldt->base; else //gdt dt = TEMU_cpu_gdt->base; segsel = segsel >> 3; unsigned long segent = dt + 8 * segsel; unsigned char segdes[8]; TEMU_read_mem(segent, 8, segdes); #if 0 // debugging code to double check segbase value unsigned long segbasenew = segdes[2] + segdes[3] * 256 + segdes[4] * 256 * 256 + segdes[7] * 256 * 256 * 256; if (segbase != segbasenew) { term_printf("segbase unexpected: 0x%08lX v.s 0x%08lX\n", segbase, segbasenew); } #endif /* Segment descriptor is stored as a memory operand */ eh->num_operands+=2; eh->memregs[op_idx][3].type = TMemLoc; eh->memregs[op_idx][3].length = 4; eh->memregs[op_idx][3].addr = segent; eh->memregs[op_idx][3].access = (uint8_t) XED_OPERAND_ACTION_INVALID; eh->memregs[op_idx][3].value = *(uint32_t *) segdes; eh->memregs[op_idx][3].tainted = 0; eh->memregs[op_idx][3].usage = memsegent0; eh->memregs[op_idx][4].type = TMemLoc; eh->memregs[op_idx][4].length = 4; eh->memregs[op_idx][4].addr = segent + 4; eh->memregs[op_idx][4].access = (uint8_t) XED_OPERAND_ACTION_INVALID; eh->memregs[op_idx][4].value = *(uint32_t *) (segdes + 4); eh->memregs[op_idx][4].tainted = 0; eh->memregs[op_idx][4].usage = memsegent1; } } // Get Base register xed_reg_enum_t base_regid = xed_decoded_inst_get_base_reg(&xedd,mem_idx); if (base_regid != XED_REG_INVALID) { eh->num_operands++; int basereg = xed2chris_regmapping[base_regid][1]; base = TEMU_cpu_regs[basereg]; eh->memregs[op_idx][1].type = TRegister; eh->memregs[op_idx][1].addr = xed2chris_regmapping[base_regid][0]; eh->memregs[op_idx][1].length = 4; eh->memregs[op_idx][1].access = (uint8_t) XED_OPERAND_ACTION_R; eh->memregs[op_idx][1].value = base; eh->memregs[op_idx][1].usage = membase; if (ignore_taint == 0) set_operand_data(&(eh->memregs[op_idx][1])); } // Get Index register and Scale xed_reg_enum_t index_regid = xed_decoded_inst_get_index_reg(&xedd,mem_idx); if (mem_idx == 0 && index_regid != XED_REG_INVALID) { eh->num_operands++; int indexreg = xed2chris_regmapping[index_regid][1]; index = TEMU_cpu_regs[indexreg]; eh->memregs[op_idx][2].type = TRegister; eh->memregs[op_idx][2].addr = xed2chris_regmapping[index_regid][0]; eh->memregs[op_idx][2].length = 4; eh->memregs[op_idx][2].access = (uint8_t) XED_OPERAND_ACTION_R; eh->memregs[op_idx][2].value = index; eh->memregs[op_idx][2].usage = memindex; if (ignore_taint == 0) set_operand_data(&(eh->memregs[op_idx][2])); // Get Scale (AKA width) (only have a scale if the index exists) if (xed_decoded_inst_get_scale(&xedd,i) != 0) { scale = (unsigned long) xed_decoded_inst_get_scale(&xedd,mem_idx); } } // Get displacement (AKA offset) displacement = (unsigned long) xed_decoded_inst_get_memory_displacement (&xedd,mem_idx); // Fix displacement for: // 1) Any instruction that pushes into the stack, since ESP is // decremented before memory operand is written using ESP. // Affects: ENTER,PUSH,PUSHA,PUSHF,CALL if (is_stackpush) { stackpushpop_acc += eh->operand[op_idx].length; displacement = displacement - stackpushpop_acc -j; } // 2) Pop instructions where the // destination operand is a memory location that uses ESP // as base or index register. // The pop operations increments ESP and the written memory // location address needs to be adjusted. // Affects: pop (%esp) else if ((category == XED_CATEGORY_POP) && (!is_stackpop)) { if ((eh->memregs[op_idx][1].addr == esp_reg) || (eh->memregs[op_idx][2].addr == esp_reg)) { displacement = displacement + eh->operand[op_idx].length; } } // Calculate memory address accessed eh->operand[op_idx].addr = j + segbase + base + index * scale + displacement; // Special handling for LEA instructions if (op_name == XED_OPERAND_AGEN) { eh->operand[op_idx].type = TMemAddress; eh->operand[op_idx].length = 4; has_page_fault = 0; // LEA won't trigger page fault } else { has_page_fault = TEMU_read_mem(eh->operand[op_idx].addr, (int)(eh->operand[op_idx].length), (uint8_t *)&(eh->operand[op_idx].value)); } // Check if instruction accesses user memory // kernel_mem_start defined in shared/read_linux.c if ((eh->operand[op_idx].addr < kernel_mem_start) && (op_name != XED_OPERAND_AGEN)) { access_user_mem = 1; } if (ignore_taint == 0) set_operand_data(&(eh->operand[op_idx])); } break; } /* Jumps */ case XED_OPERAND_PTR: // pointer (always in conjunction with a IMM0) case XED_OPERAND_RELBR: { // branch displacements xed_uint_t disp = xed_decoded_inst_get_branch_displacement(&xedd); /* Displacement is from instruction end */ /* Adjust displacement with instruction size */ disp = disp + eh->inst_size; op_idx++; eh->num_operands++; eh->operand[op_idx].type = TJump; eh->operand[op_idx].length = 4; eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); eh->operand[op_idx].value = disp; break; } /* Floating point registers */ case XED_REG_X87CONTROL: case XED_REG_X87STATUS: case XED_REG_X87TOP: case XED_REG_X87TAG: case XED_REG_X87PUSH: case XED_REG_X87POP: case XED_REG_X87POP2: op_idx++; eh->num_operands++; eh->operand[op_idx].type = TFloatRegister; eh->operand[op_idx].length = 4; eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op); default: break; } }
void OfflineX86Code::disasm(FILE* file, TCA fileStartAddr, TCA codeStartAddr, uint64_t codeLen, const PerfEventsMap<TCA>& perfEvents, BCMappingInfo bcMappingInfo, bool printAddr /* =true */, bool printBinary /* =false */) { char codeStr[MAX_INSTR_ASM_LEN]; xed_uint8_t* code = (xed_uint8_t*) alloca(codeLen); xed_uint8_t* frontier; TCA ip; TCA r10val = 0; size_t currBC = 0; if (codeLen == 0) return; auto const offset = codeStartAddr - fileStartAddr; if (fseek(file, offset, SEEK_SET)) { error("disasm error: seeking file"); } size_t readLen = fread(code, codeLen, 1, file); if (readLen != 1) { error("Failed to read {} bytes at offset {} from code file due to {}", codeLen, offset, feof(file) ? "EOF" : "read error"); } xed_decoded_inst_t xedd; // Decode and print each instruction for (frontier = code, ip = codeStartAddr; frontier < code + codeLen; ) { xed_decoded_inst_zero_set_mode(&xedd, &xed_state); xed_decoded_inst_set_input_chip(&xedd, XED_CHIP_INVALID); xed_error_enum_t xed_error = xed_decode(&xedd, frontier, 15); if (xed_error != XED_ERROR_NONE) break; // Get disassembled instruction in codeStr if (!xed_format_context(xed_syntax, &xedd, codeStr, MAX_INSTR_ASM_LEN, (uint64_t)ip, nullptr #if XED_ENCODE_ORDER_MAX_ENTRIES != 28 // Newer version of XED library , 0 #endif )) { error("disasm error: xed_format_context failed"); } // Annotate the x86 with its bytecode. currBC = printBCMapping(bcMappingInfo, currBC, (TCA)ip); if (printAddr) printf("%14p: ", ip); uint32_t instrLen = xed_decoded_inst_get_length(&xedd); if (printBinary) { uint32_t i; for (i=0; i < instrLen; i++) { printf("%02X", frontier[i]); } for (; i < 16; i++) { printf(" "); } } // For calls, we try to figure out the destination symbol name. // We look both at relative branches and the pattern: // move r10, IMMEDIATE // call r10 xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xedd); string callDest = ""; if (iclass == XED_ICLASS_CALL_NEAR || iclass == XED_ICLASS_CALL_FAR) { const xed_inst_t *xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 1); const xed_operand_t *opnd = xed_inst_operand(xi, 0); xed_operand_enum_t opndName = xed_operand_name(opnd); if (opndName == XED_OPERAND_RELBR) { if (xed_decoded_inst_get_branch_displacement_width(&xedd)) { xed_int32_t disp = xed_decoded_inst_get_branch_displacement(&xedd); TCA addr = ip + instrLen + disp; callDest = getSymbolName(addr); } } else if (opndName == XED_OPERAND_REG0) { if (xed_decoded_inst_get_reg(&xedd, opndName) == XED_REG_R10) { callDest = getSymbolName(r10val); } } } else if (iclass == XED_ICLASS_MOV) { // Look for moves into r10 and keep r10val updated const xed_inst_t* xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 2); const xed_operand_t *destOpnd = xed_inst_operand(xi, 0); xed_operand_enum_t destOpndName = xed_operand_name(destOpnd); if (destOpndName == XED_OPERAND_REG0 && xed_decoded_inst_get_reg(&xedd, destOpndName) == XED_REG_R10) { const xed_operand_t *srcOpnd = xed_inst_operand(xi, 1); xed_operand_enum_t srcOpndName = xed_operand_name(srcOpnd); if (srcOpndName == XED_OPERAND_IMM0) { TCA addr = (TCA)xed_decoded_inst_get_unsigned_immediate(&xedd); r10val = addr; } } } if (!perfEvents.empty()) { printEventStats((TCA)ip, instrLen, perfEvents); } else { printf("%48s", ""); } printf("%s%s\n", codeStr, callDest.c_str()); frontier += instrLen; ip += instrLen; } }