diff --git a/src/injector.c b/src/injector.c index 2157591bc..10eb7d21d 100644 --- a/src/injector.c +++ b/src/injector.c @@ -104,6 +104,7 @@ #include #include +#include #include #include "libdrakvuf/libdrakvuf.h" diff --git a/src/libdrakvuf/drakvuf.c b/src/libdrakvuf/drakvuf.c index 5f284263e..f28811594 100644 --- a/src/libdrakvuf/drakvuf.c +++ b/src/libdrakvuf/drakvuf.c @@ -179,92 +179,62 @@ bool drakvuf_add_trap(drakvuf_t drakvuf, drakvuf_trap_t *trap) { goto done; } - if(trap->lookup_type == LOOKUP_PID && trap->u.pid == 4) { - if (trap->module) { - vmi_instance_t vmi = drakvuf->vmi; - - // Loop kernel modules - addr_t kernel_list_head; - vmi_read_addr_ksym(vmi, "PsLoadedModuleList", &kernel_list_head); - ret = inject_traps_modules(drakvuf, NULL, trap, kernel_list_head, 4, "System"); - } - - goto done; - } - } else { - ret = inject_trap_mem(drakvuf, trap); - } + if(trap->lookup_type == LOOKUP_PID || trap->lookup_type == LOOKUP_NAME) { + if (trap->addr_type == ADDR_RVA && trap->module) { -done: - vmi_resume_vm(drakvuf->vmi); - return ret; -} + vmi_pid_t pid = ~0; + const char *name = NULL; + addr_t module_list = 0; -bool drakvuf_add_traps(drakvuf_t drakvuf, GSList *traps) { - bool ret = 0; - addr_t kernel_list_head; - vmi_instance_t vmi = drakvuf->vmi; - vmi_pause_vm(vmi); - - // Loop kernel modules - vmi_read_addr_ksym(vmi, "PsLoadedModuleList", &kernel_list_head); - ret = inject_traps_modules(drakvuf, traps, NULL, kernel_list_head, 4, "System"); - - // TODO TODO TODO - /*addr_t current_process = 0, next_list_entry = 0; - vmi_read_addr_ksym(vmi, "PsInitialSystemProcess", ¤t_process); - - addr_t list_head = current_process + offsets[EPROCESS_TASKS]; - addr_t current_list_entry = list_head; - - status_t status = vmi_read_addr_va(vmi, current_list_entry, 0, - &next_list_entry); - if (status == VMI_FAILURE) { - PRINT_DEBUG( - "Failed to read next pointer at 0x%"PRIx64" before entering loop\n", - current_list_entry); - return; - } + if(trap->u.pid == 4 || !strcmp(trap->u.proc, "System")) { + pid = 4; + name = "System"; - do { + if(VMI_FAILURE == vmi_read_addr_ksym(drakvuf->vmi, "PsLoadedModuleList", &module_list)) + goto done; + } else { + /* Process library */ + addr_t process_base; - vmi_pid_t pid; - uint32_t dtb; - vmi_read_32_va(vmi, current_process + offsets[EPROCESS_PID], 0, (uint32_t*)&pid); - vmi_read_32_va(vmi, current_process + offsets[EPROCESS_PDBASE], 0, &dtb); + if(trap->lookup_type == LOOKUP_PID) + pid = trap->u.pid; + if(trap->lookup_type == LOOKUP_NAME) + name = trap->u.proc; - char *procname = vmi_read_str_va(vmi, current_process + offsets[EPROCESS_PNAME], 0); + if( !drakvuf_find_eprocess(drakvuf, pid, name, &process_base) ) + goto done; - if (!procname) { - goto exit; - } + if(pid == ~0 && VMI_FAILURE == vmi_read_32_va(drakvuf->vmi, process_base + offsets[EPROCESS_PID], 0, (uint32_t*)&pid)) + goto done; - PRINT(drakvuf, FOUND_PROCESS_STRING, pid, dtb, procname); + if( !drakvuf_get_module_list(drakvuf, process_base, &module_list) ) + goto done; + } - free(procname); + ret = inject_traps_modules(drakvuf, trap, module_list, pid); + } - addr_t imagebase = 0, peb = 0, ldr = 0, modlist = 0; - vmi_read_addr_va(vmi, current_process + offsets[EPROCESS_PEB], 0, &peb); - vmi_read_addr_va(vmi, peb + offsets[PEB_IMAGEBASADDRESS], pid, - &imagebase); - vmi_read_addr_va(vmi, peb + offsets[PEB_LDR], pid, &ldr); - vmi_read_addr_va(vmi, ldr + offsets[PEB_LDR_DATA_INLOADORDERMODULELIST], - pid, &modlist); + if(trap->addr_type == ADDR_VA) { + addr_t dtb = vmi_pid_to_dtb(drakvuf->vmi, trap->u.pid); + if(!dtb) + goto done; - inject_traps_pe(drakvuf, traps, imagebase, pid, NULL); - inject_traps_modules(drakvuf, traps, modlist, pid); + addr_t trap_pa = vmi_pagetable_lookup(drakvuf->vmi, dtb, trap->u2.addr); + if(!trap_pa) + goto done; - current_list_entry = next_list_entry; - current_process = current_list_entry - offsets[EPROCESS_TASKS]; + ret = inject_trap_pa(drakvuf, trap, trap_pa); + goto done; + } - status = vmi_read_addr_va(vmi, current_list_entry, 0, &next_list_entry); - if (status == VMI_FAILURE) { - PRINT_DEBUG("Failed to read next pointer in loop at %"PRIx64"\n", - current_list_entry); - return; + if(trap->addr_type == ADDR_PA) { + fprintf(stderr, "DRAKVUF Trap misconfiguration: PID lookup specified for PA location\n"); + } } - } while (next_list_entry != list_head);*/ + } else { + ret = inject_trap_mem(drakvuf, trap); + } done: vmi_resume_vm(drakvuf->vmi); @@ -295,13 +265,6 @@ void drakvuf_remove_trap(drakvuf_t drakvuf, drakvuf_trap_t *trap, } } -void drakvuf_remove_traps(drakvuf_t drakvuf, GSList *traps) { - while (traps) { - remove_trap(drakvuf, traps->data); - traps = traps->next; - } -} - vmi_instance_t drakvuf_lock_and_get_vmi(drakvuf_t drakvuf) { g_mutex_lock(&drakvuf->vmi_lock); return drakvuf->vmi; diff --git a/src/libdrakvuf/injector.c b/src/libdrakvuf/injector.c index ced4d68c8..89b955f7a 100644 --- a/src/libdrakvuf/injector.c +++ b/src/libdrakvuf/injector.c @@ -132,7 +132,6 @@ struct injector { page_mode_t pm; addr_t process_info; - addr_t saved_rsp; addr_t saved_rip; addr_t saved_rax; @@ -827,8 +826,15 @@ event_response_t cr3_callback(vmi_instance_t vmi, vmi_event_t *event) { return 0; } -event_response_t injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) { +event_response_t singlestep_cb(vmi_instance_t vmi, vmi_event_t *event) { + addr_t *pa = event->data; + vmi_write_8_pa(vmi, *pa, &trap); + free(pa); + return 1u<data; @@ -845,6 +851,24 @@ event_response_t injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) { PRINT_DEBUG("INT3 Callback @ 0x%lx. PID %u. CR3 0x%lx\n", event->interrupt_event.gla, pid, cr3); + if ( cr3 != injector->target_cr3 ) { + PRINT_DEBUG("Stepping INT3 as CR3 doesn't match target process\n"); + + if ( event->interrupt_event.gla == injector->entry ) + vmi_write_8_pa(vmi, pa, &injector->entry_backup); + else if ( event->interrupt_event.gla == injector->ret ) + vmi_write_8_pa(vmi, pa, &injector->ret_backup); + else + goto notmine; + + injector->drakvuf->step_event[event->vcpu_id]->callback = singlestep_cb; + injector->drakvuf->step_event[event->vcpu_id]->data = g_memdup(&pa, sizeof(addr_t)); + event->interrupt_event.reinject = 0; + vmi_resume_vm(vmi); + + return 1u<interrupt_event.gla == injector->entry ) { if (PM2BIT(injector->pm) == BIT64) { @@ -870,6 +894,8 @@ event_response_t injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) { ctx.addr = injector->ret; vmi_write_8(vmi, &ctx, &trap); + PRINT_DEBUG("Stack setup finished and return trap added @ 0x%" PRIx64 "\n", injector->ret); + event->interrupt_event.reinject = 0; vmi_resume_vm(vmi); return 0; diff --git a/src/libdrakvuf/libdrakvuf.h b/src/libdrakvuf/libdrakvuf.h index 2186d47de..447c651ca 100644 --- a/src/libdrakvuf/libdrakvuf.h +++ b/src/libdrakvuf/libdrakvuf.h @@ -111,7 +111,6 @@ extern "C" { #pragma GCC visibility push(default) -#include #include #include @@ -245,13 +244,9 @@ bool drakvuf_init (drakvuf_t *drakvuf, void drakvuf_close (drakvuf_t drakvuf); bool drakvuf_add_trap(drakvuf_t drakvuf, drakvuf_trap_t *trap); -bool drakvuf_add_traps(drakvuf_t drakvuf, - GSList *traps); void drakvuf_remove_trap (drakvuf_t drakvuf, drakvuf_trap_t *trap, void(*free_routine)(drakvuf_trap_t *trap)); -void drakvuf_remove_traps(drakvuf_t drakvuf, - GSList *traps); void drakvuf_loop (drakvuf_t drakvuf); void drakvuf_interrupt (drakvuf_t drakvuf, int sig); @@ -287,37 +282,45 @@ char *drakvuf_get_current_process_name(drakvuf_t drakvuf, uint64_t vcpu_id, x86_registers_t *regs); - -bool drakvuf_get_current_thread_id( drakvuf_t drakvuf, - uint64_t vcpu_id, +bool drakvuf_get_current_thread_id(drakvuf_t drakvuf, + uint64_t vcpu_id, x86_registers_t *regs, - uint32_t *thread_id ); + uint32_t *thread_id); // Microsoft PreviousMode KTHREAD explanation: // https://msdn.microsoft.com/en-us/library/windows/hardware/ff559860(v=vs.85).aspx -bool drakvuf_get_current_thread_previous_mode( drakvuf_t drakvuf, - drakvuf_trap_info_t *info, - privilege_mode_t *previous_mode ); +bool drakvuf_get_current_thread_previous_mode(drakvuf_t drakvuf, + drakvuf_trap_info_t *info, + privilege_mode_t *previous_mode); + +bool drakvuf_get_thread_previous_mode(drakvuf_t drakvuf, + addr_t kthread, + privilege_mode_t *previous_mode); + +bool drakvuf_is_ethread(drakvuf_t drakvuf, + drakvuf_trap_info_t *info, + addr_t ethread_addr); -bool drakvuf_get_thread_previous_mode( drakvuf_t drakvuf, - addr_t kthread, - privilege_mode_t *previous_mode ); +bool drakvuf_is_eprocess(drakvuf_t drakvuf, + drakvuf_trap_info_t *info, + addr_t eprocess_addr); -bool drakvuf_is_ethread( drakvuf_t drakvuf, - drakvuf_trap_info_t *info, - addr_t ethread_addr ); +bool drakvuf_find_eprocess(drakvuf_t drakvuf, + vmi_pid_t find_pid, + const char *find_procname, + addr_t *eprocess_addr); -bool drakvuf_is_eprocess( drakvuf_t drakvuf, - drakvuf_trap_info_t *info, - addr_t eprocess_addr ); +bool drakvuf_get_module_list(drakvuf_t drakvuf, + addr_t eprocess_base, + addr_t *module_list); // ObReferenceObjectByHandle -bool drakvuf_obj_ref_by_handle( drakvuf_t drakvuf, - drakvuf_trap_info_t *info, - addr_t current_eprocess, - addr_t handle, - object_manager_object_t obj_type_arg, - addr_t *obj_body_addr ); +bool drakvuf_obj_ref_by_handle(drakvuf_t drakvuf, + drakvuf_trap_info_t *info, + addr_t current_eprocess, + addr_t handle, + object_manager_object_t obj_type_arg, + addr_t *obj_body_addr); #pragma GCC visibility pop diff --git a/src/libdrakvuf/private.h b/src/libdrakvuf/private.h index f80d180e6..dd47d9d88 100644 --- a/src/libdrakvuf/private.h +++ b/src/libdrakvuf/private.h @@ -110,7 +110,7 @@ #include #include #include - +#include #include #include #include diff --git a/src/libdrakvuf/vmi.c b/src/libdrakvuf/vmi.c index 5892150e3..48115a4f2 100644 --- a/src/libdrakvuf/vmi.c +++ b/src/libdrakvuf/vmi.c @@ -695,21 +695,18 @@ bool inject_trap(drakvuf_t drakvuf, } bool inject_traps_modules(drakvuf_t drakvuf, - GSList *traps, drakvuf_trap_t *trap, addr_t list_head, - vmi_pid_t pid, - const char *name) - + vmi_pid_t pid) { - PRINT_DEBUG("Inject traps in module list of [%u]: %s\n", pid, name); + vmi_instance_t vmi = drakvuf->vmi; + addr_t next_module = list_head; - if (traps == NULL && trap == NULL) + if (!trap) return 0; - vmi_instance_t vmi = drakvuf->vmi; + PRINT_DEBUG("Inject traps in module list of PID %u\n", pid); - addr_t next_module = list_head; while (1) { addr_t tmp_next = 0; @@ -719,55 +716,27 @@ bool inject_traps_modules(drakvuf_t drakvuf, break; addr_t dllbase = 0; - vmi_read_addr_va(vmi, - next_module + offsets[LDR_DATA_TABLE_ENTRY_DLLBASE], pid, - &dllbase); + vmi_read_addr_va(vmi, next_module + offsets[LDR_DATA_TABLE_ENTRY_DLLBASE], pid, &dllbase); if (!dllbase) break; - unicode_string_t *us = - vmi_read_unicode_str_va(vmi, next_module + offsets[LDR_DATA_TABLE_ENTRY_BASEDLLNAME], pid); + unicode_string_t *us = vmi_read_unicode_str_va(vmi, next_module + offsets[LDR_DATA_TABLE_ENTRY_BASEDLLNAME], pid); unicode_string_t out = { .contents = NULL }; - if (us && VMI_SUCCESS == vmi_convert_str_encoding(us, &out, "UTF-8")) { - PRINT_DEBUG("\t%s @ 0x%" PRIx64 "\n", out.contents, dllbase); - } // if - if (us) - vmi_free_unicode_str(us); - - if(out.contents) { - - if (traps) { - GSList *loop = traps; - while(loop) { - - drakvuf_trap_t *curtrap = loop->data; + if (us) { + status_t status = vmi_convert_str_encoding(us, &out, "UTF-8"); + if(VMI_SUCCESS == status) + PRINT_DEBUG("\t%s @ 0x%" PRIx64 "\n", out.contents, dllbase); - if (curtrap->module && - ( - (curtrap->lookup_type == LOOKUP_PID && pid == curtrap->u.pid) - || - (curtrap->lookup_type == LOOKUP_NAME && !strcmp(name,curtrap->u.proc)) - ) && - !strcmp((char*)out.contents,curtrap->module)) - { - if ( !inject_trap(drakvuf, curtrap, dllbase, pid) ) - return 0; - } - - loop = loop->next; - } - } else if(!strcmp((char*)out.contents,trap->module)) { - free(out.contents); - - if ( !inject_trap(drakvuf, trap, dllbase, pid) ) - return 0; - - break; - } + vmi_free_unicode_str(us); + } + if(out.contents && !strcmp((char*)out.contents,trap->module)) { free(out.contents); + + if ( !inject_trap(drakvuf, trap, dllbase, pid) ) + return 0; } next_module = tmp_next; diff --git a/src/libdrakvuf/vmi.h b/src/libdrakvuf/vmi.h index 5181d5e69..2b11d9868 100644 --- a/src/libdrakvuf/vmi.h +++ b/src/libdrakvuf/vmi.h @@ -282,11 +282,9 @@ bool inject_trap_pa(drakvuf_t drakvuf, drakvuf_trap_t *trap, addr_t pa); bool inject_traps_modules(drakvuf_t drakvuf, - GSList *traps, drakvuf_trap_t *trap, addr_t list_head, - vmi_pid_t pid, - const char *name); + vmi_pid_t pid); void remove_trap(drakvuf_t drakvuf, const drakvuf_trap_t *trap); diff --git a/src/libdrakvuf/win-processes.c b/src/libdrakvuf/win-processes.c index 0725453a3..5ae62f665 100644 --- a/src/libdrakvuf/win-processes.c +++ b/src/libdrakvuf/win-processes.c @@ -271,3 +271,72 @@ bool drakvuf_is_eprocess( drakvuf_t drakvuf, drakvuf_trap_info_t *info, addr_t e return false ; } + +bool drakvuf_get_module_list(drakvuf_t drakvuf, addr_t eprocess_base, addr_t *module_list) { + + vmi_instance_t vmi = drakvuf->vmi; + vmi_pid_t pid; + addr_t peb, ldr, modlist; + + if(!eprocess_base) + return false; + + if(VMI_FAILURE == vmi_read_32_va(vmi, eprocess_base + offsets[EPROCESS_PID], 0, (uint32_t*)&pid)) + return false; + + if(VMI_FAILURE == vmi_read_addr_va(vmi, eprocess_base + offsets[EPROCESS_PEB], 0, &peb)) + return false; + + if(VMI_FAILURE == vmi_read_addr_va(vmi, peb + offsets[PEB_LDR], pid, &ldr)) + return false; + + if(VMI_FAILURE == vmi_read_addr_va(vmi, ldr + offsets[PEB_LDR_DATA_INLOADORDERMODULELIST], pid, &modlist)) + return false; + + *module_list = modlist; + + return true; +} + +bool drakvuf_find_eprocess(drakvuf_t drakvuf, vmi_pid_t find_pid, const char *find_procname, addr_t *eprocess_addr) { + addr_t current_process = 0, next_list_entry = 0; + vmi_instance_t vmi = drakvuf->vmi; + vmi_read_addr_ksym(vmi, "PsInitialSystemProcess", ¤t_process); + + addr_t list_head = current_process + offsets[EPROCESS_TASKS]; + addr_t current_list_entry = list_head; + + status_t status = vmi_read_addr_va(vmi, current_list_entry, 0, + &next_list_entry); + if (status == VMI_FAILURE) { + PRINT_DEBUG( + "Failed to read next pointer at 0x%"PRIx64" before entering loop\n", + current_list_entry); + return false; + } + + do { + vmi_pid_t pid = ~0; + vmi_read_32_va(vmi, current_process + offsets[EPROCESS_PID], 0, (uint32_t*)&pid); + char *procname = vmi_read_str_va(vmi, current_process + offsets[EPROCESS_PNAME], 0); + + if((pid != ~0 && find_pid != ~0 && pid == find_pid) || (find_procname && procname && !strcmp(procname, find_procname))) { + *eprocess_addr = current_list_entry - offsets[EPROCESS_TASKS]; + free(procname); + return true; + } + + free(procname); + + current_list_entry = next_list_entry; + status = vmi_read_addr_va(vmi, current_list_entry, 0, &next_list_entry); + if (status == VMI_FAILURE) { + PRINT_DEBUG("Failed to read next pointer in loop at %"PRIx64"\n", + current_list_entry); + return false; + } + + } while (next_list_entry != list_head); + + return false; +} diff --git a/src/plugins/syscalls/syscalls.cpp b/src/plugins/syscalls/syscalls.cpp index 7e0183657..49eabe156 100644 --- a/src/plugins/syscalls/syscalls.cpp +++ b/src/plugins/syscalls/syscalls.cpp @@ -171,8 +171,15 @@ syscalls::syscalls(drakvuf_t drakvuf, const void *config, output_format_t output drakvuf_free_symbols(symbols); - if ( !drakvuf_add_traps(drakvuf, this->traps) ) - throw -1; + GSList *loop = this->traps; + while(loop) { + drakvuf_trap_t *trap = (drakvuf_trap_t *)loop->data; + + if ( !drakvuf_add_trap(drakvuf, trap) ) + throw -1; + + loop = loop->next; + } } syscalls::~syscalls() { diff --git a/src/plugins/syscalls/syscalls.h b/src/plugins/syscalls/syscalls.h index 54607feec..e436d3056 100644 --- a/src/plugins/syscalls/syscalls.h +++ b/src/plugins/syscalls/syscalls.h @@ -105,6 +105,7 @@ #ifndef SYSCALLS_H #define SYSCALLS_H +#include #include "plugins/plugins.h" class syscalls: public plugin {