PE文件格式详解,第二讲,NT头文件格式,以及文件头格式

作者:IBinary
出处:http://www.cnblogs.com/iBinary/
版权所有,欢迎保留原文链接进行转载:)

PS:本篇博客默认你已经有了汇编基础,所以会使用32位汇编编写最小PE进行讲解

今天详解NT 头格式,以及文件头格式,以及作用, 关于DOS头文件格式,以及DOSStub昨天的博客已经写过了.主要是分散讲解.便于理解.

一丶最小PE的生成,以及标准PE的生成

ps: (如果直接学习NT头,文件头,请不用看这个生成PE,直接看下面讲解即可)

1.标准PE的生成

为了便于学习PE文件格式,所以这里写出一个最小PE,还有一个最小的标准PE,让大家理解.

32位汇编编写.(汇编是能编写最小PE的)

首先我们先写一段基本的汇编代码,然后一层一层的优化

32位汇编代码:

.
.model flat,stdcall
option casemap:none include windows.inc
include user32.inc
include kernel32.inc      ;包含各种lib库以及头文件
includelib user32.lib
includelib kernel32.lib .data
g_szHello db "Hello",0dh,0ah,00    ;定义Hello字符串
.code
start:
invoke MessageBoxA,NULL,offset g_szHello ,NULL,MB_OK ;弹出信息框
invoke ExitProcess,0    ;退出程序
end start

很简单的汇编代码

看下EXE的大小,以及内容

2.50KB有点大了.

可以继续优化,但是比如手动敲命令行了.注意,这里使用的masm32的link连接器

首先我们要去掉分区,因为这里的EXE主要是分区太多.所以去掉.

怎么去掉? 只需要把上面的汇编代码修改一下即可.

修改为:

.
.model flat,stdcall
option casemap:none include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib .code
g_szHello db "Hello",0dh,0ah,00 ;将数据段的数据,放到代码区中
start:
invoke MessageBoxA,NULL,offset g_szHello ,NULL,MB_OK
invoke ExitProcess,
end start

很简单,就是把.data去掉即可.

这个就是标准PE了,看下文件大小.

注意一下,这里我使用的是RadAsm集成开发环境,

编译器是Masm32的link连接器. 如果使用VC6.0以及以上的,文件会变的很大,可能会有16.KB,28.KB,不利于大家学习.如果不会配置RadAsm集成开发环境,请参考以前的帖子.自己配置一下即可.

2.最小PE的生成

区合并和内存对齐优化,生成最小PE(不通用)

首先我们要知道PE中的区在哪里,以及怎么使内存对齐缩小,不至于让PE很大.

首先看下我们的标准PE格式的二进制.(使用Winhex,或者010 Editor都可以)

可以看出,生成的时候默认会为我们生成.const常量区,那么我们可以让它和代码区合并吗?

注意,如果是别的程序,是不可以合并的,因为常量区很有用,但是如果生成最小PE那么你需要合并,

最后一个Hello的位置,则是代码区

手工连接,使其合并分区,变为最小PE

命令行参数

/ALIGN:内存对齐(2的倍数即可,默认是4096)

/MERGE: 区 = 区  (合并分区)

例如link加上 写成下面这样

/ALIGN:4 /MERGE:.rdata=.text

手工编译连接看下.

不过这样写还要另外加选项,不能保证她是否是能运行,不通用,所以使用标准pe讲解

二丶NT头

首先看下NT头和文件头的结构体.

NT头:

typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;              //4个字节的PE标志
IMAGE_FILE_HEADER FileHeader;      //文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader;//可选头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

NT 头第一个成员,对应的是PE位置,4个字节.

内存分布图:

在这里,建议大家使用010编辑器,可以使用自定义PE模版,解析PE各个位置内容.

下面模版自动点击则可以解析

三丶文件头

文件头结构体:

typedef struct _IMAGE_FILE_HEADER {
WORD Machine;                   //机器型号,作用是区别这个exe是哪个CPU可以跑的.重要.
WORD NumberOfSections;             //节的数量 (可以理解为汇编中区的个数)现在我们有两个,一个.rdata 一个.text
DWORD TimeDateStamp;               //程序的编译时间,参考用,没有实际作用
DWORD PointerToSymbolTable;          //符号表地址 我们使用的PDB文件(里面有函数吗什么的)都存放在这个表中,不过微软是单独生成的PDB文件,所以这个字段没用,主要是给别人用
DWORD NumberOfSymbols;             //符号表大小
WORD SizeOfOptionalHeader;          //可选头大小,这个字段很重要.因为要通过这个字段,才知道可选头是多大,而不懂PE的人求选项头都是用sizeof()求出来的.所以真正的选项头大小要靠这个字段
WORD Characteristics;            //文件属性,描述文件信息的.
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

上面只是简单的写了下各个成员的作用.

在这里需要注意的是   可选头大小,文件属性,以及机器型号.  其余的自己看看.

1.机器型号:

机器型号,在PE中的定义,在VC++6.0中已经给出了.

代码:

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64

看下PE中怎么存储的.

按照小尾方式,则是 0x014C ,那么对应上面的宏则是386的程序(看注释),而我们的汇编编译出来的标准PE也正是标准PE,如果学习PE,自己可以去看下PE存储

2.可选头大小

这个地方是我计算偏移得出,根据结构体的类型大小,可以自己计算偏移得出.

可以看出,可选头的大小是0x00E0 大小,换算成10进制就可以知道,E0是224字节大小,所以根据这个,可以计算出可选头大小

3.文件属性

文件属性紧跟在E0 00 后面,它是0F 01

文件属性是按照位来的.

什么意思?

先看下宏定义:

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.

首先按照小尾方式查看.

0x010f

那么先看第一个1,不看后面的,找百位为1的那么就是 0x100 在上面则可以找到对应的宏,它的注释是:

32 bit word machine. 代表了他是一个32位程序
那么看个位是F,那么就找F,但是需要注意,他因为是位运算,所以是 | 连接起来了,那么F 代表了
0x0001  | 0x0002 | 0x0004 | 0x0008  那么分别就对应前4个宏
那么最终想要表示的结果是
32 bit word machine.
Relocation info stripped from file.
File is executable  (i.e. no unresolved externel references)
Line nunbers stripped from file
Local symbols stripped from file.

翻译过来就是 这是一个32位程序,是一个可执行程序....
那么训练一下,我随便写一个
0x2102
那么 按照 个 十 百 千 位去寻找
先找千位   0x2000 // File is a DLL.                                 说明这是一个DLL文件
再找百位   0x100  // 32 bit word machine.                            说明是一个32位可执行程序
再找十位   十位为零,则没有.
再找个位   0x0002 // File is executable (i.e. no unresolved externel references).     说明是一个可执行程序
那么总结一下,说明了这个文件是一个 DLL文件,是一个32位程序,是一个可执行程序 总的来说很简单,主要是熟练运用,在不使用工具的前提下,明白各个位置代表的作用 作者:IBinary
出处:http://www.cnblogs.com/iBinary/
版权所有,欢迎保留原文链接进行转载:)

PE文件格式详解,第二讲,NT头文件格式,以及文件头格式的更多相关文章

  1. PE文件格式详解,第一讲,DOS头文件格式

    PE文件格式详解,第一讲,DOS头文件格式 今天讲解PE文件格式的DOS头文件格式 首先我们要理解,什么是文件格式,我们常说的EXE可执行程序,就是一个文件格式,那么我们要了解它里面到底存了什么内容 ...

  2. PE文件格式详解,第三讲,可选头文件格式,以及节表

    PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...

  3. 第二讲,NT头文件格式,以及文件头格式

    今天详解NT 头格式,以及文件头格式,以及作用, 关于DOS头文件格式,以及DOSStub昨天的博客已经写过了.主要是分散讲解.便于理解. 一丶最小PE的生成,以及标准PE的生成 ps: (如果直接学 ...

  4. Git应用详解第二讲:Git删除、修改、撤销操作

    前言 前情提要:Git应用详解第一讲:Git分区,配置与日志 在第一讲中我们对Git进行了简单的入门介绍,相信聪明的你已经了解Git的基本使用了. 这一讲我们来进一步深入学习Git应用,着重介绍Git ...

  5. Android学习之基础知识十三 — 四大组件之服务详解第二讲(完整版的下载示例)

    上一讲学习了很多关于服务的使用技巧,但是当在真正的项目里需要用到服务的时候,可能还会有一些棘手的问题让你不知所措.接下来就来综合运用一下,尝试实现一下在服务中经常会使用到的功能——下载. 在这一讲我们 ...

  6. PE文件结构详解(二)可执行文件头

    在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格 ...

  7. PE文件格式详解(七)

    PE文件格式详解(七)   Ox00 前言 前面好几篇在讲输入表,今天要讲的是输出表和地址的是地址重定位.有了前面的基础,其实对于怎么找输出表地址重定位的表已经非常熟悉了.   0x01 输出表结构 ...

  8. BMP文件格式详解

    BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广 ...

  9. OpenGL学习--05--纹理立方体--BMP文件格式详解(转载)

    http://blog.csdn.net/o_sun_o/article/details/8351037 BMP文件格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称 ...

随机推荐

  1. 富文本编辑器UEditor的配置使用方法

    将下载的富文本编辑器的文件解压后放到 webcontent 下 如果 文件中的jsp文件夹下的controller.java文件报错的话    就将jsp下的lib文件夹中的文件都复制到  web-i ...

  2. 第3阶段——内核启动分析之make uImage编译内核(3)

    目标: 通过分析makefile,明白make uImage如何编译内核 把整个内核的makefile分成三类(makefile资料文档在linux-2.6.22.6/Documentation/bu ...

  3. vue中数据双向绑定的实现原理

    vue中最常见的属v-model这个数据双向绑定了,很好奇它是如何实现的呢?尝试着用原生的JS去实现一下. 首先大致学习了解下Object.defineProperty()这个东东吧! * Objec ...

  4. Java中死锁的简单例子及其避免

    死锁:当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞.比如,线程1已经持有了A锁并想要获得B锁的同时,线程2持有B锁并尝试获取A锁,那么这两个线程将永远地等待下去. ...

  5. 【★】KMP算法完整教程

    KMP算法完整教程 全称:                               Knuth_Morris_Pratt Algorithm(KMP算法) 类型:                 ...

  6. JUnit之TestCase和TestSuite详解

    首先介绍下TestCase以及TestSuite.    TestCase:字面意思,测试用例.为一个或多个方法提供测试方法.一般是一个test    TestSuite:测试集合,即一组测试.一个t ...

  7. 团队作业10——项目复审与事后分析(Beta阶段)

    一.Beta阶段项目复审 http://www.cnblogs.com/womenshuodedoudui/p/7001208.html 二.事后诸葛分析 http://www.cnblogs.com ...

  8. JAVA课程设计 刘舒婷 201521123096

    1.团队课程设计博客链接 2.个人负责模块说明 2.1 界面菜单的设计: 2.2 录入学生信息: 2.3 对已录入的学生信息进行修改: 3.个人代码提交记录截图 4.自己负责模块或任务详细说明 4.1 ...

  9. 201521123068 《java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  10. maven profile切换正式环境和测试环境

    有时候,我们在开发和部署的时候,有很多配置文件数据是不一样的,比如连接mysql,连接redis,一些properties文件等等 每次部署或者开发都要改配置文件太麻烦了,这个时候,就需要用到mave ...