PE Parser in Windows API

This post hosts code I have written to parse and understand the PE file format.

The code

const CHAR* ImageResourceDirectoryNameToString(ULONG namenumber)
{
	// Resource Types
	// https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
	const CHAR* name = new const CHAR[50];

	switch(namenumber)
	{
		case 1:
			name = "Cursor";
		case 2:
			name = "Bitmap";
		case 3:
			name = "Icon";
		case 4:
			name = "Menu";
		case 5:
			name = "Dialog";
		case 6:
			name = "String";
		case 7:
			name = "Font Directory";
		case 8:
			name = "Font";
		case 9:
			name = "Accelerator";
		case 10:
			name = "RcData";
		case 11:
			name = "Message Table";
		case 16:
			name = "Version";
		case 17:
			name = "DlgInclude";
		case 19:
			name = "Plug and Play";
		case 20:
			name = "VXD";
		case 21:
			name = "Animated Cursor";
		case 22:
			name = "Animated Icon";
		case 23:
			name ="HTML";
		case 24:
			name = "Manifest";
		default:
			name = "Unknown";
	}

	return name;
}

void PrintExports64(CHAR* fBuffer, IMAGE_SECTION_HEADER* hdrSection, IMAGE_FILE_HEADER hdrFile)
{
	DWORD* ExportDirRVA = (DWORD*)(*(DWORD*)((uint64_t)fBuffer + 0x3c) + 0x88 + (uint64_t)fBuffer);
	DWORD ExportDirOffset = RVAToOffset(hdrFile, *ExportDirRVA, hdrSection);
	uint64_t AddressOfExportTable = (uint64_t)fBuffer + ExportDirOffset;
	DWORD AddressOfNamesRVA = *(DWORD*)((uint64_t)AddressOfExportTable + 0x20);
	DWORD AddressOfNamesOffset = RVAToOffset(hdrFile, AddressOfNamesRVA, hdrSection);
	uint64_t AddressOfNames = AddressOfNamesOffset + (uint64_t)fBuffer;
	DWORD NumberOfNames = *(DWORD*)((uint64_t)AddressOfExportTable + 0x18);

	if (NumberOfNames == 0)
	{
		printf("\tNo exports\n");
		exit(1);
	}

	printf("Export Table:\n");
	CHAR* APIName = 0;
	for (unsigned int i = 0; i < NumberOfNames; i++)
	{
		DWORD NameRVA = *(DWORD*)(AddressOfNames + sizeof(DWORD) * i);
		DWORD NameOffset = RVAToOffset(hdrFile, NameRVA, hdrSection);
		APIName = NameOffset + (CHAR*)fBuffer;

		printf("\t%d. Name: %s\n", i + 1, APIName);
	}
}

CHAR* ReadFileWrapper(CHAR* infile)
{
	BOOL status = FALSE;

	HANDLE hFile;

	hFile = CreateFileA(infile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("[-] CreateFileA has failed: %d\n", GetLastError());
		return 0;
	}

	DWORD lpFileSizeHigh = 0;
	DWORD fSize = GetFileSize(hFile, &lpFileSizeHigh);
	if (fSize == INVALID_FILE_SIZE)
	{
		printf("[-] GetFileSize has failed: %d\n", GetLastError());
		return 0;
	}

	DWORD nNumerOfBytesToRead = fSize;
	DWORD lpNumberOfBytesRead = 0;
	OVERLAPPED lpOverlapped = { 0 };
	CHAR* lpBuffer = new CHAR[nNumerOfBytesToRead];

	status = ReadFile(hFile, lpBuffer, nNumerOfBytesToRead, &lpNumberOfBytesRead, &lpOverlapped);
	if (!status)
	{
		printf("[-] ReadFile has failed: %d\n", GetLastError());
		return 0;
	}

	return lpBuffer;
}

int main(int argc, char** argv)
{
	CHAR* fBuffer = 0;

	printf("[+] In file: %s\n", argv[1]);

	fBuffer = ReadFileWrapper(argv[1]);
	if (fBuffer == 0) 
	{
		printf("[-] ReadFileWrapper has failed. Exiting...\n");
		exit(1);
	}

	IMAGE_DOS_HEADER* hdrDOS = (IMAGE_DOS_HEADER*)fBuffer;
	IMAGE_NT_HEADERS* hdrNT = (IMAGE_NT_HEADERS*)(fBuffer + hdrDOS->e_lfanew);
	IMAGE_FILE_HEADER hdrFile = (IMAGE_FILE_HEADER)hdrNT->FileHeader;
	//IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

	PrintDOSHeader(hdrDOS);
	PrintNTHeaderSignature(hdrNT);
	PrintFileHeader(hdrFile);

	// arch
	if (hdrFile.Machine == IMAGE_FILE_MACHINE_I386)
	{
		IMAGE_NT_HEADERS32* hdrNT = (IMAGE_NT_HEADERS32*)(fBuffer + hdrDOS->e_lfanew);
		IMAGE_OPTIONAL_HEADER32 hdrOptional = (IMAGE_OPTIONAL_HEADER32)hdrNT->OptionalHeader;
		PrintOptionalHeader<IMAGE_OPTIONAL_HEADER32>(hdrOptional);
		PrintImgDataDirectory(hdrOptional);

		IMAGE_SECTION_HEADER* hdrSection = IMAGE_FIRST_SECTION(hdrNT);

		PrintSectionInformation(hdrSection, hdrFile.NumberOfSections);
	}
	else if (hdrFile.Machine == IMAGE_FILE_MACHINE_AMD64)
	{
		IMAGE_NT_HEADERS64* hdrNT = (IMAGE_NT_HEADERS64*)(fBuffer + hdrDOS->e_lfanew);
		IMAGE_OPTIONAL_HEADER64 hdrOptional = (IMAGE_OPTIONAL_HEADER64)hdrNT->OptionalHeader;
		PrintOptionalHeader<IMAGE_OPTIONAL_HEADER64>(hdrOptional);
		PrintImgDataDirectory(hdrOptional);

		IMAGE_SECTION_HEADER* hdrSection = IMAGE_FIRST_SECTION(hdrNT);

		PrintSectionInformation(hdrSection, hdrFile.NumberOfSections);
		PrintExports64(fBuffer, hdrSection, hdrFile);
	}
}

tags: #Windows API