static void showVersion(pe_ctx_t *ctx, const NODE_PERES *node) { assert(node != NULL); int count = 0; const NODE_PERES *dataEntryNode; uint32_t nameOffset; bool found = false; while (node->lastNode != NULL) { node = node->lastNode; } while (node != NULL) { if (node->nodeType != RDT_DATA_ENTRY) { node = node->nextNode; continue; } count++; //if (count==19) dataEntryNode = lastNodeByType(node, RDT_DATA_ENTRY); if (dataEntryNode == NULL) return; nameOffset = node->rootNode->resource.directoryEntry->DirectoryName.name.NameOffset; if (nameOffset == 16) { found = true; break; } node = node->nextNode; } if (!found) return; const uint64_t offsetData = pe_rva2ofs(ctx, dataEntryNode->resource.dataEntry->offsetToData); const size_t dataEntrySize = dataEntryNode->resource.dataEntry->size; const char *buffer = LIBPE_PTR_ADD(ctx->map_addr, 32 + offsetData); if (!pe_can_read(ctx, buffer, dataEntrySize)) { // TODO: Should we report something? return; } VS_FIXEDFILEINFO *info = (VS_FIXEDFILEINFO *) buffer; char value[MAX_MSG]; //snprintf(value, MAX_MSG, "%d", totalCount); snprintf(value, MAX_MSG, "%u.%u.%u.%u", (unsigned int)(info->dwProductVersionMS & 0xffff0000) >> 16, (unsigned int)info->dwProductVersionMS & 0x0000ffff, (unsigned int)(info->dwProductVersionLS & 0xffff0000) >> 16, (unsigned int)info->dwProductVersionLS & 0x0000ffff); output("File Version", value); }
static void saveResource(pe_ctx_t *ctx, const NODE_PERES *node) { assert(node != NULL); const NODE_PERES *dataEntryNode = lastNodeByType(node, RDT_DATA_ENTRY); if (dataEntryNode == NULL) return; const uint64_t offsetData = pe_rva2ofs(ctx, dataEntryNode->resource.dataEntry->offsetToData); const size_t dataEntrySize = dataEntryNode->resource.dataEntry->size; const char *buffer = LIBPE_PTR_ADD(ctx->map_addr, offsetData); if (!pe_can_read(ctx, buffer, dataEntrySize)) { // TODO: Should we report something? return; } struct stat statDir; if (stat(resourceDir, &statDir) == -1) mkdir(resourceDir, 0700); char dirName[100]; memset(dirName, 0, sizeof(dirName)); uint32_t nameOffset = node->rootNode->resource.directoryEntry->DirectoryName.name.NameOffset; const RESOURCE_ENTRY *resourceEntry = getResourceEntryByNameOffset(nameOffset); if (resourceEntry != NULL) { snprintf(dirName, sizeof(dirName), "%s/%s", resourceDir, resourceEntry->dirName); } else { snprintf(dirName, sizeof(dirName), "%s", resourceDir); } // TODO(jweyrich): Would it make sense to hardcode `RDT_LEVEL2` rather than use `node->nodeLevel-1` ? const NODE_PERES *nameNode = lastNodeByTypeAndLevel(node, RDT_DIRECTORY_ENTRY, node->nodeLevel - 1); //printf("%d\n", nameNode->resource.directoryEntry->DirectoryName.name.NameOffset); if (stat(dirName, &statDir) == -1) mkdir(dirName, 0700); char relativeFileName[100]; memset(relativeFileName, 0, sizeof(relativeFileName)); snprintf(relativeFileName, sizeof(relativeFileName), "%s/" "%" PRIu32 "%s", dirName, nameNode->resource.directoryEntry->DirectoryName.name.NameOffset, resourceEntry != NULL ? resourceEntry->extension : ".bin"); FILE *fp = fopen(relativeFileName, "wb+"); if (fp == NULL) { // TODO: Should we report something? return; } fwrite(buffer, dataEntrySize, 1, fp); fclose(fp); output("Save On", relativeFileName); }
pe_err_e pe_parse(pe_ctx_t *ctx) { ctx->pe.dos_hdr = ctx->map_addr; if (ctx->pe.dos_hdr->e_magic != MAGIC_MZ) return LIBPE_E_NOT_A_PE_FILE; const uint32_t *signature_ptr = LIBPE_PTR_ADD(ctx->pe.dos_hdr, ctx->pe.dos_hdr->e_lfanew); if (!pe_can_read(ctx, signature_ptr, sizeof(uint32_t))) return LIBPE_E_INVALID_LFANEW; // NT signature (PE\0\0), or 16-bit Windows NE signature (NE\0\0). ctx->pe.signature = *signature_ptr; switch (ctx->pe.signature) { default: //fprintf(stderr, "Invalid signature: %x\n", ctx->pe.signature); return LIBPE_E_INVALID_SIGNATURE; case SIGNATURE_NE: case SIGNATURE_PE: break; } ctx->pe.coff_hdr = LIBPE_PTR_ADD(signature_ptr, LIBPE_SIZEOF_MEMBER(pe_file_t, signature)); if (!pe_can_read(ctx, ctx->pe.coff_hdr, sizeof(IMAGE_COFF_HEADER))) return LIBPE_E_MISSING_COFF_HEADER; ctx->pe.num_sections = ctx->pe.coff_hdr->NumberOfSections; // Optional header points right after the COFF header. ctx->pe.optional_hdr_ptr = LIBPE_PTR_ADD(ctx->pe.coff_hdr, sizeof(IMAGE_COFF_HEADER)); // Figure out whether it's a PE32 or PE32+. uint16_t *opt_type_ptr = ctx->pe.optional_hdr_ptr; if (!pe_can_read(ctx, opt_type_ptr, LIBPE_SIZEOF_MEMBER(IMAGE_OPTIONAL_HEADER, type))) return LIBPE_E_MISSING_OPTIONAL_HEADER; ctx->pe.optional_hdr.type = *opt_type_ptr; switch (ctx->pe.optional_hdr.type) { default: case MAGIC_ROM: // Oh boy! We do not support ROM. Abort! //fprintf(stderr, "ROM image is not supported\n"); return LIBPE_E_UNSUPPORTED_IMAGE; case MAGIC_PE32: if (!pe_can_read(ctx, ctx->pe.optional_hdr_ptr, sizeof(IMAGE_OPTIONAL_HEADER_32))) return LIBPE_E_MISSING_OPTIONAL_HEADER; ctx->pe.optional_hdr._32 = ctx->pe.optional_hdr_ptr; ctx->pe.optional_hdr.length = sizeof(IMAGE_OPTIONAL_HEADER_32); ctx->pe.num_directories = ctx->pe.optional_hdr._32->NumberOfRvaAndSizes; ctx->pe.entrypoint = ctx->pe.optional_hdr._32->AddressOfEntryPoint; ctx->pe.imagebase = ctx->pe.optional_hdr._32->ImageBase; break; case MAGIC_PE64: if (!pe_can_read(ctx, ctx->pe.optional_hdr_ptr, sizeof(IMAGE_OPTIONAL_HEADER_64))) return LIBPE_E_MISSING_OPTIONAL_HEADER; ctx->pe.optional_hdr._64 = ctx->pe.optional_hdr_ptr; ctx->pe.optional_hdr.length = sizeof(IMAGE_OPTIONAL_HEADER_64); ctx->pe.num_directories = ctx->pe.optional_hdr._64->NumberOfRvaAndSizes; ctx->pe.entrypoint = ctx->pe.optional_hdr._64->AddressOfEntryPoint; ctx->pe.imagebase = ctx->pe.optional_hdr._64->ImageBase; break; } if (ctx->pe.num_directories > MAX_DIRECTORIES) { //fprintf(stderr, "Too many directories (%u)\n", ctx->pe.num_directories); return LIBPE_E_TOO_MANY_DIRECTORIES; } if (ctx->pe.num_sections > MAX_SECTIONS) { //fprintf(stderr, "Too many sections (%u)\n", ctx->pe.num_sections); return LIBPE_E_TOO_MANY_SECTIONS; } ctx->pe.directories_ptr = LIBPE_PTR_ADD(ctx->pe.optional_hdr_ptr, ctx->pe.optional_hdr.length); // If there are no directories, sections_ptr will point right // after the OPTIONAL header, otherwise, it will point right // after the directories. ctx->pe.sections_ptr = LIBPE_PTR_ADD(ctx->pe.directories_ptr, ctx->pe.num_directories * sizeof(IMAGE_DATA_DIRECTORY)); if (ctx->pe.num_directories > 0) { ctx->pe.directories = malloc(ctx->pe.num_directories * sizeof(IMAGE_DATA_DIRECTORY *)); if (ctx->pe.directories == NULL) return LIBPE_E_ALLOCATION_FAILURE; for (uint32_t i = 0; i < ctx->pe.num_directories; i++) { ctx->pe.directories[i] = LIBPE_PTR_ADD(ctx->pe.directories_ptr, i * sizeof(IMAGE_DATA_DIRECTORY)); } } else { ctx->pe.directories_ptr = NULL; } if (ctx->pe.num_sections > 0) { ctx->pe.sections = malloc(ctx->pe.num_sections * sizeof(IMAGE_SECTION_HEADER *)); if (ctx->pe.sections == NULL) return LIBPE_E_ALLOCATION_FAILURE; for (uint32_t i = 0; i < ctx->pe.num_sections; i++) { ctx->pe.sections[i] = LIBPE_PTR_ADD(ctx->pe.sections_ptr, i * sizeof(IMAGE_SECTION_HEADER)); } } else { ctx->pe.sections_ptr = NULL; } return LIBPE_E_OK; }
static void parse_certificates(const options_t *options, pe_ctx_t *ctx) { const IMAGE_DATA_DIRECTORY * const directory = pe_directory_by_entry(ctx, IMAGE_DIRECTORY_ENTRY_SECURITY); if (directory == NULL) return; if (directory->VirtualAddress == 0 || directory->Size == 0) return; uint32_t fileOffset = directory->VirtualAddress; // This a file pointer rather than a common RVA. // TODO(jweyrich): We should count how many certificates the file has, and based on this // decide whether to proceed and open the certificates scope. output_open_scope("certificates", OUTPUT_SCOPE_TYPE_ARRAY); while (fileOffset - directory->VirtualAddress < directory->Size) { // Read the size of this WIN_CERTIFICATE uint32_t *dwLength_ptr = LIBPE_PTR_ADD(ctx->map_addr, fileOffset); if (!pe_can_read(ctx, dwLength_ptr, sizeof(uint32_t))) { output_close_scope(); // certificates // TODO: Should we report something? return; } // Type punning uint32_t dwLength = *(uint32_t *)dwLength_ptr; WIN_CERTIFICATE *cert = LIBPE_PTR_ADD(ctx->map_addr, fileOffset); if (!pe_can_read(ctx, cert, dwLength)) { output_close_scope(); // certificates // TODO: Should we report something? return; } output_open_scope("certificate", OUTPUT_SCOPE_TYPE_OBJECT); static char value[MAX_MSG]; snprintf(value, MAX_MSG, "%u bytes", cert->dwLength); output("Length", value); snprintf(value, MAX_MSG, "0x%x (%s)", cert->wRevision, cert->wRevision == WIN_CERT_REVISION_1_0 ? "1" : cert->wRevision == WIN_CERT_REVISION_2_0 ? "2" : "unknown"); output("Revision", value); snprintf(value, MAX_MSG, "0x%x", cert->wCertificateType); switch (cert->wCertificateType) { default: bsd_strlcat(value, " (UNKNOWN)", MAX_MSG); break; case WIN_CERT_TYPE_X509: bsd_strlcat(value, " (X509)", MAX_MSG); break; case WIN_CERT_TYPE_PKCS_SIGNED_DATA: bsd_strlcat(value, " (PKCS_SIGNED_DATA)", MAX_MSG); break; case WIN_CERT_TYPE_TS_STACK_SIGNED: bsd_strlcat(value, " (TS_STACK_SIGNED)", MAX_MSG); break; } output("Type", value); fileOffset += utils_round_up(cert->dwLength, 8); // Offset to the next certificate. if (fileOffset - directory->VirtualAddress > directory->Size) EXIT_ERROR("either the attribute certificate table or the Size field is corrupted"); switch (cert->wRevision) { default: EXIT_ERROR("unknown wRevision"); case WIN_CERT_REVISION_1_0: EXIT_ERROR("WIN_CERT_REVISION_1_0 is not supported"); case WIN_CERT_REVISION_2_0: break; } switch (cert->wCertificateType) { default: EXIT_ERROR("unknown wCertificateType"); case WIN_CERT_TYPE_X509: EXIT_ERROR("WIN_CERT_TYPE_X509 is not supported"); case WIN_CERT_TYPE_PKCS_SIGNED_DATA: { CRYPT_DATA_BLOB p7data; p7data.cbData = cert->dwLength - offsetof(WIN_CERTIFICATE, bCertificate); p7data.pbData = cert->bCertificate; parse_pkcs7_data(options, &p7data); break; } case WIN_CERT_TYPE_TS_STACK_SIGNED: EXIT_ERROR("WIN_CERT_TYPE_TS_STACK_SIGNED is not supported"); case WIN_CERT_TYPE_EFI_PKCS115: EXIT_ERROR("WIN_CERT_TYPE_EFI_PKCS115 is not supported"); case WIN_CERT_TYPE_EFI_GUID: EXIT_ERROR("WIN_CERT_TYPE_EFI_GUID is not supported"); } output_close_scope(); // certificate } output_close_scope(); // certificates }
int main(int argc, char *argv[]) { pev_config_t config; PEV_INITIALIZE(&config); if (argc < 2) { usage(); return EXIT_FAILURE; } output_set_cmdline(argc, argv); options_t *options = parse_options(argc, argv); pe_ctx_t ctx; pe_err_e err = pe_load_file(&ctx, argv[argc-1]); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } err = pe_parse(&ctx); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } if (!pe_is_pe(&ctx)) EXIT_ERROR("not a valid PE file"); const IMAGE_SECTION_HEADER *section_ptr = NULL; const unsigned char *data = NULL; uint64_t data_size = 0; unsigned c = pe_sections_count(&ctx); IMAGE_SECTION_HEADER ** const sections = pe_sections(&ctx); data = ctx.map_addr; data_size = pe_filesize(&ctx); output_open_document(); if (options->headers.all || options->headers.dos || options->headers.coff || options->headers.optional || options->sections.name || options->sections.index) { options->all = false; options->content = false; } if (options->all) { options->content = true; options->headers.all = true; } if (options->content) { output_open_scope("file", OUTPUT_SCOPE_TYPE_OBJECT); output("filepath", ctx.path); print_basic_hash(data, data_size); char *imphash = NULL; // imphash = pe_imphash(&ctx, LIBPE_IMPHASH_FLAVOR_MANDIANT); // output("imphash (Mandiant)", imphash); // free(imphash); imphash = pe_imphash(&ctx, LIBPE_IMPHASH_FLAVOR_PEFILE); output("imphash", imphash); free(imphash); output_close_scope(); // file if (!options->all) // whole file content only goto BYE; } if (options->headers.all) { options->headers.dos = true; options->headers.coff = true; options->headers.optional = true; } if (options->headers.all || options->headers.dos || options->headers.coff || options->headers.optional) output_open_scope("headers", OUTPUT_SCOPE_TYPE_ARRAY); if (options->headers.all || options->headers.dos) { const IMAGE_DOS_HEADER *dos_hdr = pe_dos(&ctx); data = (const unsigned char *)dos_hdr; data_size = sizeof(IMAGE_DOS_HEADER); output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_DOS_HEADER"); print_basic_hash(data, data_size); output_close_scope(); // header } if (options->headers.all || options->headers.coff) { const IMAGE_COFF_HEADER *coff_hdr = pe_coff(&ctx); data = (const unsigned char *)coff_hdr; data_size = sizeof(IMAGE_COFF_HEADER); output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_COFF_HEADER"); print_basic_hash(data, data_size); output_close_scope(); // header } if (options->headers.all || options->headers.optional) { const IMAGE_OPTIONAL_HEADER *opt_hdr = pe_optional(&ctx); switch (opt_hdr->type) { case MAGIC_ROM: // Oh boy! We do not support ROM. Abort! fprintf(stderr, "ROM image is not supported\n"); break; case MAGIC_PE32: if (!pe_can_read(&ctx, opt_hdr->_32, sizeof(IMAGE_OPTIONAL_HEADER_32))) { // TODO: Should we report something? break; } data = (const unsigned char *)opt_hdr->_32; data_size = sizeof(IMAGE_OPTIONAL_HEADER_32); break; case MAGIC_PE64: if (!pe_can_read(&ctx, opt_hdr->_64, sizeof(IMAGE_OPTIONAL_HEADER_64))) { // TODO: Should we report something? break; } data = (const unsigned char *)opt_hdr->_64; data_size = sizeof(IMAGE_OPTIONAL_HEADER_64); break; } output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_OPTIONAL_HEADER"); print_basic_hash(data, data_size); output_close_scope(); // header } if (options->headers.all || options->headers.dos || options->headers.coff || options->headers.optional) output_close_scope(); // headers if (options->all || options->sections.name || options->sections.index) output_open_scope("sections", OUTPUT_SCOPE_TYPE_ARRAY); if (options->all) { for (unsigned int i=0; i<c; i++) { data_size = sections[i]->SizeOfRawData; data = LIBPE_PTR_ADD(ctx.map_addr, sections[i]->PointerToRawData); if (!pe_can_read(&ctx, data, data_size)) { EXIT_ERROR("Unable to read section data"); } output_open_scope("section", OUTPUT_SCOPE_TYPE_OBJECT); output("section_name", (char *)sections[i]->Name); if (data_size) { print_basic_hash(data, data_size); } output_close_scope(); // section } //output_close_scope(); // sections } else if (options->sections.name != NULL) { const IMAGE_SECTION_HEADER *section = pe_section_by_name(&ctx, options->sections.name); if (section == NULL) { EXIT_ERROR("The requested section could not be found on this binary"); } section_ptr = section; } else if (options->sections.index > 0) { const uint16_t num_sections = pe_sections_count(&ctx); if (num_sections == 0 || options->sections.index > num_sections) { EXIT_ERROR("The requested section could not be found on this binary"); } IMAGE_SECTION_HEADER ** const sections = pe_sections(&ctx); const IMAGE_SECTION_HEADER *section = sections[options->sections.index - 1]; section_ptr = section; } if (section_ptr != NULL) { if (section_ptr->SizeOfRawData > 0) { const uint8_t *section_data_ptr = LIBPE_PTR_ADD(ctx.map_addr, section_ptr->PointerToRawData); // printf("map_addr = %p\n", ctx.map_addr); // printf("section_data_ptr = %p\n", section_data_ptr); // printf("SizeOfRawData = %u\n", section_ptr->SizeOfRawData); if (!pe_can_read(&ctx, section_data_ptr, section_ptr->SizeOfRawData)) { EXIT_ERROR("The requested section has an invalid size"); } data = (const unsigned char *)section_data_ptr; data_size = section_ptr->SizeOfRawData; } else { data = (const unsigned char *)""; data_size = 0; } } if (!options->all && data != NULL) { output_open_scope("section", OUTPUT_SCOPE_TYPE_OBJECT); output("section_name", options->sections.name); print_basic_hash(data, data_size); output_close_scope(); } if (options->all || options->sections.name || options->sections.index) output_close_scope(); BYE: output_close_document(); // free free_options(options); err = pe_unload(&ctx); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } PEV_FINALIZE(&config); return EXIT_SUCCESS; }
static NODE_PERES * discoveryNodesPeres(pe_ctx_t *ctx) { #ifdef LIBPE_ENABLE_OUTPUT_COMPAT_WITH_V06 typedef struct { ImageDirectoryEntry entry; const char * const name; } ImageDirectoryEntryName; static const ImageDirectoryEntryName directoryEntryNames[] = { { IMAGE_DIRECTORY_ENTRY_EXPORT, "Export Table" }, // "Export directory", { IMAGE_DIRECTORY_ENTRY_IMPORT, "Import Table" }, // "Import directory", { IMAGE_DIRECTORY_ENTRY_RESOURCE, "Resource Table" }, // "Resource directory", { IMAGE_DIRECTORY_ENTRY_EXCEPTION, "Exception Table" }, // "Exception directory", { IMAGE_DIRECTORY_ENTRY_SECURITY, "Certificate Table" }, // "Security directory", { IMAGE_DIRECTORY_ENTRY_BASERELOC, "Base Relocation Table" }, // "Base relocation table", { IMAGE_DIRECTORY_ENTRY_DEBUG, "Debug" }, // "Debug directory", { IMAGE_DIRECTORY_ENTRY_ARCHITECTURE, "Architecture" }, // "Architecture-specific data", { IMAGE_DIRECTORY_ENTRY_GLOBALPTR, "Global Ptr" }, // "Global pointer", { IMAGE_DIRECTORY_ENTRY_TLS, "Thread Local Storage (TLS)"}, // "Thread local storage (TLS) directory", { IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, "Load Config Table" }, // "Load configuration directory", { IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, "Bound Import" }, // "Bound import directory", { IMAGE_DIRECTORY_ENTRY_IAT, "Import Address Table (IAT)"}, // "Import address table (IAT)", { IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, "Delay Import Descriptor" }, // "Delay import table", { IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, "CLR Runtime Header" }, // "COM descriptor table" { IMAGE_DIRECTORY_RESERVED, "" } // "Reserved" }; //static const size_t max_directory_entry = LIBPE_SIZEOF_ARRAY(names); #endif const IMAGE_DATA_DIRECTORY * const resourceDirectory = pe_directory_by_entry(ctx, IMAGE_DIRECTORY_ENTRY_RESOURCE); if (resourceDirectory == NULL || resourceDirectory->Size == 0) return NULL; uint64_t resourceDirOffset = pe_rva2ofs(ctx, resourceDirectory->VirtualAddress); /*char s[MAX_MSG]; if (resourceDirectory->Size != 0) { snprintf(s, MAX_MSG, "%#x (%d bytes)", resourceDirectory->VirtualAddress, resourceDirectory->Size); #ifdef LIBPE_ENABLE_OUTPUT_COMPAT_WITH_V06 output(directory_names[IMAGE_DIRECTORY_ENTRY_RESOURCE], s); // Resource table #else output(pe_directory_name(IMAGE_DIRECTORY_ENTRY_RESOURCE), s); // Resource table #endif //printf("Offset by RVA: 0x%x\n\n", resourceDirOffset); }*/ uintptr_t offset = resourceDirOffset; void *ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY))) { // TODO: Should we report something? return NULL; } NODE_PERES *node = malloc_s(sizeof(NODE_PERES)); node->lastNode = NULL; // root node->nodeType = RDT_RESOURCE_DIRECTORY; node->nodeLevel = RDT_LEVEL1; node->resource.resourceDirectory = ptr; //showNode(node); for (int i = 1, offsetDirectory1 = 0; i <= (lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL1)->resource.resourceDirectory->NumberOfNamedEntries + lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL1)->resource.resourceDirectory->NumberOfIdEntries); i++) { offsetDirectory1 += (i == 1) ? 16 : 8; offset = resourceDirOffset + offsetDirectory1; ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_DIRECTORY_ENTRY); NODE_PERES *rootNode = node; node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL1; node->resource.directoryEntry = ptr; //showNode(node); const NODE_PERES * lastDirectoryEntryNodeAtLevel1 = lastNodeByTypeAndLevel(node, RDT_DIRECTORY_ENTRY, RDT_LEVEL1); if (lastDirectoryEntryNodeAtLevel1->resource.directoryEntry->DirectoryData.data.DataIsDirectory) { offset = resourceDirOffset + lastDirectoryEntryNodeAtLevel1->resource.directoryEntry->DirectoryData.data.OffsetToDirectory; ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_RESOURCE_DIRECTORY); node->rootNode = (NODE_PERES *)lastDirectoryEntryNodeAtLevel1; node->nodeLevel = RDT_LEVEL2; node->resource.resourceDirectory = ptr; //showNode(node); for (int j = 1, offsetDirectory2 = 0; j <= (lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL2)->resource.resourceDirectory->NumberOfNamedEntries + lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL2)->resource.resourceDirectory->NumberOfIdEntries); j++) { offsetDirectory2 += (j == 1) ? 16 : 8; offset = resourceDirOffset + lastNodeByTypeAndLevel(node, RDT_DIRECTORY_ENTRY, RDT_LEVEL1)->resource.directoryEntry->DirectoryData.data.OffsetToDirectory + offsetDirectory2; ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_DIRECTORY_ENTRY); node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL2; node->resource.directoryEntry = ptr; //showNode(node); offset = resourceDirOffset + node->resource.directoryEntry->DirectoryData.data.OffsetToDirectory; // posiciona em 0x72 ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_RESOURCE_DIRECTORY); node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL3; node->resource.resourceDirectory = ptr; //showNode(node); offset += sizeof(IMAGE_RESOURCE_DIRECTORY); for (int y = 1; y <= (lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL3)->resource.resourceDirectory->NumberOfNamedEntries + lastNodeByTypeAndLevel(node, RDT_RESOURCE_DIRECTORY, RDT_LEVEL3)->resource.resourceDirectory->NumberOfIdEntries); y++) { ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_DIRECTORY_ENTRY); node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL3; node->resource.directoryEntry = ptr; //showNode(node); offset = resourceDirOffset + node->resource.directoryEntry->DirectoryName.name.NameOffset; ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DATA_STRING))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_DATA_STRING); node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL3; node->resource.dataString = ptr; //showNode(node); offset = resourceDirOffset + node->lastNode->resource.directoryEntry->DirectoryData.data.OffsetToDirectory; ptr = LIBPE_PTR_ADD(ctx->map_addr, offset); if (!pe_can_read(ctx, ptr, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) { // TODO: Should we report something? goto _error; } node = createNode(node, RDT_DATA_ENTRY); node->rootNode = rootNode; node->nodeLevel = RDT_LEVEL3; node->resource.dataEntry = ptr; //showNode(node); offset += sizeof(IMAGE_RESOURCE_DATA_ENTRY); } } } } return node; _error: if (node != NULL) freeNodes(node); return NULL; }
int main(int argc, char *argv[]) { pev_config_t config; PEV_INITIALIZE(&config); if (argc < 2) { usage(); return EXIT_FAILURE; } output_set_cmdline(argc, argv); OpenSSL_add_all_digests(); options_t *options = parse_options(argc, argv); pe_ctx_t ctx; pe_err_e err = pe_load_file(&ctx, argv[argc-1]); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } err = pe_parse(&ctx); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } if (!pe_is_pe(&ctx)) EXIT_ERROR("not a valid PE file"); const IMAGE_SECTION_HEADER *section_ptr = NULL; const unsigned char *data = NULL; uint64_t data_size = 0; unsigned c = pe_sections_count(&ctx); IMAGE_SECTION_HEADER ** const sections = pe_sections(&ctx); char hash_value[EVP_MAX_MD_SIZE * 2 + 1]; data = ctx.map_addr; data_size = pe_filesize(&ctx); output_open_document(); if (options->all) { output_open_scope("file", OUTPUT_SCOPE_TYPE_OBJECT); output("filepath", ctx.path); print_basic_hash(data, data_size); output_close_scope(); // file } output_open_scope("headers", OUTPUT_SCOPE_TYPE_ARRAY); if (options->all || options->headers.all || options->headers.dos) { const IMAGE_DOS_HEADER *dos_hdr = pe_dos(&ctx); data = (const unsigned char *)dos_hdr; data_size = sizeof(IMAGE_DOS_HEADER); output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_DOS_HEADER"); PRINT_HASH_OR_HASHES; output_close_scope(); // header } if (options->all || options->headers.all || options->headers.coff) { const IMAGE_COFF_HEADER *coff_hdr = pe_coff(&ctx); data = (const unsigned char *)coff_hdr; data_size = sizeof(IMAGE_COFF_HEADER); output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_COFF_HEADER"); PRINT_HASH_OR_HASHES; output_close_scope(); // header } if (options->all || options->headers.all || options->headers.optional) { const IMAGE_OPTIONAL_HEADER *opt_hdr = pe_optional(&ctx); switch (opt_hdr->type) { case MAGIC_ROM: // Oh boy! We do not support ROM. Abort! fprintf(stderr, "ROM image is not supported\n"); break; case MAGIC_PE32: if (!pe_can_read(&ctx, opt_hdr->_32, sizeof(IMAGE_OPTIONAL_HEADER_32))) { // TODO: Should we report something? break; } data = (const unsigned char *)opt_hdr->_32; data_size = sizeof(IMAGE_OPTIONAL_HEADER_32); break; case MAGIC_PE64: if (!pe_can_read(&ctx, opt_hdr->_64, sizeof(IMAGE_OPTIONAL_HEADER_64))) { // TODO: Should we report something? break; } data = (const unsigned char *)opt_hdr->_64; data_size = sizeof(IMAGE_OPTIONAL_HEADER_64); break; } output_open_scope("header", OUTPUT_SCOPE_TYPE_OBJECT); output("header_name", "IMAGE_OPTIONAL_HEADER"); PRINT_HASH_OR_HASHES; output_close_scope(); // header } output_close_scope(); // headers if (options->all) { output_open_scope("sections", OUTPUT_SCOPE_TYPE_ARRAY); for (unsigned int i=0; i<c; i++) { data_size = sections[i]->SizeOfRawData; data = LIBPE_PTR_ADD(ctx.map_addr, sections[i]->PointerToRawData); output_open_scope("section", OUTPUT_SCOPE_TYPE_OBJECT); output("section_name", (char *)sections[i]->Name); if (data_size) { PRINT_HASH_OR_HASHES; } output_close_scope(); // section } output_close_scope(); // sections } else if (options->sections.name != NULL) { const IMAGE_SECTION_HEADER *section = pe_section_by_name(&ctx, options->sections.name); if (section == NULL) { EXIT_ERROR("The requested section could not be found on this binary"); } section_ptr = section; } else if (options->sections.index > 0) { const uint16_t num_sections = pe_sections_count(&ctx); if (num_sections == 0 || options->sections.index > num_sections) { EXIT_ERROR("The requested section could not be found on this binary"); } IMAGE_SECTION_HEADER ** const sections = pe_sections(&ctx); const IMAGE_SECTION_HEADER *section = sections[options->sections.index - 1]; section_ptr = section; } if (section_ptr != NULL) { if (section_ptr->SizeOfRawData > 0) { const uint8_t *section_data_ptr = LIBPE_PTR_ADD(ctx.map_addr, section_ptr->PointerToRawData); // printf("map_addr = %p\n", ctx.map_addr); // printf("section_data_ptr = %p\n", section_data_ptr); // printf("SizeOfRawData = %u\n", section_ptr->SizeOfRawData); if (!pe_can_read(&ctx, section_data_ptr, section_ptr->SizeOfRawData)) { EXIT_ERROR("The requested section has an invalid size"); } data = (const unsigned char *)section_data_ptr; data_size = section_ptr->SizeOfRawData; } else { data = (const unsigned char *)""; data_size = 0; } } if (!options->all && data != NULL) { char hash_value[EVP_MAX_MD_SIZE * 2 + 1]; if (options->algorithms.all && options->all) { print_basic_hash(data, data_size); } else if (options->algorithms.alg_name != NULL) { calc_hash(options->algorithms.alg_name, data, data_size, hash_value); output(options->algorithms.alg_name, hash_value); } else { print_basic_hash(data, data_size); } } output_close_document(); // free free_options(options); err = pe_unload(&ctx); if (err != LIBPE_E_OK) { pe_error_print(stderr, err); return EXIT_FAILURE; } EVP_cleanup(); // Clean OpenSSL_add_all_digests. PEV_FINALIZE(&config); return EXIT_SUCCESS; }