// Idea from http://gleeda.blogspot.com/2010/12/identifying-memory-images.html win_ver_t find_windows_version( vmi_instance_t vmi, addr_t KdVersionBlock) { windows_instance_t windows = NULL; if (vmi->os_data == NULL) { return VMI_FAILURE; } windows = vmi->os_data; // no need to repeat this work if we already have the answer if (windows->version && windows->version != VMI_OS_WINDOWS_UNKNOWN) { return windows->version; } uint16_t size = 0; vmi_read_16_pa(vmi, KdVersionBlock + 0x14, &size); if (memcmp(&size, "\x08\x02", 2) == 0) { dbprint("--OS Guess: Windows 2000\n"); return VMI_OS_WINDOWS_2000; } else if (memcmp(&size, "\x90\x02", 2) == 0) { dbprint("--OS Guess: Windows XP\n"); return VMI_OS_WINDOWS_XP; } else if (memcmp(&size, "\x18\x03", 2) == 0) { dbprint("--OS Guess: Windows 2003\n"); return VMI_OS_WINDOWS_2003; } else if (memcmp(&size, "\x28\x03", 2) == 0) { dbprint("--OS Guess: Windows Vista\n"); return VMI_OS_WINDOWS_VISTA; } else if (memcmp(&size, "\x30\x03", 2) == 0) { dbprint("--OS Guess: Windows 2008\n"); return VMI_OS_WINDOWS_2008; } else if (memcmp(&size, "\x40\x03", 2) == 0) { dbprint("--OS Guess: Windows 7\n"); return VMI_OS_WINDOWS_7; } else { dbprint("--OS Guess: Unknown (0x%.4x)\n", size); return VMI_OS_WINDOWS_UNKNOWN; } }
static event_response_t file_name_cb(drakvuf_t drakvuf, drakvuf_trap_info_t *info) { vmi_instance_t vmi = drakvuf_lock_and_get_vmi(drakvuf); struct file_watch *watch = (struct file_watch*)info->trap->data; filetracer *f = watch->f; if (info->trap_pa == watch->file_name_buffer) { addr_t file_name = 0; uint16_t length = 0; vmi_read_addr_pa(vmi, watch->file_name_buffer, &file_name); vmi_read_16_pa(vmi, watch->file_name_length, &length); //printf("File name @ 0x%lx. Length: %u\n", file_name, length); if (file_name && length > 0 && length < VMI_PS_4KB) { char *procname = drakvuf_get_current_process_name(drakvuf, info->vcpu, info->regs); unicode_string_t str = { .contents = NULL }; str.length = length; str.encoding = "UTF-16"; str.contents = (unsigned char *)g_malloc0(length); vmi_read_va(vmi, file_name, 0, str.contents, length); unicode_string_t str2 = { .contents = NULL }; status_t rc = vmi_convert_str_encoding(&str, &str2, "UTF-8"); if (VMI_SUCCESS == rc) { switch(f->format) { case OUTPUT_CSV: printf("filetracer,%" PRIu32 ",0x%" PRIx64 ",%s,%s\n", info->vcpu, info->regs->cr3, procname, str2.contents); break; default: case OUTPUT_DEFAULT: printf("[FILETRACER] VCPU:%" PRIu32 " CR3:0x%" PRIx64 ",%s %s\n", info->vcpu, info->regs->cr3, procname, str2.contents); break; }; g_free(str2.contents); } free(str.contents); free(procname); //printf("Requesting to free writetrap @ %p\n", info->trap); info->trap->data=f; drakvuf_remove_trap(drakvuf, info->trap, free_writetrap); }
void carve_file_from_memory(drakvuf_t *drakvuf, addr_t ph_base, addr_t block_size) { addr_t aligned_file_size = struct_sizes[FILE_OBJECT]; if(PM2BIT(drakvuf->pm) == BIT32) { // 8-byte alignment on 32-bit mode if(struct_sizes[FILE_OBJECT] % 8) { aligned_file_size += 8 - (struct_sizes[FILE_OBJECT] % 8); } } else { // 16-byte alignment on 64-bit mode if(struct_sizes[FILE_OBJECT] % 16) { aligned_file_size += 16 - (struct_sizes[FILE_OBJECT] % 16); } } addr_t file_base = ph_base + block_size - aligned_file_size; addr_t file_name = file_base + offsets[FILE_OBJECT_FILENAME]; addr_t file_name_str = 0; uint16_t length = 0; vmi_read_addr_pa(drakvuf->vmi, file_name + offsets[UNICODE_STRING_BUFFER], &file_name_str); vmi_read_16_pa(drakvuf->vmi, file_name + offsets[UNICODE_STRING_LENGTH], &length); if (file_name_str && length) { unicode_string_t str = { .contents = NULL }; str.length = length; str.encoding = "UTF-16"; str.contents = malloc(length); vmi_read_va(drakvuf->vmi, file_name, 0, str.contents, length); unicode_string_t str2 = { .contents = NULL }; status_t rc = vmi_convert_str_encoding(&str, &str2, "UTF-8"); if (VMI_SUCCESS == rc) { PRINT_DEBUG("\tFile closing: %s.\n", str2.contents); volatility_extract_file(drakvuf, file_base); g_free(str2.contents); } free(str.contents); }
// Idea from http://gleeda.blogspot.com/2010/12/identifying-memory-images.html win_ver_t find_windows_version( vmi_instance_t vmi, addr_t kdbg) { windows_instance_t windows = NULL; if (vmi->os_data == NULL) { return VMI_OS_WINDOWS_UNKNOWN; } windows = vmi->os_data; // no need to repeat this work if we already have the answer if (windows->version && windows->version != VMI_OS_WINDOWS_UNKNOWN) { return windows->version; } win_ver_t version = VMI_OS_WINDOWS_UNKNOWN; vmi_read_16_pa(vmi, kdbg + 0x14, (uint16_t*)&version); // Check if it's a version we know about. // The known KDBG magic values are defined in win_ver_t switch (version) { case VMI_OS_WINDOWS_2000: case VMI_OS_WINDOWS_XP: case VMI_OS_WINDOWS_2003: case VMI_OS_WINDOWS_VISTA: case VMI_OS_WINDOWS_2008: case VMI_OS_WINDOWS_7: case VMI_OS_WINDOWS_8: break; default: version = VMI_OS_WINDOWS_UNKNOWN; break; } return version; }
// Idea from http://gleeda.blogspot.com/2010/12/identifying-memory-images.html void find_windows_version (vmi_instance_t vmi, addr_t KdVersionBlock) { // no need to repeat this work if we already have the answer if (vmi->os.windows_instance.version && vmi->os.windows_instance.version != VMI_OS_WINDOWS_UNKNOWN){ return; } // go find the answer and store it in vmi uint16_t size = 0; vmi_read_16_pa(vmi, KdVersionBlock + 0x14, &size); if (memcmp(&size, "\x08\x02", 2) == 0){ dbprint("--OS Guess: Windows 2000\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_2000; } else if (memcmp(&size, "\x90\x02", 2) == 0){ dbprint("--OS Guess: Windows XP\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_XP; } else if (memcmp(&size, "\x18\x03", 2) == 0){ dbprint("--OS Guess: Windows 2003\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_2003; } else if (memcmp(&size, "\x28\x03", 2) == 0){ dbprint("--OS Guess: Windows Vista\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_VISTA; } else if (memcmp(&size, "\x30\x03", 2) == 0){ dbprint("--OS Guess: Windows 2008\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_2008; } else if (memcmp(&size, "\x40\x03", 2) == 0){ dbprint("--OS Guess: Windows 7\n"); vmi->os.windows_instance.version = VMI_OS_WINDOWS_7; } else{ dbprint("--OS Guess: Unknown (0x%.4x)\n", size); vmi->os.windows_instance.version = VMI_OS_WINDOWS_UNKNOWN; } }
static status_t init_from_rekall_profile(vmi_instance_t vmi) { status_t ret = VMI_FAILURE; windows_instance_t windows = vmi->os_data; dbprint(VMI_DEBUG_MISC, "**Trying to init from Rekall profile\n"); reg_t kpcr = 0; addr_t kpcr_rva = 0; // try to find the kernel if we are not connecting to a file and the kernel pa/va were not already specified. if(vmi->mode != VMI_FILE && ! ( windows->ntoskrnl && windows->ntoskrnl_va ) ) { switch ( vmi->page_mode ) { case VMI_PM_IA32E: if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, GS_BASE, 0)) goto done; break; case VMI_PM_LEGACY: /* Fall-through */ case VMI_PM_PAE: if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, FS_BASE, 0)) goto done; break; default: goto done; }; if (VMI_SUCCESS == rekall_profile_symbol_to_rva(windows->rekall_profile, "KiInitialPCR", NULL, &kpcr_rva)) { if ( kpcr <= kpcr_rva || vmi->page_mode == VMI_PM_IA32E && kpcr < 0xffff800000000000 ) { dbprint(VMI_DEBUG_MISC, "**vCPU0 doesn't seem to have KiInitialPCR mapped, can't init from Rekall profile.\n"); goto done; } // If the Rekall profile has KiInitialPCR we have Win 7+ windows->ntoskrnl_va = kpcr - kpcr_rva; windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va); } else if(kpcr == 0x00000000ffdff000) { // If we are in live mode without KiInitialPCR, the KPCR has to be // at this VA (XP/Vista) and the KPCR trick [1] is still valid. // [1] http://moyix.blogspot.de/2008/04/finding-kernel-global-variables-in.html addr_t kdvb = 0, kdvb_offset = 0, kernbase_offset = 0; rekall_profile_symbol_to_rva(windows->rekall_profile, "_KPCR", "KdVersionBlock", &kdvb_offset); rekall_profile_symbol_to_rva(windows->rekall_profile, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset); vmi_read_addr_va(vmi, kpcr+kdvb_offset, 0, &kdvb); vmi_read_addr_va(vmi, kdvb+kernbase_offset, 0, &windows->ntoskrnl_va); windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va); } else { goto done; } dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl); /* * If the CR3 value points to a pagetable that hasn't been setup yet * we need to resort to finding a valid pagetable the old fashioned way. */ if (windows->ntoskrnl_va && !windows->ntoskrnl) { windows_find_cr3(vmi); windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va); } } // This could happen if we are in file mode or for Win XP if (!windows->ntoskrnl) { windows->ntoskrnl = get_ntoskrnl_base(vmi, vmi->kpgd); // get KdVersionBlock/"_DBGKD_GET_VERSION64"->KernBase addr_t kdvb = 0, kernbase_offset = 0; rekall_profile_symbol_to_rva(windows->rekall_profile, "KdVersionBlock", NULL, &kdvb); rekall_profile_symbol_to_rva(windows->rekall_profile, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset); dbprint(VMI_DEBUG_MISC, "**KdVersionBlock RVA 0x%lx. KernBase RVA: 0x%lx\n", kdvb, kernbase_offset); dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl); if (windows->ntoskrnl && kdvb && kernbase_offset) { vmi_read_addr_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, &windows->ntoskrnl_va); if(!windows->ntoskrnl_va) { vmi_read_32_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, (uint32_t*)&windows->ntoskrnl_va); } if(!windows->ntoskrnl_va) { dbprint(VMI_DEBUG_MISC, "**failed to find Windows kernel VA via KdVersionBlock\n"); goto done; } } else { dbprint(VMI_DEBUG_MISC, "**Failed to find required offsets and/or kernel base PA\n"); goto done; } } dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va); addr_t ntbuildnumber_rva; uint16_t ntbuildnumber = 0; // Let's do some sanity checking if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "NtBuildNumber", NULL, &ntbuildnumber_rva)) { goto done; } if (VMI_FAILURE == vmi_read_16_pa(vmi, windows->ntoskrnl + ntbuildnumber_rva, &ntbuildnumber)) { goto done; } if (ntbuild2version(ntbuildnumber) == VMI_OS_WINDOWS_UNKNOWN) { dbprint(VMI_DEBUG_MISC, "Unknown Windows NtBuildNumber: %u, the Rekall Profile may be incorrect for this Windows!\n", ntbuildnumber); } // The system map seems to be good, lets grab all the required offsets if(!windows->pdbase_offset) { if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_KPROCESS", "DirectoryTableBase", &windows->pdbase_offset)) { goto done; } } if(!windows->tasks_offset) { if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "ActiveProcessLinks", &windows->tasks_offset)) { goto done; } } if(!windows->pid_offset) { if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "UniqueProcessId", &windows->pid_offset)) { goto done; } } if(!windows->pname_offset) { if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "ImageFileName", &windows->pname_offset)) { goto done; } } ret = VMI_SUCCESS; dbprint(VMI_DEBUG_MISC, "**init from Rekall profile success\n"); done: return ret; }
static status_t init_from_sysmap(vmi_instance_t vmi) { status_t ret = VMI_FAILURE; windows_instance_t windows = vmi->os_data; dbprint(VMI_DEBUG_MISC, "**Trying to init from sysmap\n"); reg_t kpcr = 0; addr_t kpcr_rva = 0; if(vmi->mode != VMI_FILE) { if (vmi->page_mode == VMI_PM_IA32E) { if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, GS_BASE, 0)) { goto done; } } else if (vmi->page_mode == VMI_PM_LEGACY || vmi->page_mode == VMI_PM_PAE) { if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, FS_BASE, 0)) { goto done; } } if (VMI_SUCCESS == windows_system_map_symbol_to_address(vmi, "KiInitialPCR", NULL, &kpcr_rva)) { // If the sysmap has KiInitialPCR we have Win 7+ windows->ntoskrnl_va = kpcr - kpcr_rva; windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va); } else if(kpcr == 0x00000000ffdff000) { // If we are in live mode without KiInitialPCR, the KPCR has to be // at this VA (XP/Vista) and the KPCR trick [1] is still valid. // [1] http://moyix.blogspot.de/2008/04/finding-kernel-global-variables-in.html addr_t kdvb = 0, kdvb_offset = 0, kernbase_offset = 0; windows_system_map_symbol_to_address(vmi, "_KPCR", "KdVersionBlock", &kdvb_offset); windows_system_map_symbol_to_address(vmi, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset); vmi_read_addr_va(vmi, kpcr+kdvb_offset, 0, &kdvb); vmi_read_addr_va(vmi, kdvb+kernbase_offset, 0, &windows->ntoskrnl_va); windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va); } else { goto done; } dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl); } // This could happen if we are in file mode or for Win XP if (!windows->ntoskrnl) { windows->ntoskrnl = get_ntoskrnl_base(vmi, vmi->kpgd); // get KdVersionBlock/"_DBGKD_GET_VERSION64"->KernBase addr_t kdvb = 0, kernbase_offset = 0; windows_system_map_symbol_to_address(vmi, "KdVersionBlock", NULL, &kdvb); windows_system_map_symbol_to_address(vmi, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset); dbprint(VMI_DEBUG_MISC, "**KdVersionBlock RVA 0x%lx. KernBase RVA: 0x%lx\n", kdvb, kernbase_offset); dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl); if (windows->ntoskrnl && kdvb && kernbase_offset) { vmi_read_addr_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, &windows->ntoskrnl_va); if(!windows->ntoskrnl_va) { vmi_read_32_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, (uint32_t*)&windows->ntoskrnl_va); } if(!windows->ntoskrnl_va) { dbprint(VMI_DEBUG_MISC, "**failed to find Windows kernel VA via KdVersionBlock\n"); goto done; } } else { dbprint(VMI_DEBUG_MISC, "**Failed to find required offsets and/or kernel base PA\n"); goto done; } } dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va); addr_t ntbuildnumber_rva; uint16_t ntbuildnumber = 0; // Let's do some sanity checking if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "NtBuildNumber", NULL, &ntbuildnumber_rva)) { goto done; } if (VMI_FAILURE == vmi_read_16_pa(vmi, windows->ntoskrnl + ntbuildnumber_rva, &ntbuildnumber)) { goto done; } if (ntbuild2version(ntbuildnumber) == VMI_OS_WINDOWS_UNKNOWN) { dbprint(VMI_DEBUG_MISC, "Unknown Windows NtBuildNumber: %u. The Rekall Profile may be incorrect for this Windows!\n", ntbuildnumber); goto done; } // The system map seems to be good, lets grab all the required offsets if(!windows->pdbase_offset) { if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_KPROCESS", "DirectoryTableBase", &windows->pdbase_offset)) { goto done; } } if(!windows->tasks_offset) { if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "ActiveProcessLinks", &windows->tasks_offset)) { goto done; } } if(!windows->pid_offset) { if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "UniqueProcessId", &windows->pid_offset)) { goto done; } } if(!windows->pname_offset) { if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "ImageFileName", &windows->pname_offset)) { goto done; } } ret = VMI_SUCCESS; dbprint(VMI_DEBUG_MISC, "**init from sysmap success\n"); done: return ret; }