static void event_post_syscall(void *drcontext, int sysnum) { #ifdef SHOW_RESULTS dr_syscall_result_info_t info = { sizeof(info), }; dr_syscall_get_result_ex(drcontext, &info); if (!info.succeeded) { /* XXX: we could use the "drsyscall" Extension from the Dr. Memory * Framework (DRMF) to obtain the name of the system call (as well as * the number of arguments and the type of each). Please see the strace * sample and drstrace tool within DRMF for further information. */ dr_fprintf(STDERR, "<---- syscall %d failed (returned "PFX" == "SZFMT") ---->\n", sysnum, info.value, (ptr_int_t)info.value); } #endif if (sysnum == write_sysnum) { per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx); /* we repeat a write originally to stdout that we redirected to * stderr: on the repeat we use stdout */ if (data->repeat) { /* repeat syscall with stdout */ int i; #ifdef SHOW_RESULTS dr_fprintf(STDERR, "<---- repeating write ---->\n"); #endif dr_syscall_set_sysnum(drcontext, write_sysnum); dr_syscall_set_param(drcontext, 0, (reg_t) STDOUT); for (i = 1; i < SYS_MAX_ARGS; i++) dr_syscall_set_param(drcontext, i, data->param[i]); #ifdef WINDOWS if (dr_is_wow64()) { /* Set the xcx emulation parameter for wow64: since * we're executing the same system call again we can * use that same parameter. For new system calls we'd * need to determine the parameter from the ntdll * wrapper. */ dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/}; dr_get_mcontext(drcontext, &mc); mc.xcx = data->xcx; dr_set_mcontext(drcontext, &mc); } #endif dr_syscall_invoke_another(drcontext); } } }
static void event_post_syscall(void *drcontext, int sysnum) { #ifdef SHOW_RESULTS dr_fprintf(STDERR, " [%d] => "PFX" ("SZFMT")\n", sysnum, dr_syscall_get_result(drcontext), (ptr_int_t)dr_syscall_get_result(drcontext)); #endif if (sysnum == write_sysnum) { per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx); /* we repeat a write originally to stdout that we redirected to * stderr: on the repeat we use stdout */ if (data->repeat) { /* repeat syscall with stdout */ int i; #ifdef SHOW_RESULTS dr_fprintf(STDERR, " [%d] => repeating\n", sysnum); #endif dr_syscall_set_sysnum(drcontext, write_sysnum); dr_syscall_set_param(drcontext, 0, (reg_t) STDOUT); for (i = 1; i < SYS_MAX_ARGS; i++) dr_syscall_set_param(drcontext, i, data->param[i]); #ifdef WINDOWS if (dr_is_wow64()) { /* Set the xcx emulation parameter for wow64: since * we're executing the same system call again we can * use that same parameter. For new system calls we'd * need to determine the parameter from the ntdll * wrapper. */ dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/}; dr_get_mcontext(drcontext, &mc); mc.xcx = data->xcx; dr_set_mcontext(drcontext, &mc); } #endif dr_syscall_invoke_another(drcontext); } } }
static bool event_pre_syscall(void *drcontext, int sysnum) { bool modify_write = (sysnum == write_sysnum); dr_atomic_add32_return_sum(&num_syscalls, 1); #ifdef UNIX if (sysnum == SYS_execve) { /* our stats will be re-set post-execve so display now */ show_results(); # ifdef SHOW_RESULTS dr_fprintf(STDERR, "<---- execve ---->\n"); # endif } #endif #ifndef SHOW_RESULTS /* for sanity tests that don't show results we don't change the app's output */ modify_write = false; #endif if (modify_write) { /* store params for access post-syscall */ int i; per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx); #ifdef WINDOWS /* stderr and stdout are identical in our cygwin rxvt shell so for * our example we suppress output starting with 'H' instead */ byte *output = (byte *) dr_syscall_get_param(drcontext, 5); byte first; size_t read; bool ok = dr_safe_read(output, 1, &first, &read); if (!ok || read != 1) return true; /* data unreadable: execute normally */ if (dr_is_wow64()) { /* store the xcx emulation parameter for wow64 */ dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/}; dr_get_mcontext(drcontext, &mc); data->xcx = mc.xcx; } #endif for (i = 0; i < SYS_MAX_ARGS; i++) data->param[i] = dr_syscall_get_param(drcontext, i); /* suppress stderr */ if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDERR #ifdef WINDOWS && first == 'H' #endif ) { /* pretend it succeeded */ #ifdef UNIX /* return the #bytes == 3rd param */ dr_syscall_result_info_t info = { sizeof(info), }; info.succeeded = true; info.value = dr_syscall_get_param(drcontext, 2); dr_syscall_set_result_ex(drcontext, &info); #else /* XXX: we should also set the IO_STATUS_BLOCK.Information field */ dr_syscall_set_result(drcontext, 0); #endif #ifdef SHOW_RESULTS dr_fprintf(STDERR, "<---- skipping write to stderr ---->\n"); #endif return false; /* skip syscall */ } else if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDOUT) { if (!data->repeat) { /* redirect stdout to stderr (unless it's our repeat) */ #ifdef SHOW_RESULTS dr_fprintf(STDERR, "<---- changing stdout to stderr ---->\n"); #endif dr_syscall_set_param(drcontext, 0, (reg_t) STDERR); } /* we're going to repeat this syscall once */ data->repeat = !data->repeat; } } return true; /* execute normally */ }
static bool event_pre_syscall(void *drcontext, int sysnum) { ATOMIC_INC(num_syscalls); #ifdef LINUX if (sysnum == SYS_execve) { /* our stats will be re-set post-execve so display now */ show_results(); # ifdef SHOW_RESULTS dr_fprintf(STDERR, "<---- execve ---->\n"); # endif } #endif #ifdef SHOW_RESULTS dr_fprintf(STDERR, "[%d] "PFX" "PFX" "PFX"\n", sysnum, dr_syscall_get_param(drcontext, 0), dr_syscall_get_param(drcontext, 1), dr_syscall_get_param(drcontext, 2)); #endif if (sysnum == write_sysnum) { /* store params for access post-syscall */ int i; per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx); #ifdef WINDOWS /* stderr and stdout are identical in our cygwin rxvt shell so for * our example we suppress output starting with 'H' instead */ byte *output = (byte *) dr_syscall_get_param(drcontext, 5); byte first; size_t read; bool ok = dr_safe_read(output, 1, &first, &read); if (!ok || read != 1) return true; /* data unreadable: execute normally */ if (dr_is_wow64()) { /* store the xcx emulation parameter for wow64 */ dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/}; dr_get_mcontext(drcontext, &mc); data->xcx = mc.xcx; } #endif for (i = 0; i < SYS_MAX_ARGS; i++) data->param[i] = dr_syscall_get_param(drcontext, i); /* suppress stderr */ if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDERR #ifdef WINDOWS && first == 'H' #endif ) { /* pretend it succeeded */ #ifdef LINUX /* return the #bytes == 3rd param */ dr_syscall_set_result(drcontext, dr_syscall_get_param(drcontext, 2)); #else /* we should also set the IO_STATUS_BLOCK.Information field */ dr_syscall_set_result(drcontext, 0); #endif #ifdef SHOW_RESULTS dr_fprintf(STDERR, " [%d] => skipped\n", sysnum); #endif return false; /* skip syscall */ } else if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDOUT) { if (!data->repeat) { /* redirect stdout to stderr (unless it's our repeat) */ #ifdef SHOW_RESULTS dr_fprintf(STDERR, " [%d] STDOUT => STDERR\n", sysnum); #endif dr_syscall_set_param(drcontext, 0, (reg_t) STDERR); } /* we're going to repeat this syscall once */ data->repeat = !data->repeat; } } return true; /* execute normally */ }