用C写的一个PE分析工具(含源码)
程序功能概述:可以显示DOS头,PE头,区块表,输入表,输出表
欢迎兄弟们反馈BUG,多多提意见
代码:
//************************************************************** //Name:PE Info Detector //Code:by 鹭影依凌 //************************************************************** #include "stdio.h" #include "windows.h" //************************************************************** //全局变量声明 //************************************************************** FILE *p; //文件对象 UINT myCurFileOffset; //当前指针 UINT myCurVirtOffset; //虚拟地址 UINT i; //循环计数器 //************************************************************** //全局函数声明 //************************************************************** //@ChgRvaToFileOffset: 功能:虚拟地址转化为文件的物理地址 //VirtualOffset: 虚拟地址 //sectionVirtOffset: 当前节的虚拟地址 //sectionFileOffset: 当前节的物理地址 //@NumOfFunc: 区段的数目 UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc); //************************************************************** //主函数Main //************************************************************** int main() { //--------------------------- //PE头变量 //--------------------------- IMAGE_DOS_HEADER myDosHeader; //DOS头 IMAGE_FILE_HEADER myFileHeader; //PE头 IMAGE_OPTIONAL_HEADER32 myOptionalHeader; //PE头 //区块表和区块 IMAGE_SECTION_HEADER mySectionHeader; //区块表 //数据目录树 IMAGE_EXPORT_DIRECTORY myExportTable; //[00]输出表 IMAGE_IMPORT_DESCRIPTOR myImportTable; //[01]输入表 //*********************************************************** //打开文件,获取文件对象指针 //*********************************************************** char filename[20] = ""; //文件名 printf("请输入文件名:"); gets(filename); printf("\n"); p = fopen(filename,"r+b"); //打开文件 if(p==NULL) { MessageBox(NULL,"没有找到目标文件","提示",MB_OK); return 0; } //*********************************************************** //监测Dos Signature //*********************************************************** WORD myDosSignature; fseek(p,0,SEEK_SET); fread(&myDosSignature,sizeof(WORD),1,p); if(myDosSignature != IMAGE_DOS_SIGNATURE) { MessageBox(NULL,"DOS头错误","提示",MB_OK); return 0; } //*********************************************************** //读取Dos Header //*********************************************************** fseek(p,0,SEEK_SET); fread(&myDosHeader,sizeof(myDosHeader),1,p); //*********************************************************** printf(";===================================================;\n"); printf("DOS头结构:\n"); printf(";---------------------------------------------------;\n"); printf("e_mageic : %04X\n",myDosHeader.e_magic); printf("e_cblp : %04X\n",myDosHeader.e_cblp); printf("e_cp : %04X\n",myDosHeader.e_cp); printf("e_crlc : %04X\n",myDosHeader.e_crlc); printf("e_cparhdr : %04X\n",myDosHeader.e_cparhdr); printf("e_minalloc : %04X\n",myDosHeader.e_minalloc); printf("e_maxalloc : %04X\n",myDosHeader.e_maxalloc); printf("e_ss : %04X\n",myDosHeader.e_ss); printf("e_sp : %04X\n",myDosHeader.e_sp); printf("e_csum : %04X\n",myDosHeader.e_csum); printf("e_ip : %04X\n",myDosHeader.e_ip); printf("e_cs : %04X\n",myDosHeader.e_cs); printf("e_lfarlc : %04X\n",myDosHeader.e_lfarlc); printf("e_ovno : %04X\n",myDosHeader.e_ovno); printf("e_res : %04X\n",myDosHeader.e_res); printf("e_oemid : %04X\n",myDosHeader.e_oemid); printf("e_oeminfo : %04X\n",myDosHeader.e_oeminfo); printf("e_res2 : %04X\n",myDosHeader.e_res2); printf("e_lfanew : %04X\n",myDosHeader.e_lfanew); //*********************************************************** //读取NT SignNature //*********************************************************** DWORD myNtSignature; myCurFileOffset = myDosHeader.e_lfanew; //修改指针,指向NtHeader. fseek(p,myCurFileOffset,SEEK_SET); fread(&myNtSignature,sizeof(DWORD),1,p); if(myNtSignature != IMAGE_NT_SIGNATURE) { MessageBox(NULL,"不是有效PE文件","提示",MB_OK); return 0; } //*********************************************************** //读取File Header //*********************************************************** myCurFileOffset = myDosHeader.e_lfanew + sizeof(DWORD); //修改指针,指向FileHeader. fseek(p,myCurFileOffset,SEEK_SET); fread(&myFileHeader,sizeof(IMAGE_FILE_HEADER),1,p); printf(";===================================================;\n"); printf("IMAGE_File_HEADER 结构:\n"); printf(";---------------------------------------------------;\n"); printf("Machine :%04X \n",myFileHeader.Machine); printf("NumberOfSections :%04X \n",myFileHeader.NumberOfSections); printf("TimeDateStamp :%08X \n",myFileHeader.TimeDateStamp); printf("PointerToSymbolTable:%08X \n",myFileHeader.PointerToSymbolTable); printf("NumberOfSymbols :%08X \n",myFileHeader.NumberOfSymbols); printf("SizeOfOptionalHeader:%04X \n",myFileHeader.SizeOfOptionalHeader); printf("Characteristics :%04X \n",myFileHeader.Characteristics); //*********************************************************** //读取Optional Header //*********************************************************** myCurFileOffset += sizeof(IMAGE_FILE_HEADER); //修改指针,指向optional header fseek(p,myCurFileOffset,SEEK_SET); fread(&myOptionalHeader,sizeof(myOptionalHeader),1,p); printf(";===================================================;\n"); printf("IMAGE_OPTIONAL_HEADER 结构:\n"); printf(";---------------------------------------------------;\n"); printf("Magic :%04X\n",myOptionalHeader.Magic); printf("MajorLinkerVersion :%04X\n",myOptionalHeader.MajorLinkerVersion); printf("MinorLinkerVersion :%04X\n",myOptionalHeader.MinorLinkerVersion); printf("SizeOfCode :%04X\n",myOptionalHeader.SizeOfCode); printf("SizeOfInitializedData :%04X\n",myOptionalHeader.SizeOfInitializedData); printf("SizeOfUninitializedData :%04X\n",myOptionalHeader.SizeOfUninitializedData); printf("AddressOfEntryPoint :%04X\n",myOptionalHeader.AddressOfEntryPoint); printf("BaseOfCode :%04X\n",myOptionalHeader.BaseOfCode); printf("BaseOfData :%04X\n",myOptionalHeader.BaseOfData); // NT additional fields. printf("ImageBase :%04X\n",myOptionalHeader.ImageBase); printf("SectionAlignment :%04X\n",myOptionalHeader.SectionAlignment);//内存对齐尺寸 printf("FileAlignment :%04X\n",myOptionalHeader.FileAlignment);//文件对齐尺寸 printf("MajorOperatingSystemVersion :%04X\n",myOptionalHeader.MajorOperatingSystemVersion); printf("MinorOperatingSystemVersion :%04X\n",myOptionalHeader.MinorOperatingSystemVersion); printf("MajorImageVersion :%04X\n",myOptionalHeader.MajorImageVersion); printf("MinorImageVersion :%04X\n",myOptionalHeader.MinorImageVersion); printf("MajorSubsystemVersion :%04X\n",myOptionalHeader.MajorSubsystemVersion); printf("MinorSubsystemVersion :%04X\n",myOptionalHeader.MinorSubsystemVersion); printf("Win32VersionValue :%04X\n",myOptionalHeader.Win32VersionValue); printf("MinorLinkerVersion :%04X\n",myOptionalHeader.SizeOfImage); printf("SizeOfImage :%04X\n",myOptionalHeader.SizeOfHeaders); printf("CheckSum :%04X\n",myOptionalHeader.CheckSum); printf("Subsystem :%04X\n",myOptionalHeader.Subsystem); printf("DllCharacteristics :%04X\n",myOptionalHeader.DllCharacteristics); printf("SizeOfStackReserve :%04X\n",myOptionalHeader.SizeOfStackReserve); printf("SizeOfStackCommit :%04X\n",myOptionalHeader.SizeOfStackCommit); printf("MinorLinkerVersion :%04X\n",myOptionalHeader.SizeOfHeapReserve); printf("SizeOfHeapReserve :%04X\n",myOptionalHeader.SizeOfHeapCommit); printf("LoaderFlags :%04X\n",myOptionalHeader.LoaderFlags); printf("NumberOfRvaAndSizes :%04X\n",myOptionalHeader.NumberOfRvaAndSizes); //*********************************************************** //读取Data Directory //*********************************************************** printf(";===================================================;\n"); printf("数据目录树结构:\n"); printf(";---------------------------------------------------;\n"); for( i=0;i<16;i++) //循环输出数据目录树 { printf("DataDirectory[%x]->",i); printf("VirtualAddress: %08X ",myOptionalHeader.DataDirectory[i].VirtualAddress); printf("Size:%04X ",myOptionalHeader.DataDirectory[i].Size); printf("\n"); } //*********************************************************** //读取Section Header //*********************************************************** UINT sectionVirtOffset[20] = {0,0,0,0,0,0,0,0,0,0}; //虚拟地址 UINT sectionFileOffset[20] = {0,0,0,0,0,0,0,0,0,0}; //文件地址 UINT NumOfFunc = myFileHeader.NumberOfSections; myCurFileOffset += myFileHeader.SizeOfOptionalHeader; //修改指针,指向第一个Section Table; fseek(p,myCurFileOffset,SEEK_SET); fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p); printf(";============================================================;\n"); printf("区段信息:\n"); printf(";------------------------------------------------------------;\n"); printf(" name |VOffset |VSize |ROffset |RSize |Flags \n"); for(i = 0; i < myFileHeader.NumberOfSections; i++) { printf("%-6s ",mySectionHeader.Name); //区段名字 printf("%08X ",mySectionHeader.VirtualAddress); //虚拟偏移 printf("%08X ",mySectionHeader.Misc.VirtualSize); //虚拟大小 printf("%08X ",mySectionHeader.PointerToRawData); //文件偏移 printf("%08X ",mySectionHeader.SizeOfRawData); //文件大小 printf("%08X ",mySectionHeader.Characteristics); sectionVirtOffset[i] = mySectionHeader.VirtualAddress; sectionFileOffset[i] = mySectionHeader.PointerToRawData; printf("\n"); fseek(p,myCurFileOffset + (i+1)*sizeof(IMAGE_SECTION_HEADER),SEEK_SET); fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p); } //*********************************************************** //读取“[0]输出表” //*********************************************************** myCurVirtOffset = myOptionalHeader.DataDirectory[0].VirtualAddress;//修改指针,指向输出表 myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc); //若存在输入表,则输出 if(myCurVirtOffset > 0) { fseek(p,myCurFileOffset,SEEK_SET); fread(&myExportTable,sizeof(IMAGE_EXPORT_DIRECTORY),1,p); printf(";============================================================;\n"); printf("输出表结构:\n"); printf(";------------------------------------------------------------;\n"); printf("Characteristics %08X\n",myExportTable.Characteristics); printf("TimeDateStamp %08X\n",myExportTable.TimeDateStamp); printf("MajorVersion %08X\n",myExportTable.MajorVersion); printf("MinorVersion %08X\n",myExportTable.MinorVersion); printf("Name %08X\n",myExportTable.Name); printf("Base %08X\n",myExportTable.Base); printf("NumberOfFunctions %08X\n",myExportTable.NumberOfFunctions); printf("NumberOfNames %08X\n",myExportTable.NumberOfNames); printf("AddressOfFunctions %08X\n",myExportTable.AddressOfFunctions); printf("AddressOfNameOrdinals %08X\n",myExportTable.AddressOfNameOrdinals); printf("AddressOfNames %08X\n",myExportTable.AddressOfNames); printf(";************************************************************;\n"); printf("输出函数:\n"); printf(";------------------------------------------------------------;\n"); printf("Ordinal RVA Offset Name \n"); printf(";------------------------------------------------------------;\n"); for(i = 0;i < myExportTable.NumberOfNames;i++) { //一些壳对PE做了修改,做下校验(32 lite) if(myExportTable.AddressOfNames == 0) break; //-------------------------------------------------------| printf("number[%d] ",i+1); //序号 //-------------------------------------------------------| UINT arrayVirtOffset = myExportTable.AddressOfFunctions + i * sizeof(DWORD);//数组地址的RVA UINT arrayFileOffset = ChgRvaToFileOffset(arrayVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc); fseek(p,arrayFileOffset,SEEK_SET); UINT arrayData =0; fread(&arrayData,sizeof(DWORD),1,p); printf("%08X ",arrayData); //RVA //-------------------------------------------------------| UINT OffsetExpFuc = ChgRvaToFileOffset(arrayData,sectionVirtOffset,sectionFileOffset,NumOfFunc); printf("%08X ",OffsetExpFuc); //Offset //-------------------------------------------------------| char myExportDll[40]; UINT virtOffsetExpName = myExportTable.AddressOfNames + i * sizeof(DWORD);//数组地址的RVA UINT fileOffsetExpName = ChgRvaToFileOffset(virtOffsetExpName,sectionVirtOffset,sectionFileOffset,NumOfFunc);//数组在文件中地址 fseek(p,fileOffsetExpName,SEEK_SET); UINT expTemp =0; fread(&expTemp,40,1,p); UINT addresAnother = ChgRvaToFileOffset(expTemp,sectionVirtOffset,sectionFileOffset,NumOfFunc); fseek(p,addresAnother,SEEK_SET); fread(&myExportDll,40,1,p); printf("%s\n",myExportDll); //API Name //-------------------------------------------------------| } printf("\n"); } //************************************************************ //读取“[1]输入表” //************************************************************ myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表 myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc); //读取输入表 fseek(p,myCurFileOffset,SEEK_SET); fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); printf(";=======================================================================================;\n"); printf("输入表结构\n"); printf(";---------------------------------------------------------------------------------------;\n"); printf("DllName |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name |FirstThunk\n"); printf(";---------------------------------------------------------------------------------------;\n"); i = 0; //循环输出 while(myImportTable.FirstThunk != NULL) { char mydllname[20]; UINT mychar = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc); fseek(p,mychar,SEEK_SET); fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); printf("%-12s ", mydllname); printf("%08X ",myImportTable.OriginalFirstThunk); printf("%08X ", myImportTable.TimeDateStamp); printf("%08X ", myImportTable.ForwarderChain); printf("%08X ", myImportTable.Name); printf("%08X \n", myImportTable.FirstThunk); fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET); fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); i++; } printf("\n"); //*********************************************************** //IAT函数 //*********************************************************** myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表 myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc); printf(";=======================================================================================;\n"); printf("IAT相关函数\n"); printf(";***************************************************************************************;\n"); i = 0; //读取输入表 fseek(p,myCurFileOffset,SEEK_SET); fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); while(myImportTable.FirstThunk != NULL) { char mydllname[20]; UINT fileOffsetImpName = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc); fseek(p,fileOffsetImpName,SEEK_SET); fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); //printf("DllName |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name |FirstThunk\n"); printf("%-12s ", mydllname); printf("%08X ",myImportTable.OriginalFirstThunk); printf("%08X ", myImportTable.TimeDateStamp); printf("%08X ", myImportTable.ForwarderChain); printf("%08X ", myImportTable.Name); printf("%08X \n", myImportTable.FirstThunk); printf(";---------------------------------------------------------------------------------------;\n"); UINT fileOffsetIAT = ChgRvaToFileOffset(myImportTable.FirstThunk,sectionVirtOffset,sectionFileOffset,NumOfFunc); printf("@Thunk RVA @Thunk Offset @Tank Value @hint/OrDinal @API NAME\n"); unsigned int k = 0; while(true) { //判断是否终结 UINT myTankValue = 0; fseek(p,fileOffsetIAT + k*sizeof(DWORD),SEEK_SET); fread(&myTankValue,sizeof(DWORD),1,p); if(myTankValue == 0) break; //----------------------------------------------------------------| printf(" %08X ", myImportTable.FirstThunk + k * sizeof(DWORD));//虚拟地址 printf("%08X ",fileOffsetIAT + k * sizeof(WORD)); //文件地址 printf("%08X ",myTankValue); //ThankVALUE //----------------------------------------------------------------| UINT impTemp =0; UINT myTankWordVale = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc); fseek(p,myTankWordVale,SEEK_SET); fread(&impTemp,sizeof(WORD),1,p); printf(" %04X ",impTemp); //OrDinal //----------------------------------------------------------------| UINT myFucOffset = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc); char myFucName[40]; int m = 0; for(m=0;m<100;m++) { BYTE myByte = 0; fseek(p,myFucOffset,SEEK_SET); fread(&myByte,sizeof(BYTE),1,p); if(myByte>=0x20 && myByte <= 0x7F) { fseek(p,myFucOffset+1,SEEK_SET); fread(&myByte,sizeof(BYTE),1,p); if(myByte<0x20) myFucOffset++; else break; } else myFucOffset++; } fseek(p,myFucOffset,SEEK_SET); fread(&myFucName,40,1,p); printf(" %-s \n",myFucName); //API NAME k++; } printf(" \n"); printf(";***************************************************************************************;\n"); fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET); fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p); i++; } fclose(p); system("pause"); return 0; } UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc) { int temp = 0; UINT counter; for(counter =0;counter < NumOfFunc-1;counter++) { //依次排查 if((VirtualOffset >= sectionVirtOffset[counter]) && (VirtualOffset < sectionVirtOffset[counter+1])) { if(sectionFileOffset[counter] == 0) return 0; else { temp = sectionVirtOffset[counter] - sectionFileOffset[counter]; break; } } } //落在最后一个区段的情形 if(counter == (NumOfFunc-1)) temp = sectionVirtOffset[counter] - sectionFileOffset[counter]; return (VirtualOffset - temp); }