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

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

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

IMAGE_FILE_HEADER

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

IMAGE_OPTIONAL_HEADER(*重要)

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

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

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
IMAGE_FILE_HEADER ->Characteristics(可以看到下面的数字位数不同,而且都是1、2、4、8他们总共加起来就是16看看二进制就知道了他们占的不是同一位与一下就能取到相对应位,linux的文件属性1、2、4也是一样的)
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

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

    typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD VirtualAddress; //表首地址的RVA
    DWORD Size; //表长度
    } 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指定。

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

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

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

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

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

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

    常用
    #define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
    #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
    #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
    #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
    #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
    #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
    #define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
    #define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
    #define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
    #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. redis之常见操作

    目录 redis的常见操作 1. redis客户端登录方式 2. 设置密码 3. 获取redis的配置 4. redis键(key) 语法 实例 Redis keys (黄色为重点) redis的常见 ...

  2. 三 基于Java动态数组手写队列

    手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...

  3. primecoin 全节点日常维护操作

    primecoin 全节点日常维护操作: 一.关于primecoin维护,每天检查这6个地址是否能正常访问: http://api.primecoin.org/rest/pcoin/syncblock ...

  4. 剑指offer 二叉树的后序遍历序列

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 思路:这题目有点特殊,主要在于序列为空的时候,不是 ...

  5. Day4-F-产生冠军 HDU - 2094

    有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛. 球赛的规则如下: 如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C. 如果A打败了B,B又打败了 ...

  6. Day3-M-Cable master POJ1064

    Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Commi ...

  7. 谈一下你对uWSGI和 nginx的理解(原理)

    要注意 WSGI / uwsgi / uWSGI 这三个概念的区分. WSGI是一种通信协议. uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信. uWS ...

  8. 089、Java中String类之利用构造方法实例化

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  9. Git如何合并Commit

    如果你在 push 你的修改之前想要将本地多次修改后的 commit 合并一下变得更好看,可以使用下面的方法. 指定你要合并的 commit 相关的命令有两种 你可以通过指定修改过去的几个 commi ...

  10. gym 101911

    A. Coffee Break 题意:每天有m小时,你喝咖啡需要花一小时,你想在n个时刻都喝过一次咖啡,老板规定连续喝咖啡的间隔必须是d以上,求最少需要多少天才能喝够n次咖啡,并输出每个时刻第几天喝. ...