一、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. mysql查询嵌套where_MySQL-10(where /from 嵌套查询)
  2. Storm【实践系列-如何写一个爬虫】 - ParserBolt
  3. windows tcp ping 端口工具及使用方法
  4. lammps后处理:Python调用Ovito模块配置方法
  5. python 移动平均法_移动平均法详解
  6. JavaScript 弹窗事件
  7. 怎样在Excel顶部单元格操作锁定,技巧干货!Excel如何冻结首行单元格?
  8. VS Code Material Icon Theme插件设置自定义文件夹图标关联
  9. 计算机网线接口灯怎样是正常,电脑网线接口灯不亮是什么原因
  10. 网易乐得数据库及运维分享会
  11. python 网格交易源码_网格交易策略(难度:中级)
  12. Android 蓝牙连接
  13. 图机器学习-图神经网络
  14. Python读取键盘输入到一维列表及二维列表
  15. 了解一下winsock
  16. 程序员需知的11个在线教程网站,建议收藏!
  17. ISE14.7 Spartan3e 呼吸灯
  18. python开发和大数据开发工程师_大数据开发工程师的岗位职责
  19. 【解决方案】解决ImportError: Library “GLU“ not found.问题
  20. php微信狗,PHP 微信狗小程序 搜鱼CMS商业正版V3.1 一键生成小程序

热门文章

  1. cesium实现二三维分屏地图同步效果
  2. 发那科机器人零点找回_「发那科」FANUC机器人零点复归详解
  3. Linux下安装中文输入法--小企鹅输入法
  4. android 代码自定义checkbox,Android 自定义CheckBox样式
  5. mysql 增加主键列_MySQL添加列、删除列,创建主键等常用操作总结
  6. 数据库的ACID四原则
  7. 计算机专业 德语,计算机德语专业词汇
  8. 这些电脑软件值得收藏哦
  9. Android安卓手机APP应用自有keystore签名证书怎么生成?
  10. 评测TFN PM1200手持无线电综合测试仪性能