PE知识复习之PE的各种头属性解析

一丶DOS头结构体

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

DOS头是在16位程序下使用的.所以不用全部关心.只需要关心第一个跟最后一个成员记住即可.

DOS头大小是64个字节,十六进制是0x40 总结一下就是说. 4行只有第一行的前两个字节.以及最后一行的4个字节有用.

 WORD   e_magic  这个成员是操作系统检查的MZ头.
 LONG   e_lfanew 这个成员指向PE头.也很重要.
如果上面两个成员更改了.那么文件就不能运行了.

二丶NT头解析

  NT头也是我们所指的PE头. 其中NT头包括了文件头跟扩展头.

typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; PE标识
IMAGE_FILE_HEADER FileHeader; 文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader;扩展头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

NT头的第一个成员也很重要.是PE标识.占4个字节. DOS头的最后一个成员的偏移.就是NT头.(PE)

例如:

操作系统会检查PE头.以及MZ头.检查是否是正确的值.

而NT头中有两个子结构体.一个是文件头.一个是扩展头.这两个头比较重要.

三丶文件头解析

  文件头挺重要的.里面存储了我们的节表个数.等等一些列信息.跟扩展头息息相关.

文件头大小是20个字节. 十六进制 是0x14大小.如果按照16一行分组.那么就是一行零4个字节.是文件头总大小.

typedef struct _IMAGE_FILE_HEADER {
WORD Machine;                        机器型号.表名了我们CPU执行的这个PE文件是x86的还是x64的.有一系列宏标识.
WORD NumberOfSections;                   节表个数. 此成员很重要.标识着我们的节表有多少个.如果节个数小于节的总数那么程序就不能运行.
DWORD TimeDateStamp;                     文件时间.不重要.与文件属性里面的创建事件修改时间无关.编译器填写的
 DWORD PointerToSymbolTable; 调试器相关
DWORD NumberOfSymbols; 调试器相关.
WORD SizeOfOptionalHeader; 扩展PE头大小,此成员很重要.表明了我们的扩展头总体大小.
WORD Characteristics; 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

machine 标识 #define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64 代表是x64运行的程序. 其中 0x14c则带便是86运行的程序.具体可以查看宏

文件头中标红的都很重要. 一个是操作系统判断是什么系统运行的文件.一个是当前PE的节个数.一个表明了扩展头的大小.一个表明了文件属性

总结: 一行零4个字节.其中前4个字节很重要.分别表示机器型号.以及节个数. 一行零2个字节表明了扩展头大小.也很重要.

关于最后一个成员 是按位来做的.具体成员如下.

四丶扩展头解析

  扩展头的大小.在我们的文件头中标识着. 一般是E0大小.扩展头是可以更改的. E0十进制大小是224个字节.

我们看一下扩展头结构.

x86跟x64的扩展头是不一样的.我们直说一下x86

typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
// WORD Magic;              //标志.表名了我们的PE是x86还是x64
BYTE MajorLinkerVersion; //连接器主要版本号
BYTE MinorLinkerVersion; //连接器次要版本号 例如 3.54 主要版本就是3.次要就是54
DWORD SizeOfCode; //代码段大小,以字节为单位.
DWORD SizeOfInitializedData; //初始化数据部分的大小.
DWORD SizeOfUninitializedData; //未知初始化数据的大小
DWORD AddressOfEntryPoint; //OEP 程序入口点,驱动程序也是入口点.对于DLL而言.是可选的.没有入口则为0
DWORD BaseOfCode; //指向代码部分的指针
DWORD BaseOfData; //指向数据部分开头的指针 //
// NT additional fields.
// DWORD ImageBase; //基址.PE文件加载到内存中的基址.这个值是64k的倍数.DLL默认值是0x100000000,应用程序默认是0x00400000
windows CE除外.他是0x00010000
DWORD SectionAlignment; //PE文件加载到内存中.的内存对齐.按照这个成员进行对齐
DWORD FileAlignment; //文件对齐,PE存数据存放在文件中.按照文件对其值对其
WORD MajorOperatingSystemVersion;//所需要操作系统的主要版本号.
WORD MinorOperatingSystemVersion;//所需要操作系统的次要版本号.
WORD MajorImageVersion; //PE主版本号
WORD MinorImageVersion; //PE次版本号
WORD MajorSubsystemVersion; //子系统主要版本号.
WORD MinorSubsystemVersion; //子系统次要版本号.
DWORD Win32VersionValue; //保留成员,必须为0
DWORD SizeOfImage; //PE镜像大小.必须是内存对齐的倍数. sizeofImage/SectionAllignment == 0 才可以
DWORD SizeOfHeaders; // DOS头+NT头+节表的总大小.按照文件对齐存放 sizeofHeaders / FileAlignment == 0
   DWORD SubSystem           //表名PE文件是什么程序. 1驱动程序2窗口程序3控制台程序(DLL)
DWORD CheckSum;
WORD DllCharacteristics; //P的文件属性
DWORD SizeOfStackReserve; //堆栈保留字节数.我们的程序使用的栈空间多大靠这个成员.不过操作系统只作为参考
DWORD SizeOfStackCommit; //要为堆栈提交的字节数.不做参考
DWORD SizeOfHeapReserve; //堆保留字节数.
DWORD SizeOfHeapCommit; //本地堆提交的字节数. PS: 栈堆保留数值.斗鱼自己的sizeof(Head/stack)Commit成员有关.
DWORD LoaderFlags; //成员已经过时
DWORD NumberOfRvaAndSizes; //数据目录数组的大小
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

总结来说.上面的成员挺多的.也很重要.

OEP  AddressOfEntryPoint 指明了PE入口点.在扩展头的0x10字节位置.也就是扩展头往下数一行就是OEP. OEP所在位置是一行零4个字节.
ImageBase 基址. 指明了PE加载时候的基址.基址+ OEP就能确定代码在哪里开始运行. 0x1c位置处.也就是扩展头下数一行零12个字节,下面4个字节就是Image. Image所在位置是2行位置.
SectionAlignment 内存对齐,PE加载到内存中所需要的对齐值. 在扩展头两行位置处.往下数4个字节就是. 所在位置两行零4个字节
FileAlignment 文件对齐,PE存放在文件中的数据的对齐值.扩展头两行零4个字节位置. 所在位置是两行零八个字节.也就是两行半.
 SizeOfImage PE的镜像大小. 扩展头 三行半位置往下数4个字节 所在位置.三行零12字节位置处.
SizeOfHeaders DOS头+NT头+节表的大小.按照文件对齐放在文件中的成员. 三行零12字节位置处往下数4个字节. 所在位置是4行位置.

NumberOfRvaAndSizes 数据目录大小.所在位置六行位置处 下面都是数据目录了.数据目录指明了导入表导出表等等一些列的表格位置

关于扩展头.重要成员就这么多. 主要就是熟悉各成员之间的关系.

sizeofImage 跟 内存对齐成员有关  sizeofImage / sectionAlignment == 0
sizeofHeaders 头大小.跟文件对齐有关 SizeofHeaders / FileAlignment == 0

五丶数据目录

  数据目录在我们的扩展头中.作为一个子结构体存放

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

数据目录的作用就是指明了PE文件的导入表.导出表等等一些列表格在哪里存放. 有两个成员.一个是虚拟地址.一个是大小.

 
 
 
 

PE知识复习之PE的各种头属性解析的更多相关文章

  1. PE知识复习之PE的重定位表

    PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思.  如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234.  如果Im ...

  2. PE知识复习之PE的导入表

    PE知识复习之PE的导入表 一丶简介 上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数  函数的地址 函数名称 序号 等等. 一个进程是一组PE文件构成的.  PE文件需要依赖那些 ...

  3. PE知识复习之PE的导出表

    PE知识复习之PE的导出表 一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就 ...

  4. PE知识复习之PE合并节

    PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ...

  5. PE知识复习之PE新增节

    PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ...

  6. PE知识复习之PE扩大节

    PE知识复习之PE扩大节 一丶为什么扩大节 上面我们讲了,空白区添加我们的代码.但是有的时候.我们的空白区不够了怎么办.所以需要进行扩大节. 扩大节其实很简单.修改节数据对齐后的大小即可. 并且在PE ...

  7. PE知识复习之PE文件空白区添加代码

    PE知识复习之PE文件空白区添加代码 一丶简介 根据上面所讲PE知识.我们已经可以实现我们的一点手段了.比如PE的入口点位置.改为我们的入口位置.并且填写我们的代码.这个就是空白区添加代码. 我们也可 ...

  8. PE知识复习之PE的RVA与FOA的转换

    PE知识复习之PE的RVA与FOA的转换 一丶简介PE的两种状态 首先我们知道PE有两种状态.一种是内存展开.一种是在文件中的状态.那么此时我们有一个需求. 我们想改变一个全局变量的初始值.此时应该怎 ...

  9. PE知识复习之PE的节表

    PE知识复习之PE的节表 一丶节表信息,PE两种状态.以及重要两个成员解析. 确定节表位置: DOS + NT头下面就是节表. 确定节表数量: 节表数量在文件头中存放着.可以准确知道节表有多少个. 节 ...

随机推荐

  1. MyBatis 缓存机制

    Mybatis 有两级缓存: 一级缓存: 也称为本地缓存,SqlSession级别的缓存.一级缓存是一直开启的: 与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从 ...

  2. jieba中文分词

      jieba中文分词¶   中文与拉丁语言不同,不是以空格分开每个有意义的词,在我们处理自然语言处理的时候,大部分情况下,词汇是对句子和文章的理解基础.因此需要一个工具去把完整的中文分解成词. ji ...

  3. vscode1.30.1使用的electron3.0.10中的bug

    PS C:\GitHub\vscode2\vscode> scripts\code.bat[13:07:19] Syncronizing built-in extensions...[13:07 ...

  4. Docker安装及基本操作

    系统环境 CentOS Linux release 7.5.1804 (Core) 安装依赖包 更新系统软件 yum update 安装docker yum install docker 启动dock ...

  5. Java变成遇到的简单乱码问题

    1.乱码 --- 编码集   编码集的本质是让数字与字符产生一个映射关系,不同的编码集映射实现也不同   比如UTF-8: "中"----> -28  -72  -83 对应 ...

  6. [复试机试]c++读取/写入文本文件

    读取文件 #include <iostream> #include <cstdio> #include <string> #include <cstdlib& ...

  7. External Snapshot management

    External Snapshot management Symptom As of at least libvirt 1.1.1, external snapshot support is inco ...

  8. Spring相关问题

    1.什么是 Spring 框架?Spring 框架有哪些主要模块?Spring 框架是一个为 Java 应用程序的开发提供了综合.广泛的基础性支持的 Java 平台.Spring帮助开发者解决了开发中 ...

  9. Java线程状态Jstack线程状态BLOCKED/TIMED_WAITING/WAITING解释

    一.线程5种状态 新建状态(New) 新创建了一个线程对象. 就绪状态(Runnable) 线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运行,等待获 ...

  10. 【DFS】n皇后问题

    回溯: 递归调用代表开启一个分支,如果希望这个分支返回后某些数据恢复到分支开启前的状态以便重新开始,就要使用到回溯技巧,全排列的交换法,数独,部分和,用到了回溯.下一个状态在开始之前需要利用到之前的状 ...