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;
}