一、PE文件介绍

1. PE文件定义

PE的意思就是Portable Executable(可移植、可执行)

2. PE文件结构

如下为PE文件结构图:

PS:现在大多数PE文件都是加壳或者经过处理的,此程序只适用于最原始的PE文件

关于PE文件的解析问题,可以参考我的另一篇博文《用Winhex软件解析PE文件》

二、代码

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>//函数计算导出/导入表相对内存的偏移量
DWORD RVA2Offset(PIMAGE_NT_HEADERS pNTHeader, DWORD dwExpotRVA)
{PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++){if(dwExpotRVA >= pSection[i].VirtualAddress && dwExpotRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData)){return pSection[i].PointerToRawData + (dwExpotRVA - pSection[i].VirtualAddress);}}return 0;
}int main(int argc, char* argv[])
{char szExePath[MAX_PATH]; //声明文件名//"C:\\Program Files (x86)\\Application Verifier\\vrfauto.dll"printf("Please input the execution file path:\n");scanf("%s",szExePath);HANDLE hFile = CreateFile(szExePath, GENERIC_ALL, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); //获得PE文件句柄HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); //创建一个新的文件映射内核对象//将一个文件映射对象映射到内存,得到指向映射到内存的第一个字节的指针pbFilePVOID pbFile = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);if(INVALID_HANDLE_VALUE == hFile || NULL == hMapping || NULL == pbFile){printf("\n\t---------- The File Inexistence! ----------\n");if(NULL != pbFile){UnmapViewOfFile(pbFile);}if(NULL != hMapping){CloseHandle(hMapping);}if (INVALID_HANDLE_VALUE != hFile){CloseHandle(hFile);}return 0;}printf("<------------------------PE Header----------------------->\n");PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbFile;//pDosHeader指向DOS头起始位置printf("PE Header e_lfanew:0x%x\n",pDosHeader->e_lfanew);PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pbFile + pDosHeader->e_lfanew);//计算PE头位置if(0x00004550 != pNTHeader->Signature){printf("\n\t---------- Lawless PE File! ----------\n");if(NULL != pbFile){UnmapViewOfFile(pbFile);}if(NULL != hMapping){CloseHandle(hMapping);}if (INVALID_HANDLE_VALUE != hFile){CloseHandle(hFile);}return 0;}printf("<----------------------FileHeader---------------------->\n");WORD wNumberOfSections = (WORD)pNTHeader->FileHeader.NumberOfSections;//找到存放节数的项,并打印printf("NumberOfSections: %d\n",wNumberOfSections);WORD wSizeOfOptionalHeader= (WORD)pNTHeader->FileHeader.SizeOfOptionalHeader;//找到可选头长度,并打印printf("SizeOfOptionalHeader: %d\n",wSizeOfOptionalHeader);//可选映像头printf("<--------------------Optional Header-------------------->\n");DWORD dwSizeOfCode = (DWORD)pNTHeader->OptionalHeader.SizeOfCode;printf("SizeOfCode: 0x%08X\n",dwSizeOfCode);DWORD dwAddressOfEntryPoint = (DWORD)pNTHeader->OptionalHeader.AddressOfEntryPoint;printf("AddressOfEntryPoint: 0x%08X\n",dwAddressOfEntryPoint);DWORD dwImageBase = (DWORD)pNTHeader->OptionalHeader.ImageBase;printf("ImageBase: 0x%08X\n",dwImageBase);DWORD dwSectionAlignment = (DWORD)pNTHeader->OptionalHeader.SectionAlignment;printf("SectionAlignment: 0x%08X\n",dwSectionAlignment);DWORD dwFileAlignment = (DWORD)pNTHeader->OptionalHeader.FileAlignment;printf("FileAlignment: 0x%08X\n",dwFileAlignment);DWORD dwSizeOfImage = (DWORD)pNTHeader->OptionalHeader.SizeOfImage;printf("SizeOfImage: 0x%08X\n",dwSizeOfImage);DWORD dwNumberOfRvaAndSize = (DWORD)pNTHeader->OptionalHeader.NumberOfRvaAndSizes;printf("NumberOfRvaAndSizes: 0x%08X\n",dwNumberOfRvaAndSize);DWORD dwSectionHeaderOffset = (DWORD)pNTHeader+24+(DWORD)wSizeOfOptionalHeader;//计算节表的位置printf("<----------------------SectionTable---------------------->\n");int NumOfSec = 0;for(NumOfSec;NumOfSec<wNumberOfSections;NumOfSec++){PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(dwSectionHeaderOffset + 40*NumOfSec);printf("%d 's Name):%s\n",NumOfSec+1,pSectionHeader->Name);DWORD dwVirtualAddress = (DWORD)pSectionHeader->VirtualAddress;printf("VirtualAddress: 0x%08X\n",dwVirtualAddress);DWORD dwSizeOfRawData = (DWORD)pSectionHeader->SizeOfRawData;printf("SizeOfRawData: 0x%08X\n",dwSizeOfRawData);DWORD dwPointerToRawData = (DWORD)pSectionHeader->PointerToRawData;printf("PointerToRawData: 0x%08X\n",dwPointerToRawData);}printf("<--------------------Export Table-------------------->\n");DWORD dwExportOffset = RVA2Offset(pNTHeader, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pbFile + dwExportOffset);DWORD dwFunctionNameOffset = (DWORD)pbFile + RVA2Offset(pNTHeader, pExport->Name);DWORD* pdwNamesAddress = (DWORD*)((DWORD)pbFile + RVA2Offset(pNTHeader, pExport->AddressOfNames));DWORD* pdwFunctionAddress = (DWORD*)((DWORD)pbFile + RVA2Offset(pNTHeader, pExport->AddressOfFunctions));WORD* pwOrdinals = (WORD*)((DWORD)pbFile + RVA2Offset(pNTHeader, pExport->AddressOfNameOrdinals));printf("AddressOfNameOrdinals: 0x%08X\n",RVA2Offset(pNTHeader, pExport->AddressOfNameOrdinals));printf("AddressOfFunctions: 0x%08X\n",RVA2Offset(pNTHeader, pExport->AddressOfFunctions));printf("AddressOfNames: 0x%08X\n",RVA2Offset(pNTHeader, pExport->AddressOfNames));if(0 == pExport->NumberOfFunctions){printf("\n\t---------- No Export Tabel! ----------\n");if(NULL != pbFile){UnmapViewOfFile(pbFile);}if(NULL != hMapping){CloseHandle(hMapping);}if (INVALID_HANDLE_VALUE != hFile){CloseHandle(hFile);}return 0;}printf("FileName: %s\n", dwFunctionNameOffset);printf("NumberOfFunctions: %d\n", pExport->NumberOfFunctions);printf("NumberOfNames: %d\n\n", pExport->NumberOfNames);printf("============NameExport:\n\n");int IsFound[1000]={0};int k;for(k=0;k<pExport->NumberOfFunctions;k++){IsFound[k]=0;//printf("%d ",IsFound[k]);}int i;for(i = 0; i < pExport->NumberOfNames; i++){DWORD dwFunctionAddress = pdwFunctionAddress[pwOrdinals[i]];DWORD pdwFunNameOffset = (DWORD)pbFile + RVA2Offset(pNTHeader, pdwNamesAddress[i]);IsFound[pwOrdinals[i]]=1;printf("[ExportNum]: %-4d  [Name]: %-30s [RVA]: 0x%08X\n", pExport->Base + pwOrdinals[i], pdwFunNameOffset,dwFunctionAddress);}printf("\n============NumberExport:\n");int m;for(m = 0; m < pExport->NumberOfFunctions; m++){if(IsFound[m]!=1){DWORD dwFunctionAddress = pdwFunctionAddress[m];printf("[ExportNum]: %-4d [RVA]: 0x%08X\n", pExport->Base + m, dwFunctionAddress);}}printf("\n");printf("<--------------------Inport Table-------------------->\n");int cont = 0;do{DWORD dwInportOffset = RVA2Offset(pNTHeader, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);dwInportOffset = dwInportOffset + cont;PIMAGE_IMPORT_DESCRIPTOR  pInport = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pbFile + dwInportOffset);if(pInport->OriginalFirstThunk == 0&& pInport->TimeDateStamp == 0&& pInport->ForwarderChain== 0 && pInport->Name== 0 && pInport->FirstThunk== 0 )break;DWORD dwOriginalFirstThunk = (DWORD)pbFile + RVA2Offset(pNTHeader, pInport->OriginalFirstThunk);//VA to IATDWORD dwFirstThunk = (DWORD)pbFile + RVA2Offset(pNTHeader, pInport->FirstThunk);//VA to IATDWORD dwName = (DWORD)pbFile + RVA2Offset(pNTHeader, pInport->Name);printf("\n---------Inport File Name: %s\n\n",dwName);if(dwOriginalFirstThunk == 0x00000000){dwOriginalFirstThunk = dwFirstThunk;}DWORD* pdwTrunkData= (DWORD*)dwOriginalFirstThunk;int n=0,x=0;while(pdwTrunkData[n] != 0){DWORD TrunkData = pdwTrunkData[n];if(TrunkData < IMAGE_ORDINAL_FLAG32)//名字导入{PIMAGE_IMPORT_BY_NAME pInportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pbFile + RVA2Offset(pNTHeader, TrunkData));printf("-----------InportByName: %s\n",pInportByName->Name);}else//序号导入{DWORD FunNumber = (DWORD)(TrunkData - IMAGE_ORDINAL_FLAG32);printf("-----------InportByNumber: %-4d ",FunNumber);}if(x != 0 && x%3==0) printf("\n");n++;x++;}cont=cont+40;}while(true);if(NULL != pbFile){UnmapViewOfFile(pbFile);}if(NULL != hMapping){CloseHandle(hMapping);}if (INVALID_HANDLE_VALUE != hFile){CloseHandle(hFile);}return 0;
}

三、运行结果

1.PE头、文件头、选择头…


2.导出表部分:



3.导入表部分:



C/C++编程解析PE文件结构相关推荐

  1. 用Winhex软件解析PE文件

    一.概念 1. PE文件 PE(Portable Executable)文件,被称为可移植的可执行的文件,常见的EXE.DLL.OCX.SYS.COM都是PE文件,PE文件是微软Windows操作系统 ...

  2. 《C++ 黑客编程揭秘与防范(第2版)》——6.2 详解PE文件结构

    本节书摘来自异步社区出版社<C++ 黑客编程揭秘与防范(第2版)>一书中的第6章,第6.2节,作者:冀云,更多章节内容可以访问云栖社区"异步社区"公众号查看. 6.2 ...

  3. 《C++ 黑客编程揭秘与防范(第2版)》—第6章6.2节详解PE文件结构

    本节书摘来自异步社区<C++ 黑客编程揭秘与防范(第2版)>一书中的第6章6.2节详解PE文件结构,作者冀云,更多章节内容可以访问云栖社区"异步社区"公众号查看. 6. ...

  4. [系统安全] 四十一.APT系列(6)Python解析PE文件并获取时间戳判断来源区域

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  5. 病毒木马查杀实战第024篇:MBR病毒之编程解析引导区

    前言 通过之前的学习,相信大家已经对磁盘的引导区有了充分的认识.但是我们之前的学习都是利用现成的工具来对引导区进行解析的,而对于一名反病毒工程师而言,不单单需要有扎实的逆向分析功底,同时也需要有很强的 ...

  6. PE文件结构详解(二)可执行文件头

    by evil.eagle 转载请注明出处. http://blog.csdn.net/evileagle/article/details/11903197 在PE文件结构详解(一)基本概念里,解释了 ...

  7. 【转】PE文件结构详解--(完整版)

    (一)基本概念 PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任 ...

  8. PE文件结构与程序装载

    PE文件结构与程序装载是掌握Windows逆向.加壳.免杀等技术的基础,本文详细记录了PE文件的基本结构,用编辑器对文件结构进行分析,并介绍程序装载的相关概念和基本过程. 参考书籍:<逆向工程核 ...

  9. PE文件结构详解 --(完整版)

    From:https://blog.csdn.net/adam001521/article/details/84658708 PE结构详解:https://www.cnblogs.com/zheh/p ...

最新文章

  1. python爬虫案例-Python爬取租房数据实例,据说可以入门爬虫的小案例!
  2. SPRING事务传播特性
  3. jQuery源码学习
  4. Web Deployment Projects with Visual Studio 2005
  5. Castle.ActiveRecord的ProxyFactory配置
  6. IDEA JRebel热部署插件免费使用方法
  7. 关于一道数据库例题的解析。为什么σ age22 (πS_ID,SCORE (SC) ) 选项是错的?
  8. 新浪uc2010官方下载
  9. jemter在linux上怎么安装_【JMeter之一】在linux系统下安装jmeter
  10. 区块链未来发展三大关键词,华为云如何见招拆招?
  11. 【转】什么是磁珠(Ferrite Bead 即 FB)
  12. Ansible详解(十二)——Ansible Roles详解
  13. 影视.20190507
  14. 数学之美番外篇--贝叶斯方法
  15. .Net中数据绑定控件应用小技巧
  16. stm32与绝对式编码器的ssi接口进行通信
  17. 思路初探:采用c#实现pdf转ofd
  18. 用计算机思维认识摩斯密码(摩斯密码速记)
  19. Denoise Autoencoder
  20. w7电脑蓝屏怎么解决_Win7电脑突然蓝屏怎么办?

热门文章

  1. 碳达峰、碳中和计算原理
  2. php音频上传失败,flash导入音乐失败怎么办
  3. 《概率论与数理统计》之事件的相互关系及运算
  4. 计算机考研跨设计,浅谈2012年计算机跨考视觉转达设计考研经历
  5. 关于CMTS设备的一些备忘
  6. mybatis-plus:根据日期或时间范围查询数据的3种方式
  7. 乡村少年宫计算机课程,乡村学校少年宫计算机课程安排(5页)-原创力文档
  8. 目标检测标注工具(可自定义生成标签模板)
  9. Flink Watermark相关概念(窗口、水位线、迟到事件)
  10. 网站建设之Dreamweaver入门使用