PE头解析

PE 格式是Windows系统下组织可执行文件的格式。PE文件由文件头和对应的数据组成。目标是在不同的架构下装载器和编程工具不用重写。

PE中一大特点是不连续的位置大部分记录的都是相对地址(RVA),相对的是PE文件中记录的基地址(image base)的偏移量。进程是程序的执行状态的实体,每个进程都有自己独立的内存空间(编址)PE和内核等一起编制,所以image base也不总是确定的。

结构(参考:加密与解密)

数据结构

IMAGE_DOS_HEADER

参考:参考:http://www.openrce.org/reference_library/files/reference/PE Format.pdf

  1. IMAGE_DOS_HEADER STRUCT
  2. {
  3. +0h WORD e_magic //Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
  4. +2h WORD e_cblp //Bytes on last page of file
  5. +4h WORD e_cp //Pages in file
  6. +6h WORD e_crlc //Relocations
  7. +8h WORD e_cparhdr //Size of header in paragraphs
  8. +0ah WORD e_minalloc //Minimun extra paragraphs needs
  9. +0ch WORD e_maxalloc //Maximun extra paragraphs needs
  10. +0eh WORD e_ss //intial(relative)SS value DOS代码的初始化堆栈SS
  11. +10h WORD e_sp //intial SP value DOS代码的初始化堆栈指针SP
  12. +12h WORD e_csum //Checksum
  13. +14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
  14. +16h WORD e_cs //intial(relative)CS value DOS代码的初始堆栈入口
  15. +18h WORD e_lfarlc //File Address of relocation table
  16. +1ah WORD e_ovno // Overlay number
  17. +1ch WORD e_res[4] //Reserved words
  18. +24h WORD e_oemid // OEM identifier(for e_oeminfo)
  19. +26h WORD e_oeminfo // OEM information;e_oemid specific
  20. +29h WORD e_res2[10] // Reserved words
  21. +3ch DWORD e_lfanew //Offset to start of PE header PE头相对于文件的偏移地址
  22. } IMAGE_DOS_HEADER ENDS

对于PE来说DOS头是为了兼容16位程序的,现在都是32、64位所以我们只关心这个结构体中的两个成员(16位系统中PE头和内容是冗余数据)

e_magic、e_lfanew(第一个和最后一个)

  • e_magic 是个标志MZ 0x4D5A 判断是否是PE文件用(不是唯一)
  • e_lfanew PE头相对于文件的偏移地址

上图3CH是e_lfanew内容指向PE头地址内容位0000000E(小端存储)。

我们可以看到DOS头和PE头是间隔的那块区域叫DOS stub这个是存储16位程序的,对于32、64位系统无用

PNTHeader = ImageBase + (dosHeader->e_lfanew)

IMAGE_NT_HEADERS

  1. typedef struct _IMAGE_NT_HEADERS {
  2. +0 hDWORD Signature //
  3. +4h IMAGE_FILE_HEADER FileHeader //
  4. +18h IMAGE_OPTIONAL_HEADER32 OptionalHeader //
  5. } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
  6. #define IMAGE_NT_SIGNATURE 0x00004550
  • Signature固定为0x00004550

IMAGE_FILE_HEADER

  1. typedef struct _IMAGE_FILE_HEADER {
  2. +04h WORD Machine;//04h相对于_IMAGE_NT_HEADERS的,运行平台
  3. +06h WORD NumberOfSections;//文件的区块数(*重要)
  4. +08h DWORD TimeDateStamp;//文件创建时间 和unix时间戳一样int(secound(now-19700101))
  5. +0cH DWORD PointerToSymbolTable;//指向符号表(主要用于调试)
  6. +10H DWORD NumberOfSymbols;//符号表中符号个数(同上)
  7. +14H WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32 结构大小(*重要)IMAGE_OPTIONAL_HEADER是长度可变的。
  8. +16H WORD Characteristics;//文件属性多,种属性通过 “或运算” 同时拥有
  9. } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

IMAGE_OPTIONAL_HEADER(*重要)

  1. IMAGE_FILE_HEADERSizeOfOptionalHeader决定大小(可变长)
  2. typedef struct _IMAGE_OPTIONAL_HEADER {
  3. //
  4. // Standard fields.
  5. //
  6. +18h WORD Magic; // 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
  7. +1Ah BYTE MajorLinkerVersion; // 链接程序的主版本号
  8. +1Bh BYTE MinorLinkerVersion; // 链接程序的次版本号
  9. +1Ch DWORD SizeOfCode; // 所有含代码的节的总大小
  10. +20h DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小
  11. +24h DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小
  12. +28h DWORD AddressOfEntryPoint; // 程序执行入口RVA
  13. +2Ch DWORD BaseOfCode; // 代码的区块的起始RVA
  14. +30h DWORD BaseOfData; // 数据的区块的起始RVA
  15. //
  16. // NT additional fields.
  17. //
  18. +34h DWORD ImageBase; // 文件在内存中的的首选装载地址。
  19. +38h DWORD SectionAlignment; // 内存中的区块的对齐大小
  20. +3Ch DWORD FileAlignment; // 文件中的区块的对齐大小
  21. +40h WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号
  22. +42h WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号
  23. +44h WORD MajorImageVersion; // 可运行于操作系统的主版本号
  24. +46h WORD MinorImageVersion; // 可运行于操作系统的次版本号
  25. +48h WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号
  26. +4Ah WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号
  27. +4Ch DWORD Win32VersionValue; // 莫须有字段,不被病毒利用的话一般为0
  28. +50h DWORD SizeOfImage; // 映像装入内存后的总尺寸
  29. +54h DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小
  30. +58h DWORD CheckSum; // 映像的校检和
  31. +5Ch WORD Subsystem; // 可执行文件期望的子系统
  32. +5Eh WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0
  33. +60h DWORD SizeOfStackReserve; // 初始化时的栈大小
  34. +64h DWORD SizeOfStackCommit; // 初始化时实际提交的栈大小
  35. +68h DWORD SizeOfHeapReserve; // 初始化时保留的堆大小
  36. +6Ch DWORD SizeOfHeapCommit; // 初始化时实际提交的堆大小
  37. +70h DWORD LoaderFlags; // 与调试有关,默认为 0
  38. +74h DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来 // 一直是16
  39. +78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];// 数据目录表
  40. } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

ImageBase文件在内存中载入地址,如果有文件占据这个位置装载器会进行应用基址重定位。 对于EXE文件来说,由于每个文件总是使用独立的虚拟地址空间一般不会被别的文件抢占。 对于DLL文件来说,由于多个DLL文件全部使用宿主EXE文件的地址空间,不能保证优先装入地址没有被别的DLL使用,所以DLL文件中必须包含重定位信息,对应

  1. #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
  2. IMAGE_FILE_HEADER ->Characteristics(可以看到下面的数字位数不同,而且都是1248他们总共加起来就是16看看二进制就知道了他们占的不是同一位与一下就能取到相对应位,linux的文件属性124也是一样的)
  3. EXE文件的默认优先装入地址被定为00400000h,而DLL文件的默认优先装入地址被定为10000000h

  • AddressOfEntryPoint字段 : 程序执行入口RVA,imageBase+AddressOfEntryPoint就是程序运行的时候首先执行代码处。一般指向.text节。

  • SectionAlignment:程序载入内存后区块(节)对齐大小,每个节被载入内存后必须和CPU内存页对齐(方便设置内存页属性)最小1Kh(4KB)

  • FileAlignment:PE文件在磁盘上的对齐大小,最小为200h(512byte)一个扇区大小。

    关于对齐可以用winhex打开磁盘上的notpad.exe和内存中的notpad.exe,notpad装载的时候就被拉伸了。

  • IMAGE_DATA_DIRECTORY

    这个是个结构存储的对应表位置和大小,至于这些表有什么,做什么需要下面详细解释。

    1. typedef struct _IMAGE_DATA_DIRECTORY {
    2. DWORD VirtualAddress; //表首地址的RVA
    3. DWORD Size; //表长度
    4. } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

    下面是微软的文档上截取的,其中我们比较关心的是导入表、重定位表(DLL等)

    Size Field Description
    8 Export Table The export table address and size. For more information see .edata Section (Image Only).
    8 Import Table The import table address and size. For more information, see The .idata Section.
    8 Resource Table The resource table address and size. For more information, see The .rsrc Section.
    8 Exception Table The exception table address and size. For more information, see The .pdata Section.
    8 Certificate Table The attribute certificate table address and size. For more information, see The Attribute Certificate Table (Image Only).
    8 Base Relocation Table The base relocation table address and size. For more information, see The .reloc Section (Image Only).
    8 Debug The debug data starting address and size. For more information, see The .debug Section.
    8 Architecture Reserved, must be 0
    8 Global Ptr The RVA of the value to be stored in the global pointer register. The size member of this structure must be set to zero.
    8 TLS Table The thread local storage (TLS) table address and size. For more information, The .tls Section.
    8 Load Config Table The load configuration table address and size. For more information, The Load Configuration Structure (Image Only).
    8 Bound Import The bound import table address and size.
    8 IAT The import address table address and size. For more information, see Import Address Table.
    8 Delay Import Descriptor The delay import descriptor address and size. For more information, see Delay-Load Import Tables (Image Only).
    8 CLR Runtime Header The CLR runtime header address and size. For more information, see The .cormeta Section (Object Only).
    8 Reserved, must be zero

区块

区块由区块表映射,区块表紧跟IMAGE_NT_HEADERS;多少个区块表由_IMAGE_NT_HEADERS.FileHeader.NumberOfSections指定。

  1. typedef struct _IMAGE_SECTION_HEADER {
  2. BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //8字节的name
  3. union {
  4. DWORD PhysicalAddress;
  5. DWORD VirtualSize;
  6. } Misc;
  7. DWORD VirtualAddress;//区块RVA
  8. DWORD SizeOfRawData;//文件对齐后的尺寸
  9. DWORD PointerToRawData;//文件中的偏移
  10. DWORD PointerToRelocations;//
  11. DWORD PointerToLinenumbers;
  12. WORD NumberOfRelocations;
  13. WORD NumberOfLinenumbers;
  14. DWORD Characteristics;//区块属性
  15. } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
  16. #define IMAGE_SIZEOF_SHORT_NAME 8
  • Name八个字节的不一定以“\0”借位的字符串表示节的名字

  • Misc、PhysicalAddress、VirtualSize叫什么都行是未对齐前节的大小(可以不准确,改了也没事,编译器生成的)

  • 节在内存中的偏移地址,RVA。

  • SizeOfRawData 节在文件中对齐的尺寸

  • PointerToRawData 节在磁盘文件中的便宜,如果需要自己装载PE(不用操作系统装载)这个值有很多用处。

  • Characteristics 节属性(代码/数据,可读/可写)

    1. 常用
    2. #define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
    3. #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
    4. #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
    5. #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
    6. #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
    7. #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
    8. #define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
    9. #define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
    10. #define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
    11. #define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
    关于区块的对齐

    区块对齐分两部分,FileAlignment、SectionAlignment分别代表文件中和内存中的对齐,为了有效读取和设置属性规定,FileAlignment现在好多程序都和SectionAlignment一样大小了。SectionAlignment内存对齐值在x86上一般是内存页大小4kB(1000H)在x64当中是8KB(2000H)。

    文件偏移与虚拟地址的转换

    FileAlignment、SectionAlignment不同需要将磁盘中的PE文件拉伸。

FileOffset=VA-RVA-k

参考:加密与解密

https://docs.microsoft.com/zh-cn/windows/win32/debug/pe-format

逆向-PE头解析的更多相关文章

  1. PE头详细分析

    目录 PE头详细分析 0x00 前言 0x01 PE文件介绍 0x02 PE头详细分析 DOS头解析 NT头解析 标准PE头解析 可选PE头解析 可选PE头结构 基址 代码段地址 数据段地址 OEP程 ...

  2. C++PE文件格式解析类(轻松制作自己的PE文件解析器)

    PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣 ...

  3. PE文件解析器的编写(二)——PE文件头的解析

    之前在学习PE文件格式的时候,是通过自己查看各个结构,自己一步步计算各个成员在结构中的偏移,然后在计算出其在文件中的偏移,从而找到各个结构的值,但是在使用C语言编写这个工具的时候,就比这个方便的多,只 ...

  4. PE文件解析 基础篇

    PE文件解析 基础篇 来源 https://bbs.pediy.com/thread-247114.htm 前言 之前学习了PE格式,为了更好的理解,决定写一个类似LoadPE的小工具. 编译器是VS ...

  5. 零基础逆向工程17_PE结构01_PE头解析_手动

    PE文件的两种状态 1.在硬盘中 节省硬盘空间 硬盘对齐 内存对齐 2.在内存中 3.PE磁盘文件与内存映像结构图 PE文件为什么要分节 -- 手动解析:PE文件 分析软件:飞鸽传书http://ww ...

  6. pe头

    1.dos头 结构: struct _IMAGE_DOS_HEADER {     WORD e_magic;     WORD e_cblp;     WORD e_cp;     WORD e_c ...

  7. Windows Pe 第三章 PE头文件(下)

    3.5  数据结构字段详解 3.5.1  PE头IMAGE_NT_HEADER的字段 1.IMAGE_NT_HEADER.Signature +0000h,双字.PE文件标识,被定义为00004550 ...

  8. Windows Pe 第三章 PE头文件(中)

    这一章的上半部分大体介绍了下PE文件头,下半部分是详细介绍里面的内容,这一章一定要多读几遍,好好记记基础概念和知识,方便之后的学习. 简单回忆一下: 3.4  PE文件头部解析 3.4.1 DOS M ...

  9. PE文件学习系列三-PE头详解

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 最近比较忙 ...

随机推荐

  1. Law of large numbers and Central limit theorem

    大数定律 Law of large numbers (LLN) 虽然名字是 Law,但其实是严格证明过的 Theorem weak law of large number (Khinchin's la ...

  2. OpenCV数字识别

    输入命令: conda install opencv 返回信息:

  3. kafka在zookeeper默认使用/为根目录,将/更换为/kafka

    需求:kafka在zookeeper默认使用/为根目录,将/更换为/kafka 步骤:1.进入kafka的根目录: [root@node01 kafka_2.11-1.0.0]# cd /export ...

  4. 一、iBatis进行分页查询

    1.ibatis理解: iBatis属于半自动化的ORM框架,我们需要编写SQL语句,由iBatis进行数据库访问,返回结果.而iBatis可以为我们做的更多,比如对查询参数集合.结果.分页查询.事务 ...

  5. Linux系统使用ss命令查看端口状态

    Linux系统使用ss命令查看端口状态 目录 1.可用工具 2.ss帮助 2.1 选项分类说明 2.2 过滤选项family 2.3 过滤选项state 2.4 状态之间的关系 3.ss的使用 3.1 ...

  6. container-coding-codec

    1 数字容器格式 container format 1.1 一些音频专有的容器: 1.2 静态图像专用的容器: 1.3 视频容器,可以容纳多种类型的音频和视频以及其他媒体 1.4 视频容器格式概述 1 ...

  7. JDBC和连接池

    JDBC 所有的数据库操作框架都是用在JDBC的基础上做多次封装的,因为JDBC的操作很复杂 引入Jar包 连接数据库操作 书写sql语句,传参 查询,取值 关闭连接 //1.注册驱动(静态方法)(包 ...

  8. Hyper-V网卡ping不通本机

    可能的解决方案: 添加网卡时选择"旧版"

  9. du与df的区别

    我们知道,磁盘的整体数据是记录在superblock中的,但是每一个文件的容量信息则在inode当中记载的.因此,引出了两个查看这些数据信息的命令: df:列出文件系统的整体磁盘使用量.由于df主要读 ...

  10. ffmpeg 学习: 004-参考文档进行的开发

    背景 在学习ffmpeg时,由于文档老旧以及ffmpeg新旧版本对于一些api的改动,导致学习受阻. 本来可以直接下载老的库,使用老的源码进行学习,但本人觉得,一味地守旧并不是一种好的方法. ffmp ...