addr_t v2p_ia32e (vmi_instance_t vmi, addr_t dtb, addr_t vaddr, page_info_t *info) { uint64_t pml4e = 0, pdpte = 0, pde = 0, pte = 0; // are we in compatibility mode OR 64-bit mode ??? // validate address based on above (e.g., is it canonical?) // determine what MAXPHYADDR is dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: lookup vaddr = 0x%.16"PRIx64"\n", vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: dtb = 0x%.16"PRIx64"\n", dtb); pml4e = get_pml4e(vmi, vaddr, dtb, &info->l4_a); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pml4e = 0x%.16"PRIx64"\n", pml4e); if (ENTRY_PRESENT(vmi->os_type, pml4e)) { info->l4_v = pml4e; pdpte = get_pdpte_ia32e(vmi, vaddr, pml4e, &info->l3_a); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pdpte = 0x%.16"PRIx64"\n", pdpte); if (ENTRY_PRESENT(vmi->os_type, pdpte)) { info->l3_v = pdpte; if (PAGE_SIZE_FLAG(pdpte)) { // pdpte maps a 1GB page info->paddr = get_gigpage_ia32e(vaddr, pdpte); info->size = VMI_PS_1GB; dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: 1GB page\n"); } else { pde = get_pde_ia32e(vmi, vaddr, pdpte, &info->l2_a); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pde = 0x%.16"PRIx64"\n", pde); } if (ENTRY_PRESENT(vmi->os_type, pde)) { info->l2_v = pde; if (PAGE_SIZE_FLAG(pde)) { // pde maps a 2MB page info->paddr = get_2megpage_ia32e(vaddr, pde); info->size = VMI_PS_2MB; dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: 2MB page\n"); } else { pte = get_pte_ia32e(vmi, vaddr, pde, &info->l1_a); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: pte = 0x%.16"PRIx64"\n", pte); } if (ENTRY_PRESENT(vmi->os_type, pte)) { info->l1_v = pte; info->size = VMI_PS_4KB; info->paddr = get_paddr_ia32e(vaddr, pte); } } } } dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: paddr = 0x%.16"PRIx64"\n", info->paddr); return info->paddr; }
static void extract_ca_file(filedelete* f, drakvuf_t drakvuf, const drakvuf_trap_info_t* info, vmi_instance_t vmi, addr_t control_area, access_context_t* ctx, const char* filename, uint64_t fo_flags) { addr_t subsection = control_area + f->control_area_size; addr_t segment = 0; addr_t test = 0; addr_t test2 = 0; size_t filesize = 0; /* Check whether subsection points back to the control area */ ctx->addr = control_area + f->offsets[CONTROL_AREA_SEGMENT]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &segment) ) return; ctx->addr = segment + f->offsets[SEGMENT_CONTROLAREA]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &test) || test != control_area ) return; ctx->addr = segment + f->offsets[SEGMENT_SIZEOFSEGMENT]; if ( VMI_FAILURE == vmi_read_64(vmi, ctx, &test) ) return; ctx->addr = segment + f->offsets[SEGMENT_TOTALNUMBEROFPTES]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, (uint32_t*)&test2) ) return; if ( test != (test2 * 4096) ) return; const int curr_sequence_number = ++f->sequence_number; char* file = NULL; if ( asprintf(&file, "%s/file.%06d.mm", f->dump_folder, curr_sequence_number) < 0 ) return; FILE* fp = fopen(file, "w"); free(file); if (!fp) return; while (subsection) { /* Check whether subsection points back to the control area */ ctx->addr = subsection + f->offsets[SUBSECTION_CONTROLAREA]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &test) || test != control_area ) break; addr_t base = 0; addr_t start = 0; uint32_t ptes = 0; ctx->addr = subsection + f->offsets[SUBSECTION_SUBSECTIONBASE]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &base) ) break; ctx->addr = subsection + f->offsets[SUBSECTION_PTESINSUBSECTION]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, &ptes) ) break; ctx->addr = subsection + f->offsets[SUBSECTION_STARTINGSECTOR]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, (uint32_t*)&start) ) break; /* * The offset into the file is stored implicitely * based on the PTE's location within the Subsection. */ addr_t subsection_offset = start * 0x200; addr_t ptecount; for (ptecount=0; ptecount < ptes; ptecount++) { addr_t pteoffset = base + f->mmpte_size * ptecount; addr_t fileoffset = subsection_offset + ptecount * 0x1000; addr_t pte = 0; ctx->addr = pteoffset; if ( VMI_FAILURE == vmi_read(vmi, ctx, f->mmpte_size, &pte, NULL) ) break; if ( ENTRY_PRESENT(1, pte) ) { uint8_t page[4096]; if ( VMI_FAILURE == vmi_read_pa(vmi, VMI_BIT_MASK(12,48) & pte, 4096, &page, NULL) ) continue; if ( !fseek ( fp, fileoffset, SEEK_SET ) ) { if ( fwrite(page, 4096, 1, fp) ) filesize = MAX(filesize, fileoffset + 4096); } } } ctx->addr = subsection + f->offsets[SUBSECTION_NEXTSUBSECTION]; if ( !vmi_read_addr(vmi, ctx, &subsection) ) break; } fclose(fp); print_extraction_information(f, drakvuf, info, filename, filesize, fo_flags, curr_sequence_number); save_file_metadata(f, info, curr_sequence_number, control_area, filename, filesize, fo_flags); }
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; }
GSList* get_va_pages_ia32e(vmi_instance_t vmi, addr_t dtb) { GSList *ret = NULL; uint8_t entry_size = 0x8; #define IA32E_ENTRIES_PER_PAGE 0x200 // 0x1000/0x8 uint64_t *pml4_page = malloc(VMI_PS_4KB); addr_t pml4e_location = dtb & VMI_BIT_MASK(12,51); if (VMI_PS_4KB != vmi_read_pa(vmi, pml4e_location, pml4_page, VMI_PS_4KB)) { free(pml4_page); return ret; } uint64_t *pdpt_page = malloc(VMI_PS_4KB); uint64_t *pgd_page = malloc(VMI_PS_4KB); uint64_t *pt_page = malloc(VMI_PS_4KB); uint64_t pml4e_index; for(pml4e_index = 0; pml4e_index < IA32E_ENTRIES_PER_PAGE; pml4e_index++, pml4e_location += entry_size) { uint64_t pml4e_value = pml4_page[pml4e_index]; if(!ENTRY_PRESENT(vmi->os_type, pml4e_value)) { continue; } uint64_t pdpte_location = pml4e_value & VMI_BIT_MASK(12,51); if (VMI_PS_4KB != vmi_read_pa(vmi, pdpte_location, pdpt_page, VMI_PS_4KB)) { continue; } uint64_t pdpte_index; for(pdpte_index = 0; pdpte_index < IA32E_ENTRIES_PER_PAGE; pdpte_index++, pdpte_location++) { uint64_t pdpte_value = pdpt_page[pdpte_index]; if(!ENTRY_PRESENT(vmi->os_type, pdpte_value)) { continue; } if(PAGE_SIZE(pdpte_value)) { page_info_t *info = g_malloc0(sizeof(page_info_t)); info->vaddr = (pml4e_index << 39) | (pdpte_index << 30); info->paddr = get_gigpage_ia32e(info->vaddr, pdpte_value); info->size = VMI_PS_1GB; info->x86_ia32e.pml4e_location = pml4e_location; info->x86_ia32e.pml4e_value = pml4e_value; info->x86_ia32e.pdpte_location = pdpte_location; info->x86_ia32e.pdpte_value = pdpte_value; ret = g_slist_prepend(ret, info); continue; } uint64_t pgd_location = pdpte_value & VMI_BIT_MASK(12,51); if (VMI_PS_4KB != vmi_read_pa(vmi, pgd_location, pgd_page, VMI_PS_4KB)) { continue; } uint64_t pgde_index; for(pgde_index = 0; pgde_index < IA32E_ENTRIES_PER_PAGE; pgde_index++, pgd_location += entry_size) { uint64_t pgd_value = pgd_page[pgde_index]; if(ENTRY_PRESENT(vmi->os_type, pgd_value)) { if(PAGE_SIZE(pgd_value)) { page_info_t *info = g_malloc0(sizeof(page_info_t)); info->vaddr = (pml4e_index << 39) | (pdpte_index << 30) | (pgde_index << 21); info->paddr = get_2megpage_ia32e(info->vaddr, pgd_value); info->size = VMI_PS_2MB; info->x86_ia32e.pml4e_location = pml4e_location; info->x86_ia32e.pml4e_value = pml4e_value; info->x86_ia32e.pdpte_location = pdpte_location; info->x86_ia32e.pdpte_value = pdpte_value; info->x86_ia32e.pgd_location = pgd_location; info->x86_ia32e.pgd_value = pgd_value; ret = g_slist_prepend(ret, info); continue; } uint64_t pte_location = (pgd_value & VMI_BIT_MASK(12,51)); if (VMI_PS_4KB != vmi_read_pa(vmi, pte_location, pt_page, VMI_PS_4KB)) { continue; } uint64_t pte_index; for(pte_index = 0; pte_index < IA32E_ENTRIES_PER_PAGE; pte_index++, pte_location += entry_size) { uint64_t pte_value = pt_page[pte_index]; if(ENTRY_PRESENT(vmi->os_type, pte_value)) { page_info_t *info = g_malloc0(sizeof(page_info_t)); info->vaddr = (pml4e_index << 39) | (pdpte_index << 30) | (pgde_index << 21) | (pte_index << 12); info->paddr = get_paddr_ia32e(info->vaddr, pte_value); info->size = VMI_PS_4KB; info->x86_ia32e.pml4e_location = pml4e_location; info->x86_ia32e.pml4e_value = pml4e_value; info->x86_ia32e.pdpte_location = pdpte_location; info->x86_ia32e.pdpte_value = pdpte_value; info->x86_ia32e.pgd_location = pgd_location; info->x86_ia32e.pgd_value = pgd_value; info->x86_ia32e.pte_location = pte_location; info->x86_ia32e.pte_value = pte_value; ret = g_slist_prepend(ret, info); continue; } } } } } } free(pt_page); free(pgd_page); free(pdpt_page); free(pml4_page); return ret; }
status_t v2p_ia32e (vmi_instance_t vmi, addr_t dtb, addr_t vaddr, page_info_t *info) { status_t status = VMI_FAILURE; // are we in compatibility mode OR 64-bit mode ??? // validate address based on above (e.g., is it canonical?) // determine what MAXPHYADDR is dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: lookup vaddr = 0x%.16"PRIx64"\n", vaddr); dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: dtb = 0x%.16"PRIx64"\n", dtb); status = get_pml4e(vmi, vaddr, dtb, &info->x86_ia32e.pml4e_location, &info->x86_ia32e.pml4e_value); if (status != VMI_SUCCESS) { goto done; } if (!ENTRY_PRESENT(vmi->os_type, info->x86_ia32e.pml4e_value)) { status = VMI_FAILURE; goto done; } status = get_pdpte_ia32e(vmi, vaddr, info->x86_ia32e.pml4e_value, &info->x86_ia32e.pdpte_location, &info->x86_ia32e.pdpte_value); if (status != VMI_SUCCESS) { goto done; } if (!ENTRY_PRESENT(vmi->os_type, info->x86_ia32e.pdpte_value)) { status = VMI_FAILURE; goto done; } if (PAGE_SIZE(info->x86_ia32e.pdpte_value)) { // pdpte maps a 1GB page info->size = VMI_PS_1GB; info->paddr = get_gigpage_ia32e(vaddr, info->x86_ia32e.pdpte_value); status = VMI_SUCCESS; dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: 1GB page\n"); goto done; } status = get_pde_ia32e(vmi, vaddr, info->x86_ia32e.pdpte_value, &info->x86_ia32e.pgd_location, &info->x86_ia32e.pgd_value); if (status != VMI_SUCCESS) { goto done; } if (!ENTRY_PRESENT(vmi->os_type, info->x86_ia32e.pgd_value)) { status = VMI_FAILURE; goto done; } if (PAGE_SIZE(info->x86_ia32e.pgd_value)) { // pde maps a 2MB page info->size = VMI_PS_2MB; info->paddr = get_2megpage_ia32e(vaddr, info->x86_ia32e.pgd_value); status = VMI_SUCCESS; dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: 2MB page\n"); goto done; } status = get_pte_ia32e(vmi, vaddr, info->x86_ia32e.pgd_value, &info->x86_ia32e.pte_location, &info->x86_ia32e.pte_value); if (status != VMI_SUCCESS) { goto done; } if (!ENTRY_PRESENT(vmi->os_type, info->x86_ia32e.pte_value)) { status = VMI_FAILURE; goto done; } info->size = VMI_PS_4KB; info->paddr = get_paddr_ia32e(vaddr, info->x86_ia32e.pte_value); status = VMI_SUCCESS; done: dbprint(VMI_DEBUG_PTLOOKUP, "--PTLookup: paddr = 0x%.16"PRIx64"\n", info->paddr); return status; }