正在学习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(); }