static addr_t find_kdversionblock_address_fast( vmi_instance_t vmi) { // Note: this function has several limitations: // -the KD version block signature cannot cross block (frame) boundaries // -reading PA 0 fails; hope the KD version block is not in frame 0 // // Todo: // -support matching across frames (can this happen in windows?) addr_t kdvb_address = 0; addr_t block_pa = 0; addr_t memsize = vmi_get_memsize(vmi); size_t read = 0; void *bm = 0; // boyer-moore internal state int find_ofs = 0; #define BLOCK_SIZE 1024 * 1024 * 1 unsigned char haystack[BLOCK_SIZE]; if (VMI_PM_IA32E == vmi->page_mode) { bm = boyer_moore_init("\x00\xf8\xff\xffKDBG", 8); find_ofs = 0xc; } else { bm = boyer_moore_init("\x00\x00\x00\x00\x00\x00\x00\x00KDBG", 12); find_ofs = 0x8; } // if-else for (block_pa = 4096; block_pa < memsize; block_pa += BLOCK_SIZE) { read = vmi_read_pa(vmi, block_pa, haystack, BLOCK_SIZE); if (BLOCK_SIZE != read) { continue; } int match_offset = boyer_moore2(bm, haystack, BLOCK_SIZE); if (-1 != match_offset) { kdvb_address = block_pa + (unsigned int) match_offset - find_ofs; break; } // if } // outer for if (kdvb_address) dbprint("--Found KD version block at PA %.16"PRIx64"\n", kdvb_address); boyer_moore_fini(bm); return kdvb_address; }
int find_pname_offset( vmi_instance_t vmi, check_magic_func check) { addr_t block_pa = 0; addr_t offset = 0; uint32_t value = 0; void *bm = 0; bm = boyer_moore_init((unsigned char *)"Idle", 4); #define BLOCK_SIZE 1024 * 1024 * 1 unsigned char block_buffer[BLOCK_SIZE]; if (NULL == check) { check = get_check_magic_func(vmi); } for (block_pa = 4096; block_pa + BLOCK_SIZE < vmi->max_physical_address; block_pa += BLOCK_SIZE) { if ( VMI_FAILURE == vmi_read_pa(vmi, block_pa, BLOCK_SIZE, block_buffer, NULL) ) { continue; } for (offset = 0; offset < BLOCK_SIZE; offset += 8) { memcpy(&value, block_buffer + offset, 4); if (check(value)) { // look for specific magic # dbprint (VMI_DEBUG_MISC, "--%s: found magic value 0x%.8"PRIx32" @ offset 0x%.8"PRIx64"\n", __FUNCTION__, value, block_pa + offset); unsigned char haystack[0x500]; if ( VMI_FAILURE == vmi_read_pa(vmi, block_pa + offset, 0x500, haystack, NULL) ) { continue; } int i = boyer_moore2(bm, haystack, 0x500); if (-1 == i) { continue; } else { vmi->init_task = block_pa + offset; dbprint (VMI_DEBUG_MISC, "--%s: found Idle process at 0x%.8"PRIx64" + 0x%x\n", __FUNCTION__, block_pa + offset, i); boyer_moore_fini(bm); return i; } } } } boyer_moore_fini(bm); return 0; }
status_t find_kdbg_address_faster( vmi_instance_t vmi, addr_t *kdbg_pa, addr_t *kernel_pa, addr_t *kernel_va) { dbprint(VMI_DEBUG_MISC, "**Trying find_kdbg_address_faster\n"); status_t ret = VMI_FAILURE; // This scan requires the location of the KPCR // which we get from the GS/FS register on live machines. // For file mode this needs to be further investigated. if (VMI_FILE == vmi->mode) { return ret; } void *bm = boyer_moore_init((unsigned char *)"KDBG", 4); int find_ofs = 0x10; reg_t cr3 = 0, fsgs = 0; if (VMI_FAILURE == driver_get_vcpureg(vmi, &cr3, CR3, 0)) { goto done; } switch ( vmi->page_mode ) { case VMI_PM_IA32E: if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, GS_BASE, 0)) goto done; break; case VMI_PM_LEGACY: /* Fall-through */ case VMI_PM_PAE: if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, FS_BASE, 0)) goto done; break; default: goto done; }; // We start the search from the KPCR, which has to be mapped into the kernel. // We further know that the Windows kernel is page aligned // so we are just checking if the page has a valid PE header // and if the first item in the export table is "ntoskrnl.exe". // Once the kernel is found, we find the .data section // and limit the string search for "KDBG" into that region. // start searching at the lower part from the kpcr // then switch to the upper part if needed int step = -VMI_PS_4KB; addr_t page_paddr; access_context_t ctx = { .translate_mechanism = VMI_TM_NONE, }; scan: if ( VMI_FAILURE == vmi_pagetable_lookup(vmi, cr3, fsgs, &page_paddr) ) goto done; page_paddr &= ~VMI_BIT_MASK(0,11); for (; page_paddr + step < vmi->max_physical_address; page_paddr += step) { uint8_t page[VMI_PS_4KB]; ctx.addr = page_paddr; status_t rc = peparse_get_image(vmi, &ctx, VMI_PS_4KB, page); if (VMI_FAILURE == rc) { continue; } struct pe_header *pe_header = NULL; struct dos_header *dos_header = NULL; void *optional_pe_header = NULL; uint16_t optional_header_type = 0; struct export_table et; peparse_assign_headers(page, &dos_header, &pe_header, &optional_header_type, &optional_pe_header, NULL, NULL); addr_t export_header_offset = peparse_get_idd_rva(IMAGE_DIRECTORY_ENTRY_EXPORT, &optional_header_type, optional_pe_header, NULL, NULL); if (!export_header_offset || page_paddr + export_header_offset >= vmi->max_physical_address) continue; if ( VMI_SUCCESS == vmi_read_pa(vmi, page_paddr + export_header_offset, sizeof(struct export_table), &et, NULL)) { if ( !(et.export_flags || !et.name) && page_paddr + et.name + 12 >= vmi->max_physical_address) continue; unsigned char name[13] = {0}; if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr + et.name, 12, name, NULL) ) continue; if (strcmp("ntoskrnl.exe", (const char *)name)) { continue; } } else { continue; } uint32_t c; for (c=0; c < pe_header->number_of_sections; c++) { struct section_header section; addr_t section_addr = page_paddr + dos_header->offset_to_pe + sizeof(struct pe_header) + pe_header->size_of_optional_header + c*sizeof(struct section_header); // Read the section header from memory if ( VMI_FAILURE == vmi_read_pa(vmi, section_addr, sizeof(struct section_header), (uint8_t *)§ion, NULL) ) continue; // .data check if (memcmp(section.short_name, "\x2E\x64\x61\x74\x61", 5) != 0) { continue; } uint8_t *haystack = alloca(section.size_of_raw_data); if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr + section.virtual_address, section.size_of_raw_data, haystack, NULL) ) continue; int match_offset = boyer_moore2(bm, haystack, section.size_of_raw_data); if (-1 != match_offset) { // We found the structure, but let's verify it. // The kernel is always mapped into VA at the same offset // it is found on physical memory + the kernel boundary. // Read "KernBase" from the haystack uint64_t *kernbase = (uint64_t *)&haystack[(unsigned int) match_offset + sizeof(uint64_t)]; int zeroes = __builtin_clzll(page_paddr); if ((*kernbase) << zeroes == page_paddr << zeroes) { *kernel_pa = page_paddr; *kernel_va = *kernbase; *kdbg_pa = page_paddr + section.virtual_address + (unsigned int) match_offset - find_ofs; ret = VMI_SUCCESS; dbprint(VMI_DEBUG_MISC, "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa); goto done; } else { dbprint(VMI_DEBUG_MISC, "--WARNING: KernBase in KdDebuggerDataBlock at PA %.16"PRIx64" doesn't point back to this page.\n", page_paddr + section.virtual_address + (unsigned int) match_offset - find_ofs); } } break; } } if (step<0) { step = VMI_PS_4KB; goto scan; } done: boyer_moore_fini(bm); return ret; }
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; }
status_t find_kdbg_address( vmi_instance_t vmi, addr_t *kdbg_pa, addr_t *kernel_va) { dbprint(VMI_DEBUG_MISC, "**Trying find_kdbg_address\n"); status_t ret = VMI_FAILURE; *kdbg_pa = 0; addr_t paddr = 0; unsigned char haystack[VMI_PS_4KB]; addr_t memsize = vmi_get_max_physical_address(vmi); void *bm64 = boyer_moore_init((unsigned char *)"\x00\xf8\xff\xffKDBG", 8); void *bm32 = boyer_moore_init((unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00KDBG", 12); uint32_t find_ofs_64 = 0xc, find_ofs_32 = 0x8, find_ofs = 0; for (; paddr<memsize; paddr+=VMI_PS_4KB) { find_ofs = 0; if (VMI_FAILURE == vmi_read_pa(vmi, paddr, VMI_PS_4KB, &haystack, NULL)) continue; int match_offset = boyer_moore2(bm64, haystack, VMI_PS_4KB); if (-1 != match_offset) { find_ofs = find_ofs_64; } else { match_offset = boyer_moore2(bm32, haystack, VMI_PS_4KB); } if (-1 != match_offset) { if (!find_ofs) { find_ofs = find_ofs_32; } // Read "KernBase" from the haystack long unsigned int kernbase_offset = 0; kdbg_symbol_offset("KernBase", &kernbase_offset); if ( match_offset - find_ofs + kernbase_offset + sizeof(uint64_t) >= VMI_PS_4KB ) continue; memcpy(kernel_va, &haystack[(unsigned int) match_offset - find_ofs + kernbase_offset], sizeof(uint64_t)); *kdbg_pa = paddr + (unsigned int) match_offset - find_ofs; ret = VMI_SUCCESS; break; } } dbprint(VMI_DEBUG_MISC, "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa); boyer_moore_fini(bm32); boyer_moore_fini(bm64); return ret; }
int find_pname_offset( vmi_instance_t vmi, check_magic_func check) { addr_t block_pa = 0; addr_t offset = 0; uint32_t value = 0; size_t read = 0; void *bm = 0; bm = boyer_moore_init("Idle", 4); #define BLOCK_SIZE 1024 * 1024 * 1 unsigned char block_buffer[BLOCK_SIZE]; if (NULL == check) { check = get_check_magic_func(vmi); } for (block_pa = 4096; block_pa < vmi->size; block_pa += BLOCK_SIZE) { read = vmi_read_pa(vmi, block_pa, block_buffer, BLOCK_SIZE); if (BLOCK_SIZE != read) { continue; } for (offset = 0; offset < BLOCK_SIZE; offset += 8) { memcpy(&value, block_buffer + offset, 4); if (check(value)) { // look for specific magic # dbprint ("--%s: found magic value 0x%.8"PRIx32" @ offset 0x%.8"PRIx64"\n", __FUNCTION__, value, block_pa + offset); unsigned char haystack[0x500]; read = vmi_read_pa(vmi, block_pa + offset, haystack, 0x500); if (0x500 != read) { continue; } int i = boyer_moore2(bm, haystack, 0x500); if (-1 == i) { continue; } else { vmi->init_task = block_pa + offset + vmi->os.windows_instance.tasks_offset; dbprint ("--%s: found Idle process at 0x%.8"PRIx64" + 0x%x\n", __FUNCTION__, block_pa + offset, i); boyer_moore_fini(bm); return i; } } } } boyer_moore_fini(bm); return 0; }