一、流程
1、File-> FileBuffer
2、添加节
3、定位重定位表
4、移动重定位表
5、修复重定位的地址
6、存盘
二、演示
1、File-> FileBuffer
2、添加节
3、定位重定位表
DWORD RelocationFoa = NULL;//重定位表FOA
if (pOptionalHeader->DataDirectory[5].VirtualAddress == 0)
{
printf("重定位表不存在!\n");
return;
}
RelocationFoa = RvaToFoa(pOptionalHeader->DataDirectory[5].VirtualAddress,pFileBuffer);//获取重定位表的地址FOA
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + RelocationFoa);//定位重定位表
4、移动重定位表
LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer+pNewSec->PointerToRawData);//定位新节表的地址
while (pRelocationDirectory->VirtualAddress!=0 && pRelocationDirectory->SizeOfBlock!=0)
{
// (1)将重定位块copy到目标地址
memcpy(pNewSecAddr, pRelocationDirectory, pRelocationDirectory->SizeOfBlock);
// (2)将目标地址后移
pNewSecAddr = (PVOID)((DWORD)pNewSecAddr + pRelocationDirectory->SizeOfBlock);
// (3)将旧重定位表块后移
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationDirectory + pRelocationDirectory->SizeOfBlock);
}
5、修复重定位的地址
pOptionalHeader->DataDirectory[5].VirtualAddress = (DWORD)pNewSecAddr;
6、存盘
isok = MemeryTOFile(NewBuffer,Size+1000,FILEPATH_OUT);
if(isok)
{
printf("存盘成功");
return;
}
//释放内存
free(pFileBuffer);
free(NewBuffer);
return;
三、完整代码
#include "stdafx.h"
#include <windows.h>
#include "stdlib.h"
#define FILEPATH_IN "C:/testdll.dll"
#define FILEPATH_OUT "C:/copyxx.dll"
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer )
{
FILE *pFile = NULL;
DWORD fileSize = 0; //文件大小
LPVOID pTempFileBuffer = NULL; //缓冲区首地址
pFile = fopen(lpszFile,"rb"); //打开文件
if(!pFile)
{
printf("打开文件失败");
return NULL;
}
//读取文件大小
fseek(pFile,0,SEEK_END); //将指针从开始的位置移动到末尾
fileSize = ftell(pFile); //获取数据大小
//分配缓冲区(申请内存)
pTempFileBuffer = malloc(fileSize);
if(!pTempFileBuffer)
{
printf("分配空间失败");
fclose(pFile);
return NULL;
}
//将文件数据读取到缓冲区
fseek(pFile,0,SEEK_SET); //将指针指向开始
size_t n = fread(pTempFileBuffer,fileSize,1,pFile); //将数据读取到缓冲区中
if(!n)
{
printf("读取数据失败");
free(pTempFileBuffer); //释放内存
fclose(pFile); //关闭文件
return NULL;
}
//关闭文件
*pFileBuffer = pTempFileBuffer;
pTempFileBuffer = NULL;
fclose(pFile); //关闭文件
return fileSize;
}
BOOL MemeryTOFile(LPVOID pMemBuffer,size_t size,LPSTR lpszFile)
{
FILE *fp = NULL;
fp = fopen(lpszFile,"wb+");
if(!fp)
{
printf("存盘失败");
return FALSE;
}
fwrite(pMemBuffer,size,1,fp); //向磁盘写入数据
fclose(fp); //关闭文件
fp = NULL;
return TRUE;
}
//**********************************************************************
DWORD RvaToFoa(DWORD RVA,LPVOID pFileBuffer)
{
DWORD FOA = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
if(RVA <= pOptionalHeader->SizeOfHeaders)
return RVA;
for(;RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
DWORD FoaToRva(DWORD FOA,LPVOID pFileBuffer)
{
DWORD RVA = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
if(FOA <= pOptionalHeader->SizeOfHeaders)
return FOA;
for(;FOA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
RVA = FOA - pSectionHeader->PointerToRawData + pSectionHeader->VirtualAddress ;
return RVA;
}
VOID MoveRelocation()
{
DWORD Size = 0;
BOOL isok = FALSE;
LPVOID pFileBuffer = NULL;
//File-> FileBuffer
Size = ReadPEFile(FILEPATH_IN,&pFileBuffer); //调用函数读取文件数据
if(!pFileBuffer || !Size)
{
printf("File-> FileBuffer失败");
return;
}
PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头
PIMAGE_NT_HEADERS pNtHeader = NULL;//NT头
PIMAGE_FILE_HEADER pFileHeader = NULL;//标准PE头
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;//拓展PE头
PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表
PIMAGE_SECTION_HEADER pNewSec = NULL;//新节表结构
PIMAGE_BASE_RELOCATION pRelocationDirectory = NULL; //导出表结构体
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
//判断是否有足够的空间添加节表
if((DWORD)pNtHeader - (DWORD)pDosHeader - 0x40 < sizeof(IMAGE_SECTION_HEADER))
{
printf("没有多余空间");
free(pFileBuffer);
return;
}
memcpy((void*)((DWORD)pDosHeader + 0x40),
pNtHeader,
(DWORD)(pSectionHeader + pFileHeader->NumberOfSections) - (DWORD)pNtHeader);
pDosHeader->e_lfanew = 0x40;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
//新增节表结构
pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections);
memset(pNewSec, 0, (DWORD)(pSectionHeader + pFileHeader->NumberOfSections) - (DWORD)pNtHeader);
//修改节表内容
memcpy(pNewSec->Name,".export",8);//修改节表名
PIMAGE_SECTION_HEADER upSecHeader = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections-1);
if(upSecHeader->Misc.VirtualSize > upSecHeader->SizeOfRawData)//修改节表VrituallAddress
{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->Misc.VirtualSize;
}else{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->SizeOfRawData;
}
pNewSec->SizeOfRawData = 0x1000;//新增的节区的大小
pNewSec->PointerToRawData = upSecHeader->PointerToRawData + upSecHeader->SizeOfRawData;//文件中的偏移
pNewSec->Characteristics = 0x60000020;//修改属性(可执行)
//修改NT头属性
pFileHeader->NumberOfSections += 1;//修改NumberOfSection数量
pOptionalHeader->SizeOfImage += 0x1000;//修改SizeOfImage大小
LPVOID NewBuffer = malloc(Size+0x1000);//申请内存
memset(NewBuffer, 0, Size+0x1000);//初始化内存
memcpy(NewBuffer, pFileBuffer,Size);//复制内存
DWORD RelocationFoa = NULL;//重定位表FOA
if (pOptionalHeader->DataDirectory[5].VirtualAddress == 0)
{
printf("重定位表不存在!\n");
return;
}
RelocationFoa = RvaToFoa(pOptionalHeader->DataDirectory[5].VirtualAddress,pFileBuffer);//获取重定位表的地址FOA
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + RelocationFoa);//定位重定位表
LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer+pNewSec->PointerToRawData);//定位新节表的地址
while (pRelocationDirectory->VirtualAddress!=0 && pRelocationDirectory->SizeOfBlock!=0)
{
// (1)将重定位块copy到目标地址
memcpy(pNewSecAddr, pRelocationDirectory, pRelocationDirectory->SizeOfBlock);
// (2)将目标地址后移
pNewSecAddr = (PVOID)((DWORD)pNewSecAddr + pRelocationDirectory->SizeOfBlock);
// (3)将旧重定位表块后移
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationDirectory + pRelocationDirectory->SizeOfBlock);
}
pOptionalHeader->DataDirectory[5].VirtualAddress = (DWORD)pNewSecAddr;
isok = MemeryTOFile(NewBuffer,Size+1000,FILEPATH_OUT);
if(isok)
{
printf("存盘成功");
return;
}
//释放内存
free(pFileBuffer);
free(NewBuffer);
return;
}
//**********************************************************************
int main(int argc, char* argv[])
{
MoveRelocation();
getchar();
return 0;
}