PE文件格式

c++

Posted by YiMiTuMi on June 24, 2021

PE文件格式

建议自行百度。

VirtualAddress 转 PionterToRawData

1.

先判断是否在文件头中,文件头不会被拉伸

2.

判断那个节表:

x > VirtualAddress

x < VirtualAddress + misc.virtualSize

3.

找到对应节表后计算差值y:

x - VirtualAddress = y

4.

PionterToRawData + 插值 = FOA

y + PionterToRawData = FileBufforAddress

导入表打印

根据函数名字查找函数地址:

1.遍历AddressOfNames表找到对应的函数名,获得下标

2.根据下标在AddressOfNameOrdinals表获取对应下表的值。

3.将获取的值当作下标在AddressOfFunction表中查询出地址。

根据序号查找函数地址:

1.将获取的序号 - Base,获取出值。

2.将获取的值当作下标在AddressOfFunction表中查询出地址。

PE功能程序

PEOperation.h

#pragma once
#include <Windows.h>

typedef struct _IMAGE_FILE_INFO
{
	LPVOID pFileBuffer; //硬盘中文件的地址
	LPVOID pImageBuffer; //文件读取到内存中的地址
	PIMAGE_DOS_HEADER pDosHeader; //dos头
	PIMAGE_NT_HEADERS pNtHeader;  //NT头
	PIMAGE_FILE_HEADER pPeHeader; //标准PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionalPeHeader; //可选PE头
	PIMAGE_SECTION_HEADER pSectionHeader; //第一个节表
	DWORD dwFileSize;

}IMAGE_FILE_INFO , *PIMAGE_FILE_INFO;

//节表大小
#define SINGLE_SECTION_TABLE_SIZE 40

//返回值
#define SURPLUS_SPACE_INSUFFICIENT 1
#define SURPLUS_SPACE_EXIST_USABLE_DATA 2
#define SURPLUS_SPACE_USABLE 3

class CPEOperation
{

public:
	CPEOperation(void);
	~CPEOperation(void);

public:
	
	//RVAToFOA
	DWORD RVAToFOA(DWORD dwRva);

	//获取文件在内存中的地址
	BOOL ReadPEFile(LPSTR lpSzFilePath);

	//将文件映像对齐到内存中
	BOOL CopyFileBufferToImageBase(LPVOID pFileBuffer);

	void GetPeFileInfo(PIMAGE_FILE_INFO OutImageFileInfo);

	//导出表
	BOOL GetExportFunctionTable();
	
	//重定位表
	BOOL GetRelocationTable();

	//导入表
	BOOL GetImportTable();

	//绑定导入表
	BOOL GetBindImportTable();

	//增加新的节表
	BOOL AddNewSectionTable();
	
	//修复IAT表
	BOOL RepairImportTable();

private:

	//判断新增节剩余空间是否足够,并且剩余空间是否存在可用数据
	void JudgeSurplusSpaceUse(int &iReturnType, DWORD &dwHeaderSurplusSize, DWORD dwLastSecotrLastAddress);

	BOOL DirectAddNewSectionTable(DWORD &dwLastSecotrStartOffset, DWORD &dwLastSecotrLastOffset);

public:

	PIMAGE_FILE_INFO m_pImageFileInfo;

};

/*
假如你要置的是第k位,要把第k位置1,目标int是a那么:
a = a|(1<<(k-1));
假如你要把第k位置为0,那么:
a = a&(~(1<<(k-1)));
*/

PEOperation.cpp

#include "StdAfx.h"
#include "PEOperation.h"
#include <string>

using namespace std;

CPEOperation::CPEOperation(void)
{
	m_pImageFileInfo = new IMAGE_FILE_INFO;
}

CPEOperation::~CPEOperation(void)
{
	if (m_pImageFileInfo->pFileBuffer != NULL)
	{
		free(m_pImageFileInfo->pFileBuffer);
	}

	if (m_pImageFileInfo->pImageBuffer != NULL)
	{
		free(m_pImageFileInfo->pImageBuffer);
	}

	if (m_pImageFileInfo != NULL)
	{
		delete m_pImageFileInfo;
	}
}

void CPEOperation::GetPeFileInfo(PIMAGE_FILE_INFO OutImageFileInfo)
{
	OutImageFileInfo = m_pImageFileInfo;
}

//RVAToFOA
DWORD CPEOperation::RVAToFOA(DWORD dwRva)
{
	DWORD dwFoa;

	//判断是否在文件头中, 在则返回
	if (dwRva <= m_pImageFileInfo->pOptionalPeHeader->SizeOfHeaders)
	{
		return dwRva;
	}
	
	//先判断Rva属于哪个节
	PIMAGE_SECTION_HEADER pSector = m_pImageFileInfo->pSectionHeader; //节表开始的位置
	//循环节表
	int iSecotrNumber = (int)m_pImageFileInfo->pPeHeader->NumberOfSections; //获取节表数量
	for (;iSecotrNumber != 0; iSecotrNumber--, pSector++)
	{
		//当前节起始的虚拟地址和当前虚拟地址+节的大小,判断RVA是否在里面
		if (dwRva >= pSector->VirtualAddress && dwRva <= (pSector->VirtualAddress + pSector->SizeOfRawData)) 
		{
			//计算差值
			DWORD dwDifference = dwRva - pSector->VirtualAddress;
			
			//FOA = 差值 + PointerToRawData
			
			dwFoa = dwDifference + pSector->PointerToRawData;
			
			break;
		}	
	}

	return dwFoa;
}


BOOL CPEOperation::ReadPEFile(LPSTR lpSzFilePath)
{
	FILE* pFile = NULL;
	DWORD dwFileSize = 0;
	LPVOID pTempFileBuffer = NULL;

	//打开文件	
	fopen_s(&pFile, lpSzFilePath, "rb"); 
	if (pFile == NULL)
	{
		printf("无法打开文件!");
		return FALSE;
	}

	//读取文件大小
	fseek(pFile, 0, SEEK_END); 
	dwFileSize = ftell(pFile); //该函数对大于2^31-1文件,即:2.1G以上的文件操作时可能出错。
	fseek(pFile, 0 , SEEK_SET);

	//分配缓冲区
	pTempFileBuffer = malloc(dwFileSize);
	if (pTempFileBuffer == NULL)
	{
		printf("分配空间失败");
		fclose(pFile);
		return FALSE;
	}

	//将文件读取到缓冲区
	size_t iSize = fread(pTempFileBuffer, dwFileSize, 1, pFile);
	if (!iSize)
	{
		printf("读取文件到缓冲区失败!");
		free(pTempFileBuffer);
		fclose(pFile);
		return FALSE;
	}

	fclose(pFile);
	
	//将文件映像到内存(字节对齐)
	if (!CopyFileBufferToImageBase(pTempFileBuffer))
	{
		printf("文件映像到内存失败!");
		return FALSE; 
	}
	
	m_pImageFileInfo->pFileBuffer = pTempFileBuffer;
	m_pImageFileInfo->dwFileSize = dwFileSize;
	pTempFileBuffer = NULL;

	return TRUE;
}

BOOL CPEOperation::CopyFileBufferToImageBase(LPVOID pFileBuffer)
{
	PIMAGE_DOS_HEADER pDos = NULL;
	PIMAGE_NT_HEADERS pNt = NULL;
	PIMAGE_FILE_HEADER pPe = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalPe = NULL;
	PIMAGE_SECTION_HEADER pSection = NULL;
	LPVOID pImageBuffer = NULL;
	
	if (pFileBuffer == NULL)
	{
		printf("缓冲区指针无效");
		return FALSE;
	}
	
	//判断Mz标记
	/*
	if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志!");
		return FALSE;
	}
	*/
	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) //获取前两个字符
	{
		printf("不是有效的MZ标志!");
		return FALSE;
	}

	//获取DOS头
	pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
	m_pImageFileInfo->pDosHeader = pDos;
	
	//判断PE标记
	if (*((PDWORD)((DWORD)pFileBuffer + pDos->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志!");
		return FALSE;
	}
	
	pNt = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDos->e_lfanew);
	pPe = (PIMAGE_FILE_HEADER)((DWORD)pNt + 4);     //标准PE头

	pOptionalPe = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPe + IMAGE_SIZEOF_FILE_HEADER); //可选pe头

	m_pImageFileInfo->pNtHeader = pNt;
	m_pImageFileInfo->pPeHeader = pPe;
	m_pImageFileInfo->pOptionalPeHeader = pOptionalPe;

	pSection = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalPe + pPe->SizeOfOptionalHeader);
	
	//分配在内存中的空间(对齐) SizeOfImage 文件在内存中对齐后的大小
	pImageBuffer = malloc(pOptionalPe->SizeOfImage);
	if (pImageBuffer == NULL)
	{
		printf("分配SizeOfImage内存失败!");
		return FALSE;
	}

	memset(pImageBuffer, 0, pOptionalPe->SizeOfImage); //初始化
	
	//根据sizeOfHeaders, 先拷贝头
	memcpy(pImageBuffer, pDos, pOptionalPe->SizeOfHeaders);
	
	//拷贝节表
	PIMAGE_SECTION_HEADER pTempSection = pSection;
	m_pImageFileInfo->pSectionHeader = pTempSection;

	for (int i = 0; i < pPe->NumberOfSections; i++, pTempSection++)
	{
		memcpy(
				(void*)((DWORD)pImageBuffer + pTempSection->VirtualAddress),   //目的地
				(void*)((DWORD)pDos + pTempSection->PointerToRawData),		//源
				pTempSection->SizeOfRawData	                                 //大小
				);
	}
	
	
	m_pImageFileInfo->pImageBuffer = pImageBuffer;
	pImageBuffer = NULL;
	
	return TRUE;
}

//导出表
BOOL CPEOperation::GetExportFunctionTable()
{
	//获取导出表地址, 导出表第一个就是
	PIMAGE_DATA_DIRECTORY pExportFunctionData = (PIMAGE_DATA_DIRECTORY)m_pImageFileInfo->pOptionalPeHeader->DataDirectory;
	if (pExportFunctionData == NULL)
	{
		printf("获取DataDirectory数据失败!");
		return FALSE;
	}

	if (pExportFunctionData->VirtualAddress == 0)
	{
		printf("当前EXE没有导出表!");
		return FALSE;
	}
	

	PIMAGE_EXPORT_DIRECTORY pExportFunctionInfo = (PIMAGE_EXPORT_DIRECTORY)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pExportFunctionData->VirtualAddress));
	if (pExportFunctionInfo == NULL)
	{
		printf("获取导入表数据失败!");
		return FALSE;
	}
	
	char* name = (char*)(RVAToFOA(pExportFunctionInfo->Name) + (DWORD)m_pImageFileInfo->pFileBuffer);
	

	printf("%s Base :%d \n", name, pExportFunctionInfo->Base);	
	
	for (int i = 0; i < (int)pExportFunctionInfo->NumberOfFunctions; i++)
	{
		printf("------------------------------------\n");

		DWORD AddressFunction = *(PDWORD)(RVAToFOA(pExportFunctionInfo->AddressOfFunctions) + (DWORD)m_pImageFileInfo->pFileBuffer + (i * sizeof(DWORD)));

		if (AddressFunction == 0)
		{
			continue;
		}
		
		printf("%d", AddressFunction);

		//查询AddressOfNameOrdinals表
		int iCount = 0;
		BOOL bFind = FALSE;
		
		while (iCount < (int)pExportFunctionInfo->NumberOfFunctions) //或者判断 
		{
			WORD AddressOfNameOrdinals = *(PWORD)(RVAToFOA(pExportFunctionInfo->AddressOfNameOrdinals) + (DWORD)m_pImageFileInfo->pFileBuffer + (iCount * sizeof(WORD)));
			
			if (AddressOfNameOrdinals == i)
			{
				//打印序号 = AddressOfNameOrdinals的值 + Base
				printf(": AddressOfNameOrdinals索引 %d : 函数序号 %d", iCount, AddressOfNameOrdinals + pExportFunctionInfo->Base);
			
				bFind = TRUE;
				break;
			}
			iCount++;
		}
		//IMAGE_THUNK_DATA

		//如果数据在符号表内,说明是以名字输出的, 名字表里存的也是偏移
		if (bFind)
		{
			DWORD FunctionInfoName = (RVAToFOA(pExportFunctionInfo->AddressOfNames) + (DWORD)m_pImageFileInfo->pFileBuffer + (iCount * sizeof(DWORD)));
			DWORD dwFunctionInfoName = RVAToFOA(*(PDWORD)(FunctionInfoName)) + (DWORD)m_pImageFileInfo->pFileBuffer; //名字表里存的也是偏移 + ImageBeas
			char* szFunctionInfoName = (char*)dwFunctionInfoName;
			
			printf(": %s\n", szFunctionInfoName);	
		}
		else
		{
			printf(" : %d\n", AddressFunction, i + pExportFunctionInfo->Base);
		}
	}

	return TRUE;
}


//重定位表
BOOL CPEOperation::GetRelocationTable()
{
	//获取重定位表的RVA,在PIMAGE_DATA_DIRECTORY的第5个,每个PIMAGE_DATA_DIRECTORY位8个字节
	PIMAGE_DATA_DIRECTORY pRelocationTable = (PIMAGE_DATA_DIRECTORY)(m_pImageFileInfo->pOptionalPeHeader->DataDirectory);
	pRelocationTable += 5;

	if (pRelocationTable == NULL)
	{
		printf("获取DataDirectory数据失败!");
		return FALSE;
	}
	
	int iRelocationTableCount = 0;

	//获取第一个重定位表的结构体	
	PIMAGE_BASE_RELOCATION pRelocationTableInfoFirst = (PIMAGE_BASE_RELOCATION)((DWORD)m_pImageFileInfo->pFileBuffer +  RVAToFOA(pRelocationTable->VirtualAddress));
	PIMAGE_BASE_RELOCATION pRelocationTableInfoNext = pRelocationTableInfoFirst;

	while(TRUE)
	{	
		
		PIMAGE_BASE_RELOCATION pRelocationTableInfo = pRelocationTableInfoNext;
		if (pRelocationTableInfo->SizeOfBlock == 0 || pRelocationTableInfo->VirtualAddress == 0)
		{
			break;
		}
		
		printf("第%d块------------------\n", iRelocationTableCount + 1);

		//计算当前重定位表有多少个TypeOffset
		int iTypeOffsetCount = (int)(pRelocationTableInfo->SizeOfBlock - 8) / 2;

		//循环TypeOffset数组
		DWORD wTypeOffsetAddress = (DWORD)pRelocationTableInfo + 8; //获取TypeOffset数组的首地址
		for (int i = 0; i != iTypeOffsetCount; i++)
		{
			//wTypeOffsetAddress = wTypeOffsetAddress + (i * sizeof(WORD));
			WORD TypeOffsetInfo = (WORD)(*((PDWORD)(wTypeOffsetAddress + (i * sizeof(WORD)))));

			WORD TypeOffsetFlag = (TypeOffsetInfo >> 12) & 0x000F;

			if (((BYTE)TypeOffsetFlag) == IMAGE_REL_BASED_HIGHLOW || ((BYTE)TypeOffsetFlag) == IMAGE_REL_BASED_DIR64)  
			{
				//计算要修正的地址,成定位表里的计算出的地址指向的数据是要修复的地址,要加上基址

				DWORD RelocationAddress = RVAToFOA(pRelocationTableInfo->VirtualAddress) + (DWORD)(TypeOffsetInfo & 0x0FFF);  //与 VirtualAddress 合成偏移地址
				
				DWORD allRelocationAddress =  RelocationAddress + (DWORD)m_pImageFileInfo->pFileBuffer; //偏移地址 + 基址, 指向要修复的地址

				DWORD dwModAddress =  (DWORD)(*(PDWORD)allRelocationAddress);   //修复的地址

				printf("地址:%x , 加上基址的地址:%x, 要修复的地址:%x \n", RelocationAddress, allRelocationAddress, dwModAddress);
			}

		}
		
		//计算下个重定位表的地址
		pRelocationTableInfoNext = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTableInfo + pRelocationTableInfo->SizeOfBlock);

		iRelocationTableCount++;
	}
	return TRUE;
}


//导入表
BOOL CPEOperation::GetImportTable()
{
	//获取重定位表的RVA,在PIMAGE_DATA_DIRECTORY的第2个,每个PIMAGE_DATA_DIRECTORY位8个字节
	PIMAGE_DATA_DIRECTORY pRelocationTable = (PIMAGE_DATA_DIRECTORY)(m_pImageFileInfo->pOptionalPeHeader->DataDirectory);
	pRelocationTable++;

	if (pRelocationTable == NULL)
	{
		printf("获取DataDirectory数据失败!");
		return FALSE;
	}

	//获取第一个导入表结构导入表结构
	PIMAGE_IMPORT_DESCRIPTOR pImportTableInfo = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pRelocationTable->VirtualAddress));

	//循环导入表
	while (TRUE)
	{
		if (!pImportTableInfo->FirstThunk)
		{
			break;
		}
		
		//打印Dll名称
		char* dllName = (char*)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImportTableInfo->Name));
		DWORD dwTimeDataStamp = pImportTableInfo->TimeDateStamp;
		printf("----------%s---------------TimeDataStamp : %d---------------\n", dllName, dwTimeDataStamp);

		
		//获取函数名
		PIMAGE_THUNK_DATA pImageThunkData = (PIMAGE_THUNK_DATA)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImportTableInfo->OriginalFirstThunk));
		DWORD szNameAndSerialNumber = pImportTableInfo->OriginalFirstThunk;
	
		while (*((PDWORD)pImageThunkData))
		{
			//先判断是序号还是名称导入
			if ((DWORD)pImageThunkData->u1.AddressOfData & 0x80000000) //判断最高位是否为一
			{
				DWORD szNameAndSerialNumberN = szNameAndSerialNumber & 0x0FFF; //把第32位置为0
				printf("序号导入:%d \n", szNameAndSerialNumberN);
			}
			else
			{
				//以名字导出
				PIMAGE_IMPORT_BY_NAME pImageImporotByName = (PIMAGE_IMPORT_BY_NAME)((PDWORD)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImageThunkData->u1.AddressOfData)));
				printf("名称导入(Hit/Name):%d - %s \n", pImageImporotByName->Hint, (char*)pImageImporotByName->Name);
			}
			
			szNameAndSerialNumber += 4;
			pImageThunkData++;
		}

		pImportTableInfo++;
	}
		
	return TRUE;
}

//修复IAT表
BOOL CPEOperation::RepairImportTable()
{
	//获取重定位表的RVA,在PIMAGE_DATA_DIRECTORY的第2个,每个PIMAGE_DATA_DIRECTORY位8个字节
	PIMAGE_DATA_DIRECTORY pRelocationTable = (PIMAGE_DATA_DIRECTORY)(m_pImageFileInfo->pOptionalPeHeader->DataDirectory);
	pRelocationTable++;

	if (pRelocationTable == NULL)
	{
		printf("获取DataDirectory数据失败!");
		return FALSE;
	}

	//获取第一个导入表结构导入表结构
	PIMAGE_IMPORT_DESCRIPTOR pImportTableInfo = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pRelocationTable->VirtualAddress));

	printf("文件基址:%x , 映像后基址:%x ,默认映像地址 \n", (DWORD)m_pImageFileInfo->pFileBuffer, (DWORD)m_pImageFileInfo->pImageBuffer, m_pImageFileInfo->pOptionalPeHeader->ImageBase);

	//循环导入表
	while (TRUE)
	{
		if (!pImportTableInfo->FirstThunk)
		{
			break;
		}

		//打印Dll名称
		char* dllName = (char*)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImportTableInfo->Name));
		DWORD dwTimeDataStamp = pImportTableInfo->TimeDateStamp;
		printf("----------%s---------------TimeDataStamp : %d---------------\n", dllName, dwTimeDataStamp);

		PDWORD dwIATAddress = (PDWORD)(RVAToFOA(pImportTableInfo->FirstThunk) + (DWORD)m_pImageFileInfo->pFileBuffer);

		//获取函数名
		PIMAGE_THUNK_DATA pImageThunkData = (PIMAGE_THUNK_DATA)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImportTableInfo->OriginalFirstThunk));
		DWORD szNameAndSerialNumber = pImportTableInfo->OriginalFirstThunk;

		//获取当前DLL句柄
		HMODULE hDll = GetModuleHandleA(dllName);

		while (*((PDWORD)pImageThunkData))
		{
			//先判断是序号还是名称导入
			if ((DWORD)pImageThunkData->u1.AddressOfData & 0x80000000) //判断最高位是否为一
			{

			}
			else
			{
				//以名字导出
				PIMAGE_IMPORT_BY_NAME pImageImporotByName = (PIMAGE_IMPORT_BY_NAME)((PDWORD)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pImageThunkData->u1.AddressOfData)));

				//根据名字获取
				DWORD dwFunctionAddr = 0;

				if (hDll != NULL)
				{
					dwFunctionAddr = (DWORD)GetProcAddress(hDll, (char*)pImageImporotByName->Name); //根据函数名获取函数地址
					*dwIATAddress = dwFunctionAddr;   //修复IAT
				}

				printf("名称导入(Hit/Name):%d - %s , IAT : %x , 要修复的函数地址:%x\n", pImageImporotByName->Hint, (char*)pImageImporotByName->Name, (DWORD)(*dwIATAddress), dwFunctionAddr);

			}

			szNameAndSerialNumber += 4;
			pImageThunkData++;
			dwIATAddress++;
		}

		pImportTableInfo++;
	}

	return TRUE;
}

BOOL CPEOperation::GetBindImportTable()
{
	//获取绑定表的RVA,在PIMAGE_DATA_DIRECTORY的第12个,每个PIMAGE_DATA_DIRECTORY位8个字节
	PIMAGE_DATA_DIRECTORY pRelocationTable = (PIMAGE_DATA_DIRECTORY)(m_pImageFileInfo->pOptionalPeHeader->DataDirectory);
	pRelocationTable += 12;

	if (pRelocationTable->VirtualAddress == NULL)
	{
		printf("绑定导入表不存在!");
		return FALSE;
	}
	
	printf("---------------------------------绑定导入表----------------------------------- \n");

	PIMAGE_BOUND_IMPORT_DESCRIPTOR pImageBindTable = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((DWORD)m_pImageFileInfo->pFileBuffer + RVAToFOA(pRelocationTable->VirtualAddress));
	DWORD dwImageBindTableFirst = (DWORD)pImageBindTable;
	
	//循环 IMAGE_BOUND_IMPORT_DESCRIPTOR
	while (pImageBindTable->TimeDateStamp)
	{
		//DllName = 第一个PIMAGE_BOUND_IMPORT_DESCRIPTOR的地址 + OffsetModuleName
		char* dllName = (char*)(DWORD)(dwImageBindTableFirst + pImageBindTable->OffsetModuleName);
		printf("--------------------------dllName : %s \n", dllName);

		int iNumberOfModule = (int)pImageBindTable->NumberOfModuleForwarderRefs;
		
		//循环  IMAGE_BOUND_FORWARDER_REF(依赖于上一个Dll的dll) IMAGE_BOUND_FORWARDER_REF和IMAGE_BOUND_IMPORT_DESCRIPTOR的大小一样
		for (; iNumberOfModule != 0; iNumberOfModule--)
		{
			pImageBindTable++;
				
			PIMAGE_BOUND_FORWARDER_REF pImageBoundForwarder = (PIMAGE_BOUND_FORWARDER_REF)pImageBindTable;
			
			char* dllName = (char*)((DWORD)(dwImageBindTableFirst + pImageBoundForwarder->OffsetModuleName));
			printf("dllName : %s \n", dllName);
			
		}
		
		pImageBindTable++;
	}

	return TRUE;
}


//增加新的节表
BOOL CPEOperation::AddNewSectionTable()
{
	//先判断大小是否足够添加一个新节表
	
	//获取最后一个节的最后的位置,一个节表40个字节
	int iSecotrNumber = (int)m_pImageFileInfo->pPeHeader->NumberOfSections; //获取节表数量

	DWORD dwLastSecotrStartAddress = ((DWORD)m_pImageFileInfo->pSectionHeader) + (DWORD)((iSecotrNumber - 1) * SINGLE_SECTION_TABLE_SIZE); //最后一个节的开始地址
	DWORD dwLastSecotrLastAddress = dwLastSecotrStartAddress + SINGLE_SECTION_TABLE_SIZE;

	DWORD dwUseSize =  dwLastSecotrLastAddress - ((DWORD)m_pImageFileInfo->pFileBuffer); //获取已使用的大小
	DWORD dwHeaderSurplusSize  = (m_pImageFileInfo->pOptionalPeHeader->SizeOfHeaders) - dwUseSize; //获取剩余的大小
	
	int iReturnType = 0;
	JudgeSurplusSpaceUse(iReturnType, dwHeaderSurplusSize, dwLastSecotrLastAddress); //判断字节是否足够,如果足够判断剩下空间是否存在有用数据
	
	if (iReturnType == SURPLUS_SPACE_INSUFFICIENT)
	{
		printf("剩余空间不足!");
		return FALSE;
	}
	else if (iReturnType == SURPLUS_SPACE_INSUFFICIENT)
	{
		//存在可用空间需要提升数据
		

	}
	else if (iReturnType == SURPLUS_SPACE_USABLE)
	{
		//可以直接添加新段

		DWORD dwLastSecotrStartOffset = dwLastSecotrStartAddress - (DWORD)m_pImageFileInfo->pFileBuffer; //获取偏移
		DWORD dwLastSecotrLastOffset = dwLastSecotrStartOffset + SINGLE_SECTION_TABLE_SIZE;		  //获取偏移

		DirectAddNewSectionTable(dwLastSecotrStartOffset, dwLastSecotrLastOffset);
	}
	
	return TRUE;
}

void CPEOperation::JudgeSurplusSpaceUse(int &iReturnType, DWORD &dwHeaderSurplusSize, DWORD dwLastSecotrLastAddress)
{
	iReturnType = SURPLUS_SPACE_USABLE;
	
	//先判断剩余空间是否足够
	if (dwHeaderSurplusSize < (SINGLE_SECTION_TABLE_SIZE * 2)) //最后要加一个全零的节表保证结尾为NULL
	{
		iReturnType = SURPLUS_SPACE_INSUFFICIENT;
		return;
	}

	//判断是否存在有用数据
	byte* byText = (byte*)((PDWORD)dwLastSecotrLastAddress);
	for (int i = 1; i != dwHeaderSurplusSize; i++)
	{
		if (*byText != 0x00)
		{
			iReturnType = SURPLUS_SPACE_EXIST_USABLE_DATA;
			return;
		}
	}
	
	return;
}

BOOL CPEOperation::DirectAddNewSectionTable(DWORD &dwLastSecotrStartOffset, DWORD &dwLastSecotrLastOffset)
{
	LPVOID pFileBufferNew = NULL;
	pFileBufferNew = malloc(m_pImageFileInfo->dwFileSize);
	if (pFileBufferNew == NULL)
	{
		printf("分配空间失败!");
		return FALSE;
	}

	memset(pFileBufferNew, 0, m_pImageFileInfo->dwFileSize); //初始化为零
	memcpy(pFileBufferNew, m_pImageFileInfo->pFileBuffer, m_pImageFileInfo->dwFileSize);

	DWORD dwLastSecotrStartAddress = (DWORD)pFileBufferNew + dwLastSecotrStartOffset; //最后一个节的开始地址
	DWORD dwLastSecotrLastAddress = (DWORD)pFileBufferNew + dwLastSecotrLastOffset;
	
	//将后面2个节表的大小置为0
	memset((LPVOID)dwLastSecotrLastAddress, 0, (SINGLE_SECTION_TABLE_SIZE * 2)); //初始化为零
	
	//Copy一个节表
	memcpy((LPVOID)(dwLastSecotrLastAddress), (LPVOID)((DWORD)m_pImageFileInfo->pFileBuffer + dwLastSecotrStartOffset), SINGLE_SECTION_TABLE_SIZE);
	
	//修改PE头中节的数量
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBufferNew;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD)pFileBufferNew + pDos->e_lfanew);
	PIMAGE_FILE_HEADER pPe = (PIMAGE_FILE_HEADER)((DWORD)pNt + 4);     //标准PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionalPe = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPe + IMAGE_SIZEOF_FILE_HEADER); //可选pe头
	
	(int)pPe->NumberOfSections++; //增加一个节表
	pOptionalPe->SizeOfImage += SINGLE_SECTION_TABLE_SIZE;  //曾加一个节的大小

	//在最后新加一个节的内存
	PIMAGE_SECTION_HEADER pLastSection = (PIMAGE_SECTION_HEADER)((DWORD)m_pImageFileInfo->pFileBuffer + dwLastSecotrStartOffset);
	DWORD dwLastSectionSize = pLastSection->VirtualAddress + pLastSection->SizeOfRawData;
	
	memset((LPVOID)((DWORD)m_pImageFileInfo->pFileBuffer + pLastSection->PointerToRawData + pLastSection->SizeOfRawData), 0, pLastSection->SizeOfRawData);

	
	//修改节表的数据
	PIMAGE_SECTION_HEADER pNewAddSection = (PIMAGE_SECTION_HEADER)(dwLastSecotrLastAddress);
	
	memcpy(pNewAddSection, ".NewAdd", 8); //名字
	pNewAddSection->VirtualAddress = dwLastSectionSize;
	pNewAddSection->PointerToRawData = pLastSection->PointerToRawData + pLastSection->SizeOfRawData;

	//保存文件
	//FILE* pFile = NULL;
	//fopen_s(&pFile, "C:\\Users\\WGH\\Desktop\\InStallDriver_new.exe", "rb"); 
	/*
	FILE fp;
	fopen_s(fp,"C:\\Users\\WGH\\Desktop\\InStallDriver.exe", "wb");
	if (fp != NULL)
	{
		fwrite(pFileBufferNew, size, 1, fp);
	}
	fclose(fp);

	if (pFileBufferNew != NULL)
	{
		free(pFileBufferNew);
	}
	*/
	return TRUE;
}

Main.cpp

#include "stdafx.h"
#include "PEOperation.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

	//PIMAGE_FILE_INFO imageFileInfo = new IMAGE_FILE_INFO;

	CPEOperation peInfo;

	//peInfo.ReadPEFile("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\lyt.web.common-0.0.1-SNAPSHOT.jar");
	//peInfo.ReadPEFile("F:\\BaiduNetdisk\\baidunetdisk.exe");
	peInfo.ReadPEFile("C:\\Windows\\System32\\Windows.CloudStore.dll");
	//peInfo.GetExportFunctionTable();
	//peInfo.GetRelocationTable();
	
	/*
	peInfo.GetPeFileInfo(imageFileInfo);
	
	if (imageFileInfo != NULL)
	{
		delete imageFileInfo;
	}
	*/
	
	peInfo.GetExportFunctionTable();

	//peInfo.GetImportTable();
	
	//peInfo.AddNewSectionTable();
	
	return 0;
}