[HCPC] Win32 > Debug > AnalyzePE

// PE イメージの解析 Ver.2008.10.01
// Copyright (C) 2008 T.Hirase, All rights reserved.
//-----------------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")	// needs "DbgHelp.dll"

#define MyPrint(X) OutputDebugStringA(X); printf(X)

typedef enum tagAppReturnValues {
	APP_SUCCESS,
	APP_ERR_OPEN_FILE,
	APP_ERR_CREATE_FILE_MAPPING,
	APP_ERR_MAP_VIEW_OF_FILE,
	APP_ERR_NOT_COFF_FILE,
	APP_ERR_NO_EXPORT_DIRECTORY,
} AppReturnValues;

void printUsage();
void printCategory(const char* category);
void printSubCategory(const char* subCategory);
void printElement(const char* subject, const char* detail);
AppReturnValues analyze_and_printPE(const char* fname);
AppReturnValues analyze_and_printNTHeader(LPVOID fileMap);
AppReturnValues analyze_and_printExportModules(LPVOID fileMap, PIMAGE_NT_HEADERS ntHeader);

int main(int argc, char* argv[])
{
	AppReturnValues ret;
	if (argc < 2) {
		printUsage();
		return 0;
	}

	ret = analyze_and_printPE(argv[1]);
	return (int)ret;
}

void printUsage()
{
}

void printCategory(const char* category)
{
	MyPrint("==================== ");
	MyPrint(category);
	MyPrint(" ====================\n");
}

void printSubCategory(const char* subCategory)
{
	MyPrint("[");
	MyPrint(subCategory);
	MyPrint("]\n");
}

void printElement(const char* subject, const char* detail)
{
	MyPrint("  ");
	MyPrint(subject);
	MyPrint(" : ");
	MyPrint(detail);
	MyPrint("\n");
}

AppReturnValues analyze_and_printPE(const char* fname)
{
	AppReturnValues ret;
	HANDLE fileHandle;
	HANDLE fileMappingHandle;
	LPVOID fileMap;

	fileHandle = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (fileHandle == INVALID_HANDLE_VALUE) {
		return APP_ERR_OPEN_FILE;
	}

	fileMappingHandle = CreateFileMappingA(fileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
	if (fileMappingHandle == INVALID_HANDLE_VALUE) {
		CloseHandle(fileHandle);
		return APP_ERR_CREATE_FILE_MAPPING;
	}

	fileMap = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
	if (fileMap == NULL) {
		CloseHandle(fileMappingHandle);
		CloseHandle(fileHandle);
		return APP_ERR_MAP_VIEW_OF_FILE;
	}

	ret = APP_SUCCESS;
	/* PE ファイルの検証 (COFFを含む) */
	ret = analyze_and_printNTHeader(fileMap);

	UnmapViewOfFile(fileMap);

	CloseHandle(fileMappingHandle);
	CloseHandle(fileHandle);
	return APP_SUCCESS;
}

AppReturnValues analyze_and_printNTHeader(LPVOID fileMap)
{
	bool isDllImage = false;
	const char * ptr2StringLiteral;
	PIMAGE_NT_HEADERS ntHdr = ImageNtHeader(fileMap);
	if (ntHdr->Signature != 0x00004550) {
		return APP_ERR_NOT_COFF_FILE;
	}

	printCategory("NT Header");
	printSubCategory("File Header");

	if (ntHdr->FileHeader.SizeOfOptionalHeader > 0) {
		// PE Type
		switch (ntHdr->OptionalHeader.Magic)
		{
		case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
			ptr2StringLiteral = "32bit PE";
			break;
		case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
			ptr2StringLiteral = "64bit PE";
			break;
		case IMAGE_ROM_OPTIONAL_HDR_MAGIC:
			ptr2StringLiteral = "ROM PE";
			break;
		}
		printElement("PE Type", ptr2StringLiteral);

		// Subsystem
		switch (ntHdr->OptionalHeader.Subsystem)
		{
		case IMAGE_SUBSYSTEM_UNKNOWN                 :   // Unknown subsystem.
			ptr2StringLiteral = "Unknown";
			break;
		case IMAGE_SUBSYSTEM_NATIVE                  :   // Image doesn't require a subsystem.
			ptr2StringLiteral = "Native";
			break;
		case IMAGE_SUBSYSTEM_WINDOWS_GUI             :   // Image runs in the Windows GUI subsystem.
			ptr2StringLiteral = "Windows GUI";
			break;
		case IMAGE_SUBSYSTEM_WINDOWS_CUI             :   // Image runs in the Windows character subsystem.
			ptr2StringLiteral = "Windows CUI";
			break;
		case IMAGE_SUBSYSTEM_OS2_CUI                 :   // image runs in the OS/2 character subsystem.
			ptr2StringLiteral = "OS2 CUI";
			break;
		case IMAGE_SUBSYSTEM_POSIX_CUI               :   // image runs in the Posix character subsystem.
			ptr2StringLiteral = "POSIX CUI";
			break;
		case IMAGE_SUBSYSTEM_NATIVE_WINDOWS          :   // image is a native Win9x driver.
			ptr2StringLiteral = "Windows 9x driver";
			break;
		case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI          :   // Image runs in the Windows CE subsystem.
			ptr2StringLiteral = "Windows CE";
			break;
		case IMAGE_SUBSYSTEM_EFI_APPLICATION         :   //
			ptr2StringLiteral = "EFI Application";
			break;
		case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER :   //
			ptr2StringLiteral = "EFI Boot Service Driver";
			break;
		case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER      :   //
			ptr2StringLiteral = "EFI Runtime Driver";
			break;
		case IMAGE_SUBSYSTEM_EFI_ROM                 : 
			ptr2StringLiteral = "EFI ROM";
			break;
		case IMAGE_SUBSYSTEM_XBOX                    : 
			ptr2StringLiteral = "XBOX";
			break;
		case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: 
			ptr2StringLiteral = "Windows Boot Application";
			break;
		default:
			ptr2StringLiteral = "Unrecognizable";
			break;
		}
		printElement("Subsystem Type", ptr2StringLiteral);

		{
			char verStr[256] = {0};
			sprintf_s(verStr, _countof(verStr), "%d.%d", ntHdr->OptionalHeader.MajorImageVersion, ntHdr->OptionalHeader.MinorImageVersion);
			printElement("Image Version", verStr);
		}
	}

	switch (ntHdr->FileHeader.Machine)
	{
	case IMAGE_FILE_MACHINE_UNKNOWN           :	// 0
		ptr2StringLiteral = "Unknown";
		break;
	case IMAGE_FILE_MACHINE_I386              :	// 0x014c  // Intel 386.
		ptr2StringLiteral = "Intel 386";
		break;
	case IMAGE_FILE_MACHINE_R3000             :	// 0x0162  // MIPS little-endian
		ptr2StringLiteral = "MIPS Little-Endian R3000";
		break;
	case 0x0160                               :	// 0x0160  // MIPS big-endian
		ptr2StringLiteral = "MIPS Big-Endian R3000";
		break;
	case IMAGE_FILE_MACHINE_R4000             :	// 0x0166  // MIPS little-endian
		ptr2StringLiteral = "MIPS Little-Endian R4000";
		break;
	case IMAGE_FILE_MACHINE_R10000            :	// 0x0168  // MIPS little-endian
		ptr2StringLiteral = "MIPS Little-Endian R10000";
		break;
	case IMAGE_FILE_MACHINE_WCEMIPSV2         :	// 0x0169  // MIPS little-endian WCE v2
		ptr2StringLiteral = "MPIS Little-Endian WCE v2";
		break;
	case IMAGE_FILE_MACHINE_ALPHA             :	// 0x0184  // Alpha_AXP
		ptr2StringLiteral = "Alpha AXP";
		break;
	case IMAGE_FILE_MACHINE_SH3               :	// 0x01a2  // SH3 little-endian
		ptr2StringLiteral = "SH3 Little-Endian";
		break;
	case IMAGE_FILE_MACHINE_SH3DSP            :	// 0x01a3
		ptr2StringLiteral = "SH3DSP";
		break;
	case IMAGE_FILE_MACHINE_SH3E              :	// 0x01a4  // SH3E little-endian
		ptr2StringLiteral = "SH3E Little-Endian";
		break;
	case IMAGE_FILE_MACHINE_SH4               :	// 0x01a6  // SH4 little-endian
		ptr2StringLiteral = "SH4 Little-Endian";
		break;
	case IMAGE_FILE_MACHINE_SH5               :	// 0x01a8  // SH5
		ptr2StringLiteral = "SH5";
		break;
	case IMAGE_FILE_MACHINE_ARM               :	// 0x01c0  // ARM Little-Endian
		ptr2StringLiteral = "ARM Little-Endian";
		break;
	case IMAGE_FILE_MACHINE_THUMB             :	// 0x01c2
		ptr2StringLiteral = "THUMB";
		break;
	case IMAGE_FILE_MACHINE_AM33              :	// 0x01d3
		ptr2StringLiteral = "AM33";
		break;
	case IMAGE_FILE_MACHINE_POWERPC           :	// 0x01F0  // IBM PowerPC Little-Endian
		ptr2StringLiteral = "IBM PowerPC Little-Endian";
		break;
	case IMAGE_FILE_MACHINE_POWERPCFP         :	// 0x01f1
		ptr2StringLiteral = "POWER PCFP";
		break;
	case IMAGE_FILE_MACHINE_IA64              :	// 0x0200  // Intel 64
		ptr2StringLiteral = "Intel 64";
		break;
	case IMAGE_FILE_MACHINE_MIPS16            :	// 0x0266  // MIPS
		ptr2StringLiteral = "MPIS";
		break;
	case IMAGE_FILE_MACHINE_ALPHA64           :	// 0x0284  // ALPHA64 (=IMAGE_FILE_MACHINE_AXP64)
		ptr2StringLiteral = "ALPHA64 (AXP64)";
		break;
	case IMAGE_FILE_MACHINE_MIPSFPU           :	// 0x0366  // MIPS
		ptr2StringLiteral = "MPIS FPU";
		break;
	case IMAGE_FILE_MACHINE_MIPSFPU16         :	// 0x0466  // MIPS
		ptr2StringLiteral = "MPIS FPU16";
		break;
	case IMAGE_FILE_MACHINE_TRICORE           :	// 0x0520  // Infineon
		ptr2StringLiteral = "TRICODE (Infineon)";
		break;
	case IMAGE_FILE_MACHINE_CEF               :	// 0x0CEF
		ptr2StringLiteral = "CEF";
		break;
	case IMAGE_FILE_MACHINE_EBC               :	// 0x0EBC  // EFI Byte Code
		ptr2StringLiteral = "EFI Byte Code";
		break;
	case IMAGE_FILE_MACHINE_AMD64             :	// 0x8664  // AMD64 (K8)
		ptr2StringLiteral = "AMD64 (K8)";
		break;
	case IMAGE_FILE_MACHINE_M32R              :	// 0x9041  // M32R little-endian
		ptr2StringLiteral = "M32R Little-Endian)";
		break;
	case IMAGE_FILE_MACHINE_CEE               :	// 0xC0EE
		ptr2StringLiteral = "CEE";
		break;
	default:
		ptr2StringLiteral = "Unrecognizable";
		break;
	}
	printElement("Machine", ptr2StringLiteral);

	printElement("RELOCS_STRIPPED        " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED        ) == IMAGE_FILE_RELOCS_STRIPPED        ) ? "TRUE" : "FALSE"); // Relocation info stripped from file.
	printElement("EXECUTABLE_IMAGE       " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE       ) == IMAGE_FILE_EXECUTABLE_IMAGE       ) ? "TRUE" : "FALSE"); // File is executable  (i.e. no unresolved externel references).
	printElement("LINE_NUMS_STRIPPED     " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED     ) == IMAGE_FILE_LINE_NUMS_STRIPPED     ) ? "TRUE" : "FALSE"); // Line nunbers stripped from file.
	printElement("LOCAL_SYMS_STRIPPED    " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED    ) == IMAGE_FILE_LOCAL_SYMS_STRIPPED    ) ? "TRUE" : "FALSE"); // Local symbols stripped from file.
	printElement("AGGRESIVE_WS_TRIM      " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM      ) == IMAGE_FILE_AGGRESIVE_WS_TRIM      ) ? "TRUE" : "FALSE"); // Agressively trim working set
	printElement("LARGE_ADDRESS_AWARE    " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE    ) == IMAGE_FILE_LARGE_ADDRESS_AWARE    ) ? "TRUE" : "FALSE"); // App can handle >2gb addresses
	printElement("BYTES_REVERSED_LO      " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_BYTES_REVERSED_LO      ) == IMAGE_FILE_BYTES_REVERSED_LO      ) ? "TRUE" : "FALSE"); // Bytes of machine word are reversed.
	printElement("32BIT_MACHINE          " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_32BIT_MACHINE          ) == IMAGE_FILE_32BIT_MACHINE          ) ? "TRUE" : "FALSE"); // 32 bit word machine.
	printElement("DEBUG_STRIPPED         " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED         ) == IMAGE_FILE_DEBUG_STRIPPED         ) ? "TRUE" : "FALSE"); // Debugging info stripped from file in .DBG file
	printElement("REMOVABLE_RUN_FROM_SWAP" , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) == IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) ? "TRUE" : "FALSE"); // If Image is on removable media, copy and run from the swap file.
	printElement("NET_RUN_FROM_SWAP      " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP      ) == IMAGE_FILE_NET_RUN_FROM_SWAP      ) ? "TRUE" : "FALSE"); // If Image is on Net, copy and run from the swap file.
	printElement("SYSTEM                 " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_SYSTEM                 ) == IMAGE_FILE_SYSTEM                 ) ? "TRUE" : "FALSE"); // System File.
	printElement("DLL                    " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL                    ) == IMAGE_FILE_DLL                    ) ? "TRUE" : "FALSE"); // File is a DLL.
	printElement("UP_SYSTEM_ONLY         " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY         ) == IMAGE_FILE_UP_SYSTEM_ONLY         ) ? "TRUE" : "FALSE"); // File should only be run on a UP machine
	printElement("BYTES_REVERSED_HI      " , ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_BYTES_REVERSED_HI      ) == IMAGE_FILE_BYTES_REVERSED_HI      ) ? "TRUE" : "FALSE"); // Bytes of machine word are reversed.

	isDllImage = ((ntHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL);
	if (isDllImage) {
		analyze_and_printExportModules(fileMap, ntHdr);
	}

	return APP_SUCCESS;
}

AppReturnValues analyze_and_printExportModules(LPVOID fileMap, PIMAGE_NT_HEADERS ntHdr)
{
	ULONG                   size;
	PIMAGE_SECTION_HEADER   sectionHeader;
	PIMAGE_EXPORT_DIRECTORY exportDirectory;
	LPCSTR pname;
	ULONG* ppfuname;
	WORD * pordinal;

	exportDirectory = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToDataEx(fileMap, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size, &sectionHeader);
	if (exportDirectory == NULL) {
		return APP_ERR_NO_EXPORT_DIRECTORY;
	}

	printSubCategory("Exported Functions");

	pname    = (LPCSTR)ImageRvaToVa(ntHdr, fileMap, exportDirectory->Name, &sectionHeader);
	ppfuname = (ULONG*)ImageRvaToVa(ntHdr, fileMap, exportDirectory->AddressOfNames, &sectionHeader);
	pordinal = (WORD *)ImageRvaToVa(ntHdr, fileMap, exportDirectory->AddressOfNameOrdinals, &sectionHeader);
	
	for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i, ++ppfuname, ++pordinal)
	{
		LPSTR pfun     = (LPSTR)ImageRvaToVa(ntHdr, fileMap, *ppfuname, &sectionHeader);
		WORD  ordinal  = *pordinal + (WORD)exportDirectory->Base;
		LPSTR funcName =  pfun;
		printElement("Function", funcName);
	}

	return APP_SUCCESS;
}

更新履歴

2008.10.01
(初)