uint64_t get_pdpte_ia32e (vmi_instance_t vmi, addr_t vaddr, uint64_t pml4e) { uint64_t value = 0; addr_t pdpte_address = get_bits_51to12(pml4e) | get_pdpt_index_ia32e(vaddr); dbprint("--PTLookup: pdpte_address = 0x%.16"PRIx64"\n", pdpte_address); vmi_read_64_pa(vmi, pdpte_address, &value); return value; }
uint64_t get_pdpi (vmi_instance_t instance, uint32_t vaddr, uint32_t cr3) { uint64_t value; uint32_t pdpi_entry = get_pdptb(cr3) + pdpi_index(vaddr); dbprint("--PTLookup: pdpi_entry = 0x%.8x\n", pdpi_entry); vmi_read_64_pa(instance, pdpi_entry, &value); return value; }
uint64_t get_pml4e (vmi_instance_t vmi, addr_t vaddr, reg_t cr3) { uint64_t value = 0; addr_t pml4e_address = get_bits_51to12(cr3) | get_pml4_index(vaddr); dbprint("--PTLookup pml4e_address = 0x%.16"PRIx64"\n", pml4e_address); vmi_read_64_pa(vmi, pml4e_address, &value); return value; }
static inline uint64_t get_pte_pae (vmi_instance_t instance, uint32_t vaddr, uint64_t pgd, addr_t *pte_entry) { uint64_t value; *pte_entry = ptba_base_pae(pgd) + pte_index_pae(vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: pte_entry = 0x%.8"PRIx64"\n", *pte_entry); if(VMI_FAILURE == vmi_read_64_pa(instance, *pte_entry, &value)) { value = 0; } return value; }
static inline uint64_t get_pde_ia32e (vmi_instance_t vmi, addr_t vaddr, uint64_t pdpte, addr_t *pde_address) { uint64_t value; *pde_address = get_bits_51to12(pdpte) | get_pd_index_ia32e(vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pde_address = 0x%.16"PRIx64"\n", *pde_address); if(VMI_FAILURE == vmi_read_64_pa(vmi, *pde_address, &value)) { value = 0; } return value; }
static inline uint64_t get_pml4e (vmi_instance_t vmi, addr_t vaddr, reg_t cr3, addr_t *pml4e_address) { uint64_t value; *pml4e_address = get_bits_51to12(cr3) | get_pml4_index(vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup pml4e_address = 0x%.16"PRIx64"\n", *pml4e_address); if(VMI_FAILURE == vmi_read_64_pa(vmi, *pml4e_address, &value)) { value = 0; } return value; }
static inline uint64_t get_pdpi (vmi_instance_t instance, uint32_t vaddr, addr_t dtb, addr_t *pdpi_entry) { uint64_t value; *pdpi_entry = get_pdptb(dtb) + pdpi_index(vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: pdpi_entry = 0x%.16"PRIx64"\n", *pdpi_entry); if(VMI_FAILURE == vmi_read_64_pa(instance, *pdpi_entry, &value)) { value = 0; } return value; }
static inline status_t get_pml4e (vmi_instance_t vmi, addr_t vaddr, reg_t cr3, addr_t *pml4e_address, uint64_t *pml4e_value) { *pml4e_value = 0; *pml4e_address = (cr3 & VMI_BIT_MASK(12,51)) | get_pml4_index(vaddr); if(VMI_FAILURE == vmi_read_64_pa(vmi, *pml4e_address, pml4e_value)) { dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: error reading pml4e_address = 0x%.16"PRIx64"\n", *pml4e_address); return VMI_FAILURE; } dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pml4e_address = 0x%.16"PRIx64"\n", *pml4e_address); return VMI_SUCCESS; }
static inline status_t get_pdpi (vmi_instance_t instance, uint32_t vaddr, addr_t dtb, addr_t *pdpi_entry, uint64_t *pdpi_value) { *pdpi_entry = get_pdptb(dtb) + pdpi_index(vaddr); if(VMI_FAILURE == vmi_read_64_pa(instance, *pdpi_entry, pdpi_value)) { dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: failed to read pdpi_entry = 0x%.16"PRIx64"\n", *pdpi_entry); return VMI_FAILURE; } dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: pdpi_entry = 0x%.16"PRIx64", pdpi_value = 0x%.16"PRIx64"\n", *pdpi_entry, *pdpi_value); return VMI_SUCCESS; }
static inline status_t get_pgd_pae (vmi_instance_t instance, uint32_t vaddr, uint64_t pdpe, addr_t *pgd_entry, addr_t *pgd_value) { *pgd_value = 0; *pgd_entry = pdba_base_pae(pdpe) + pgd_index_pae(vaddr); if(VMI_FAILURE == vmi_read_64_pa(instance, *pgd_entry, pgd_value)) { dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: failed to read pgd_entry = 0x%.8"PRIx64"\n", *pgd_entry); return VMI_FAILURE; } dbprint(VMI_DEBUG_PTLOOKUP, "--PAE PTLookup: pgd_entry = 0x%.8"PRIx64", pgd_value = 0x%.8"PRIx64"\n", *pgd_entry, *pgd_value); return VMI_SUCCESS; }
status_t vmi_read_addr_pa( vmi_instance_t vmi, addr_t paddr, addr_t *value) { if (vmi->page_mode == VMI_PM_IA32E) { return vmi_read_64_pa(vmi, paddr, value); } else { uint32_t tmp = 0; status_t ret = vmi_read_32_pa(vmi, paddr, &tmp); *value = (uint64_t) tmp; return ret; } }
static inline status_t get_pde_ia32e (vmi_instance_t vmi, addr_t vaddr, uint64_t pdpte, addr_t *pde_address, addr_t *pde_value) { *pde_value = 0; *pde_address = (pdpte & VMI_BIT_MASK(12,51)) | get_pd_index_ia32e(vaddr); if(VMI_FAILURE == vmi_read_64_pa(vmi, *pde_address, pde_value)) { dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: failed to read pde_address = 0x%.16"PRIx64"\n", *pde_address); return VMI_FAILURE; } dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pde_address = 0x%.16"PRIx64"pde_value= 0x%.16"PRIx64"\n", *pde_address, *pde_value); return VMI_SUCCESS; }
/* Tries to find the kernel page directory by doing an exhaustive search * through the memory space for the System process. The page directory * location is then pulled from this eprocess struct. */ static status_t get_kpgd_method2( vmi_instance_t vmi) { addr_t sysproc = 0; windows_instance_t windows = NULL; if (vmi->os_data == NULL) { errprint("VMI_ERROR: No OS data initialized\n"); return VMI_FAILURE; } windows = vmi->os_data; sysproc = windows->sysproc; /* get address for System process */ if (!sysproc) { if ((sysproc = windows_find_eprocess(vmi, "System")) == 0) { dbprint(VMI_DEBUG_MISC, "--failed to find System process.\n"); goto error_exit; } printf("LibVMI Suggestion: set win_sysproc=0x%"PRIx64" in libvmi.conf for faster startup.\n", sysproc); } dbprint(VMI_DEBUG_MISC, "--got PA to PsInitialSystemProcess (0x%.16"PRIx64").\n", sysproc); /* Get address for page directory (from system process). We are reading 64-bit value here deliberately as we might not know the page mode yet */ if (VMI_FAILURE == vmi_read_64_pa(vmi, sysproc + windows->pdbase_offset, &vmi->kpgd)) { dbprint(VMI_DEBUG_MISC, "--failed to resolve PD for System process\n"); goto error_exit; } if (!vmi->kpgd) { dbprint(VMI_DEBUG_MISC, "--kpgd was zero\n"); goto error_exit; } if (VMI_FAILURE == vmi_read_64_pa(vmi, sysproc + windows->tasks_offset, &vmi->init_task)) { dbprint(VMI_DEBUG_MISC, "--failed to resolve address of System process\n"); goto error_exit; } vmi->init_task -= windows->tasks_offset; /* If the page mode is already known to be 32-bit we just mask the value here. If don't know the page mode yet it will be determined using heuristics in find_page_mode later. */ switch(vmi->page_mode) { case VMI_PM_LEGACY: case VMI_PM_PAE: { uint32_t mask = ~0; vmi->kpgd &= mask; vmi->init_task &= mask; break; } default: break; } dbprint(VMI_DEBUG_MISC, "**set kpgd (0x%.16"PRIx64").\n", vmi->kpgd); dbprint(VMI_DEBUG_MISC, "**set init_task (0x%.16"PRIx64").\n", vmi->init_task); return VMI_SUCCESS; error_exit: return VMI_FAILURE; }
status_t find_kdbg_address_fast( vmi_instance_t vmi, addr_t *kdbg_pa, addr_t *kernel_pa, addr_t *kernel_va) { dbprint(VMI_DEBUG_MISC, "**Trying find_kdbg_address_fast\n"); status_t ret = VMI_FAILURE; reg_t cr3; if (VMI_FAILURE == driver_get_vcpureg(vmi, &cr3, CR3, 0)) { return ret; } addr_t memsize = vmi_get_max_physical_address(vmi); GSList *va_pages = vmi_get_va_pages(vmi, (addr_t)cr3); void *bm = 0; // boyer-moore internal state unsigned char haystack[VMI_PS_4KB]; int find_ofs = 0; if (VMI_PM_IA32E == vmi->page_mode) { bm = boyer_moore_init((unsigned char *)"\x00\xf8\xff\xffKDBG", 8); find_ofs = 0xc; } else { bm = boyer_moore_init((unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00KDBG", 12); find_ofs = 0x8; } // if-else GSList *va_pages_loop = va_pages; while (va_pages_loop) { page_info_t *vap = (page_info_t *)va_pages_loop->data; // We might get pages that are greater than 4Kb // so we are just going to split them to 4Kb pages while (vap && vap->size >= VMI_PS_4KB) { vap->size -= VMI_PS_4KB; addr_t page_paddr = vap->paddr+vap->size; if (page_paddr + VMI_PS_4KB - 1 > memsize) { continue; } if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr, VMI_PS_4KB, haystack, NULL) ) continue; int match_offset = boyer_moore2(bm, haystack, VMI_PS_4KB); if (-1 != match_offset) { addr_t tmp_kva = 0, tmp_kpa = 0; addr_t tmp_kdbg = page_paddr + (unsigned int) match_offset - find_ofs; if (VMI_FAILURE == vmi_read_64_pa(vmi, tmp_kdbg + sizeof(DBGKD_DEBUG_DATA_HEADER64), &tmp_kva)) { continue; } if ( VMI_FAILURE == vmi_pagetable_lookup(vmi, cr3, tmp_kva, &tmp_kpa) ) continue; *kdbg_pa = tmp_kdbg; *kernel_va = tmp_kva; *kernel_pa = tmp_kpa; ret = VMI_SUCCESS; goto done; } } g_free(vap); va_pages_loop = va_pages_loop->next; } done: // free the rest of the list while (va_pages_loop) { g_free(va_pages_loop->data); va_pages_loop = va_pages_loop->next; } g_slist_free(va_pages); if (VMI_SUCCESS == ret) dbprint(VMI_DEBUG_MISC, "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa); boyer_moore_fini(bm); return ret; }
GSList* get_va_pages_ia32e(vmi_instance_t vmi, addr_t dtb) { GSList *ret = NULL; uint8_t entry_size = 0x8; #define PDES_AND_PTES_PER_PAGE 0x200 // 0x1000/0x8 uint64_t pml4e; for(pml4e=0;pml4e<PDES_AND_PTES_PER_PAGE;pml4e++) { addr_t vaddr = pml4e << 39; addr_t pml4e_a = 0; uint64_t pml4e_value = get_pml4e(vmi, vaddr, dtb, &pml4e_a); if(!ENTRY_PRESENT(vmi->os_type, pml4e_value)) { continue; } uint64_t pdpte; for(pdpte=0;pdpte<PDES_AND_PTES_PER_PAGE;pdpte++) { vaddr = (pml4e << 39) | (pdpte << 30); addr_t pdpte_a = 0; uint64_t pdpte_value = get_pdpte_ia32e(vmi, vaddr, pml4e_value, &pdpte_a); if(!ENTRY_PRESENT(vmi->os_type, pdpte_value)) { continue; } if(PAGE_SIZE_FLAG(pdpte_value)) { page_info_t *p = g_malloc0(sizeof(page_info_t)); p->vaddr = vaddr; p->paddr = get_gigpage_ia32e(vaddr, pdpte_value); p->size = VMI_PS_1GB; p->l4_a = pml4e_a; p->l4_v = pml4e_value; p->l3_a = pdpte_a; p->l3_v = pdpte_value; ret = g_slist_append(ret, p); continue; } uint64_t pgd_curr = pdba_base_ia32e(pdpte_value); uint64_t j; for(j=0;j<PTRS_PER_PAE_PGD;j++,pgd_curr+=entry_size) { uint64_t soffset = vaddr + (j * PTRS_PER_PAE_PGD * PTRS_PER_PAE_PTE * entry_size); uint64_t entry; if(VMI_FAILURE == vmi_read_64_pa(vmi, pgd_curr, &entry)) { continue; } if(ENTRY_PRESENT(vmi->os_type, entry)) { if(PAGE_SIZE_FLAG(entry)) { page_info_t *p = g_malloc0(sizeof(page_info_t)); p->vaddr = soffset; p->paddr = get_2megpage_ia32e(vaddr, entry); p->size = VMI_PS_2MB; p->l4_a = pml4e_a; p->l4_v = pml4e_value; p->l3_a = pdpte_a; p->l3_v = pdpte_value; p->l2_a = pgd_curr; p->l2_v = entry; ret = g_slist_append(ret, p); continue; } uint64_t pte_curr = pte_pfn_ia32e(entry); uint64_t k; for(k=0;k<PTRS_PER_PAE_PTE;k++,pte_curr+=entry_size) { uint64_t pte_entry; if(VMI_FAILURE == vmi_read_64_pa(vmi, pte_curr, &pte_entry)) { continue; } if(ENTRY_PRESENT(vmi->os_type, pte_entry)) { page_info_t *p = g_malloc0(sizeof(page_info_t)); p->vaddr = soffset + k * VMI_PS_4KB; p->paddr = get_paddr_ia32e(vaddr, pte_entry); p->size = VMI_PS_4KB; p->l4_a = pml4e_a; p->l4_v = pml4e_value; p->l3_a = pdpte_a; p->l3_v = pdpte_value; p->l2_a = pgd_curr; p->l2_v = entry; p->l1_a = pte_curr; p->l1_v = pte_entry; ret = g_slist_append(ret, p); continue; } } } } } } return ret; }