Exemple #1
0
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);

}
Exemple #2
0
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);
}
Exemple #3
0
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;
}
Exemple #4
0
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
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}