コード例 #1
0
ファイル: ir.c プロジェクト: Arunpreet/dynamorio
/* emits the instruction to buf (for tests that wish to do additional checks on
 * the output) */
static void
test_instr_encode_and_decode(void *dc, instr_t *instr, uint len_expect,
                             /* also checks one operand's size */
                             bool src, uint opnum, opnd_size_t sz, uint bytes)
{
    opnd_t op;
    opnd_size_t opsz;
    instr_t *decin;
    uint len;
    byte *pc = instr_encode(dc, instr, buf);
    len = (int) (pc - (byte *)buf);
#if VERBOSE
    disassemble_with_info(dc, buf, STDOUT, true, true);
#endif
    ASSERT(len == len_expect);
    decin = instr_create(dc);
    decode(dc, buf, decin);
    ASSERT(instr_same(instr, decin));

    /* PR 245805: variable sizes should be resolved on decode */
    if (src)
        op = instr_get_src(decin, opnum);
    else
        op = instr_get_dst(decin, opnum);
    opsz = opnd_get_size(op);
    ASSERT(opsz == sz && opnd_size_in_bytes(opsz) == bytes);

    instr_destroy(dc, instr);
    instr_destroy(dc, decin);
}
コード例 #2
0
ファイル: ir.c プロジェクト: Arunpreet/dynamorio
/* PR 332254: test xchg vs nop */
static void
test_nop_xchg(void *dc)
{
    /*   0x0000000000671460  87 c0                xchg   %eax %eax -> %eax %eax
     *   0x0000000000671460  48 87 c0             xchg   %rax %rax -> %rax %rax
     *   0x0000000000671460  41 87 c0             xchg   %r8d %eax -> %r8d %eax
     *   0x0000000000671460  46 90                nop
     *   0x0000000000671460  4e 90                nop
     *   0x0000000000671460  41 90                xchg   %r8d %eax -> %r8d %eax
     */
    instr_t *instr;
    instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_EAX), opnd_create_reg(REG_EAX));
    test_instr_encode(dc, instr, 2);
#ifdef X64
    /* we don't do the optimal "48 90" instead of "48 87 c0" */
    instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_RAX), opnd_create_reg(REG_RAX));
    test_instr_encode(dc, instr, 3);
    /* we don't do the optimal "41 90" instead of "41 87 c0" */
    instr = INSTR_CREATE_xchg(dc, opnd_create_reg(REG_R8D), opnd_create_reg(REG_EAX));
    test_instr_encode(dc, instr, 3);
    /* ensure we treat as nop and NOT xchg if doesn't have rex.b */
    buf[0] = 0x46;
    buf[1] = 0x90;
    instr = instr_create(dc);
# if VERBOSE
    disassemble_with_info(dc, buf, STDOUT, true, true);
# endif
    decode(dc, buf, instr);
    ASSERT(instr_get_opcode(instr) == OP_nop);
    instr_destroy(dc, instr);
    buf[0] = 0x4e;
    buf[1] = 0x90;
    instr = instr_create(dc);
# if VERBOSE
    disassemble_with_info(dc, buf, STDOUT, true, true);
# endif
    decode(dc, buf, instr);
    ASSERT(instr_get_opcode(instr) == OP_nop);
    instr_destroy(dc, instr);
    buf[0] = 0x41;
    buf[1] = 0x90;
    instr = instr_create(dc);
# if VERBOSE
    disassemble_with_info(dc, buf, STDOUT, true, true);
# endif
    decode(dc, buf, instr);
    ASSERT(instr_get_opcode(instr) == OP_xchg);
    instr_destroy(dc, instr);
#endif
}
コード例 #3
0
ファイル: winsysnums.c プロジェクト: AVGirl/dynamorio
/* returns false on failure */
static bool
decode_function(void *dcontext, byte *entry)
{
    byte *pc, *pre_pc;
    int num_instr = 0;
    bool found_ret = false;
    instr_t *instr;
    if (entry == NULL)
        return false;
    instr = instr_create(dcontext);
    pc = entry;
    while (true) {
        instr_reset(dcontext, instr);
        pre_pc = pc;
        pc = decode(dcontext, pc, instr);
        instr_set_translation(instr, pre_pc);
        dr_print_instr(dcontext, STDOUT, instr, "");
        if (instr_is_return(instr)) {
            found_ret = true;
            break;
        }
        num_instr++;
        if (num_instr > MAX_INSTRS_IN_FUNCTION) {
            print("ERROR: hit max instr limit %d\n", MAX_INSTRS_IN_FUNCTION);
            break;
        }
    }
    instr_destroy(dcontext, instr);
    return found_ret;
}
コード例 #4
0
ファイル: rw.c プロジェクト: awesome-security/dynStruct
void memory_write(void *pc, void *prev_pc)
{
  void		*drcontext = dr_get_current_drcontext();
  instr_t	*instr = instr_create(drcontext);
  dr_mcontext_t mctx;
  opnd_t	dst;
  ctx_t		ctx;
  
  pc = dr_app_pc_for_decoding(pc);

  mctx.flags = DR_MC_CONTROL|DR_MC_INTEGER;
  mctx.size = sizeof(mctx);
  dr_get_mcontext(drcontext, &mctx);

  instr_init(drcontext, instr);
  if (!decode(drcontext, pc, instr))
    {
      dr_printf("Decode of instruction at %p failed\n", pc);
      return;
    }

  ctx.addr = prev_pc;
  ctx.dr_addr = prev_pc;

  for (int i = 0; i < instr_num_dsts(instr); i++)
    {
      dst = instr_get_dst(instr, i);
      check_opnd(dst, pc, 0, drcontext, &mctx, &ctx);
    }

  instr_destroy(drcontext, instr);
}
コード例 #5
0
static
dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t* bb,
                         bool for_trace, bool translating)
{
    instr_t *instr;
    instr_t *next_instr;
    reg_t in_eax = -1;

    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);
        if (instr_get_opcode(instr) == OP_mov_imm &&
            opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX)
            in_eax = opnd_get_immed_int(instr_get_src(instr, 0));
        if (instr_is_syscall(instr) &&
            in_eax == SYS_getpid) {
            instr_t *myval = INSTR_CREATE_mov_imm
                (drcontext, opnd_create_reg(REG_EAX), OPND_CREATE_INT32(-7));
            instr_set_translation(myval, instr_get_app_pc(instr));
            instrlist_preinsert(bb, instr, myval);
            instrlist_remove(bb, instr);
            instr_destroy(drcontext, instr);
        }
    }
    return DR_EMIT_DEFAULT;
}
コード例 #6
0
ファイル: ir.c プロジェクト: Arunpreet/dynamorio
static void
test_disp_control_helper(void *dc, int disp,
                         bool encode_zero_disp, bool force_full_disp, bool disp16,
                         uint len_expect)
{
    byte *pc;
    uint len;
    instr_t *instr = INSTR_CREATE_mov_ld
        (dc, opnd_create_reg(REG_ECX),
         opnd_create_base_disp_ex(disp16 ? IF_X64_ELSE(REG_EBX, REG_BX) :
                                  REG_XBX, REG_NULL, 0,
                                  disp, OPSZ_4,
                                  encode_zero_disp, force_full_disp, disp16));
    pc = instr_encode(dc, instr, buf);
    len = (int) (pc - (byte *)buf);
#if VERBOSE
    pc = disassemble_with_info(dc, buf, STDOUT, true, true);
#endif
    ASSERT(len == len_expect);
    instr_reset(dc, instr);
    decode(dc, buf, instr);
    ASSERT(instr_num_srcs(instr) == 1 &&
           opnd_is_base_disp(instr_get_src(instr, 0)) &&
           BOOLS_MATCH(encode_zero_disp, 
                       opnd_is_disp_encode_zero(instr_get_src(instr, 0))) &&
           BOOLS_MATCH(force_full_disp,
                       opnd_is_disp_force_full(instr_get_src(instr, 0))) &&
           BOOLS_MATCH(disp16,
                       opnd_is_disp_short_addr(instr_get_src(instr, 0))));
    instr_destroy(dc, instr);
}
コード例 #7
0
ファイル: instrace.c プロジェクト: CharithYMendis/Helium
void
instrace_thread_exit(void *drcontext)
{
    per_thread_t *data;
	int i;

	if (client_arg->instrace_mode == INS_TRACE){
		ins_trace(drcontext);
	}

    data = drmgr_get_tls_field(drcontext, tls_index);
    dr_mutex_lock(mutex);
    num_refs += data->num_refs;
    dr_mutex_unlock(mutex);

    dr_close_file(data->outfile);
	if (log_mode){
		dr_close_file(data->logfile);
	}

	dr_thread_free(drcontext, data->buf_base, INSTR_BUF_SIZE);
	dr_thread_free(drcontext, data->output_array, OUTPUT_BUF_SIZE);

	DEBUG_PRINT("%s - thread id : %d, cloned instructions freeing now - %d\n",ins_pass_name, dr_get_thread_id(drcontext),data->static_ptr);

	for(i=0 ; i<data->static_ptr; i++){
		instr_destroy(dr_get_current_drcontext(),data->static_array[i]);
	}

	dr_thread_free(drcontext, data->static_array, sizeof(instr_t *)*client_arg->static_info_size);
    dr_thread_free(drcontext, data, sizeof(per_thread_t));

	DEBUG_PRINT("%s - exiting thread done %d\n", ins_pass_name, dr_get_thread_id(drcontext));

}
コード例 #8
0
ファイル: ir.c プロジェクト: Arunpreet/dynamorio
/* emits the instruction to buf (for tests that wish to do additional checks on
 * the output) */
static void
test_instr_encode(void *dc, instr_t *instr, uint len_expect)
{
    instr_t *decin;
    uint len;
    byte *pc = instr_encode(dc, instr, buf);
    len = (int) (pc - (byte *)buf);
#if VERBOSE
    disassemble_with_info(dc, buf, STDOUT, true, true);
#endif
    ASSERT(len == len_expect);
    decin = instr_create(dc);
    decode(dc, buf, decin);
    ASSERT(instr_same(instr, decin));
    instr_destroy(dc, instr);
    instr_destroy(dc, decin);
}
コード例 #9
0
ファイル: instrlist.c プロジェクト: DynamoRIO/dynamorio
/* frees the Instrs in the instrlist_t */
void
instrlist_clear(dcontext_t *dcontext, instrlist_t *ilist)
{
    instr_t *instr;
    while (NULL != (instr = instrlist_first(ilist))) {
        instrlist_remove(ilist, instr);
        instr_destroy(dcontext, instr);
    }
}
コード例 #10
0
ファイル: utils.c プロジェクト: zhaoqin/Umbra
/* Remove the rest instructions from ilist after instr (including instr) */
void
instrlist_truncate(void *drcontext, instrlist_t *ilist, instr_t *instr)
{
    instr_t *next_instr;

    DR_ASSERT_MSG(instr != NULL, "Wrong instr to truncate!");
    for(; instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);
        instrlist_remove(ilist, instr);
        instr_destroy(drcontext, instr);
    }
}
コード例 #11
0
ファイル: winsysnums.c プロジェクト: AVGirl/dynamorio
static void
look_for_usercall(void *dcontext, byte *entry, const char *sym, LOADED_IMAGE *img,
                  const char *modpath)
{
    bool found_push_imm = false;
    int imm = 0;
    app_pc pc, pre_pc;
    instr_t *instr;
    if (entry == NULL)
        return;
    instr = instr_create(dcontext);
    pc = entry;
    while (true) {
        instr_reset(dcontext, instr);
        pre_pc = pc;
        pc = decode(dcontext, pc, instr);
        if (verbose) {
            instr_set_translation(instr, pre_pc);
            dr_print_instr(dcontext, STDOUT, instr, "");
        }
        if (pc == NULL || !instr_valid(instr))
            break;
        if (instr_get_opcode(instr) == OP_push_imm) {
            found_push_imm = true;
            imm = (int) opnd_get_immed_int(instr_get_src(instr, 0));
        } else if (instr_is_call_direct(instr) && found_push_imm) {
            app_pc tgt = opnd_get_pc(instr_get_target(instr));
            bool found = false;
            int i;
            for (i = 0; i < NUM_USERCALL; i++) {
                if (tgt == usercall_addr[i]) {
                    dr_printf("Call #0x%02x to %s at %s+0x%x\n", imm, usercall_names[i],
                              sym, pre_pc - entry);
                    found = true;
                    break;
                }
            }
            if (found)
                break;
        } else if (instr_is_return(instr))
            break;
        if (pc - entry > MAX_BYTES_BEFORE_USERCALL)
            break;
    }
    instr_destroy(dcontext, instr);
}
コード例 #12
0
ファイル: allocs.c プロジェクト: ampotos/dynStruct
// return the addr of the previous instructions
// a bad addr can be return in some specific case but generally work good
void *get_prev_instr_pc(void *pc, void *drc)
{
  instr_t	*instr = instr_create(drc);
  void		*tmp_pc;

  for (int ct = 1; ; ct++)
    {
      tmp_pc = dr_app_pc_for_decoding(pc - ct);
      if (decode(drc, tmp_pc, instr))
	{
	  if (instr_is_call(instr) && decode_next_pc(drc, tmp_pc) == pc)
	    break;
	}
      instr_reuse(drc, instr);
    }

  instr_destroy(drc, instr);

  return tmp_pc;
}
コード例 #13
0
ファイル: optimize.c プロジェクト: zhaoqin/Umbra
/* this function to optimize some register stealing code away 
 * for case like below:
 * 
 *  restore %reg
 *  ...
 *  save %reg
 *  
 *  if the %reg is not updated in between, the save %reg can be 
 * optimized out
 */
static void
optimize_register_stealing(void *drcontext, 
                           umbra_info_t *umbra_info,
                           void *tag,
                           instrlist_t *ilist)
{
    instr_t *instr, *nexti;
    instr_t *reg_restore[NUM_SPILL_REGS];
    reg_id_t regs[NUM_SPILL_REGS];
    int i;

    /* skip reg eax */
    for (i = 1; i < NUM_SPILL_REGS; i++) {
        reg_restore[i] = NULL;
        regs[i] = REG_SPILL_START + i;
    }
    
    for (instr = instrlist_first(ilist); instr != NULL; instr = nexti) {
        nexti = instr_get_next(instr);
        if (instr_get_app_pc(instr) != NULL && 
            !instr_is_meta_may_fault(instr)) {
            /* check if app code update register */
            for (i = 1; i < NUM_SPILL_REGS; i++) {
                if (register_is_updated(instr, regs[i])) 
                    reg_restore[i] = NULL;
            }
        } else {
            for (i = 1; i < NUM_SPILL_REGS; i++) {
                if (instr_is_reg_restore(instr, regs[i], umbra_info)) {
                    reg_restore[i] = instr;
                    break; 
                } else if (instr_is_reg_save(instr, regs[i], umbra_info) &&
                           reg_restore[i] != NULL) {
                    instrlist_remove(ilist, instr);
                    instr_destroy(drcontext, instr);
                    break;
                }
            }
        }
    }
}
コード例 #14
0
/* Truncates every basic block to the length specified in the CL option (see dr_init) */
dr_emit_flags_t
bb_event_truncate(void *drcontext, void *, instrlist_t *bb, bool, bool)
{
    uint app_instruction_count = 0;
    instr_t *next, *instr = instrlist_first(bb);

    while (instr != NULL) {
        next = instr_get_next(instr);
        if (!instr_is_meta(instr)) {
            if (app_instruction_count == bb_truncation_length) {
                instrlist_remove(bb, instr);
                instr_destroy(drcontext, instr);
            } else {
                app_instruction_count++;
            }
        }
        instr = next;
    }

    return DR_EMIT_DEFAULT;
}
コード例 #15
0
ファイル: memdump.c プロジェクト: CharithYMendis/Helium
void memdump_exit_event(void)
{

	int i = 0;

	md_delete_list(filter_head, false);
	md_delete_list(done_head, false);
	md_delete_list(app_pc_head, false);

	dr_global_free(client_arg, sizeof(client_arg_t));
	drmgr_unregister_tls_field(tls_index);
	if (log_mode){
		dr_close_file(logfile);
	}
	for (i = 0; i < instr_clone_amount; i++){
		instr_destroy(dr_get_current_drcontext(), instr_clones[i]);
	}
	dr_mutex_destroy(mutex);
	drutil_exit();
	drmgr_exit();
	drwrap_exit();

}
コード例 #16
0
ファイル: ir.c プロジェクト: melbcat/DynamoRIO-for-ARM
/* make sure the following are consistent (though they could still all be wrong :))
 * with respect to instr length and opcode:
 * - decode_fast
 * - decode
 * - INSTR_CREATE_
 * - encode
 */
static void
test_all_opcodes(void *dc)
{
    byte *pc, *next_pc;
    byte *end;
    instrlist_t *ilist = instrlist_create(dc);
    instr_t *instr;

    /* we cannot pass on variadic args as separate args to another
     * macro, so we must split ours by # args (xref PR 208603)
     */

#   define MEMARG(sz) (opnd_create_base_disp(REG_XCX, REG_NULL, 0, 0x37, sz))
#   define IMMARG(sz)  opnd_create_immed_int(37, sz)
#   define TGTARG      opnd_create_instr(instrlist_last(ilist))
#   define REGARG(reg) opnd_create_reg(REG_##reg)
#   define X86_ONLY    1
#   define X64_ONLY    2

#   define OPCODE(opc, icnm, ...) \
    int len_##icnm;
#   include "ir_0args.h"
#   include "ir_1args.h"
#   include "ir_2args.h"
#   include "ir_3args.h"
#   include "ir_4args.h"
#   undef OPCODE

    /* we can encode+fast-decode some instrs cross-platform but we
     * leave that testing to the regression run on that platform */ 

#   define OPCODE(opc, icnm, flags) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \
        instrlist_append(ilist, INSTR_CREATE_##icnm(dc)); \
        len_##icnm = instr_length(dc, instrlist_last(ilist)); \
    } } while (0);
#   include "ir_0args.h"
#   undef OPCODE

#   define OPCODE(opc, icnm, flags, arg1) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \
        instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1)); \
        len_##icnm = instr_length(dc, instrlist_last(ilist)); \
    } } while (0);
#   include "ir_1args.h"
#   undef OPCODE

#   define OPCODE(opc, icnm, flags, arg1, arg2) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \
        instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2)); \
        len_##icnm = instr_length(dc, instrlist_last(ilist)); \
    } } while (0);
#   include "ir_2args.h"
#   undef OPCODE

#   define OPCODE(opc, icnm, flags, arg1, arg2, arg3) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \
        instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2, arg3)); \
        len_##icnm = instr_length(dc, instrlist_last(ilist)); \
    } } while (0);
#   include "ir_3args.h"
#   undef OPCODE

#   define OPCODE(opc, icnm, flags, arg1, arg2, arg3, arg4) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \
        instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2, arg3, arg4)); \
        len_##icnm = instr_length(dc, instrlist_last(ilist)); \
    } } while (0);
#   include "ir_4args.h"
#   undef OPCODE

    end = instrlist_encode(dc, ilist, buf, false);

    instr = instr_create(dc);
    pc = buf;

#   define OPCODE(opc, icnm, flags, ...) do { \
    if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0 && len_##icnm != 0) { \
        instr_reset(dc, instr); \
        next_pc = decode(dc, pc, instr); \
        ASSERT((next_pc - pc) == decode_sizeof(dc, pc, NULL _IF_X64(NULL))); \
        ASSERT((next_pc - pc) == len_##icnm); \
        ASSERT(instr_get_opcode(instr) == OP_##opc); \
        pc = next_pc; \
    } } while (0);
#   include "ir_0args.h"
#   include "ir_1args.h"
#   include "ir_2args.h"
#   include "ir_3args.h"
#   include "ir_4args.h"
#   undef OPCODE

#if VERBOSE
    for (pc = buf; pc < end; )
        pc = disassemble_with_info(dc, pc, STDOUT, true, true);
#endif

    instr_destroy(dc, instr);
    instrlist_clear_and_destroy(dc, ilist);
}
コード例 #17
0
ファイル: winsysnums.c プロジェクト: Arunpreet/dynamorio
/* returns false on failure */
static bool
decode_syscall_num(void *dcontext, byte *entry, syscall_info_t *info)
{
    /* FIXME: would like to fail gracefully rather than have a DR assertion
     * on non-code! => use DEBUG=0 INTERNAL=1 DR build!
     */
    bool found_syscall = false, found_eax = false, found_edx = false, found_ecx = false;
    bool found_ret = false;
    byte *pc;
    int num_instr = 0;
    instr_t *instr;
    if (entry == NULL)
        return false;
    info->num_args = -1; /* if find sysnum but not args */
    info->sysnum = -1;
    info->fixup_index = -1;
    instr = instr_create(dcontext);
    pc = entry;
    /* FIXME - we don't support decoding 64bit instructions in 32bit mode, but I want
     * this to work on 32bit machines.  Hack fix based on the wrapper pattern, we skip
     * the first instruction (mov r10, rcx) here, the rest should decode ok.
     * Xref PR 236203. */
    if (expect_x64 && *pc == 0x4c && *(pc+1) == 0x8b && *(pc+2) == 0xd1)
        pc += 3;
    while (true) {
        instr_reset(dcontext, instr);
        pc = decode(dcontext, pc, instr);
        if (verbose)
            dr_print_instr(dcontext, STDOUT, instr, "");
        if (pc == NULL || !instr_valid(instr))
            break;
        /* ASSUMPTION: a mov imm of 0x7ffe0300 into edx followed by an
         * indirect call via edx is a system call on XP and later
         * On XP SP1 it's call *edx, while on XP SP2 it's call *(edx)
         * For wow it's a call through fs.
         * FIXME - core exports various is_*_syscall routines (such as
         * instr_is_wow64_syscall()) which we could use here instead of
         * duplicating if they were more flexible about when they could
         * be called (instr_is_wow64_syscall() for ex. asserts if not
         * in a wow process).
         */
        if (/* int 2e or x64 or win8 sysenter */
            (instr_is_syscall(instr) && found_eax && (expect_int2e || expect_x64 || expect_sysenter)) ||
            /* sysenter case */
            (expect_sysenter && found_edx && found_eax &&
             instr_is_call_indirect(instr) &&
             /* XP SP{0,1}, 2003 SP0: call *edx */
             ((opnd_is_reg(instr_get_target(instr)) &&
               opnd_get_reg(instr_get_target(instr)) == REG_EDX) ||
              /* XP SP2, 2003 SP1: call *(edx) */
              (opnd_is_base_disp(instr_get_target(instr)) &&
               opnd_get_base(instr_get_target(instr)) == REG_EDX &&
               opnd_get_index(instr_get_target(instr)) == REG_NULL &&
               opnd_get_disp(instr_get_target(instr)) == 0))) ||
            /* wow case 
             * we don't require found_ecx b/c win8 does not use ecx
             */
            (expect_wow && found_eax &&
             instr_is_call_indirect(instr) &&
             opnd_is_far_base_disp(instr_get_target(instr)) &&
             opnd_get_base(instr_get_target(instr)) == REG_NULL &&
             opnd_get_index(instr_get_target(instr)) == REG_NULL &&
             opnd_get_segment(instr_get_target(instr)) == SEG_FS)) {
            found_syscall = true;
        } else if (instr_is_return(instr)) {
            if (!found_ret) {
                process_ret(instr, info);
                found_ret = true;
            }
            break;
        } else if (instr_is_cti(instr)) {
            if (instr_get_opcode(instr) == OP_call) {
                /* handle win8 x86 which has sysenter callee adjacent-"inlined"
                 *     ntdll!NtYieldExecution:
                 *     77d7422c b801000000      mov     eax,1
                 *     77d74231 e801000000      call    ntdll!NtYieldExecution+0xb (77d74237)
                 *     77d74236 c3              ret
                 *     77d74237 8bd4            mov     edx,esp
                 *     77d74239 0f34            sysenter
                 *     77d7423b c3              ret
                 */
                byte *tgt;
                assert(opnd_is_pc(instr_get_target(instr)));
                tgt = opnd_get_pc(instr_get_target(instr));
                /* we expect only ret or ret imm, and possibly some nops (in gdi32).
                 * XXX: what about jmp to shared ret (seen in the past on some syscalls)?
                 */
                if (tgt > pc && tgt <= pc + 16) {
                    bool ok = false;
                    do {
                        if (pc == tgt) {
                            ok = true;
                            break;
                        }
                        instr_reset(dcontext, instr);
                        pc = decode(dcontext, pc, instr);
                        if (verbose)
                            dr_print_instr(dcontext, STDOUT, instr, "");
                        if (instr_is_return(instr)) {
                            process_ret(instr, info);
                            found_ret = true;
                        } else if (!instr_is_nop(instr))
                            break;
                        num_instr++;
                    } while (num_instr <= MAX_INSTRS_BEFORE_SYSCALL);
                    if (ok)
                        continue;
                }
            }
            /* assume not a syscall wrapper if we hit a cti */
            break; /* give up gracefully */
        } else if ((!found_eax || !found_edx || !found_ecx) &&
            instr_get_opcode(instr) == OP_mov_imm &&
            opnd_is_reg(instr_get_dst(instr, 0))) {
            if (!found_eax && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX) {
                info->sysnum = (int) opnd_get_immed_int(instr_get_src(instr, 0));
                found_eax = true;
            } else if (!found_edx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EDX) {
                int imm = (int) opnd_get_immed_int(instr_get_src(instr, 0));
                if (imm == 0x7ffe0300)
                    found_edx = true;
            } else if (!found_ecx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
                found_ecx = true;
                info->fixup_index = (int) opnd_get_immed_int(instr_get_src(instr, 0));
            }
        } else if (instr_get_opcode(instr) == OP_xor &&
                   opnd_is_reg(instr_get_src(instr, 0)) &&
                   opnd_get_reg(instr_get_src(instr, 0)) == REG_ECX &&
                   opnd_is_reg(instr_get_dst(instr, 0)) &&
                   opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
            /* xor to 0 */
            found_ecx = true;
            info->fixup_index = 0;
        }
        num_instr++;
        if (num_instr > MAX_INSTRS_BEFORE_SYSCALL) /* wrappers should be short! */
            break; /* avoid weird cases like NPXEMULATORTABLE */
    }
    instr_destroy(dcontext, instr);
    return found_syscall;
}
コード例 #18
0
ファイル: inc2add.c プロジェクト: Arunpreet/dynamorio
/* replaces inc with add 1, dec with sub 1 
 * returns true if successful, false if not
 */
static bool
replace_inc_with_add(void *drcontext, instr_t *instr, instrlist_t *trace)
{
    instr_t *in;
    uint eflags;
    int opcode = instr_get_opcode(instr);
    bool ok_to_replace = false;

    DR_ASSERT(opcode == OP_inc || opcode == OP_dec);
#ifdef VERBOSE
    dr_print_instr(drcontext, STDOUT, instr, "in replace_inc_with_add:\n\t");
#endif

    /* add/sub writes CF, inc/dec does not, make sure that's ok */
    for (in = instr; in != NULL; in = instr_get_next(in)) {
	eflags = instr_get_eflags(in);
	if ((eflags & EFLAGS_READ_CF) != 0) {
#ifdef VERBOSE
            dr_print_instr(drcontext, STDOUT, in,
                           "\treads CF => cannot replace inc with add: ");
#endif
	    return false;
	}
	if (instr_is_exit_cti(in)) {
	    /* to be more sophisticated, examine instructions at
	     * target of exit cti (if it is a direct branch).
	     * for this example, we give up if we hit a branch.
	     */
	    return false;
	}
	/* if writes but doesn't read, ok */
	if ((eflags & EFLAGS_WRITE_CF) != 0) {
	    ok_to_replace = true;
	    break;
	}
    }
    if (!ok_to_replace) {
#ifdef VERBOSE
        dr_printf("\tno write to CF => cannot replace inc with add\n");
#endif
	return false;
    }
    if (opcode == OP_inc) {
#ifdef VERBOSE
        dr_printf("\treplacing inc with add\n");
#endif
	in = INSTR_CREATE_add(drcontext, instr_get_dst(instr, 0),
			      OPND_CREATE_INT8(1));
    } else {
#ifdef VERBOSE
        dr_printf("\treplacing dec with sub\n");
#endif
	in = INSTR_CREATE_sub(drcontext, instr_get_dst(instr, 0),
			      OPND_CREATE_INT8(1));
    }
    if (instr_get_prefix_flag(instr, PREFIX_LOCK))
        instr_set_prefix_flag(in, PREFIX_LOCK);
    instr_set_translation(in, instr_get_app_pc(instr));
    instrlist_replace(trace, instr, in);
    instr_destroy(drcontext, instr);
    return true;
}
コード例 #19
0
ファイル: winsysnums.c プロジェクト: AVGirl/dynamorio
/* returns false on failure */
static bool
decode_syscall_num(void *dcontext, byte *entry, syscall_info_t *info, LOADED_IMAGE *img)
{
    /* FIXME: would like to fail gracefully rather than have a DR assertion
     * on non-code! => use DEBUG=0 INTERNAL=1 DR build!
     */
    bool found_syscall = false, found_eax = false, found_edx = false, found_ecx = false;
    bool found_ret = false;
    byte *pc, *pre_pc;
    int num_instr = 0;
    instr_t *instr;
    byte *preferred = get_preferred_base(img);
    if (entry == NULL)
        return false;
    info->num_args = -1; /* if find sysnum but not args */
    info->sysnum = -1;
    info->fixup_index = -1;
    instr = instr_create(dcontext);
    pc = entry;
    /* FIXME - we don't support decoding 64bit instructions in 32bit mode, but I want
     * this to work on 32bit machines.  Hack fix based on the wrapper pattern, we skip
     * the first instruction (mov r10, rcx) here, the rest should decode ok.
     * Xref PR 236203. */
    if (expect_x64 && *pc == 0x4c && *(pc+1) == 0x8b && *(pc+2) == 0xd1)
        pc += 3;
    while (true) {
        instr_reset(dcontext, instr);
        pre_pc = pc;
        pc = decode(dcontext, pc, instr);
        if (verbose) {
            instr_set_translation(instr, pre_pc);
            dr_print_instr(dcontext, STDOUT, instr, "");
        }
        if (pc == NULL || !instr_valid(instr))
            break;
        if (instr_is_syscall(instr) || instr_is_call_indirect(instr)) {
            /* If we see a syscall instr or an indirect call which is not syscall,
             * we assume this is not a syscall wrapper.
             */
            found_syscall = process_syscall_instr(dcontext, instr, found_eax, found_edx);
            if (!found_syscall)
                break; /* assume not a syscall wrapper, give up gracefully */
        } else if (instr_is_return(instr)) {
            /* we must break on return to avoid case like win8 x86
             * which has sysenter callee adjacent-"inlined"
             *     ntdll!NtYieldExecution:
             *     77d7422c b801000000  mov     eax,1
             *     77d74231 e801000000  call    ntdll!NtYieldExecution+0xb (77d74237)
             *     77d74236 c3          ret
             *     77d74237 8bd4        mov     edx,esp
             *     77d74239 0f34        sysenter
             *     77d7423b c3          ret
             */
            if (!found_ret) {
                process_ret(instr, info);
                found_ret = true;
            }
            break;
        } else if (instr_get_opcode(instr) == OP_call) {
            found_syscall = process_syscall_call(dcontext, pc, instr,
                                                 found_eax, found_edx);
            /* If we see a call and it is not a sysenter callee,
             * we assume this is not a syscall wrapper.
             */
            if (!found_syscall)
                break; /* assume not a syscall wrapper, give up gracefully */
        } else if (instr_is_cti(instr)) {
            /* We expect only ctis like ret or ret imm, syscall, and call, which are
             * handled above. Give up gracefully if we hit any other cti.
             * XXX: what about jmp to shared ret (seen in the past on some syscalls)?
             */
            /* Update: win10 TH2 1511 x64 has a cti:
             *   ntdll!NtContinue:
             *   00007ff9`13185630 4c8bd1          mov     r10,rcx
             *   00007ff9`13185633 b843000000      mov     eax,43h
             *   00007ff9`13185638 f604250803fe7f01 test    byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
             *   00007ff9`13185640 7503            jne     ntdll!NtContinue+0x15 (00007ff9`13185645)
             *   00007ff9`13185642 0f05            syscall
             *   00007ff9`13185644 c3              ret
             *   00007ff9`13185645 cd2e            int     2Eh
             *   00007ff9`13185647 c3              ret
             */
            if (expect_x64 && instr_is_cbr(instr) &&
                opnd_get_pc(instr_get_target(instr)) == pc + 3/*syscall;ret*/) {
                /* keep going */
            } else
                break;
        } else if ((!found_eax || !found_edx || !found_ecx) &&
                   instr_get_opcode(instr) == OP_mov_imm &&
                   opnd_is_reg(instr_get_dst(instr, 0))) {
            if (!found_eax && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX) {
                info->sysnum = (int) opnd_get_immed_int(instr_get_src(instr, 0));
                found_eax = true;
            } else if (!found_edx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EDX) {
                uint imm = (uint) opnd_get_immed_int(instr_get_src(instr, 0));
                if (imm == 0x7ffe0300 ||
                    /* On Win10 the immed is ntdll!Wow64SystemServiceCall */
                    (expect_wow && imm > (ptr_uint_t)preferred &&
                     imm < (ptr_uint_t)preferred + img->SizeOfImage))
                    found_edx = true;
            } else if (!found_ecx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
                found_ecx = true;
                info->fixup_index = (int) opnd_get_immed_int(instr_get_src(instr, 0));
            }
        } else if (instr_get_opcode(instr) == OP_xor &&
                   opnd_is_reg(instr_get_src(instr, 0)) &&
                   opnd_get_reg(instr_get_src(instr, 0)) == REG_ECX &&
                   opnd_is_reg(instr_get_dst(instr, 0)) &&
                   opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
            /* xor to 0 */
            found_ecx = true;
            info->fixup_index = 0;
        }
        num_instr++;
        if (num_instr > MAX_INSTRS_BEFORE_SYSCALL) /* wrappers should be short! */
            break; /* avoid weird cases like NPXEMULATORTABLE */
    }
    instr_destroy(dcontext, instr);
    return found_syscall;
}
コード例 #20
0
ファイル: optimize.c プロジェクト: zhaoqin/Umbra
static instr_t *
analyze_client_code(void *drcontext, 
                    instrlist_t *ilist,
                    instr_t *where,
                    ref_info_t *ref_info)
{
    instr_t *next, *lea, *and, *cmp, *jcc, *sub;
    opnd_t   ref, opnd;
    ref_cache_t *cache;
    reg_id_t reg;
    int      pos, i;

    next = instr_get_next(where);
    if (next == NULL)
        return NULL;
    
    if (instr_get_opcode(where) != OP_lea)
        return next;

    /* lea [ref] => r1 */
    ref = instr_get_src(where, 0);
    if (!opnd_is_base_disp(ref) || opnd_get_index(ref) != DR_REG_NULL)
        return next;

    lea = where;
    and = next;
    cmp = instr_get_next(and);
    jcc = instr_get_next(cmp);

    if (instr_get_app_pc(and) == NULL   &&
        instr_get_opcode(and) == OP_and &&
        instr_get_app_pc(cmp) == NULL   &&
        instr_get_opcode(cmp) == OP_cmp &&
        instr_get_app_pc(jcc) == NULL   &&
        instr_get_opcode(jcc) == OP_jz) {
        /* find pattern of 
         *   lea [ref] => reg
         *   and 0xffffffff00000000 reg
         *   cmp cache->tag  reg
         *   jz
         */
        opnd  = instr_get_src(cmp, 1);
        cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, tag);
        for (i = 0; i < 10; ) {
            lea = instr_get_next(lea);
            if (!instr_is_label(lea))
                i++;
        }
        DR_ASSERT(instr_get_opcode(lea) == OP_lea);
    } else if (instr_get_app_pc(next) == NULL &&
               instr_get_opcode(next) == OP_sub) {
        opnd  = instr_get_src(next, 0);
        cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, offset);
    } else {
        return next;
    }

    reg = opnd_get_base(ref);
    UMBRA_REG_TO_POS(reg, pos);
    if (ref_info[pos].cache == NULL) {
        ref_info[pos].cache = cache;
    } else {
        sub = instr_get_next(lea);
        DR_ASSERT(instr_get_opcode(sub) == OP_sub);
        while (lea != where) {
            next = instr_get_next(where);
            instrlist_remove(ilist, where);
            instr_destroy(drcontext, where);
            where = next;
        }
        opnd = OPND_CREATE_ABSMEM((void *)(reg_t)ref_info[pos].cache + 
                                  offsetof(ref_cache_t, offset),
                                  OPSZ_PTR);
        instr_set_src(sub, 0, opnd);
        if (proc_info.client.app_unit_bits  > 0 && 
            proc_info.client.shd_unit_bits != 0)
            next = instr_get_next(sub); /* reg & mask => reg */
        if (proc_info.client.orig_addr) {
            next = instr_get_next(next); /* mov reg => r2 */
            next = instr_get_next(next); /* r2 & bit_mask => r2 */
        }
    }

    next = instr_get_next(lea);
    return instr_get_next(next);
}