PE知识复习之PE的各种头属性解析
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的各种头属性解析的更多相关文章
- PE知识复习之PE的重定位表
		PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思. 如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234. 如果Im ... 
- PE知识复习之PE的导入表
		PE知识复习之PE的导入表 一丶简介 上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数 函数的地址 函数名称 序号 等等. 一个进程是一组PE文件构成的. PE文件需要依赖那些 ... 
- PE知识复习之PE的导出表
		PE知识复习之PE的导出表 一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就 ... 
- PE知识复习之PE合并节
		PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ... 
- PE知识复习之PE新增节
		PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ... 
- PE知识复习之PE扩大节
		PE知识复习之PE扩大节 一丶为什么扩大节 上面我们讲了,空白区添加我们的代码.但是有的时候.我们的空白区不够了怎么办.所以需要进行扩大节. 扩大节其实很简单.修改节数据对齐后的大小即可. 并且在PE ... 
- PE知识复习之PE文件空白区添加代码
		PE知识复习之PE文件空白区添加代码 一丶简介 根据上面所讲PE知识.我们已经可以实现我们的一点手段了.比如PE的入口点位置.改为我们的入口位置.并且填写我们的代码.这个就是空白区添加代码. 我们也可 ... 
- PE知识复习之PE的RVA与FOA的转换
		PE知识复习之PE的RVA与FOA的转换 一丶简介PE的两种状态 首先我们知道PE有两种状态.一种是内存展开.一种是在文件中的状态.那么此时我们有一个需求. 我们想改变一个全局变量的初始值.此时应该怎 ... 
- PE知识复习之PE的节表
		PE知识复习之PE的节表 一丶节表信息,PE两种状态.以及重要两个成员解析. 确定节表位置: DOS + NT头下面就是节表. 确定节表数量: 节表数量在文件头中存放着.可以准确知道节表有多少个. 节 ... 
随机推荐
- 【转】Zookeeper 安装和配置
			转自:http://coolxing.iteye.com/blog/1871009 Zookeeper的安装和配置十分简单, 既可以配置成单机模式, 也可以配置成集群模式. 下面将分别进行介绍. 单机 ... 
- Javascript 的变量提升与预解析
			一.什么是变量提升 在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分 二.怎么实现 ... 
- BZOJ 3622
			直接算 $a_i>b_i$ 对数恰为 $k$ 的不好算 那么可以先算 $a_i>b_i$ 对数至少 $k$ 的 这个排序后随便dp一下就好 那么再除了一下 用 $f_i$ 表示 $a_i& ... 
- Flume+Kafka+Storm整合
			Flume+Kafka+Storm整合 1. 需求: 有一个客户端Client可以产生日志信息,我们需要通过Flume获取日志信息,再把该日志信息放入到Kafka的一个Topic:flume-to-k ... 
- 怎样做ie兼容性
			1.<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />强制把不标准的转 ... 
- 二、JAVA基础、语法
			第二节:JAVA基础.语法 1.修饰符.变量: Java中主要有如下几种类型的变量 局部变量 ... 
- Java_异常处理
			这篇我们聊聊java中的异常.首先我们要知道什么是异常? Exception: exception翻译过来就是“意外”的意思.事实上,异常的本质就是程序的错误,包括程序逻辑错误和系统错误.错误在编写程 ... 
- java将数据库中查询到的数据导入到Excel表格
			1.Maven需要的依赖 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> ... 
- 12.JavaScript字符串方法
			JS字符串常用方法总结 动态方法:1.str.charAt(index); 返回子字符串,index为字符串下标,index取值范围[0,str.length-1] 动态方法:2.str.charC ... 
- js面向对象自定义MyString()的构造器函数,实现内建String()属性和方法:
			js面向对象自定义MyString()的构造器函数,实现内建String()属性和方法: var s = new MyString('hello'); s.length; s[0]; // " ... 
