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; }
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; }
/* * This functions is responsible for setting up * Windows specific variables: * - ntoskrnl (*) * - ntoskrnl_va (*) * - kdbg_offset (*) * - kdbg_va (*) * The variables marked with (*) can be also specified * in the libvmi config. */ status_t init_from_kdbg( vmi_instance_t vmi) { status_t ret = VMI_FAILURE; addr_t kernbase_pa = 0; addr_t kernbase_va = 0; addr_t kdbg_pa = 0; if (vmi->os_data == NULL) { goto exit; } windows_instance_t windows = vmi->os_data; /* If all 3 values are specified in the config, we can calculate ntoskrnl_va, * but can't verify if there is no arch for doing translations. */ if (windows->kdbg_va && windows->kdbg_offset && windows->ntoskrnl && !vmi->arch_interface) { /* All values were user specified, so set them, but we can't use * translations to verify them */ windows->ntoskrnl_va = windows->kdbg_va - windows->kdbg_offset; goto done; } if (!vmi->arch_interface) { /* nothing that requires a virtual-to-physical translation will work * so skip straight to the physical only methods. */ goto find_kdbg; } /* Otherwise, look up what we need and check for consistency */ if (windows->kdbg_va) { dbprint(VMI_DEBUG_MISC, "**using KdDebuggerDataBlock address=0x%"PRIx64" from config\n", windows->kdbg_va); if (VMI_SUCCESS != windows_kdbg_lookup(vmi, "KernBase", &windows->ntoskrnl_va)) { dbprint(VMI_DEBUG_MISC, "**Error reading KernBase value, falling back to search methods\n"); goto find_kdbg; } dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va); if (windows->kdbg_offset) { /* only needed ntoskrnl_va, verify the other values */ if (windows->kdbg_va != (windows->ntoskrnl_va + windows->kdbg_offset)) { errprint("Invalid configuration values for win_kdvb and win_kdbg\n"); goto exit; } } else { windows->kdbg_offset = windows->kdbg_va - windows->ntoskrnl_va; } } else if (windows->ntoskrnl && windows->kdbg_offset) { /* Calculate ntoskrnl_va and kdbg_va */ unsigned long offset = 0; kdbg_symbol_offset("KernBase", &offset); if (VMI_FAILURE == vmi_read_addr_pa(vmi, windows->ntoskrnl + windows->kdbg_offset + offset, &windows->ntoskrnl_va)) { errprint("Inconsistent addresses passed in the config!\n"); goto exit; } dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va); windows->kdbg_va = windows->ntoskrnl_va - windows->kdbg_offset; dbprint(VMI_DEBUG_MISC, "**set KdDebuggerDataBlock address=0x%"PRIx64"\n", windows->kdbg_va); } else { /* only ntoskrnl or kdbg_offset were given, which are not * enough to find and calculate the others, so fall back to search methods. */ goto find_kdbg; } addr_t test = 0; if (!windows->ntoskrnl) { if ( VMI_FAILURE == vmi_translate_kv2p(vmi, windows->ntoskrnl_va, &windows->ntoskrnl) ) goto find_kdbg; dbprint(VMI_DEBUG_MISC, "**set KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl); } else if (VMI_FAILURE == vmi_translate_kv2p(vmi, windows->ntoskrnl_va, &test) || test != windows->ntoskrnl) { errprint("Invalid configuration values, win_ntoskrnl not match translated KernBase physical address\n"); goto exit; } goto done; // We don't have the standard config informations // so lets try our kdbg search method find_kdbg: dbprint(VMI_DEBUG_MISC, "**Attempting KdDebuggerDataBlock search methods\n"); if (VMI_SUCCESS == find_kdbg_address_instant(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) { goto found; } if (VMI_SUCCESS == find_kdbg_address_faster(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) { goto found; } if (VMI_SUCCESS == find_kdbg_address_fast(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) { goto found; } /* NOTE: This is the only method that does anything for VMI_FILE */ if (VMI_SUCCESS == find_kdbg_address(vmi, &kdbg_pa, &kernbase_va)) { kernbase_pa = get_ntoskrnl_base(vmi, 0); goto found; } dbprint(VMI_DEBUG_MISC, "**All KdDebuggerDataBlock search methods failed\n"); goto exit; found: windows->ntoskrnl_va = kernbase_va; dbprint(VMI_DEBUG_MISC, "**set KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va); if (!windows->ntoskrnl) { windows->ntoskrnl = kernbase_pa; printf("LibVMI Suggestion: set win_ntoskrnl=0x%"PRIx64" in libvmi.conf for faster startup.\n", windows->ntoskrnl); } else if (windows->ntoskrnl != kernbase_pa) { errprint("LibVMI found physical kernel base address 0x%"PRIx64" that conflicts with provided value from config file!\n", kernbase_pa); goto exit; } if (!windows->kdbg_offset) { windows->kdbg_offset = kdbg_pa - windows->ntoskrnl; printf("LibVMI Suggestion: set win_kdbg=0x%"PRIx64" in libvmi.conf for faster startup.\n", windows->kdbg_offset); } else if (windows->kdbg_offset != kdbg_pa - kernbase_pa) { errprint("LibVMI found win_kdbg offset 0x%"PRIx64" that conflicts with provided value from config file!\n", kdbg_pa - kernbase_pa); goto exit; } if (!windows->kdbg_va) { windows->kdbg_va = windows->ntoskrnl_va + windows->kdbg_offset; printf("LibVMI Suggestion: set win_kdvb=0x%"PRIx64" in libvmi.conf for faster startup.\n", windows->kdbg_va); } else if (windows->kdbg_va != windows->ntoskrnl_va + windows->kdbg_offset) { errprint("LibVMI found win_kdvb offset 0x%"PRIx64" that conflicts with provided value from config file!\n", windows->ntoskrnl_va + windows->kdbg_offset); goto exit; } done: if (!kdbg_pa) { kdbg_pa = windows->ntoskrnl + windows->kdbg_offset; } windows->version = find_windows_version(vmi, kdbg_pa); if (VMI_OS_WINDOWS_UNKNOWN == windows->version) { errprint("Unsupported Windows version or incorrect configuration\n"); } ret = VMI_SUCCESS; exit: return ret; }