pe文件二进制解析(用c/c++解析一个二进制pe文件)

pe文件二进制解析


c++解析pe文件控制台版本

c 复制代码
#include<iostream>
#include<windows.h>
#include<vector>


/*
	RVA(相对虚拟地址)与FOA(文件偏移地址)的转换
	1.得到  的值:内存地址 - ImageBase
	2.判断是否位于PE头中,如果是:FOV = RVA
	3.判断RVA位于哪个节:
		RVA >= 节.VirtualAddress
		RVA <= 节.VirtualAddress + 当前节内存对齐后的大小
		差值 = RVA - 节.VirtualAddress
*/


using namespace std;


// 定义一个存放节表数据的结构体
typedef struct SectionTable {
	// 在虚拟内存中的地址
	DWORD myVirtualAddress;
	// 在文件中的偏移
	DWORD myPointerToRawData;
}SECTION_TABLE, * PSECTION_TABLE;

// 基本数据结构体
typedef struct BaseData {
	ULONGLONG myImageBase;
	DWORD mySectionAlignment;
	DWORD myFileAlignment;
}BASE_DATA, * PBASE_DATA;

// 表地址结构体
typedef struct TableAddress {
	DWORD myVirtualAddress;
	DWORD mySize;
}TABLE_ADDRESS, * PTABLE_ADDRESS;

// 创建一个全局的节表数组和表地址数组
vector<SectionTable> g_sectionTable;
vector<TableAddress> g_tableAddress;

// 全局的基本数据
BaseData g_baseData;


// 节的数量
WORD NumberOfSections = 0;

// 文件对齐和内存对齐是否一致
BOOL FILE_EQUALS_MEMORY = TRUE;

// 获取标准pe文件头信息
void getStandardPeHeaderAttribute(IMAGE_FILE_HEADER standardPeHeader);
// 获取扩展pe文件头信息
void getExtendPeHeaderAttribute(IMAGE_OPTIONAL_HEADER extendPeHeader);
// 获取数据目录信息
void getDataDirectoryInfo(const IMAGE_DATA_DIRECTORY* dataDirectory);
// 获取节表信息并把值放入数组中
void getSectionHerader(PIMAGE_SECTION_HEADER sectionHerader, IMAGE_FILE_HEADER standardPeHeader);
// RVA 转 FOA
DWORD rvaToFoa(DWORD address);


// 获取导出表
void getExportsInfo(const char* peFileBuffer);
// 获取导入表
void getImportsInfo(const char* peFileBuffer);
// 获取重定位表
void getRepositionInfo(const char* peFileBuffer);





int main() {
	// 判断是否是PE文件
	HANDLE hPeFile = CreateFile(L"C://Users//BananaLi//Desktop//mydll.dll",
		GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hPeFile != INVALID_HANDLE_VALUE) { // 文件打开成功
		// 得到文件大小
		DWORD peFileSize = GetFileSize(hPeFile, NULL);
		printf("文件大小为:%d 字节\n", peFileSize);
		// 读文件
		char* peFileBuffer = new char[peFileSize] {0};

		if (ReadFile(hPeFile, peFileBuffer, peFileSize, NULL, NULL)) {
			// 讲读取到的文件内容转换为IMAGE_DOS_HEADER结构体
			PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)peFileBuffer;

			if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
				cout << "该文件不是PE文件\n";
				exit(0);
			}
			else
			{
				// 解析头文件
				printf("PE文件头:0x%X\n", pDosHeader->e_magic);
				printf("PE文件偏移:0x%X\n", pDosHeader->e_lfanew);

				// 获取nt头
				PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(peFileBuffer + pDosHeader->e_lfanew);
				if (pNtHeader->Signature != IMAGE_NT_SIGNATURE){
					cout << "该文件不是PE文件\n";
					exit(0);
				}
				else 
				{
					// 获取标准pe头
					printf("PE头标识:0x%X\n", pNtHeader->Signature);
					IMAGE_FILE_HEADER standardPeHeader = pNtHeader->FileHeader;
					printf("标准PE头大小:%lld 字节\n",sizeof(standardPeHeader));
					getStandardPeHeaderAttribute(standardPeHeader);
					
					// 获取扩展pe头
					IMAGE_OPTIONAL_HEADER extendPeHeader = pNtHeader->OptionalHeader;
					printf("扩展PE头大小:%lld 字节\n", sizeof(extendPeHeader));
					getExtendPeHeaderAttribute(extendPeHeader);

					// 获取节表的数据
					PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(peFileBuffer + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
					printf("节表的大小:%d 字节\n", standardPeHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER);
					// 获取节表范围数据
					getSectionHerader(sectionHeader, standardPeHeader);

					// 获取导出表的数据
					getExportsInfo(peFileBuffer);

					// 获取导入表的数据
					getImportsInfo(peFileBuffer);

					// 获取重定位表的数据
					getRepositionInfo(peFileBuffer);
				}

				
			}
			
			
		}

		delete[] peFileBuffer; // 回收
	}
	else {
		cout << "文件打开失败,请检查文件是否存在\n";
	}


	system("pause");
	return 0;
}


void getStandardPeHeaderAttribute(IMAGE_FILE_HEADER standardPeHeader) {
	cout << "标准PE头信息如下:\n";
	printf("可以运行在什么样的CPU上:0x%X\n", standardPeHeader.Machine);
	printf("节的数量:%d\n", standardPeHeader.NumberOfSections);
	printf("编译器填写的时间戳:%d\n", standardPeHeader.TimeDateStamp);
	printf("调试相关:0x%X\n", standardPeHeader.PointerToSymbolTable);
	printf("调试相关:0x%X\n", standardPeHeader.NumberOfSymbols);
	printf("可选PE头的大小(32位PE文件:0xE0 , 64位PE文件:0xF0):0x%X\n", standardPeHeader.SizeOfOptionalHeader);
	printf("文件属性:0x%X\n", standardPeHeader.Characteristics);

	// TODO 后续添加文件属性解析
}


void getExtendPeHeaderAttribute(IMAGE_OPTIONAL_HEADER extendPeHeader) {
	cout << "扩展PE头信息如下:\n";
	printf("Magic(10B就是32位,20B就是64位的应用程序):0x%X\n", extendPeHeader.Magic);
	printf("链接器版本号:0x%X\n", extendPeHeader.MajorLinkerVersion);
	printf("链接器版本号:0x%X\n", extendPeHeader.MinorLinkerVersion);
	printf("所有代码节的总和(文件对齐后的大小 *编译器填写无实际作用):0x%X\n", extendPeHeader.SizeOfCode);
	printf("包含所有已经初始化数据的节的部大小(文件对齐后的大小 *编译器填写无实际作用):0x%X\n", extendPeHeader.SizeOfInitializedData);
	printf("包含未初始化数据的节的总大小(文件对齐后的大小 *编译器填写无实际作用):0x%X\n", extendPeHeader.SizeOfUninitializedData);
	printf("程序入口(重要):0x%X\n", extendPeHeader.AddressOfEntryPoint);
	printf("代码开始的基地(*编译器填写无实际作用):0x%X\n", extendPeHeader.BaseOfCode);
	printf("内存镜像基地(重要):0x%llX\n", extendPeHeader.ImageBase);
	g_baseData.myImageBase = extendPeHeader.ImageBase;
	printf("内存对齐(重要):0x%X\n", extendPeHeader.SectionAlignment);
	g_baseData.mySectionAlignment = extendPeHeader.SectionAlignment;
	printf("文件对齐(重要):0x%X\n", extendPeHeader.FileAlignment);
	g_baseData.myFileAlignment = extendPeHeader.FileAlignment;
	printf("标识操作系统版本号(主版本号):0x%X\n", extendPeHeader.MajorOperatingSystemVersion);
	printf("标识操作系统版本号(次版本号):0x%X\n", extendPeHeader.MinorOperatingSystemVersion);
	printf("PE文件自身的版本号(主版本号):0x%X\n", extendPeHeader.MajorImageVersion);
	printf("PE文件自身的版本号(次版本号):0x%X\n", extendPeHeader.MinorImageVersion);
	printf("运行所所需子系统版本号(主版本号):0x%X\n", extendPeHeader.MajorSubsystemVersion);
	printf("运行所所需子系统版本号(次版本号):0x%X\n", extendPeHeader.MinorSubsystemVersion);
	printf("子系统版本的值必须为0:0x%X\n", extendPeHeader.Win32VersionValue);
	printf("内存中整个PE文件的映射的尺寸,可比实际的值大,必须是SectionAlignment的整数倍:0x%X\n", extendPeHeader.SizeOfImage);
	printf("所有头+节表按照文件对齐后的大小,否则加载会出错:0x%X\n", extendPeHeader.SizeOfHeaders);
	printf("核验和,一些系统文件有要求,用来判断文件是否被修改:0x%X\n", extendPeHeader.CheckSum);
	printf("子系统 (驱动程序1 图形界面2 控制台,DLL3 ):0x%X\n", extendPeHeader.Subsystem);
	printf("文件特性 不是针对DLL文件的:0x%X\n", extendPeHeader.DllCharacteristics);
	printf("初始化时保留的栈大小:0x%llX\n", extendPeHeader.SizeOfStackReserve);
	printf("初始化时实际提交的大小:0x%llX\n", extendPeHeader.SizeOfStackCommit);
	printf("初始化时保留的堆大小:0x%llX\n", extendPeHeader.SizeOfHeapReserve);
	printf("初始化时实践提交的大小:0x%llX\n", extendPeHeader.SizeOfHeapCommit);
	printf("调试相关:0x%X\n", extendPeHeader.LoaderFlags);
	printf("目录项数目:0x%X\n", extendPeHeader.NumberOfRvaAndSizes);
	printf("数据目录大小:%lld\n", sizeof(extendPeHeader.DataDirectory));

	// TODO DllCharacteristics属性解析

	// 判断文件对齐和内存对齐是否一致
	if (extendPeHeader.SectionAlignment != extendPeHeader.FileAlignment) FILE_EQUALS_MEMORY = FALSE;
	
	IMAGE_DATA_DIRECTORY *dataDirectory = extendPeHeader.DataDirectory;
	// TODO IMAGE_DATA_DIRECTORY属性解析
	getDataDirectoryInfo(dataDirectory);
	
}




void getDataDirectoryInfo(const IMAGE_DATA_DIRECTORY* dataDirectory) {

	

	for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
		
		TableAddress tableAddress;

		switch (i)
		{
			case 0 :printf("1.导出表:\n");
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 1 :printf("2.导入表:\n");
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 2 :printf("3.资源表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 3 :printf("4.异常处理表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 4 :printf("5.安全目录:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 5 :printf("6.基址重定位表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 6 :printf("7.调试目录:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 7 :printf("8.架构特定数据:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 8 :printf("9.全局指针表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 9 :printf("10.线程局部存储表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 10 :printf("11.加载配置表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 11 :printf("12.绑定导入表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 12 :printf("13.导入地址表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 13 :printf("14.延迟导入表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 14 :printf("15.COM描符表:\n"); 
				printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);
				tableAddress.myVirtualAddress = dataDirectory[i].VirtualAddress;
				tableAddress.mySize = dataDirectory[i].Size;
				g_tableAddress.push_back(tableAddress);
				break;
			case 15 :printf("16.保留(目前未使用)\n"); 
				/*printf("VirtualAddress:0x%X\n", dataDirectory[i].VirtualAddress);
				printf("VirtualSize:0x%X\n", dataDirectory[i].Size);*/
				break;
		default:
			break;
		}

		
	}


	/*
	一共有十六个IMAGE_DATA_DIRECTORYENDS结构
	IMAGE_DIRECTORY_ENTRY_EXPORT        导出表
	IMAGE_DIRECTORY_ENTRY_IMPORT        导入表
	IMAGE_DIRECTORY_ENTRY_RESOURCE     资源
	IMAGE_DIRECTORY_ENTRY_EXCEPTION     异常(具体资料不详)
	IMAGE_DIRECTORY_ENTRY_SECURITY      安全(具体资料不详)
	IMAGE_DIRECTORY_ENTRY_BASERELOC    重定位表
	IMAGE_DIRECTORY_ENTRY_DEBUG         调试信息
	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 版权信息
	IMAGE_DIRECTORY_ENTRY_GLOBALPTR    具体资料不详
	IMAGE_DIRECTORY_ENTRY_TLS            Thread Local Storage
	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG  具体资料不详
	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 具体资料不详
	IMAGE_DIRECTORY_ENTRY_IAT              导入函数地址表
	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT  具体资料不详
	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 具体资料不详
	未使用保留
	*/
}

void getSectionHerader(PIMAGE_SECTION_HEADER sectionHerader, IMAGE_FILE_HEADER standardPeHeader) {

	cout << "节表信息如下:\n";
	// 获取节表的个数
	WORD sectionTableNum = standardPeHeader.NumberOfSections;
	for (int i = 0; i < sectionTableNum; i++) {
		SectionTable mySectionTable;
		printf("节表的名称:%s\n", sectionHerader->Name);
		printf("节没有对齐时的大小(可以不准确):0x%X\n", sectionHerader->Misc);
		printf("在内存中的偏移地址,加上ImageBase才是内存中的真正地址:0x%X\n", sectionHerader->VirtualAddress);
		mySectionTable.myVirtualAddress = sectionHerader->VirtualAddress;
		printf("节在文件中对齐后的尺寸:0x%X\n", sectionHerader->SizeOfRawData);

		printf("节在文件中的偏移:0x%X\n", sectionHerader->PointerToRawData);
		mySectionTable.myPointerToRawData = sectionHerader->PointerToRawData;
		g_sectionTable.push_back(mySectionTable);
		printf("调用相关:0x%X\n", sectionHerader->PointerToRelocations);
		printf("调用相关:0x%X\n", sectionHerader->PointerToLinenumbers);
		printf("调用相关:0x%X\n", sectionHerader->NumberOfRelocations);
		printf("调用相关:0x%X\n", sectionHerader->NumberOfLinenumbers);
		printf("节的属性:0x%X\n", sectionHerader->Characteristics);
		sectionHerader++; // 每次加一个节表结构体

	}

}


// Rva -> FOA
DWORD rvaToFoa(DWORD address) {

	for (int i = 0; i < g_sectionTable.size() - 1; i++) {

		if (address >= g_sectionTable[i].myVirtualAddress && address < g_sectionTable[i + 1].myVirtualAddress) {
			// 节上的偏移
			DWORD offsetAddress = address - g_sectionTable[i].myVirtualAddress;
			// 节上的偏移加上节在文件的偏移 = 节在文件上的位置 
			return g_sectionTable[i].myPointerToRawData + offsetAddress;
		}

		// 判断最后一个节
		if (address == g_sectionTable[i + 1].myVirtualAddress) {
			// 节上的偏移
			DWORD offsetAddress = address - g_sectionTable[i + 1].myVirtualAddress;
			// 节上的偏移加上节在文件的偏移 = 节在文件上的位置 
			return g_sectionTable[i + 1].myPointerToRawData + offsetAddress;
		}
	}

}


// 获取导出表
void getExportsInfo(const char* peFileBuffer) {

	//IMAGE_EXPORT_DIRECTORY exportDirectory;


	if (FILE_EQUALS_MEMORY) {
		// 文件对齐跟内存对齐一样不需要做处理
	}
	else {
		TableAddress exportAddress = g_tableAddress[IMAGE_DIRECTORY_ENTRY_EXPORT];
		if (exportAddress.myVirtualAddress == 0) {
			// 当前程序不存在导出表
			return;
		}
		DWORD fileAddress = rvaToFoa(exportAddress.myVirtualAddress);
		// 这里指向导出表的结构体
		PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(peFileBuffer + fileAddress);
		// 获取所有导出的函数个数 
		DWORD exportCount = exportDirectory->NumberOfFunctions;
		// 获取函数名导出的函数个数
		DWORD nameCount = exportDirectory->NumberOfNames;
		printf("Characteristics(未使用):0x%X\n", exportDirectory->Characteristics);
		printf("TimeDateStamp(时间戳):0x%X\n", exportDirectory->TimeDateStamp);
		printf("MajorVersion(未使用):0x%X\n", exportDirectory->MajorVersion);
		printf("MinorVersion(未使用):0x%X\n", exportDirectory->MinorVersion);
		printf("Name(指向该导出表文件名字符串):%s\n", peFileBuffer + rvaToFoa(exportDirectory->Name));
		printf("Base(导出函数起始序号):0x%X\n", exportDirectory->Base);
		printf("NumberOfFunctions(所有导出函数的个数):%d\n", exportCount);
		printf("NumberOfNames(以函数名导出的函数个数):%d\n", nameCount);
		printf("AddressOfFunctions(导出函数地址表 重要):0x%X\n", exportDirectory->AddressOfFunctions);
		printf("AddressOfNames(导出函数名称表 重要):0x%X\n", exportDirectory->AddressOfNames);
		printf("AddressOfNameOrdinals(导出函数序号表 重要):0x%X\n", exportDirectory->AddressOfNameOrdinals);

		//printf("AddressOfFunctions地址:0x%X\n", rvaToFoa(exportDirectory->AddressOfFunctions));
		//printf("AddressOfNames地址:0x%X\n", rvaToFoa(exportDirectory->AddressOfNames));
		//printf("AddressOfNameOrdinals地址:0x%X\n", rvaToFoa(exportDirectory->AddressOfNameOrdinals));

		// 读取函数地址表
		DWORD addressFuncFoa = rvaToFoa(exportDirectory->AddressOfFunctions);
		for (int i = 0; i < exportCount; i++) {
			// 打印函数地址
			DWORD* tempAddress = (DWORD*)(peFileBuffer + addressFuncFoa);
			printf("第%d个函数地址为:0x%X\n", i, rvaToFoa(*(tempAddress + i)));
		}


		// 读取函数名称表
		DWORD nameFuncFoa = rvaToFoa(exportDirectory->AddressOfNames);
		for (int i = 0; i < nameCount; i++) {
			DWORD* tempName = (DWORD*)(peFileBuffer + nameFuncFoa);
			printf("第%d个函数名称为:%s\n", i, peFileBuffer + rvaToFoa(*(tempName + i)));
		}


	}

}

// 获取导入表
void getImportsInfo(const char* peFileBuffer) {
	if (FILE_EQUALS_MEMORY) {
		// TODO 文件对齐跟内存对齐一样不需要做处理
	}
	else {
		int importCount = 0;
		
		TableAddress ImportAddress = g_tableAddress[IMAGE_DIRECTORY_ENTRY_IMPORT];
		// rva转foa
		DWORD fileAddress = rvaToFoa(ImportAddress.myVirtualAddress);
		// 这里指向导入表的结构体

		
		PIMAGE_IMPORT_DESCRIPTOR importDirectory = (PIMAGE_IMPORT_DESCRIPTOR)(peFileBuffer + fileAddress);

		// 遍历导入表
		while (importDirectory->Name != 0) {
			int iatCount = 1;
			char * dllName = (char*)(peFileBuffer + rvaToFoa(importDirectory->Name));
			printf("对应导入表名称:%s\n", dllName);
			printf("OriginalFirstThunk对应导入表的INT地址和使用的方法:0x%X\n", rvaToFoa(importDirectory->OriginalFirstThunk));

			
			PIMAGE_THUNK_DATA OriginalFirstThunkIAT = (PIMAGE_THUNK_DATA)(peFileBuffer + rvaToFoa(importDirectory->OriginalFirstThunk));
			// reinterpret_cast c++ 推荐使用
			//PIMAGE_THUNK_DATA OriginalFirstThunkIAT = reinterpret_cast<PIMAGE_THUNK_DATA>(peFileBuffer + rvaToFoa(importDirectory->OriginalFirstThunk));
			// 遍历INT表,有多少个PIMAGE_THUNK_DATA结构体就表示有多少个导入函数
			while (OriginalFirstThunkIAT->u1.Ordinal != 0 || OriginalFirstThunkIAT->u1.AddressOfData != 0) {
				//printf("%d.%s对应导入表的INT:0x%X\n", iatCount, dllName, OriginalFirstThunkIAT->u1.Ordinal);
				// 判断最高位是否为1
				if ((OriginalFirstThunkIAT->u1.Ordinal & 0x80000000) != TRUE) {
					DWORD IATRav = rvaToFoa(OriginalFirstThunkIAT->u1.Ordinal); // IMAGE_IMPORT_BY_NAME
					PIMAGE_IMPORT_BY_NAME dllImport = (PIMAGE_IMPORT_BY_NAME)(peFileBuffer + IATRav);
					printf("Hint:%d\n", dllImport->Hint);
					printf("Name:%s\n", dllImport->Name);
				}
				else {
					// TODO 最高位为1,解析导出序号,通过通过序号来获取导入函数
					
				}
				OriginalFirstThunkIAT++;
				iatCount++;
			}
			//printf("FirstThunk对应导入表的IAT:0x%X\n", rvaToFoa(importDirectory->FirstThunk));
			importDirectory++;
			importCount++;

		}
		
	}


}


// 获取重定位表
void getRepositionInfo(const char* peFileBuffer) {

	// 获取重定位表地址
	TableAddress repositionAddress = g_tableAddress[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	// 得到文件地址
	DWORD fileAddress = rvaToFoa(repositionAddress.myVirtualAddress);
	// 解析结构体
	PIMAGE_BASE_RELOCATION relocationDirectory = (PIMAGE_BASE_RELOCATION)(peFileBuffer + fileAddress);

	DWORD size = 0;
	
	while (true) {

		// 重新计算重定位表地址
		PIMAGE_BASE_RELOCATION relocationDirectory = (PIMAGE_BASE_RELOCATION)(peFileBuffer + fileAddress + size);
		
		if (relocationDirectory->VirtualAddress == 0 && relocationDirectory->SizeOfBlock == 0) {
			// 定位表结束
			break;

		}

		// 定位偏移地址位置
		WORD* relocation = (WORD*)(peFileBuffer + fileAddress + size + sizeof(IMAGE_BASE_RELOCATION));

		// 解析重定位表地址偏移
		for (int i = 0; i < (relocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); i++) {

			printf("relocation:0x%X \n", *relocation);

			// 提取高4位 重定位类型
			WORD type = (*relocation >> 12) & 0xF;

			// 提取低12位 偏移量
			WORD offset = *relocation & 0xFFF;

			printf("type:0x%X \n", type);

			printf("offset:0x%X \n", offset);

			relocation++;

		}

		printf("VirtualAddress:0x%X \n", relocationDirectory->VirtualAddress);
		printf("SizeOfBlock:%d 字节 \n", relocationDirectory->SizeOfBlock);

		size += relocationDirectory->SizeOfBlock;

	}



}

解析信息

重定位表信息

节表信息

导出方法和导入方法

16张表地址和大小

pe头信息,标准pe头信息,扩展pe头信息

相关推荐
炎芯随笔5 分钟前
【C++】【设计模式】生产者-消费者模型
开发语言·c++·设计模式
乌鸦94426 分钟前
《类和对象(下)》
开发语言·c++·类和对象+
逐光沧海1 小时前
数据结构基础--蓝桥杯备考
数据结构·c++·算法·蓝桥杯
前进的程序员1 小时前
嵌入式开发中 C++ 跨平台开发经验与解决方案
开发语言·c++
菜一头包1 小时前
c++ std库中的文件操作学习笔记
c++·笔记·学习
吃个早饭3 小时前
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
c语言·c++·蓝桥杯
阿沁QWQ4 小时前
单例模式的两种设计
开发语言·c++·单例模式
六bring个六4 小时前
qtcreater配置opencv
c++·qt·opencv·计算机视觉·图形渲染·opengl
yxc_inspire5 小时前
基于Qt的app开发第八天
开发语言·c++·qt