bool drakvuf_get_module_base_addr( drakvuf_t drakvuf, addr_t module_list_head, const char *module_name, addr_t *base_addr_out ) { addr_t base_addr ; size_t name_len = strlen( module_name ); vmi_instance_t vmi = drakvuf->vmi; addr_t next_module = module_list_head; while( 1 ) { addr_t tmp_next = 0; if ( vmi_read_addr_va( vmi, next_module, 4, &tmp_next ) != VMI_SUCCESS ) break; if ( module_list_head == tmp_next ) break; base_addr = 0 ; if ( vmi_read_addr_va( vmi, next_module + offsets[LDR_DATA_TABLE_ENTRY_DLLBASE], 4, &base_addr ) != VMI_SUCCESS ) break; if ( ! base_addr ) break; unicode_string_t *us = vmi_read_unicode_str_va( vmi, next_module + offsets[LDR_DATA_TABLE_ENTRY_BASEDLLNAME], 4 ); if ( us ) { unicode_string_t out = { 0 }; if ( vmi_convert_str_encoding( us, &out, "UTF-8" ) == VMI_SUCCESS ) { if ( ! strncasecmp( (char *)out.contents, module_name, name_len ) ) { free( out.contents ); vmi_free_unicode_str( us ); *base_addr_out = base_addr ; return true ; } free( out.contents ); } vmi_free_unicode_str( us ); } next_module = tmp_next ; } return false ; }
int main( int argc, char **argv) { vmi_instance_t vmi; uint32_t offset; addr_t next_module, list_head; /* this is the VM or file that we are looking at */ char *name = argv[1]; /* initialize the libvmi library */ if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, name) == VMI_FAILURE) { printf("Failed to init LibVMI library.\n"); return 1; } /* pause the vm for consistent memory access */ vmi_pause_vm(vmi); /* get the head of the module list */ if (VMI_OS_LINUX == vmi_get_ostype(vmi)) { vmi_read_addr_ksym(vmi, "modules", &next_module); } else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) { vmi_read_addr_ksym(vmi, "PsLoadedModuleList", &next_module); } list_head = next_module; /* walk the module list */ while (1) { /* follow the next pointer */ addr_t tmp_next = 0; vmi_read_addr_va(vmi, next_module, 0, &tmp_next); /* if we are back at the list head, we are done */ if (list_head == tmp_next) { break; } /* print out the module name */ /* Note: the module struct that we are looking at has a string * directly following the next / prev pointers. This is why you * can just add the length of 2 address fields to get the name. * See include/linux/module.h for mode details */ if (VMI_OS_LINUX == vmi_get_ostype(vmi)) { char *modname = NULL; if (VMI_PM_IA32E == vmi_get_page_mode(vmi)) { // 64-bit paging modname = vmi_read_str_va(vmi, next_module + 16, 0); } else { modname = vmi_read_str_va(vmi, next_module + 8, 0); } printf("%s\n", modname); free(modname); } else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) { /*TODO don't use a hard-coded offsets here */ /* this offset works with WinXP SP2 */ unicode_string_t *us = vmi_read_unicode_str_va(vmi, next_module + 0x2c, 0); unicode_string_t out = { 0 }; // both of these work if (us && VMI_SUCCESS == vmi_convert_str_encoding(us, &out, "UTF-8")) { printf("%s\n", out.contents); // if (us && // VMI_SUCCESS == vmi_convert_string_encoding (us, &out, "WCHAR_T")) { // printf ("%ls\n", out.contents); free(out.contents); } // if if (us) vmi_free_unicode_str(us); } next_module = tmp_next; } error_exit: /* resume the vm */ vmi_resume_vm(vmi); /* cleanup any memory associated with the libvmi instance */ vmi_destroy(vmi); return 0; }