Windows解析dll文件的导出表

头文件CpeUtil.h的内容:

#pragma once
#include<Windows.h>


class CPeUtil
{
public:
	CPeUtil();
	~CPeUtil();

	BOOL LoadFile(const char* path);
	BOOL InitPeInfo();
	void PrintSectionHeaders();
	void GetExportTable();

private:
	char* fileBuff;
	DWORD FileSize;
	PIMAGE_DOS_HEADER pDosHeader;
	PIMAGE_NT_HEADERS pNtHeader;
	PIMAGE_FILE_HEADER pFileHeader;
	PIMAGE_OPTIONAL_HEADER pOptionHeader;
	DWORD Rva2Foa(DWORD rva);
};

源文件CPeUtil.cpp内容:

#include "CPeUtil.h"
#include "stdio.h"

CPeUtil::CPeUtil()
{
	fileBuff = NULL;
	FileSize = 0;
	pDosHeader = NULL;
	pNtHeader = NULL;;
	pFileHeader = NULL;
	pOptionHeader = NULL;
}

CPeUtil::~CPeUtil()
{
	if (NULL != fileBuff)
	{
		delete[] fileBuff;
	}
}

BOOL CPeUtil::LoadFile(const char* path)
{
	HANDLE hFile = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	if (hFile == 0)
	{
		return FALSE;
	}
	FileSize = GetFileSize(hFile, 0);
	fileBuff = new char[FileSize] {0};

	DWORD realReadBytes = 0;
	BOOL readSuccess = ReadFile(hFile, fileBuff, FileSize, &realReadBytes, 0);
	if (0 == readSuccess)
	{
		return FALSE;
	}
	if (this->InitPeInfo())
	{
		return TRUE;
	}

	return FALSE;
}

BOOL CPeUtil::InitPeInfo()
{
	pDosHeader = (PIMAGE_DOS_HEADER)fileBuff;
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		return FALSE;
	}

	pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + fileBuff);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		return FALSE;
	}

	pFileHeader = &pNtHeader->FileHeader;
	pOptionHeader = &pNtHeader->OptionalHeader;


	return TRUE;
}

void CPeUtil::PrintSectionHeaders()
{
	PIMAGE_SECTION_HEADER pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeader);
	for (int i = 0; i < pFileHeader->NumberOfSections; ++i)
	{
		char name[9] = { 0 };
		memcpy_s(name, 9, pSectionHeaders->Name, 8);
		printf("区段名称=%s
", name);
		pSectionHeaders++;
	}
}

///< 解析导出表
void CPeUtil::GetExportTable()
{
	IMAGE_DATA_DIRECTORY directory = pOptionHeader->DataDirectory[0];
	///< 得到导出表的位置
	PIMAGE_EXPORT_DIRECTORY pexport = (PIMAGE_EXPORT_DIRECTORY)(Rva2Foa(directory.VirtualAddress) + fileBuff);
	char* dllName = Rva2Foa(pexport->Name) + fileBuff;
	printf("文件名称:%s
", dllName);

	DWORD * funcAddr = (DWORD*)(Rva2Foa(pexport->AddressOfFunctions) + fileBuff);
	WORD * peot = (WORD*)(Rva2Foa(pexport->AddressOfNameOrdinals) + fileBuff); ///<序号表的地址
	DWORD * pent = (DWORD*)(Rva2Foa(pexport->AddressOfNames) + fileBuff);

	for (int i = 0; i < pexport->NumberOfFunctions; ++i)
	{
		printf("函数地址为:%x  ****  ", *funcAddr);
		for (int j = 0; j < pexport->NumberOfNames; ++j)
		{
			if (peot[j] == i)
			{
				char* funName =(char*)(Rva2Foa(pent[j]) + fileBuff);
				printf("函数名称为: %s
", funName);
			}
		}

		funcAddr++;
	}
}

DWORD CPeUtil::Rva2Foa(DWORD rva)
{
	PIMAGE_SECTION_HEADER pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeader);
	for (int i = 0; i < pFileHeader->NumberOfSections; ++i)
	{
		if (rva >= pSectionHeaders->VirtualAddress && rva < pSectionHeaders->VirtualAddress + pSectionHeaders->Misc.VirtualSize)
		{
			///< FOA = 数据的RVA - 区段的RVA + 数据的FOA
			return rva - pSectionHeaders->VirtualAddress + pSectionHeaders->PointerToRawData;
		}
		pSectionHeaders++;
	}
	return 0;
}

main.cpp的内容

#include<iostream>
#include "CPeUtil.h"


int main()
{
	CPeUtil peUtil;
	BOOL success = peUtil.LoadFile("./7z.dll");
	if (success)
	{
		//peUtil.PrintSectionHeaders();
		peUtil.GetExportTable();
		return 0;
	}
	printf("加载PE文件失败
");
	return 0;
}