void cfi_call_instrumentation_snapahot(void *dcontext, instrlist_t *ilist, instr_t *where, void *callee) { uint dstack_offs = 0, pad = 0; unsigned int eflags_offs; CFI_ASSERT(dcontext != NULL, "cfi_call_instrumentation_snapahot: dcontext cannot be NULL"); instr_t *next_snapshot = INSTR_CREATE_label(dcontext); PRE(ilist, where, INSTR_CREATE_pushf(dcontext)); dstack_offs += XSP_SZ; eflags_offs = dstack_offs; PRE(ilist, where, INSTR_CREATE_push(dcontext, opnd_create_reg(DR_REG_RDI))); dstack_offs += XSP_SZ; PRE(ilist, where, INSTR_CREATE_mov_imm(dcontext, opnd_create_reg(DR_REG_RDI), OPND_CREATE_INT64(&flag_memory_snapshot))); PRE(ilist, where, INSTR_CREATE_mov_ld(dcontext, opnd_create_reg(DR_REG_RDI), opnd_create_base_disp(DR_REG_RDI, DR_REG_NULL, 0, 0, OPSZ_PTR))); PRE(ilist, where, INSTR_CREATE_cmp(dcontext, opnd_create_reg(DR_REG_RDI), OPND_CREATE_INT8(0x0))); PRE(ilist, where, INSTR_CREATE_jcc(dcontext, OP_je, opnd_create_instr(next_snapshot))); PRE(ilist, where, INSTR_CREATE_push(dcontext, opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, dstack_offs - eflags_offs, OPSZ_STACK))); PRE(ilist, where, INSTR_CREATE_and(dcontext, opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, 0, OPSZ_STACK), OPND_CREATE_INT32(~(EFLAGS_NON_SYSTEM | EFLAGS_IF)))); PRE(ilist, where, INSTR_CREATE_popf(dcontext)); instrlist_set_our_mangling(ilist, true); cfi_insert_meta_native_call_vargs(dcontext, ilist, where, true/*clean*/, callee); instrlist_set_our_mangling(ilist, false); cfi_insert_native_call(dcontext, ilist, where, callee /*, opnd_create_reg(DR_REG_RAX)*/); PRE(ilist, where, next_snapshot); PRE(ilist, where, INSTR_CREATE_pop(dcontext, opnd_create_reg(DR_REG_RDI))); PRE(ilist, where, INSTR_CREATE_popf(dcontext)); /* dstack_offs = cfi_prepare_for_native_call(dcontext, ilist, where); instrlist_set_our_mangling(ilist, true); cfi_insert_meta_native_call_vargs(dcontext, ilist, where, true*//*clean*//*, callee); instrlist_set_our_mangling(ilist, false); cfi_cleanup_after_native_call(dcontext, ilist, where);*/ }
static void test_instr_as_immed(void) { void *drcontext = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(drcontext); byte *pc; instr_t *ins0, *ins1, *ins2; opnd_t opnd; byte *highmem = PREFERRED_ADDR; pc = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, highmem); ASSERT(pc == highmem); /* Test push_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); instrlist_insert_push_instr_addr(drcontext, ins0, highmem, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_pop (drcontext, opnd_create_reg(DR_REG_RAX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); /* Test mov_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); /* Beyond TOS, but a convenient mem dest */ opnd = opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, -8, OPSZ_8); instrlist_insert_mov_instr_addr(drcontext, ins0, highmem, opnd, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_RAX), opnd)); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); instrlist_clear_and_destroy(drcontext, ilist); dr_raw_mem_free(highmem, PAGE_SIZE); }
static void test_indirect_cti(void *dc) { /* 0x004275f4 ff d1 call %ecx %esp -> %esp (%esp) 0x004275f4 66 ff d1 data16 call %cx %esp -> %esp (%esp) 0x004275f4 67 ff d1 addr16 call %ecx %sp -> %sp (%sp) 0x00427794 ff 19 lcall (%ecx) %esp -> %esp (%esp) 0x00427794 66 ff 19 data16 lcall (%ecx) %esp -> %esp (%esp) 0x00427794 67 ff 1f addr16 lcall (%bx) %sp -> %sp (%sp) */ instr_t *instr; instr = INSTR_CREATE_call_ind(dc, opnd_create_reg(REG_XCX)); test_instr_encode(dc, instr, 2); #ifndef X64 /* only on AMD can we shorten, so we don't test it */ instr = instr_create_2dst_2src(dc, OP_call_ind, opnd_create_reg(REG_XSP), opnd_create_base_disp(REG_XSP, REG_NULL, 0, -2, OPSZ_2), opnd_create_reg(REG_CX), opnd_create_reg(REG_XSP)); test_instr_encode(dc, instr, 3); #endif instr = instr_create_2dst_2src(dc, OP_call_ind, opnd_create_reg(IF_X64_ELSE(REG_ESP, REG_SP)), opnd_create_base_disp(IF_X64_ELSE(REG_ESP, REG_SP), REG_NULL, 0, -(int)sizeof(void*), OPSZ_ret), /* only on AMD can we shorten, so we don't test it */ opnd_create_reg(REG_XCX), opnd_create_reg(IF_X64_ELSE(REG_ESP, REG_SP))); test_instr_encode(dc, instr, 3); /* invalid to have far call go through reg since needs 6 bytes */ instr = INSTR_CREATE_call_far_ind(dc, opnd_create_base_disp(REG_XCX, REG_NULL, 0, 0, OPSZ_6)); test_instr_encode(dc, instr, 2); instr = instr_create_2dst_2src(dc, OP_call_far_ind, opnd_create_reg(REG_XSP), opnd_create_base_disp(REG_XSP, REG_NULL, 0, -4, OPSZ_4), opnd_create_base_disp(REG_XCX, REG_NULL, 0, 0, OPSZ_4), opnd_create_reg(REG_XSP)); test_instr_encode(dc, instr, 3); instr = instr_create_2dst_2src(dc, OP_call_far_ind, opnd_create_reg(IF_X64_ELSE(REG_ESP, REG_SP)), opnd_create_base_disp(IF_X64_ELSE(REG_ESP, REG_SP), REG_NULL, 0, -8, OPSZ_8_rex16_short4), opnd_create_base_disp(IF_X64_ELSE(REG_EBX, REG_BX), REG_NULL, 0, 0, OPSZ_6), opnd_create_reg(IF_X64_ELSE(REG_ESP, REG_SP))); test_instr_encode(dc, instr, 3); /* case 10710: make sure we can encode these guys 0x00428844 0e push %cs %esp -> %esp (%esp) 0x00428844 1e push %ds %esp -> %esp (%esp) 0x00428844 16 push %ss %esp -> %esp (%esp) 0x00428844 06 push %es %esp -> %esp (%esp) 0x00428844 0f a0 push %fs %esp -> %esp (%esp) 0x00428844 0f a8 push %gs %esp -> %esp (%esp) 0x00428844 1f pop %esp (%esp) -> %ds %esp 0x00428844 17 pop %esp (%esp) -> %ss %esp 0x00428844 07 pop %esp (%esp) -> %es %esp 0x00428844 0f a1 pop %esp (%esp) -> %fs %esp 0x00428844 0f a9 pop %esp (%esp) -> %gs %esp */ #ifndef X64 test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_CS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_DS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_SS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_ES)), 1); #endif test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_FS)), 2); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_GS)), 2); #ifndef X64 test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_DS)), 1); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_SS)), 1); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_ES)), 1); #endif test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_FS)), 2); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_GS)), 2); }
static void test_indirect_cti(void *dc) { /* 0x004275f4 ff d1 call %ecx %esp -> %esp (%esp) 0x004275f4 66 ff d1 data16 call %cx %esp -> %esp (%esp) 0x004275f4 67 ff d1 addr16 call %ecx %sp -> %sp (%sp) 0x00427794 ff 19 lcall (%ecx) %esp -> %esp (%esp) 0x00427794 66 ff 19 data16 lcall (%ecx) %esp -> %esp (%esp) 0x00427794 67 ff 1f addr16 lcall (%bx) %sp -> %sp (%sp) */ instr_t *instr; instr = INSTR_CREATE_call_ind(dc, opnd_create_reg(REG_ECX)); test_instr_encode(dc, instr, 2); instr = instr_create_2dst_2src(dc, OP_call_ind, opnd_create_reg(REG_ESP), opnd_create_base_disp(REG_ESP, REG_NULL, 0, 0, OPSZ_2), opnd_create_reg(REG_CX), opnd_create_reg(REG_ESP)); test_instr_encode(dc, instr, 3); instr = instr_create_2dst_2src(dc, OP_call_ind, opnd_create_reg(REG_SP), opnd_create_base_disp(REG_SP, REG_NULL, 0, 0, OPSZ_4_short2), opnd_create_reg(REG_ECX), opnd_create_reg(REG_SP)); test_instr_encode(dc, instr, 3); /* invalid to have far call go through reg since needs 6 bytes */ instr = INSTR_CREATE_call_far_ind(dc, opnd_create_base_disp(REG_ECX, REG_NULL, 0, 0, OPSZ_6)); test_instr_encode(dc, instr, 2); instr = instr_create_2dst_2src(dc, OP_call_far_ind, opnd_create_reg(REG_ESP), opnd_create_base_disp(REG_ESP, REG_NULL, 0, 0, OPSZ_2), opnd_create_base_disp(REG_ECX, REG_NULL, 0, 0, OPSZ_4), opnd_create_reg(REG_ESP)); test_instr_encode(dc, instr, 3); instr = instr_create_2dst_2src(dc, OP_call_far_ind, opnd_create_reg(REG_SP), opnd_create_base_disp(REG_SP, REG_NULL, 0, 0, OPSZ_4_short2), opnd_create_base_disp(REG_BX, REG_NULL, 0, 0, OPSZ_6), opnd_create_reg(REG_SP)); test_instr_encode(dc, instr, 3); /* case 10710: make sure we can encode these guys 0x00428844 0e push %cs %esp -> %esp (%esp) 0x00428844 1e push %ds %esp -> %esp (%esp) 0x00428844 16 push %ss %esp -> %esp (%esp) 0x00428844 06 push %es %esp -> %esp (%esp) 0x00428844 0f a0 push %fs %esp -> %esp (%esp) 0x00428844 0f a8 push %gs %esp -> %esp (%esp) 0x00428844 1f pop %esp (%esp) -> %ds %esp 0x00428844 17 pop %esp (%esp) -> %ss %esp 0x00428844 07 pop %esp (%esp) -> %es %esp 0x00428844 0f a1 pop %esp (%esp) -> %fs %esp 0x00428844 0f a9 pop %esp (%esp) -> %gs %esp */ test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_CS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_DS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_SS)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_ES)), 1); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_FS)), 2); test_instr_encode(dc, INSTR_CREATE_push(dc, opnd_create_reg(SEG_GS)), 2); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_DS)), 1); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_SS)), 1); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_ES)), 1); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_FS)), 2); test_instr_encode(dc, INSTR_CREATE_pop(dc, opnd_create_reg(SEG_GS)), 2); }
void watchpoint_indirect_call_event(dcontext_t *drcontext, instrlist_t *ilist, instr_t *instr, instr_t *next_instr, bool mangle_calls, uint flags) { opnd_t instr_opnd; reg_id_t base_reg; unsigned long used_registers = 0; app_pc pc; struct memory_operand_modifier ops = {0}; instr_t *begin_instrumenting = INSTR_CREATE_label(drcontext); instr_t *done_instrumenting = INSTR_CREATE_label(drcontext); instr_t *nop = INSTR_CREATE_nop(drcontext); instr_t *emulated; memset(&ops, 0, sizeof(struct memory_operand_modifier)); if(instr_reads_memory(instr)) { instr_opnd = instr_get_src(instr, 0); if (opnd_is_rel_addr(instr_opnd) || opnd_is_abs_addr(instr_opnd)) { }else if (opnd_is_base_disp(instr_opnd)) { for_each_src_operand(instr, &ops, (opnd_callback_t *) memory_src_operand_finder); // base_reg = opnd_get_reg(instr_opnd); switch(ops.found_operand.value.base_disp.base_reg) { case DR_REG_RSP: case DR_REG_ESP: case DR_REG_SP: case DR_REG_RBP: case DR_REG_EBP: case DR_REG_BP: return; default: break; } collect_regs(&used_registers, instr, instr_num_srcs, instr_get_src ); collect_regs(&used_registers, instr, instr_num_dsts, instr_get_dst ); reg_id_t reg_watched_addr = get_next_free_reg(&used_registers); opnd_t opnd_watched_addr = opnd_create_reg(reg_watched_addr); reg_id_t reg_unwatched_addr = get_next_free_reg(&used_registers); opnd_t opnd_unwatched_addr = opnd_create_reg(reg_unwatched_addr); PRE(ilist, instr, begin_instrumenting); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pushf(drcontext)); PRE(ilist, instr, INSTR_CREATE_lea(drcontext, opnd_watched_addr, opnd_create_base_disp(opnd_get_base(ops.found_operand), opnd_get_index(ops.found_operand), opnd_get_scale(ops.found_operand), opnd_get_disp(ops.found_operand), OPSZ_lea))); PRE(ilist, instr, INSTR_CREATE_mov_imm(drcontext, opnd_unwatched_addr, OPND_CREATE_INT64(WATCHPOINT_INDEX_MASK))); PRE(ilist, instr, INSTR_CREATE_or(drcontext, opnd_unwatched_addr, opnd_watched_addr)); emulated = instr_clone(drcontext, instr); emulated->translation = 0; ops.replacement_operand = opnd_create_base_disp( reg_unwatched_addr, DR_REG_NULL,1, 0 , ops.found_operand.size); for_each_operand(emulated, &ops, (opnd_callback_t *) memory_operand_replacer); PRE(ilist, instr, INSTR_CREATE_popf(drcontext)); PRE(ilist, instr, emulated); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_jmp_short(drcontext, opnd_create_instr(done_instrumenting))); pc = instr->translation; instr->translation = 0; // hack! instr_being_modified(instr, false); instr_set_ok_to_mangle(instr, false); if(NULL != pc){ nop->translation = pc + instr->length; } POST(ilist, instr, nop); POST(ilist, instr, done_instrumenting); } } }