一个PE文件的学习程序[原创]

  1. #pragma comment( lib, "Imagehlp.lib" )
  2. #include<windows.h>
  3. #include<Imagehlp.h>
  4. #include<memory.h>
  5. #include<iostream>
  6. using namespace std;
  7. class AnalysisPE
  8. {
  9.  //一些辅助宏的定义; 
  10. #define NUMOFSECTION pNTHeader->FileHeader.NumberOfSections
  11. public:
  12.     AnalysisPE(){}
  13.     AnalysisPE(PTCHAR iname){
  14.         setPEName(iname);
  15.     }
  16.     ~AnalysisPE(){
  17.         _UnLoadFile();
  18.     }
  19.     VOID setPEName(PTCHAR iname){ 
  20.         name = iname;
  21.         hFile=NULL;
  22.         hFileMapping=NULL;
  23.         hMapView=NULL;
  24.         if(!_LoadFile()){
  25.             cout << "加载文件失败!/n";
  26.             return;
  27.         }
  28.         _walkThroughPE();
  29.     }
  30.     BOOL isPEFile(){ return isPE; }
  31.     VOID printSectionHeaders();
  32.     VOID printNTHeaderInfo();
  33.     VOID printImageFileHeaderInfo();
  34.     VOID printImageOptionalHeaderInfo();
  35.     VOID printImportInfo();
  36. private:
  37.     BOOL _LoadFile();  //把要分析的文件加载到内存;
  38.     VOID _UnLoadFile();
  39.     VOID _walkThroughPE(); //粗略地遍历PE文件;
  40.     DWORD _getRawAddress(DWORD pVirtualAddress,  DWORD pPEHeader);
  41. private:
  42.     PTCHAR name;
  43.     HANDLE hFile;
  44.     HANDLE hFileMapping;
  45.     HANDLE hMapView;
  46.     BOOL isPE;
  47.     PIMAGE_DOS_HEADER pDOSHeader;
  48.     PIMAGE_NT_HEADERS pNTHeader;
  49.     PIMAGE_SECTION_HEADER pSectionHeader;
  50. };
  51. VOID AnalysisPE::printImportInfo()
  52. {
  53.     cout << "========================================================/n【Import information!】/n";
  54.     PIMAGE_OPTIONAL_HEADER pOpn_header = &pNTHeader->OptionalHeader;
  55.     DWORD pFileHeader = (DWORD)&pNTHeader->FileHeader;
  56.     DWORD pAddress = pOpn_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  57.     DWORD rawAddress = _getRawAddress(pAddress, (DWORD)pFileHeader);
  58.     PIMAGE_IMPORT_DESCRIPTOR pImportDec = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDOSHeader + rawAddress);
  59.     while(1)
  60.     {
  61.         IMAGE_IMPORT_DESCRIPTOR cmp;
  62.         memset(&cmp, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));
  63.         if( 0 == memcmp(&cmp, pImportDec, sizeof(IMAGE_IMPORT_DESCRIPTOR)))
  64.             break;
  65.         DWORD* desp = (DWORD*)((DWORD)pDOSHeader + _getRawAddress(pImportDec->OriginalFirstThunk, (DWORD)pFileHeader));
  66.         DWORD* addr = (DWORD*)((DWORD)pDOSHeader + _getRawAddress(pImportDec->FirstThunk, (DWORD)pFileHeader));
  67.         if(*desp || *addr)
  68.         {
  69.             char* dllName = (char*)((DWORD)pDOSHeader + _getRawAddress(pImportDec->Name, (DWORD)pFileHeader));
  70.             cout << "/n==========/n" << dllName << endl;
  71.             while(*desp || *addr)
  72.             {
  73.                 if(IMAGE_ORDINAL_FLAG&*desp) //序号导入
  74.                     cout << IMAGE_ORDINAL(*desp)<<"/t/t";
  75.                 else  //名字导入
  76.                 {
  77.                     PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pDOSHeader + _getRawAddress(*desp, (DWORD)pFileHeader));
  78.                     cout << pName->Hint << "/t" << (char*)(&pName->Name) << "/t";
  79.                 }
  80.                 cout << *addr << endl;
  81.                 desp = (DWORD*)((DWORD)desp + sizeof(DWORD));
  82.                 addr = (DWORD*)((DWORD)addr + sizeof(DWORD));
  83.             }
  84.         }
  85.         pImportDec = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDec + sizeof(IMAGE_IMPORT_DESCRIPTOR));
  86.     }
  87. }
  88. //因为文件对齐(FileAlignment)和内存对齐(SectionAlignment)不一样(见以下IMAGE_OPTIONAL_HEADER中的分析),所以这个函数是有必要的!
  89. DWORD AnalysisPE::_getRawAddress(DWORD pVirtualAddress,  DWORD pPEHeader)
  90. {
  91.     DWORD rt=-1;
  92.     int sectionNum = PIMAGE_FILE_HEADER(pPEHeader)->NumberOfSections;
  93.     DWORD pSectionAddress = pPEHeader + sizeof(IMAGE_FILE_HEADER) + PIMAGE_FILE_HEADER(pPEHeader)->SizeOfOptionalHeader;
  94.     for(int i=0; i<sectionNum; i++)
  95.     {
  96.         PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)pSectionAddress;
  97.         DWORD begin = pSection->VirtualAddress;
  98.         DWORD end = pSection->VirtualAddress + pSection->Misc.VirtualSize;
  99.         if(pVirtualAddress<end && pVirtualAddress>=begin)
  100.         {
  101.             rt = pSection->PointerToRawData + pVirtualAddress - begin;
  102.             break;
  103.         }
  104.         pSectionAddress += sizeof(IMAGE_SECTION_HEADER);
  105.     }
  106.     return rt;
  107. }
  108. // 相关结构体如下(可以在WinNT.h中找到):
  109. //
  110. //typedef struct _IMAGE_OPTIONAL_HEADER {
  111. //    //
  112. //    // Standard fields.
  113. //    //
  114. //
  115. //    WORD    Magic;
  116. //    BYTE    MajorLinkerVersion;
  117. //    BYTE    MinorLinkerVersion;
  118. //    DWORD   SizeOfCode;
  119. //    DWORD   SizeOfInitializedData;
  120. //    DWORD   SizeOfUninitializedData;
  121. //    DWORD   AddressOfEntryPoint;
  122. //    DWORD   BaseOfCode;
  123. //    DWORD   BaseOfData;
  124. //
  125. //    //
  126. //    // NT additional fields.
  127. //    //
  128. //
  129. //    DWORD   ImageBase;
  130. //    DWORD   SectionAlignment;
  131. //    DWORD   FileAlignment;
  132. //    WORD    MajorOperatingSystemVersion;
  133. //    WORD    MinorOperatingSystemVersion;
  134. //    WORD    MajorImageVersion;
  135. //    WORD    MinorImageVersion;
  136. //    WORD    MajorSubsystemVersion;
  137. //    WORD    MinorSubsystemVersion;
  138. //    DWORD   Win32VersionValue;
  139. //    DWORD   SizeOfImage;
  140. //    DWORD   SizeOfHeaders;
  141. //    DWORD   CheckSum;
  142. //    WORD    Subsystem;
  143. //    WORD    DllCharacteristics;
  144. //    DWORD   SizeOfStackReserve;
  145. //    DWORD   SizeOfStackCommit;
  146. //    DWORD   SizeOfHeapReserve;
  147. //    DWORD   SizeOfHeapCommit;
  148. //    DWORD   LoaderFlags;
  149. //    DWORD   NumberOfRvaAndSizes;
  150. //    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
  151. //} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
  152. VOID AnalysisPE::printImageOptionalHeaderInfo()
  153. {
  154.     if(isPE!=TRUE)
  155.         return;
  156.     cout << "/n----Information provided by IMAGE_OPTIONAL_HEADER as Follows:/n ";
  157.     PIMAGE_OPTIONAL_HEADER pOpn_header = &pNTHeader->OptionalHeader;
  158.     cout << "Standard fields./n";
  159.     cout << "SizeOfInitializedData is : " << pOpn_header->SizeOfInitializedData << endl;
  160.     cout << "SizeOfUninitializedData is : " << pOpn_header->SizeOfUninitializedData << endl;
  161.     cout << "AddressOfEntryPoint is : " << pOpn_header->AddressOfEntryPoint << endl;
  162.     cout << "NT additional fields./n";
  163.     cout << "ImageBase is : " << pOpn_header->ImageBase << endl;
  164.     cout << "SectionAlignment is : " << pOpn_header->SectionAlignment << endl;
  165.     cout << "FileAlignment is : " << pOpn_header->FileAlignment << endl;
  166.     cout << "MajorOperatingSystemVersion is : " << pOpn_header->MajorOperatingSystemVersion << endl;
  167.     cout << "MinorOperatingSystemVersion is : " << pOpn_header->MinorOperatingSystemVersion << endl;
  168.     cout << "SizeOfImage is : " << pOpn_header->SizeOfImage << endl;
  169.     cout << "SizeOfHeaders is : " << pOpn_header->SizeOfHeaders << endl;
  170.     if(IMAGE_SUBSYSTEM_WINDOWS_GUI==pOpn_header->Subsystem)
  171.         cout << "Image runs in the Windows GUI subsystem./n";
  172.     if(IMAGE_SUBSYSTEM_WINDOWS_CUI==pOpn_header->Subsystem)
  173.         cout << "Image runs in the Windows character subsystem./n";
  174. }
  175. // 相关结构体如下(可以在WinNT.h中找到):
  176. //
  177. //typedef struct _IMAGE_FILE_HEADER {
  178. //    WORD    Machine;
  179. //    WORD    NumberOfSections;
  180. //    DWORD   TimeDateStamp;
  181. //    DWORD   PointerToSymbolTable;
  182. //    DWORD   NumberOfSymbols;
  183. //    WORD    SizeOfOptionalHeader;
  184. //    WORD    Characteristics;
  185. //} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
  186. //
  187. VOID AnalysisPE::printImageFileHeaderInfo()
  188. {
  189.     if(isPE!=TRUE)
  190.         return;
  191.     cout << "/n----Information provided by IMAGE_FILE_HEADER as Follows:/n ";
  192.     cout << "Machine is : " << pNTHeader->FileHeader.Machine << "  ";
  193.     if(IMAGE_FILE_MACHINE_I386 == pNTHeader->FileHeader.Machine)
  194.         cout << ", that means Intel 386. /n";
  195.     cout << "NumberOfSections is : " << pNTHeader->FileHeader.NumberOfSections << endl;
  196.     cout << "TimeDateStamp is : " << pNTHeader->FileHeader.TimeDateStamp << endl;
  197.     cout << "Characteristics is : " << pNTHeader->FileHeader.Characteristics << endl;
  198.     //对Characteristics的一个研究
  199.     if(IMAGE_FILE_EXECUTABLE_IMAGE&pNTHeader->FileHeader.Characteristics)
  200.         cout << "File is executable/n";
  201.     if(IMAGE_FILE_DLL&pNTHeader->FileHeader.Characteristics)
  202.         cout << "File is a DLL./n";
  203. }
  204. VOID AnalysisPE::printNTHeaderInfo()
  205. {
  206.     cout << "/n=======================================================/n"
  207.         << "Analysis NT header: /n";
  208.     printImageFileHeaderInfo();
  209.     printImageOptionalHeaderInfo();
  210. }
  211. VOID AnalysisPE::printSectionHeaders()
  212. {
  213.     if(isPE!=TRUE)
  214.         return;
  215.     cout << "/n=======================================================/n"
  216.         << "PE Section headers:/n";
  217.     cout << "There are " << NUMOFSECTION << " sections in this PE!/n";
  218.     cout << "/nname/tsize/taddr/tread/twrite/texcute/n";
  219.     PIMAGE_SECTION_HEADER pSH = pSectionHeader;
  220.     for(int i=0; i<NUMOFSECTION; i++)
  221.     {
  222.         cout <<pSH->Name<< "/t"
  223.             << pSH->SizeOfRawData << "/t"
  224.             << pSH->VirtualAddress << "/t"
  225.             << (pSH->Characteristics&IMAGE_SCN_MEM_READ? "true" : "false") << "/t"
  226.             << (pSH->Characteristics&IMAGE_SCN_MEM_WRITE? "true" : "false") << "/t"
  227.             << (pSH->Characteristics&IMAGE_SCN_MEM_EXECUTE? "true" : "false") << endl;
  228.         pSH = (PIMAGE_SECTION_HEADER)((DWORD)pSH + sizeof(IMAGE_SECTION_HEADER));
  229.     }
  230. }
  231. VOID AnalysisPE::_walkThroughPE()
  232. {
  233.     //文件的装载起始位置就是DOS头;
  234.     pDOSHeader = (PIMAGE_DOS_HEADER)hMapView;  
  235.     if(IMAGE_DOS_SIGNATURE != pDOSHeader->e_magic){ //判断DOS的标识是否正确
  236.         cout << "not PE file because of the DOS Magic number is not right!/n";
  237.         isPE = FALSE;
  238.         return;
  239.     }
  240.     //DOS头中的e_lfanew就是NT头的相对虚拟地址RVA;
  241.     pNTHeader  = (PIMAGE_NT_HEADERS)((DWORD)hMapView + pDOSHeader->e_lfanew);  
  242.     if(IMAGE_NT_SIGNATURE != pNTHeader->Signature){ //判断PE的标识是否正确
  243.         cout << "not PE file because of the NT Signature is not right/n";
  244.         isPE = FALSE;
  245.         return;
  246.     }
  247.     isPE = TRUE;  //是的,这是一个PE文件
  248.     //得到节表(Section Table)的地址
  249.     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS)); 
  250. }
  251. BOOL AnalysisPE::_LoadFile()
  252. {
  253.     BOOL Flag = TRUE;
  254.     __try{
  255.         hFile = CreateFile(
  256.             this->name, 
  257.             GENERIC_READ|GENERIC_EXECUTE , 
  258.             0,NULL, OPEN_EXISTING, 
  259.             FILE_ATTRIBUTE_NORMAL, 
  260.             NULL);
  261.         hFileMapping = CreateFileMapping(
  262.             hFile, NULL, PAGE_EXECUTE_READ, 
  263.             0, 0, TEXT("testdll.dll"));
  264.         hMapView = MapViewOfFile(
  265.             hFileMapping , 
  266.             FILE_MAP_EXECUTE|FILE_MAP_READ, 
  267.             0, 0, 0);
  268.     }
  269.     __finally{
  270.         if(INVALID_HANDLE_VALUE==hFile){
  271.             Flag = FALSE;
  272.             cout << "Error handle: create file fail!/n";
  273.         }
  274.         if(NULL == hFileMapping){
  275.             Flag = FALSE;
  276.             cout << "Error to create file mapping!/n";
  277.         }
  278.         if(NULL == hMapView){
  279.             Flag = FALSE;
  280.             cout << "Error to maping view of file!/n";
  281.         }
  282.     }
  283.     return Flag;
  284. }
  285. VOID AnalysisPE::_UnLoadFile()
  286. {
  287.     if(NULL!=hMapView)
  288.         UnmapViewOfFile(hMapView);
  289.     if(NULL!=hFileMapping)
  290.         CloseHandle(hFileMapping);
  291.     if( INVALID_HANDLE_VALUE!=hFile || NULL!=hFile )
  292.         CloseHandle(hFile);
  293. }
  294. void main()
  295. {
  296.     AnalysisPE test;
  297.     test.setPEName(TEXT("c://aa.exe"));  //这里是想要测试的PE文件
  298.     cout << (test.isPEFile()==TRUE ? "yes, it's PE" : "Shit, not a PE at all!") << endl;
  299.     test.printNTHeaderInfo();
  300.     test.printSectionHeaders();
  301.     test.printImportInfo();
  302.     system("pause");
  303. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值