正在学习PE文件结构相关知识,学习到重定位表时使用PEDIY想查看某文件的重定位表,却发现貌似没有这项功能,正好就动手锻炼一下自己,也便于理解学到的东西,在此分享下……
注:控制台程序,显示的同时将重定位表写入到文件:PE文件名+.RelocTable.Log
另外请教如何写出体积较小的窗口程序,学习了MFC,写出的窗口程序必须打包库文件,一打包就得2M多……
源码如下(编译环境:Win 7+VS2005):
(如有不妥之处,望高手指出,不胜感激……
)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define PE_HEAD_OFFSET 0x3C //相对文件头
#define IMAGE_SETION_HEAD_OFFSET 0xF8 //相对PE头
#define IMAGE_SETION_NUMBER_OFFSET 0x06 //相对PE头
int IsPE(FILE *ExeFile)
{
char MZ[2]={0};
fseek(ExeFile,0,0);
fread(MZ,sizeof(char),2,ExeFile);
if(MZ[0]=='M' && MZ[1]=='Z')
return 1;
return 0;
}
int IsMemoryZero(void *Buffer,int MemorySize) //不全为0返回假,全为0返回真
{
char *TempBuffer=(char *)Buffer;
int i;
for(i=0;i<MemorySize;i++)
{
if(TempBuffer[i]!=0)
break;
}
return !(i<MemorySize);
}
int GetPEHeadAddr(FILE *ExeFile)
{
fseek(ExeFile,PE_HEAD_OFFSET,0);
int PEHeadOffset=0;
fread(&PEHeadOffset,sizeof(int),1,ExeFile);
return PEHeadOffset;
}
int RVAToOffset(int RVA,FILE *ExeFile)
{
int PEHeadOffset=GetPEHeadAddr(ExeFile);
IMAGE_SECTION_HEADER ImgSetHead={0};
WORD NumberOfSetions=0;
fseek(ExeFile,PEHeadOffset+IMAGE_SETION_NUMBER_OFFSET,0);
fread(&NumberOfSetions,sizeof(WORD),1,ExeFile);
fseek(ExeFile,IMAGE_SETION_HEAD_OFFSET+PEHeadOffset,0);
int i;
for(i=0;i<NumberOfSetions;i++)
{
fread(&ImgSetHead,sizeof(IMAGE_SECTION_HEADER),1,ExeFile);
if(ImgSetHead.VirtualAddress<=RVA && RVA<ImgSetHead.VirtualAddress+ImgSetHead.SizeOfRawData)
break;
}
if(i>=NumberOfSetions)
return 0;
return ImgSetHead.PointerToRawData-ImgSetHead.VirtualAddress+RVA;
}
int OffsetToRVA(int Offset,FILE *ExeFile)
{
int PEHeadOffset=GetPEHeadAddr(ExeFile);
IMAGE_SECTION_HEADER ImgSetHead={0};
WORD NumberOfSetions=0;
fseek(ExeFile,PEHeadOffset+IMAGE_SETION_NUMBER_OFFSET,0);
fread(&NumberOfSetions,sizeof(WORD),1,ExeFile);
fseek(ExeFile,IMAGE_SETION_HEAD_OFFSET+PEHeadOffset,0);
int i;
for(i=0;i<NumberOfSetions;i++)
{
fread(&ImgSetHead,sizeof(IMAGE_SECTION_HEADER),1,ExeFile);
if(ImgSetHead.PointerToRawData<=Offset && Offset<ImgSetHead.PointerToRawData+ImgSetHead.SizeOfRawData)
break;
}
if(i>=NumberOfSetions)
return 0;
return ImgSetHead.VirtualAddress+Offset-ImgSetHead.PointerToRawData;
}
void GetImageOption(FILE *ExeFile,IMAGE_OPTIONAL_HEADER32 *ImgOpt)
{
int PEHead=GetPEHeadAddr(ExeFile);
fseek(ExeFile,PEHead+0x18,0);
fread(ImgOpt,sizeof(IMAGE_OPTIONAL_HEADER32),1,ExeFile);
}
void ShowRelocTable(char *ExeName,char *LogName)
{
FILE *ExeFile=fopen(ExeName,"rb+");
if(!IsPE(ExeFile))
{
printf("不是有效的PE文件!\n");
return;
}
FILE *LogFile=fopen(LogName,"w+");
fseek(LogFile,0,0);
IMAGE_OPTIONAL_HEADER32 ImgOpt={0};
GetImageOption(ExeFile,&ImgOpt);
int RelocTableAddr=RVAToOffset(ImgOpt.DataDirectory[5].VirtualAddress,ExeFile);
IMAGE_BASE_RELOCATION ImgRelTab={0};
fseek(ExeFile,RelocTableAddr,0);
fread(&ImgRelTab,sizeof(IMAGE_BASE_RELOCATION),1,ExeFile);
while(!IsMemoryZero(&ImgRelTab,sizeof(IMAGE_BASE_RELOCATION)))
{
int n=(ImgRelTab.SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/2;
printf("重定位页面起始地址:%X,本项重定位块长度:%X,本项重定位条目:%d\n",ImgRelTab.VirtualAddress,ImgRelTab.SizeOfBlock,n);
fprintf(LogFile,"重定位页面起始地址:%X,本项重定位块长度:%X,本项重定位条目:%d\n",ImgRelTab.VirtualAddress,ImgRelTab.SizeOfBlock,n);
for(int i=0;i<n;i++)
{
WORD RelData=0;
fread(&RelData,sizeof(WORD),1,ExeFile);
printf("高4位标志:%d,\t低12位偏移:%4X,\t重定位位置:%8X\n",(RelData & 0xF000)/0x1000,RelData & 0x0FFF,ImgRelTab.VirtualAddress+(RelData & 0x0FFF));
fprintf(LogFile,"高4位标志:%d,\t低12位偏移:%4X,\t重定位位置:%8X\n",(RelData & 0xF000)/0x1000,RelData & 0x0FFF,ImgRelTab.VirtualAddress+(RelData & 0x0FFF));
}
//printf("本项重定位表已结束,按任意键查看下一项……\n\n");
//getchar();
fread(&ImgRelTab,sizeof(IMAGE_BASE_RELOCATION),1,ExeFile);
}
fclose(LogFile);
fclose(ExeFile);
printf("已将重定位表写入日志文件:%s,按任意键退出……",LogName);
}
void main()
{
char ExeName[100]={0};
char LogName[100]={0};
printf("请输入要查询的EXE文件名:\n");
scanf("%s",ExeName);
strcpy(LogName,ExeName);
strcat(LogName,".RelocTable.Log");
getchar();
ShowRelocTable(ExeName,LogName);
getchar();
}