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; }
status_t peparse_get_export_table( vmi_instance_t vmi, const access_context_t *ctx, 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. access_context_t _ctx = *ctx; addr_t export_header_rva = 0; size_t export_header_size = 0; #define MAX_HEADER_BYTES 1024 // keep under 1 page uint8_t image[MAX_HEADER_BYTES]; if (VMI_FAILURE == peparse_get_image(vmi, ctx, 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; } dbprint(VMI_DEBUG_PEPARSE, "--PEParse: DLL base 0x%.16"PRIx64". Export header [RVA] 0x%.16"PRIx64". Size %" PRIu64 ".\n", ctx->addr, export_header_rva, export_header_size); _ctx.addr = ctx->addr + export_header_rva; if ( VMI_FAILURE == vmi_read(vmi, &_ctx, sizeof(struct export_table), et, NULL) ) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: failed to map export header\n"); /* * Sometimes Windows maps the export table on page-boundaries, * such that the first export_flags field (which is reserved) is. * not actually accessible (the page is not mapped). See Issue #260. */ if (!((_ctx.addr+4) & 0xfff)) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: export table is mapped on page boundary\n"); _ctx.addr += 4; if ( VMI_FAILURE == vmi_read(vmi, &_ctx, sizeof(struct export_table)-4, (void*)((char*)et+4), NULL) ) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: still failed to map export header\n"); return VMI_FAILURE; } // Manually set the reserved field to zero in this case et->export_flags = 0; } else { return VMI_FAILURE; } } /* sanity check */ if (et->export_flags || !et->name) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: bad export directory table\n"); return VMI_FAILURE; } return VMI_SUCCESS; }