event_response_t after_extract_buf(vmi_instance_t vmi, vmi_event_t *event) { printf("Called after_extract_buf!\n"); // read in all the bytes at buf uint8_t buffer[EXTRACT_SIZE]; vmi_read_va(vmi, rng_buf, 0, buffer, EXTRACT_SIZE); printf("old buf: "); for (int i = 0; i < EXTRACT_SIZE; i++) { printf("%02x ",buffer[i]); } printf("\n"); // modify rng buffer! vmi_write_va(vmi, rng_buf , 0, RNG_VALUE, EXTRACT_SIZE); // read in all the bytes at buf again (sanity check) vmi_read_va(vmi, rng_buf, 0, buffer, EXTRACT_SIZE); printf("new buf: "); for (int i = 0; i < EXTRACT_SIZE; i++) { printf("%02x ",buffer[i]); } printf("\n"); return VMI_SUCCESS; }
addr_t eprocess_list_search( vmi_instance_t vmi, addr_t list_head, int offset, size_t len, void *value) { addr_t next_process = 0; addr_t tasks_offset = 0; addr_t rtnval = 0; void *buf = g_malloc0(len); if ( !buf ) goto exit; if ( VMI_FAILURE == vmi_get_offset(vmi, "win_tasks", &tasks_offset) ) goto exit; if ( VMI_FAILURE == vmi_read_addr_va(vmi, list_head + tasks_offset, 0, &next_process) ) goto exit; if ( VMI_FAILURE == vmi_read_va(vmi, list_head + offset, 0, len, buf, NULL) ) goto exit; if (memcmp(buf, value, len) == 0) { rtnval = list_head + tasks_offset; goto exit; } list_head = next_process; while(1) { addr_t tmp_next = 0; if ( VMI_FAILURE == vmi_read_addr_va(vmi, next_process, 0, &tmp_next) ) goto exit; if (list_head == tmp_next) { break; } if ( VMI_FAILURE == vmi_read_va(vmi, next_process + offset - tasks_offset, 0, len, buf, NULL) ) goto exit; if (memcmp(buf, value, len) == 0) { rtnval = next_process; goto exit; } next_process = tmp_next; } exit: g_free(buf); return rtnval; }
event_response_t overwrite_buf(vmi_instance_t vmi, vmi_event_t *event) { printf("Called overwrite_buf!\n"); // local vars addr_t val_addr = 0; uint8_t buf[EXTRACT_SIZE]; // Print everything out //printf("VCPU: %d\n", event->vcpu_id); //printf("Pagetable id: %d\n", event->vmm_pagetable_id); //printf("Instruction pointer: 0x%x\n", event->interrupt_event.gla); //printf("Physical page of instruction: 0x%x\n", event->interrupt_event.gfn); //printf("Page offset: 0x%x\n", event->interrupt_event.offset); //printf("Interrupt type (1 is INT3): %d\n", event->interrupt_event.intr); ////////////////////////// // Access random number // ////////////////////////// // Print amd64 function args --> see below link for reference // https://blogs.oracle.com/eschrock/entry/debugging_://blogs.oracle.com/eschrock/entry/debugging_on_amd64_part_twoon_amd64_part_two printf("Reading RDI register (*r): 0x%llx\n", event->regs.x86->rdi); printf("Reading RSI register (*tmp): 0x%llx\n", event->regs.x86->rsi); printf("Reading RSP+0x16: 0x%llx (should be the same as RSI)\n", event->regs.x86->rsp+0x16); // val_addr is our RSP+0x16 val_addr = event->regs.x86->rsp + 0x16; // what's currently at RSP+0x16? vmi_read_va(vmi, val_addr, 0, buf, EXTRACT_SIZE); printf("old buf: "); for (int i = 0; i < EXTRACT_SIZE; i++) { printf("%02x ",buf[i]); } printf("\n"); // modify rng buffer! (should be at RSP+0x16, from static code analysis) vmi_write_va(vmi, val_addr, 0, RNG_VALUE , EXTRACT_SIZE); // what's at RSP+0x16 now? vmi_read_va(vmi, val_addr, 0, buf, EXTRACT_SIZE); printf("new buf: "); for (int i = 0; i < EXTRACT_SIZE; i++) { printf("%02x ",buf[i]); } printf("\n"); return VMI_SUCCESS; }
END_TEST #if ENABLE_KVM == 1 /* test vmi_get_dgvma */ // we use vmi_read_va() to verify vmi_get_dgvma() START_TEST (test_vmi_get_dgvma) { vmi_instance_t vmi = NULL; vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, get_testvm()); vmi_shm_snapshot_create(vmi); addr_t va = 0x0; size_t count = 4096; unsigned long max_size = 0xffff; void *buf_readva = malloc(count); void *buf_dgvma = NULL; for (; va + count <= max_size; va += count) { size_t read_va = vmi_read_va(vmi, va, 0, buf_readva, count); size_t read_dgvma = vmi_get_dgvma(vmi, va, 0, &buf_dgvma, count); fail_unless(read_va == read_dgvma, "vmi_get_dgvma(0x%"PRIx64 ") read size %d dosn't conform to %d of vmi_read_va()", va, read_dgvma, read_va); int cmp = memcmp(buf_readva, buf_dgvma, read_va); fail_unless(0 == cmp, "vmi_get_dgvma(0x%"PRIx64 ") contents dosn't conform to vmi_read_va()", va); } free(buf_readva); vmi_shm_snapshot_destroy(vmi); vmi_destroy(vmi); }
addr_t eprocess_list_search( vmi_instance_t vmi, int offset, size_t len, void *value) { addr_t next_process, list_head; int tasks_offset; void *buf = malloc(len); addr_t rtnval = 0; tasks_offset = vmi_get_offset(vmi, "win_tasks"); vmi_read_addr_ksym(vmi, "PsInitialSystemProcess", &list_head); vmi_read_addr_va(vmi, list_head + tasks_offset, 0, &next_process); vmi_read_va(vmi, list_head + offset, 0, buf, len); if (memcmp(buf, value, len) == 0) { rtnval = list_head + tasks_offset; goto exit; } list_head = next_process; while(1) { addr_t tmp_next = 0; vmi_read_addr_va(vmi, next_process, 0, &tmp_next); if (list_head == tmp_next) { break; } vmi_read_va(vmi, next_process + offset - tasks_offset, 0, buf, len); if (memcmp(buf, value, len) == 0) { rtnval = next_process; goto exit; } next_process = tmp_next; } exit: free(buf); return rtnval; }
event_response_t bnrand_callback(vmi_instance_t vmi, vmi_event_t *event) { uint64_t nbytes; addr_t buf_addr; uint8_t* buffer; vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->regs.x86->cr3); printf("Called bnrand_callback from pid %d!\n"); // look at args printf("Reading RDI register (*buf): 0x%llx\n", event->regs.x86->rdi); printf("Reading RSI register (bytes): 0x%llx\n", event->regs.x86->rsi); printf("Reading RDX register (*rnd): 0x%llx\n", event->regs.x86->rdx); // read in all the bytes at buf nbytes = event->regs.x86->rsi; buf_addr = event->regs.x86->rdi; buffer = malloc(nbytes); // allocate buffer vmi_read_va(vmi, buf_addr, pid, buffer, nbytes); printf("old buf: "); for (unsigned int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); // modify rng buffer! vmi_write_va(vmi, buf_addr, pid, RNG_VALUE, nbytes); // read in all the bytes at buf again (sanity check) vmi_read_va(vmi, buf_addr, pid, buffer, nbytes); printf("new buf: "); for (unsigned int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); return VMI_SUCCESS; }
size_t vmi_read_ksym( vmi_instance_t vmi, char *sym, void *buf, size_t count) { addr_t vaddr = vmi_translate_ksym2v(vmi, sym); if (0 == vaddr) { dbprint("--%s: vmi_translate_ksym2v failed for '%s'\n", __FUNCTION__, sym); return 0; } return vmi_read_va(vmi, vaddr, 0, buf, count); }
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); }
/////////////////////////////////////////////////////////// // Easy access to virtual memory static status_t vmi_read_X_va( vmi_instance_t vmi, addr_t vaddr, vmi_pid_t pid, void *value, int size) { size_t len_read = vmi_read_va(vmi, vaddr, pid, value, size); if (len_read == size) { return VMI_SUCCESS; } else { return VMI_FAILURE; } }
event_response_t urandom_read_end(vmi_instance_t vmi, vmi_event_t *event) { printf("Called urandom_read_end!\n"); // read in all the bytes at buf uint8_t buffer[nbytes]; vmi_read_va(vmi, rng_buf, 0, buffer, nbytes); printf("buf: "); for (int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); // clear global vars rng_buf = 0; nbytes = 0; return VMI_SUCCESS; }
event_response_t check_buf(vmi_instance_t vmi, vmi_event_t *event) { printf("Called check_buf!\n"); // sanity check if (rng_buf == 0 || nbytes == 0) { printf("We don't have a buf or nbytes! AHHHHHH! 0x%llx %u\n", rng_buf, nbytes); } // read in all the bytes at buf uint8_t buffer[nbytes]; vmi_read_va(vmi, rng_buf, 0, buffer, nbytes); printf("buf: "); for (int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); return VMI_SUCCESS; }
int main( int argc, char **argv) { if ( argc != 3 ) return 1; vmi_instance_t vmi; unsigned char *memory = malloc(PAGE_SIZE); /* this is the VM or file that we are looking at */ char *name = argv[1]; /* this is the address to map */ char *addr_str = argv[2]; addr_t addr = (addr_t) strtoul(addr_str, NULL, 16); /* initialize the libvmi library */ if (VMI_FAILURE == vmi_init_complete(&vmi, name, VMI_INIT_DOMAINNAME, NULL, VMI_CONFIG_GLOBAL_FILE_ENTRY, NULL, NULL)) { printf("Failed to init LibVMI library.\n"); goto error_exit; } /* get the symbol's memory page */ if (VMI_FAILURE == vmi_read_va(vmi, addr, 0, PAGE_SIZE, memory, NULL)) { printf("failed to map memory.\n"); goto error_exit; } vmi_print_hex(memory, PAGE_SIZE); error_exit: if (memory) free(memory); /* cleanup any memory associated with the libvmi instance */ vmi_destroy(vmi); return 0; }
// Helpful resource for describing the Kernel's representation of virtual memory // http://www.seas.ucla.edu/~uentao/spring15/CS33_1A_Week10.1.pdf // More helpful stuff // http://lxr.free-electrons.com/source/include/linux/sched.h#L1378 // http://lxr.free-electrons.com/source/include/linux/mm_types.h#L390 // keep following mm_types -> fs -> path -> dcache addr_t walk_vmmap_for_lib(vmi_instance_t vmi, addr_t proc, char* libname) { // returns base address of first mmap'd occurrence of library // local vars addr_t mm; addr_t mmap; addr_t vm_area_st_itr; addr_t file; addr_t path; addr_t dentry; addr_t iname; addr_t vm_start; char filename[32]; // walk the structs TODO: check each of these dereferences for errors and fail nicely // task_struct->mm->mmap->vm_next->vm_next->vm_next->...->vm_file->path vmi_read_64_va(vmi, proc + mm_offset, 0, &mm); // read address of mm //printf("mm is at 0x%llx\n",mm); vmi_read_64_va(vmi, mm + mmap_offset, 0, &mmap); // read address of first mmap in list //printf("mmap is at 0x%llx\n",mmap); vm_area_st_itr = mmap; // while (vm_area_st_itr != 0) { // iterate over vm_area_structs vmi_read_64_va(vmi, vm_area_st_itr + vm_area_file_offset, 0, &file); // get this struct's file pointer //printf("file is at 0x%llx\n",file); path = file + file_path_offset; // not a pointer, so no need to dereference //printf("path is at 0x%llx\n",path); vmi_read_64_va(vmi, path + dentry_offset, 0, &dentry); // get dentry //printf("dentry is at 0x%llx\n",dentry); iname = dentry + iname_offset; // pointer to filename that was loaded into memory here //printf("iname is at 0x%llx\n",iname); vmi_read_va(vmi, iname, 0, filename, sizeof(filename)); //printf("filename is %s\n",filename); if (strncmp(filename, libname, sizeof(libname)) == 0) { // if we've found the lib vmi_read_64_va(vmi, vm_area_st_itr + vm_area_start_offset, 0, &vm_start); // grab address of start of memory-mapped region //printf("base address of memory is 0x%llx\n", vm_start); return vm_start; } // go to next vmi_read_64_va(vmi, vm_area_st_itr + vm_area_next_offset, 0, &vm_area_st_itr); } return 0; // Failure }
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); }
status_t peparse_get_image_virt( vmi_instance_t vmi, addr_t base_vaddr, vmi_pid_t pid, size_t len, const uint8_t * const image) { uint32_t nbytes = vmi_read_va(vmi, base_vaddr, pid, (void *)image, len); if(nbytes != len) { dbprint(VMI_DEBUG_MISC, "--PEPARSE: failed to read PE header\n"); return VMI_FAILURE; } if(VMI_SUCCESS != peparse_validate_pe_image(image, len)) { dbprint(VMI_DEBUG_MISC, "--PEPARSE: failed to validate PE header(s)\n"); return VMI_FAILURE; } return VMI_SUCCESS; }
static unicode_string_t * vmi_read_win_unicode_struct_va( vmi_instance_t vmi, addr_t vaddr, vmi_pid_t pid) { unicode_string_t *us = 0; // return val size_t struct_size = 0; size_t read = 0; addr_t buffer_va = 0; uint16_t buffer_len = 0; if (VMI_PM_IA32E == vmi_get_page_mode(vmi)) { // 64 bit guest win64_unicode_string_t us64 = { 0 }; struct_size = sizeof(us64); // read the UNICODE_STRING struct read = vmi_read_va(vmi, vaddr, pid, &us64, struct_size); if (read != struct_size) { dbprint ("--%s: failed to read UNICODE_STRING at VA 0x%.16"PRIx64" for pid %d\n", __FUNCTION__, vaddr, pid); goto out_error; } // if buffer_va = us64.pBuffer; buffer_len = us64.length; } else { win32_unicode_string_t us32 = { 0 }; struct_size = sizeof(us32); // read the UNICODE_STRING struct read = vmi_read_va(vmi, vaddr, pid, &us32, struct_size); if (read != struct_size) { dbprint ("--%s: failed to read UNICODE_STRING at VA 0x%.16"PRIx64" for pid %d\n", __FUNCTION__, vaddr, pid); goto out_error; } // if buffer_va = us32.pBuffer; buffer_len = us32.length; } // if-else // allocate the return value us = safe_malloc(sizeof(unicode_string_t)); us->length = buffer_len; us->contents = safe_malloc(sizeof(uint8_t) * (buffer_len + 2)); read = vmi_read_va(vmi, buffer_va, pid, us->contents, us->length); if (read != us->length) { dbprint ("--%s: failed to read buffer at VA 0x%.16"PRIx64" for pid %d\n", __FUNCTION__, buffer_va, pid); goto out_error; } // if // end with NULL (needed?) us->contents[buffer_len] = 0; us->contents[buffer_len + 1] = 0; us->encoding = "UTF-16"; return us; out_error: if (us) { if (us->contents) { free(us->contents); } free(us); } return 0; }
void injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) { struct injector *injector = event->data; addr_t pa = (event->interrupt_event.gfn << 12) + event->interrupt_event.offset; reg_t cr3; vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("INT3 @ 0x%lx. PID %u\n", pa, pid); if (pa == injector->userspace_return) { event->interrupt_event.reinject = 0; if (pid != injector->target_pid) { printf("Userspace return trap hit by another PID, not the target (%u)\n", injector->target_pid); vmi_write_8_pa(vmi, pa, &injector->userspace_return_backup); vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap); return; } injector->target_pid = pid; injector->target_rip = pa; injector->backup = injector->userspace_return_backup; injector->userspace_return = 0; hijack_thread(injector, vmi, event->vcpu_id, pid); /* injector->ss_enabled = 1; memset(&injector->ss_event, 0, sizeof(vmi_event_t)); injector->ss_event.type = VMI_EVENT_SINGLESTEP; injector->ss_event.callback = ss_callback; injector->ss_event.data = injector; SET_VCPU_SINGLESTEP(injector->ss_event.ss_event, event->vcpu_id); vmi_register_event(vmi, &injector->ss_event); */ vmi_clear_event(vmi, &injector->cr3_event); injector->mm_count++; return; } if (pa == injector->target_rip) { event->interrupt_event.reinject = 0; if (pid != injector->target_pid) { printf("Return trap hit by another PID, not the target (%u)\n", injector->target_pid); vmi_write_8_pa(vmi, pa, &injector->backup); vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap); return; } reg_t rax; vmi_get_vcpureg(vmi, &rax, RAX, event->vcpu_id); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("RAX: 0x%lx\n", rax); printf("Restoring RSP to 0x%lx\n", injector->saved_rsp); printf("Restoring RAX to 0x%lx\n", injector->saved_rax); printf("Restoring RCX to 0x%lx\n", injector->saved_rcx); printf("Restoring RDX to 0x%lx\n", injector->saved_rdx); printf("Restoring R8 to 0x%lx\n", injector->saved_r8); printf("Restoring R9 to 0x%lx\n", injector->saved_r9); vmi_set_vcpureg(vmi, injector->saved_rsp, RSP, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rax, RAX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rcx, RCX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rdx, RDX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_r8, R8, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_r9, R9, event->vcpu_id); if (rax) { printf("-- CreateProcessA SUCCESS --\n"); if (PM2BIT(injector->pm) == BIT32) { struct process_information_32 pip; vmi_read_va(vmi, injector->process_info, pid, &pip, sizeof(struct process_information_32)); printf("\tProcess handle: 0x%x. Thread handle: 0x%x\n", pip.hProcess, pip.hThread); printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId); injector->pid = pip.dwProcessId; injector->tid = pip.dwThreadId; injector->hProc = pip.hProcess; injector->hThr = pip.hThread; } else { struct process_information_64 pip; vmi_read_va(vmi, injector->process_info, pid, &pip, sizeof(struct process_information_64)); printf("\tProcess handle: 0x%lx. Thread handle: 0x%lx\n", pip.hProcess, pip.hThread); printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId); injector->pid = pip.dwProcessId; injector->tid = pip.dwThreadId; injector->hProc = pip.hProcess; injector->hThr = pip.hThread; } if (injector->pid && injector->tid) { injector->ret = rax; injector->cr3_event.callback = waitfor_cr3_callback; injector->cr3_event.reg_event.equal = vmi_pid_to_dtb(vmi, injector->pid); injector->cr3_event.data = injector; vmi_register_event(vmi, &injector->cr3_event); printf("\tInjected process CR3: 0x%lx\n", injector->cr3_event.reg_event.equal); } } else { injector->clone->interrupted = 1; } vmi_write_8_pa(vmi, pa, &injector->backup); vmi_clear_event(vmi, event); } else { event->interrupt_event.reinject = 1; } }
status_t peparse_get_export_table( vmi_instance_t vmi, addr_t base_vaddr, vmi_pid_t pid, struct export_table *et, addr_t *export_table_rva, size_t *export_table_size) { // Note: this function assumes a "normal" PE where all the headers are in // the first page of the PE and the field DosHeader.OffsetToPE points to // an address in the first page. addr_t export_header_rva = 0; addr_t export_header_va = 0; size_t export_header_size = 0; size_t nbytes = 0; #define MAX_HEADER_BYTES 1024 // keep under 1 page uint8_t image[MAX_HEADER_BYTES]; if(VMI_FAILURE == peparse_get_image_virt(vmi, base_vaddr, pid, MAX_HEADER_BYTES, image)) { return VMI_FAILURE; } void *optional_header = NULL; uint16_t magic = 0; peparse_assign_headers(image, NULL, NULL, &magic, &optional_header, NULL, NULL); export_header_rva = peparse_get_idd_rva(IMAGE_DIRECTORY_ENTRY_EXPORT, &magic, optional_header, NULL, NULL); export_header_size = peparse_get_idd_size(IMAGE_DIRECTORY_ENTRY_EXPORT, &magic, optional_header, NULL, NULL); if(export_table_rva) { *export_table_rva=export_header_rva; } if(export_table_size) { *export_table_size=export_header_size; } /* Find & read the export header; assume a different page than the headers */ export_header_va = base_vaddr + export_header_rva; dbprint (VMI_DEBUG_MISC, "--PEParse: found export table at [VA] 0x%.16"PRIx64" = 0x%.16"PRIx64" + 0x%"PRIx64"\n", export_header_va, ((windows_instance_t)vmi->os_data)->ntoskrnl_va, export_header_rva); nbytes = vmi_read_va(vmi, export_header_va, pid, et, sizeof(*et)); if (nbytes != sizeof(struct export_table)) { dbprint(VMI_DEBUG_MISC, "--PEParse: failed to map export header\n"); return VMI_FAILURE; } /* sanity check */ if (et->export_flags || !et->name) { dbprint(VMI_DEBUG_MISC, "--PEParse: bad export directory table\n"); return VMI_FAILURE; } return VMI_SUCCESS; }