文章目录
一、流程二、流程三、完整代码
一、流程
1、File-> FileBuffer 2、获取头信息 3、获取结构体数组的信息 4、获取导出表的地址RVA和FOA 5、获取导出表在文件中的地址 6、循环重定位表 7、获取数据块的FOA 8、判断数据块在那个节中 9、获取要修改数据的个数和位置 10、循环要修改的数据并判断是否要修改 11、指向下一个数据块
二、流程
1、File-> FileBuffer 2、获取头信息 3、获取结构体数组的信息
//指向数组
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionHeader->DataDirectory;
4、获取导出表的地址RVA和FOA
//重定位表的地址Rva
DWORD dwRelocationTableRva = pDataDirectory[5].VirtualAddress;
//重定位表的地址Foa
DWORD dwRelocationTableFoa = RvaToFoa(pFileBuffer,dwRelocationTableRva);
5、获取导出表在文件中的地址
//重定位表在文件中的地址
PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + dwRelocationTableFoa);
6、循环重定位表
//循环重定位表
for(int i=1 ; pRelocationTable->SizeOfBlock && pRelocationTable->VirtualAddress ; i++)
{
}
7、获取数据块的FOA
//重定位表中数据的Foa
DWORD Foa = RvaToFoa(pFileBuffer,pRelocationTable->VirtualAddress);
8、判断数据块在那个节中
//循环判断数据在哪个节中
for(int t=0 ; pNTHeader->FileHeader.NumberOfSections ; t++)
{
//节的起始和结束位置
DWORD Begin = RvaToFoa(pFileBuffer,pSectionHeader[t].VirtualAddress);
DWORD End = RvaToFoa(pFileBuffer,pSectionHeader[t].VirtualAddress) + pSectionHeader[t].Misc.VirtualSize;
//判断
if(Foa >= Begin && Foa <= End)
{
memcpy(SecName,pSectionHeader[t].Name,8);
break;
}
}
printf("-------------------------------------%s-------------------------------------\n",SecName);
9、获取要修改数据的个数和位置
//要修改的数据个数
DWORD Size = (pRelocationTable->SizeOfBlock - 0x8)/2;
//要修改数据的起始位置
PWORD RecAddr = (PWORD)((PBYTE)pRelocationTable + 8);
10、循环要修改的数据并判断是否要修改
//循环要修改的数据
for(DWORD j=0 ; j < Size ; j++)
{
//要修改数据的真实地址
DWORD Offset = (RecAddr[j] & 0X0FFF) + Foa;
//判断是否需要修改0是不需要修改,3是需要修改
WORD Type = RecAddr[j] >> 12;
if(Type == 0)
{
printf("\t\t[%d]\t[---------------]\tABSOLUTE[%d]\n",j+1,Type);
continue;
}
//打印数据真实地址和类型
printf("\t\t[%d]\t[%08X]\tHIGHLOW[%d]\n",j+1,Offset,Type);
}
11、指向下一个数据块
//重置节名
memset(SecName,0,9);
//指向下一个数据块
pRelocationTable = (PIMAGE_BASE_RELOCATION)((PBYTE)pRelocationTable + pRelocationTable->SizeOfBlock);
三、完整代码
#include "stdafx.h"
#include <windows.h>
#include "stdlib.h"
#define FILEPATH_IN "C:/testdll.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;
}
//**********************************************************************
DWORD RvaToFoa(IN LPVOID pFileBuffer, IN DWORD dwRva)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x4);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
for(int i=0 ; i < pPEHeader->NumberOfSections ; i++)
{
//节在内存中的位置RVA
DWORD dwSectionBeginRva = pSectionHeader[i].VirtualAddress;
//节在内存中相对于文件中结束的位置RVA
DWORD dwSectionEndRva = pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData;
//判断RVA是否在当前节中
if(dwRva >= dwSectionBeginRva && dwRva <= dwSectionEndRva)
{
//FOA = RVA - 节在内存中的位置 + 节在文件中的偏移
DWORD dwFoa = dwRva - dwSectionBeginRva + pSectionHeader[i].PointerToRawData;
return dwFoa;
}
}
}
//**********************************************************************
VOID TestPrintRelocation()
{
LPVOID pFileBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//File-> FileBuffer
DWORD Size = ReadPEFile(FILEPATH_IN,&pFileBuffer); //调用函数读取文件数据
if(!pFileBuffer || !Size)
{
printf("File-> FileBuffer失败");
return;
}
BYTE SecName[9] = {0};
//获取头信息
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 0x4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pNTHeader->FileHeader.SizeOfOptionalHeader);
//指向数组
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionHeader->DataDirectory;
//重定位表的地址Rva
DWORD dwRelocationTableRva = pDataDirectory[5].VirtualAddress;
//重定位表的地址Foa
DWORD dwRelocationTableFoa = RvaToFoa(pFileBuffer,dwRelocationTableRva);
//重定位表在文件中的地址
PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + dwRelocationTableFoa);
//循环重定位表
for(int i=1 ; pRelocationTable->SizeOfBlock && pRelocationTable->VirtualAddress ; i++)
{
//重定位表中数据的Foa
DWORD Foa = RvaToFoa(pFileBuffer,pRelocationTable->VirtualAddress);
//循环判断数据在哪个节中
for(int t=0 ; pNTHeader->FileHeader.NumberOfSections ; t++)
{
//节的起始和结束位置
DWORD Begin = RvaToFoa(pFileBuffer,pSectionHeader[t].VirtualAddress);
DWORD End = RvaToFoa(pFileBuffer,pSectionHeader[t].VirtualAddress) + pSectionHeader[t].Misc.VirtualSize;
//判断
if(Foa >= Begin && Foa <= End)
{
memcpy(SecName,pSectionHeader[t].Name,8);
break;
}
}
printf("-------------------------------------%s-------------------------------------\n",SecName);
//要修改的数据个数
DWORD Size = (pRelocationTable->SizeOfBlock - 0x8)/2;
//要修改数据的起始位置
PWORD RecAddr = (PWORD)((PBYTE)pRelocationTable + 8);
printf("\t\tIndex\tFoa\t\ttype\t[BLOCK Items]\n");
//循环要修改的数据
for(DWORD j=0 ; j < Size ; j++)
{
//要修改数据的真实地址
DWORD Offset = (RecAddr[j] & 0X0FFF) + Foa;
//判断是否需要修改0是不需要修改,3是需要修改
WORD Type = RecAddr[j] >> 12;
if(Type == 0)
{
printf("\t\t[%d]\t[---------------]\tABSOLUTE[%d]\n",j+1,Type);
continue;
}
//打印数据真实地址和类型
printf("\t\t[%d]\t[%08X]\tHIGHLOW[%d]\n",j+1,Offset,Type);
}
//重置节名
memset(SecName,0,9);
//指向下一个数据块
pRelocationTable = (PIMAGE_BASE_RELOCATION)((PBYTE)pRelocationTable + pRelocationTable->SizeOfBlock);
}
}
//**********************************************************************
int main(int argc, char* argv[])
{
TestPrintRelocation();
getchar();
return 0;
}