文章目录

  • PE文件
  • DOS头部
  • PE/NT头解析
  • 区段头/区块表解析
  • 数据目录表(存放在某个区段)
    • 1. 导出表
    • 2. 导入表
    • 3. 重定位表

PE文件

  • PE文件:PE文件是在windows平台可执行的文件。
  • 包括:.exe(可执行程序),.dll(动态链接库),.sys(驱动程序)



DOS头部

  • 概念:

    • DOS头部共64个字节
    • DOS头部是一个结构体,包含如下字段:
  • 重要字段:

    • e_magic(前两个字节):DOS头签名,可执行文件的标志.(固定的值:4D 5A
    • e_lfanew(后四个字节):PE头的偏移位置
  • DOS头解析:

    #include<Windows.h>
    #include<iostream>// 获取DOS头
    PIMAGE_DOS_HEADER get_pe_dos_header(char* pBuff)
    {return (PIMAGE_DOS_HEADER)pBuff;
    }
    // 解析DOS头
    void parse_pedos_header(const char* path)
    {DWORD fSize = 0;char* pBuff = NULL;DWORD dwReadSize = 0;// 1.打开文件HANDLE hfile = CreateFileA(path, // 文件路径GENERIC_READ, // 打开文件读方式FILE_SHARE_READ,// 共享方式NULL, // 安全属性OPEN_EXISTING, // 创建标志FILE_ATTRIBUTE_NORMAL, //默认创建NULL);// 1.2 获取文件大小fSize = GetFileSize(hfile, NULL); // 获取文件大小pBuff = new char[fSize]; // 申请文件大小空间// 2. 读取到内存中ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);// 3. 解析PE文件的DOS头部PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuff;//PIMAGE_DOS_HEADER pDos = get_pe_dos_header(pBuff);//pDos->e_magic; //DOS头签名,0x5A4D//pDos->e_lfanew; // PE头的偏移// 4. 判断是否是PE文件if (pDos->e_magic != IMAGE_DOS_SIGNATURE){printf("这不是一个PE文件\n");}printf("e_lfanew=%d\n", pDos->e_lfanew);// 5. 关闭文件句柄CloseHandle(hfile);
    }int main() {parse_pedos_header("crackme1.exe");
    }
    
  • 其他:

    • 程序在硬盘中和在内存中存储状态不一样,在内存中的对齐值比在硬盘中大

PE/NT头解析

  • 概念

    • NT头是一个结构体,包含三个字段:
  • 重要字段:

    • Signature(前4个字节):NT头签名,PE标志,固定值 50 45 00 00
    • FileHeader(20个字节):文件头
    • OptionalHeader(大小不固定):可选PE头
  • NT头解析:

    • FileHeader(文件头,共20字节):

    重要字段:

    • Machine(2个字节):程序允许的CPU型号,如果为0表示可以在任何CPU上执行。若为0x014C,表示能在386及后续的CPU上运行
    • NumberOfSections(2个字节):文件中存在的区段的数量
    • TimeDateStamp(4个字节):时间戳
    • SizeOfOptionalHeader(2个字节):可选PE头的大小,32位PE文件默认E0,64位默认F0
    • Characteristics(2个字节):文件属性,每个位有不同的含义
    • OptionalHeader(可选PE头)

    重要字段:

    • Magic(2个字节):表示是32位PE文件还是64位PE文件。0x010B表示32位,0x020B表示64位
    • SizeOfCode(4个字节):所有代码的总大小,按照FileAlignment对齐后的大小
    • SizeOfInitializedData(4个字节):已初始化的数据大小,按照FileAlignment对齐
    • SizeOfUninitializedData(4个字节):未初始化的数据大小 按照FileAlignment对齐
    • AddressOfEntryPoint(4个字节):程序入口 OEP(偏移地址)
    • BaseOfCode(4个字节):代码开始地址
    • BaseOfData(4个字节):数据开始地址
    • ImageBase(4个字节):内存镜像地址(程序被加载到内存后的起始地址(绝对地址))
    • SectionAlignment(4个字节):内存对齐大小
    • FileAlignment(4个字节):文件对齐大小
    • SizeOfImage(4个字节):文件在内存中的大小,按SectionAlignment对齐后的大小
    • SizeOfHeaders(4个字节):DOS头+NT头+标准PE头+可选PE头+区段头,按照FileAlignment对齐后的大小
    • NumberOfRvaAndSizes(4个字节):数据目录表的个数
    • DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:存放数据目录表

区段头/区块表解析

  • 概念:

    • 区段头由多个结构体组成,有多少个区段就有多少个对应的的结构体:
  • 重要字段:

    • Name[IMAGE_SIZEOF_SHORT_NAME(8)](8个字节):区段名称,注意此处跟字符串不一样,不会以0结尾
    • union {
      DWORD PhysicalAddress;
      DWORD VirtualSize;
      } Misc(8个字节)
      :该区段在内存中的真实大小(未对齐)
    • VirtualAddress(4个字节):区段在内存中的偏移位置,+ImageBase 为真正的地址。
    • SizeOfRawData(4个字节):区段在文件中对齐后大小
    • PointerToRawData(4个字节):区段在文件中的偏移位置
    • Characteristics(4个字节):区段属性 (是否可读 是否可写 是否可执行等等)

数据目录表(存放在某个区段)

  • 概念:

    可选PE头中包含两个字段:

    • NumberOfRvaAndSizes(4个字节):数据目录表的个数
    • DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:存放数据目录表


1. 导出表

  • 概念:

    • 导出表存放该程序中定义的可供外部使用的函数
  • 重要字段:

    • DWORD Name:指向导出表文件名 RVA -->FOA+FileBuff=char *name;
    • DWORD Base:导出函数起始序号
    • DWORD NumberOfFunctions:导出函数个数
    • DWORD NumberOfNames:以名称导出函数个数
    • DWORD AddressOfFunctions:导出函数地址表 RVA–>FOA +FileBuff
    • DWORD AddressOfNames:导出函数名称表 // RVA from base of image
    • DWORD AddressOfNameOrdinals:导出函数序号表 // RVA from base of image

    FOA(文件偏移)与RVA(内存偏移)的转换:

    数据的RVA - 区段地址的RVA = 数据的FOA - 区段地址的FOA = 数据距离区段起始位置有多远,注意无论是RVA还是FOA都是偏移

    • 数据的FOA = 数据的RVA - 区段地址的RVA + 区段地址的FOA
    • 数据的RVA = 数据的FOA - 区段地址的FOA + 区段地址的RVA

2. 导入表

  • 知识点准备:

    • 调用dll文件函数原理
      程序在调用dll文件函数时,并不是把dll文件函数的代码编译到当前文件中,而是把dll文件对应的函数地址保存到了当前文件中
    • 一个进程空间中的exe、dll文件如何被加载到内存中
      exe文件先导入内存,然后再导入dll文件到内存中
    1. HMODULE hModule = LoadLibraryW(L"Dll1.dll"):将dll文件加载到内存中,并将ImageBase的值存放到hModule中
    2. GetProcAddress(hModule, “my_export2”):从dll文件中拿到对应的函数的地址
    3. 将得到的函数地址填到exe文件中的对应位置
    • exe文件调用的动态链接库在内存中与在硬盘中有什么不同
      内存中,exe文件中的 dll文件的对应的函数地址 在exe硬盘中 存放的是一个RVA,该RVA转为FOA后,发现存放的是对应的函数名称
    • 在硬盘中,exe文件存放使用的dll文件中的函数名称(准确的说是一个RVA值,该RVA转为FOA后,发现存放的是对应的函数名称)
    • 在内存中,exe文件存放使用的dll文件中的函数地址
  • 概念:

    • 导入表存放该程序使用的外部函数的信息:
  • 重要字段:

    • union {
      DWORD Characteristics; // 0 for terminating null import descriptor
      DWORD OriginalFirstThunk; // RVA,指向(IMAGE_THUNK_DATA,导入名称表)结构体数组,Import name table,简称INT
      } DUMMYUNIONNAME;(8个字节)

    • TimeDateStamp:时间戳。为-1时,IAT在硬盘存储时会存放函数的地址而不是名称(由于存放地址可能会造成冲突,因此需要让所有dll文件导入内存的位置固定)
    • Name:RVA,存放dll的名称
    • FirstThunk:RVA,IAT 导入地址表 IMAGE_THUNK_DATA数组。在硬盘存储时,一般和INT一样(但不绝对);在内存存储时,会存函数的在内存中的地址。

3. 重定位表

  • 概念:

    用来存放程序中已经写死的地址的数据位置,一个PE文件中包含多个重定位表

  • 重要字段:

    • VirtualAddress:内存所在位置
    • sizeofBlock: 块的大小
  • 解释:

    • 为什么要有多个重定位表?
      每个重定位表会保存地址在某一个内存区域上的那些写死地址的数据位置,超出这个区域(0x1000,因为有分页的影响)之外的需要创建一个新的重定位表来保存
    • 如何判定一个重定位表中保存的哪些数据是真正需要修复的?
      由于用16位(2个字节)保存偏移,因此只要高4位等于3(0011),那么就证明这个地址需要修复。

【逆向】PE文件解析相关推荐

  1. 15.windbg-dds、dps、dqs、PE文件解析

    以下默认windbg加载calc程序 d*s dds.dps和dqs命令显示给定范围内存的内容,它们是把内存区域转储出来,并把内存中每个元素都视为一个符号对其进行解析,dds是四字节视为一个符号,dq ...

  2. 图解VC++版PE文件解析器源码分析

    该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...

  3. PE文件解析(1):Dos头与NT头

    文章目录 DOS头 NT头 标准NT头 可选NT头 什么是PE文件? PE文件是在windows平台可执行的文件. 包括:.exe(可执行程序),dll(动态链接库).sys(驱动程序) 这是PE文件 ...

  4. 快速查询PE文件知识点和PE文件解析(下)

    延迟加载导入表 延迟加载导入表(Delay Load Import Table)是PE中引入的专门用来描述与动态链接库延迟加载相关的数据,因为这些数据所起的作用和结构与导入表数据基本一致,所以称为延迟 ...

  5. PE文件解析-文件头与整体介绍

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

  6. 编写PE文件解析器(三)

    下面有几个表网上资料比较少,因为几乎用不到,我查文档写写吧,这篇写得比较久很抱歉. 7.IMAGE_DIRECTORY_ENTRY_EXCEPTION[异常处理表] CPU特定的并且基于表的异常处理. ...

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

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

  8. 网络安全学习第6篇 - 爆破及PE文件解释

    1.请采用暴力破解的方式去尝试破解crack.exe文件(在实验报告中说明破解原理即可,无需提交破解后的文件) 2.请依据参考文档中的内容编写一个小程序,使其可以实现如下功能: ①判断一个文件是否为P ...

  9. 基于PEview分析PE文件(4-1)

    1 PE文件 1.1 PE文件简介 PE文件是Portable Executable(可移植的可执行文件)的简写.EXE.DLL.SYS.COM都是PE文件,PE文件是微软Windows操作系统上的程 ...

最新文章

  1. Java连接Oracle数据库示例
  2. 继续转 [转]php版本的cron定时任务执行器
  3. word2007中如何隐藏工具栏
  4. [翻译]运用文件解析器在任意文件中使用虚拟应用路径(~)
  5. perl 包下载官方网站(速度很快的) 和 解压安装指令
  6. HTML头标签使用-又一次定向,refresh
  7. python水仙花数的代码_Python水仙花数的编程代码写法
  8. 简述对CAN协议栈的理解
  9. 毕业生就业管理系统 C++
  10. IoT全品类全场景来了,但5G时代“大雁群飞”仍需紧盯“服务”
  11. Java实战干货分享
  12. 虚拟机RedHatLinux9安装Oralce92全过程
  13. 如何防御网站被ddos攻击 首先要了解什么是流量攻击
  14. latex中插入图片以及固定图片位置
  15. 怎么防抄板:从保护固件与安全认证开始
  16. MacbookPro 2015 13-ich 成功更换硬盘的方案(intel 760p 1T)
  17. 十个1分钟换来健康,搞IT必看
  18. 产品干货 | 没有产品功能,谈不上用户体验
  19. 12本大神级程序员必读书籍,从菜鸟走向牛逼!
  20. 【毕业季】送给学弟、妹的礼物。

热门文章

  1. 我用三年见证拼多多的“黑化史”
  2. 数字化转型之路 —— 制造业如何突出重围
  3. c语言分治法求众数重数_分治算法:求众数及其重数
  4. 人工智能在绘画方面傻瓜相机_傻瓜智能合约
  5. 哈工大数据结构期末_21哈工大计算机考研 | 备考重点与参考书目推荐!
  6. JavaScript控制打印机打印条形码----条形码产生部分
  7. Glass Beads
  8. 当从 Java 进程查看时该主机的主机名称和规范名称不一致。
  9. vue+typescript怎么写computed
  10. 连接器线缆供应链扎推上市IPO,抢滩资本市场是行业竞争分水岭么?