DR_EXPORT void dr_init(client_id_t id) { /* Look up start_monitor() and stop_monitor() in the target app. * These functions are dummy markers that tell us when to start * and stop printing syscalls. */ /* NOTE - we could use dr_module_lookup_by_name, but we use the iterator instead * to test it out. */ dr_module_iterator_t *iter = dr_module_iterator_start(); while (dr_module_iterator_hasnext(iter)) { module_data_t *data = dr_module_iterator_next(iter); if (strcmp(dr_module_preferred_name(data), TEST_NAME) == 0) { module_handle_t lib = data->handle; start_pc = (app_pc)dr_get_proc_address(lib, "start_monitor"); stop_pc = (app_pc)dr_get_proc_address(lib, "stop_monitor"); } dr_free_module_data(data); } dr_module_iterator_stop(iter); if (start_pc == NULL || stop_pc == NULL) { dr_fprintf(STDERR, "ERROR: did not find start/stop markers\n"); } /* Register the BB hook */ dr_register_bb_event(bb_event); #ifdef LINUX /* With early injection, libc won't be loaded until later. */ dr_register_module_load_event(event_module_load); #endif }
static void event_module_load(void *drcontext, const module_data_t *info, bool loaded) { uint64 early_inject; /* do some more dr_get_proc_address testing */ if (strncmp(dr_module_preferred_name(info), "libc.", 5) == 0) { module_handle_t lib = info->handle; dr_export_info_t fn_info; dr_fprintf(STDERR, "found libc\n"); if (dr_get_proc_address(lib, "malloc") == NULL) dr_fprintf(STDERR, "ERROR: can't find malloc in libc\n"); if (dr_get_proc_address(lib, "free") == NULL) dr_fprintf(STDERR, "ERROR: can't find free in libc\n"); if (dr_get_proc_address(lib, "printf") == NULL) dr_fprintf(STDERR, "ERROR: can't find printf in libc\n"); /* i#884: gettimeofday is indirect code on my system, and calling it * will crash unless we wait until libc is fully relocated. * dr_get_proc_address() wraps the fault in a try/except and returns * NULL. The _ex variant does not, so we use that to test the lookup. */ if (!dr_get_proc_address_ex(lib, "gettimeofday", &fn_info, sizeof(fn_info))) dr_fprintf(STDERR, "ERROR: can't find gettimeofday in libc\n"); dr_unregister_module_load_event(event_module_load); } }
static bool exception_event_redirect(void *dcontext, dr_exception_t *excpt) { app_pc addr; dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,}; module_data_t *data = dr_lookup_module_by_name("client."EVENTS".exe"); dr_fprintf(STDERR, "exception event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find "EVENTS".exe module\n"); return true; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); mcontext = *excpt->mcontext; mcontext.pc = addr; if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in "EVENTS".exe\n"); return true; } #ifdef X64 /* align properly in case redirect function relies on conventions (i#419) */ mcontext.xsp = ALIGN_BACKWARD(mcontext.xsp, 16) - sizeof(void*); #endif dr_redirect_execution(&mcontext); dr_fprintf(STDERR, "should not be reached, dr_redirect_execution() should not return\n"); return true; }
static dr_signal_action_t signal_event_redirect(void *dcontext, dr_siginfo_t *info) { if (info->sig == SIGSEGV) { app_pc addr; module_data_t *data = dr_lookup_module_by_name("client."EVENTS); dr_fprintf(STDERR, "signal event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find client."EVENTS" module\n"); return DR_SIGNAL_DELIVER; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in client."EVENTS"\n"); return DR_SIGNAL_DELIVER; } #ifdef X64 /* align properly in case redirect function relies on conventions (i#384) */ info->mcontext->xsp = ALIGN_BACKWARD(info->mcontext->xsp, 16) - sizeof(void*); #endif info->mcontext->pc = addr; return DR_SIGNAL_REDIRECT; } return DR_SIGNAL_DELIVER; }
static bool drmgr_cls_init(void) { /* For callback init we watch for KiUserCallbackDispatcher. * For callback exit we watch for NtCallbackReturn or int 0x2b. */ static int cls_initialized; /* 0=not tried; >0=success; <0=failure */ module_data_t *data; module_handle_t ntdll_lib; app_pc addr_cbret; drmgr_priority_t priority = {sizeof(priority), "drmgr_cls", NULL, NULL, 0}; if (cls_initialized > 0) return true; else if (cls_initialized < 0) return false; cls_initialized = -1; if (!drmgr_register_bb_instrumentation_event(drmgr_event_bb_analysis, drmgr_event_bb_insert, &priority)) return false; dr_register_filter_syscall_event(drmgr_event_filter_syscall); data = dr_lookup_module_by_name("ntdll.dll"); if (data == NULL) { /* fatal error: something is really wrong w/ underlying DR */ return false; } ntdll_lib = data->handle; dr_free_module_data(data); addr_KiCallback = (app_pc) dr_get_proc_address(ntdll_lib, "KiUserCallbackDispatcher"); if (addr_KiCallback == NULL) return false; /* should not happen */ /* the wrapper is not good enough for two reasons: one, we want to swap * contexts at the last possible moment, not prior to executing a few * instrs; second, we'll miss hand-rolled syscalls */ addr_cbret = (app_pc) dr_get_proc_address(ntdll_lib, "NtCallbackReturn"); if (addr_cbret == NULL) return false; /* should not happen */ sysnum_NtCallbackReturn = drmgr_decode_sysnum_from_wrapper(addr_cbret); if (sysnum_NtCallbackReturn == -1) return false; /* should not happen */ cls_initialized = 1; return true; }
static void wrap_unwindtest_addr(OUT app_pc *addr, const char *name, const module_data_t *mod) { bool ok; *addr = (app_pc) dr_get_proc_address(mod->handle, name); CHECK(*addr != NULL, "cannot find lib export"); ok = drwrap_wrap(*addr, wrap_unwindtest_pre, wrap_unwindtest_post); CHECK(ok, "wrap unwindtest failed"); CHECK(drwrap_is_wrapped(*addr, wrap_unwindtest_pre, wrap_unwindtest_post), "drwrap_is_wrapped query failed"); }
static int get_sysnum(const char *wrapper) { byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, wrapper); dr_free_module_data(data); if (entry == NULL) return -1; return drmgr_decode_sysnum_from_wrapper(entry); }
static void wrap_addr(OUT app_pc *addr, const char *name, const module_data_t *mod, bool pre, bool post) { bool ok; *addr = (app_pc) dr_get_proc_address(mod->handle, name); CHECK(*addr != NULL, "cannot find lib export"); ok = drwrap_wrap(*addr, pre ? wrap_pre : NULL, post ? wrap_post : NULL); CHECK(ok, "wrap failed"); CHECK(drwrap_is_wrapped(*addr, pre ? wrap_pre : NULL, post ? wrap_post : NULL), "drwrap_is_wrapped query failed"); }
DR_EXPORT void dr_init(client_id_t id) { /* Look up start_instrument() and stop_instrument() in the app. * These functions are markers that tell us when to start and stop * instrumenting. */ module_data_t *prog = dr_lookup_module_by_name("client.cbr4.exe"); ASSERT(prog != NULL); start_pc = (app_pc)dr_get_proc_address(prog->handle, "start_instrument"); stop_pc = (app_pc)dr_get_proc_address(prog->handle, "stop_instrument"); ASSERT(start_pc != NULL && stop_pc != NULL); dr_free_module_data(prog); table = new_table(); dr_register_bb_event(bb_event); dr_register_exit_event(dr_exit); }
static void module_load_event(void *drcontext, const module_data_t *mod, bool loaded) { app_pc towrap = (app_pc)dr_get_proc_address(mod->handle, "SSL_write"); if (towrap != NULL) { bool ok = drwrap_wrap(towrap, wrap_pre_SSL_write, NULL); if (!ok) { dr_fprintf(STDERR, "Couldn’t wrap SSL_write\n"); DR_ASSERT(ok); } } towrap = (app_pc)dr_get_proc_address(mod->handle, "SSL_read"); if (towrap != NULL) { bool ok = drwrap_wrap(towrap, wrap_pre_SSL_read, wrap_post_SSL_read); if (!ok) { dr_fprintf(STDERR, "Couldn’t wrap SSL_read\n"); DR_ASSERT(ok); } } towrap = (app_pc)dr_get_proc_address(mod->handle, "gnutls_record_send"); if (towrap != NULL) { bool ok = drwrap_wrap(towrap, wrap_pre_SSL_write, NULL); if (!ok) { dr_fprintf(STDERR, "Couldn’t wrap gnutls_record_send\n"); DR_ASSERT(ok); } } towrap = (app_pc)dr_get_proc_address(mod->handle, "gnutls_record_recv"); if (towrap != NULL) { bool ok = drwrap_wrap(towrap, wrap_pre_SSL_read, wrap_post_SSL_read); if (!ok) { dr_fprintf(STDERR, "Couldn’t wrap gnutls_record_recv\n"); DR_ASSERT(ok); } } }
static int get_write_sysnum(void) { #ifdef LINUX return SYS_write; #else byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); DR_ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, "NtWriteFile"); DR_ASSERT(entry != NULL); dr_free_module_data(data); return drmgr_decode_sysnum_from_wrapper(entry); #endif }
DR_EXPORT void dr_init(client_id_t id) { module_data_t *data; dr_fprintf(STDERR, "thank you for testing the client interface\n"); dr_register_bb_event(bb_event); data = dr_lookup_module_by_name("kernel32.dll"); if (data != NULL) { exit_proc_addr = (void *)dr_get_proc_address(data->handle, "ExitProcess"); if (exit_proc_addr == NULL) dr_fprintf(STDERR, "ERROR: unable to find kernel32!ExitProcess\n"); dr_free_module_data(data); } else { dr_fprintf(STDERR, "ERROR: unable to find ntdll.dll\n"); } }
static int get_write_sysnum(void) { /* XXX: we could use the "drsyscall" Extension from the Dr. Memory Framework * (DRMF) to obtain the number of any system call from the name. */ #ifdef UNIX return SYS_write; #else byte *entry; module_data_t *data = dr_lookup_module_by_name("ntdll.dll"); DR_ASSERT(data != NULL); entry = (byte *) dr_get_proc_address(data->handle, "NtWriteFile"); DR_ASSERT(entry != NULL); dr_free_module_data(data); return drmgr_decode_sysnum_from_wrapper(entry); #endif }
DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { module_data_t *app; generic_func_t repeatme_addr; drmgr_init(); if (drfuzz_init(id) != DRMF_SUCCESS) EXPECT(false, "drfuzz failed to init"); dr_register_exit_event(exit_event); /* fuzz repeatme */ app = dr_get_main_module(); if (app == NULL) EXPECT(false, "failed to get application module"); repeatme_addr = dr_get_proc_address(app->handle, "repeatme"); if (repeatme_addr == NULL) EXPECT(false, "failed to find function repeatme"); if (drfuzz_fuzz_target(repeatme_addr, 1, 0, DRWRAP_CALLCONV_DEFAULT, pre_fuzz_cb, post_fuzz_cb) != DRMF_SUCCESS) EXPECT(false, "drfuzz failed to fuzz function repeatme"); dr_free_module_data(app); }
static dr_signal_action_t signal_event_redirect(void *dcontext, dr_siginfo_t *info) { if (info->sig == SIGSEGV) { app_pc addr; module_data_t *data = dr_lookup_module_by_name("client.events"); dr_fprintf(STDERR, "signal event redirect\n"); if (data == NULL) { dr_fprintf(STDERR, "couldn't find client.events module\n"); return DR_SIGNAL_DELIVER; } addr = (app_pc)dr_get_proc_address(data->handle, "redirect"); dr_free_module_data(data); if (addr == NULL) { dr_fprintf(STDERR, "Couldn't find function redirect in client.events\n"); return DR_SIGNAL_DELIVER; } info->mcontext->pc = addr; return DR_SIGNAL_REDIRECT; } return DR_SIGNAL_DELIVER; }
static void module_load_event(void *drcontext, const module_data_t *mod, bool loaded) { app_pc towrap = (app_pc) dr_get_proc_address(mod->start, IF_WINDOWS_ELSE("HeapAlloc", "malloc")); if (towrap != NULL) { #ifdef SHOW_RESULTS bool ok = #endif drwrap_wrap(towrap, wrap_pre, wrap_post); #ifdef SHOW_RESULTS if (ok) dr_fprintf(STDERR, "<wrapped HeapAlloc @"PFX"\n", towrap); else { /* We expect this w/ forwarded exports (e.g., on win7 both * kernel32!HeapAlloc and kernelbase!HeapAlloc forward to * the same routine in ntdll.dll) */ dr_fprintf(STDERR, "<FAILED to wrap HeapAlloc @"PFX": already wrapped?\n", towrap); } #endif } }
static void module_load_event(void *drcontext, const module_data_t *mod, bool loaded) { if (strstr(dr_module_preferred_name(mod), "client.drwrap-test.appdll.") != NULL) { bool ok; instr_t inst; app_pc init_pc, pc, next_pc; load_count++; if (load_count == 2) { /* test no-frills */ drwrap_set_global_flags(DRWRAP_NO_FRILLS); } addr_replace = (app_pc) dr_get_proc_address(mod->handle, "replaceme"); CHECK(addr_replace != NULL, "cannot find lib export"); ok = drwrap_replace(addr_replace, (app_pc) replacewith, false); CHECK(ok, "replace failed"); addr_replace2 = (app_pc) dr_get_proc_address(mod->handle, "replaceme2"); CHECK(addr_replace2 != NULL, "cannot find lib export"); ok = drwrap_replace_native(addr_replace2, (app_pc) replacewith2, true/*at entry*/, 0, (void *)(ptr_int_t)DRWRAP_NATIVE_PARAM, false); CHECK(ok, "replace_native failed"); init_pc = (app_pc) dr_get_proc_address(mod->handle, "replace_callsite"); CHECK(init_pc != NULL, "cannot find lib export"); /* Find callsite: we assume we'll linearly hit a ret. We take final call * to skip any PIC call. */ instr_init(drcontext, &inst); pc = init_pc; do { instr_reset(drcontext, &inst); next_pc = decode(drcontext, pc, &inst); if (!instr_valid(&inst)) break; /* if initial jmp, follow it to handle ILT-indirection */ if (pc == init_pc && instr_is_ubr(&inst)) next_pc = opnd_get_pc(instr_get_target(&inst)); else if (instr_is_call(&inst)) addr_replace_callsite = pc; pc = next_pc; } while (instr_valid(&inst) && !instr_is_return(&inst)); CHECK(addr_replace_callsite != NULL, "cannot find lib export"); ok = drwrap_replace_native(addr_replace_callsite, (app_pc) replace_callsite, false/*!at entry*/, 0, (void *)(ptr_int_t)DRWRAP_NATIVE_PARAM, false); CHECK(ok, "replace_native failed"); instr_free(drcontext, &inst); wrap_addr(&addr_level0, "level0", mod, true, true); wrap_addr(&addr_level1, "level1", mod, true, true); wrap_addr(&addr_level2, "level2", mod, true, true); wrap_addr(&addr_tailcall, "makes_tailcall", mod, true, true); wrap_addr(&addr_skipme, "skipme", mod, true, true); wrap_addr(&addr_repeat, "repeatme", mod, true, true); wrap_addr(&addr_preonly, "preonly", mod, true, false); wrap_addr(&addr_postonly, "postonly", mod, false, true); wrap_addr(&addr_runlots, "runlots", mod, false, true); /* test longjmp */ wrap_unwindtest_addr(&addr_long0, "long0", mod); wrap_unwindtest_addr(&addr_long1, "long1", mod); wrap_unwindtest_addr(&addr_long2, "long2", mod); wrap_unwindtest_addr(&addr_long3, "long3", mod); wrap_unwindtest_addr(&addr_longdone, "longdone", mod); drmgr_set_tls_field(drcontext, tls_idx, (void *)(ptr_uint_t)0); #ifdef WINDOWS /* test SEH */ /* we can't do this test for no-frills b/c only one wrap per addr */ if (load_count == 1) { ok = drwrap_wrap_ex(addr_long0, wrap_unwindtest_seh_pre, wrap_unwindtest_seh_post, NULL, DRWRAP_UNWIND_ON_EXCEPTION); CHECK(ok, "wrap failed"); ok = drwrap_wrap_ex(addr_long1, wrap_unwindtest_seh_pre, wrap_unwindtest_seh_post, NULL, DRWRAP_UNWIND_ON_EXCEPTION); CHECK(ok, "wrap failed"); ok = drwrap_wrap_ex(addr_long2, wrap_unwindtest_seh_pre, wrap_unwindtest_seh_post, NULL, DRWRAP_UNWIND_ON_EXCEPTION); CHECK(ok, "wrap failed"); ok = drwrap_wrap_ex(addr_long3, wrap_unwindtest_seh_pre, wrap_unwindtest_seh_post, NULL, DRWRAP_UNWIND_ON_EXCEPTION); CHECK(ok, "wrap failed"); ok = drwrap_wrap_ex(addr_longdone, wrap_unwindtest_seh_pre, wrap_unwindtest_seh_post, NULL, DRWRAP_UNWIND_ON_EXCEPTION); CHECK(ok, "wrap failed"); } #endif /* test leaner wrapping */ if (load_count == 2) drwrap_set_global_flags(DRWRAP_NO_FRILLS | DRWRAP_FAST_CLEANCALLS); wrap_addr(&addr_skip_flags, "skip_flags", mod, true, false); } }