我们将获取PE信息的操作单独封装到一个类文件中,在这个文件中,我们需要定义一个结构_PE_INFO用于封装PE相关信息并供外部调用,除此之外我们还需要定义RVA转文件偏移,文件偏移转,获取PE文件的信息,修复重定位信息,获取导出全局变量的文件偏移,设置新OEP,添加区段等函数。
在Pack_Dll中添加一个CProcessingPE类,在ProcessingPE.h文件中内容如下:
#pragma once
#include <Windows.h>
#include <string.h>
#include <stdlib.h>
// 关键PE信息
typedef struct _PE_INFO
{
DWORD dwOEP; // 入口点
DWORD dwImageBase; // 映像基址
PIMAGE_DATA_DIRECTORY pDataDir; // 数据目录指针
IMAGE_DATA_DIRECTORY stcExport; // 导出目录
PIMAGE_SECTION_HEADER pSectionHeader; // 区段表头部指针
}PE_INFO, *PPE_INFO;
class CProcessingPE
{
public:
CProcessingPE(void);
~CProcessingPE(void);
public:
DWORD RVAToOffset(ULONG uRvaAddr); // RVA转文件偏移
DWORD OffsetToRVA(ULONG uOffsetAddr); // 文件偏移转RVA
BOOL GetPeInfo(LPVOID lpImageData, DWORD dwImageSize, PPE_INFO pPeInfo); // 获取PE文件的信息
void FixReloc(DWORD dwLoadImageAddr); // 修复重定位信息
PVOID GetExpVarAddr(LPCTSTR strVarName); // 获取导出全局变量的文件偏移
void SetOEP(DWORD dwOEP); // 设置新OEP
PVOID AddSection(LPCTSTR strName, DWORD dwSize, DWORD dwChara, PIMAGE_SECTION_HEADER pNewSection, PDWORD lpSize); // 添加区段
void SetDLL(); // 去除DLL动态加载标识
private:
DWORD m_dwFileDataAddr; // 目标文件所在缓存区的地址
DWORD m_dwFileDataSize; // 目标文件大小
PIMAGE_DOS_HEADER m_pDos_Header; // DOS头指针
PIMAGE_NT_HEADERS m_pNt_Header; // NT头指针
PE_INFO m_stcPeInfo; // PE关键信息
};
ProcessingPE.cpp 实现如下:
#include "stdafx.h"
#include "ProcessingPE.h"
CProcessingPE::CProcessingPE(void)
{
ZeroMemory(&m_stcPeInfo, sizeof(PE_INFO));
}
CProcessingPE::~CProcessingPE(void)
{
}
/************************************************************************/
/* 方法名称: RVAToOffset
/* 方法全称: CProcessingPE::RVAToOffset
/* 参数: ULONG uRvaAddr RVA地址值
/* 返回值: DWORD 成功返回Offset,失败则返回0
/* 说明: 相对虚拟地址(RVA)转文件偏移(Offset)
/************************************************************************/
DWORD CProcessingPE::RVAToOffset(ULONG uRvaAddr)
{
//获取区段头表
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(m_pNt_Header);
//获取区段的数量 --- nt表中的文件头中
DWORD dwSize = m_pNt_Header->FileHeader.NumberOfSe