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 }
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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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 (LIBPE_IS_PAST_THE_END(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; }