本次的了解主要讲解 PE的基本概念、MS-DOS文件头、PE文件头、区块、输入表、输出表等。

这里我将会结合一个简单的小程序来加深我对PE文件结构的了解。

使用学习工具:有StudyPE、LordPE、PEID。

学习PE建议看书。。和自己动手。。。

PE文件:

  在WIN上,32位的可执行文件是PE文件,64位的是PE32+文件 ,DLL文件的格式和PE格式差不多,唯一的区别是PE和DLL的有一个字段标识这个文件是EXE还是DLL。

  

如上就是一个PE文件的结构图,PE文件使用的是一个平面地址空间,所有的数据都融合在一起,文件的内容又被分割为不同的区块(Section),

各个区块按页的边界来对齐。每个块都有自己的属性(是否可读,是否可写,是否可执行等等)。

基地址:

当PE文件被装载器装载了之后,内存中的板块被称为模块。映射文件的起始地址被称为模块句柄---内存中的模块代表这进程从这个可执行文件中所需要的代码、数据、资源、输入表、输出表及其他东西所使用的东西放在一个连续的内存块中。在装载中,PE文件的一个字段会告诉系统把文件映射到内存需要多少内存,不能被映射的数据被放置在文件的尾部。

在WIN32中,可以使用HMODULE GetModuleHandle(LPCTSTR lpModuleName)来获得一个模块的名称。当传递一个可执行文件或者DLL作为参数,

如果系统成功找到这个文件,就会返回该可执行文件或者DLL文件映像加载到的基地址。

在PE文件中,有一个字符设置了基地址,VC++建立的exe文件的基地址是0x00400000h,DLL文件的基地址是0x10000000h。

相对虚拟地址:

为了让程序的载入更加的灵活-也为了在PE文件中出现有确定的内存地址,出现了相对虚拟地址(Relative Vritual Address, RVA),当你的程序加载后,假设你的text块的RVA = 0x00001000h,映射到程序中时,VA(虚拟地址) = ImagineBase(基地址)+RVA(相对虚拟地址),你的代码区块在内存中就开始与0x00401000h。

文件偏移地址:

因为我们的文件是存储在磁盘上的,某个数据相对于文件头的偏移量就是这个数据的偏移地址,称为文件偏移地址(File Offset)或者物理地址(RAW Offset),偏移地址的起始值是0。

MS-DOS头部(IMAGE_DOS_HEADER):

每个PE文件是以一个DOS程序开始的,还有MZ header之后的DOS stub(DOS块)。如果这个可执行文件不能被这个系统支持,会打印一串提示符

"This program cannot be run is MS-DOS mode",DOS头部中主要是WORD e_magic和 LONG e_lfanew这个字段比较重要。这些数据结构可以在winnt.h中找到。

#define IMAGE_DOS_SIGNATURE 0x5A4D
#define IMAGE_OS2_SIGNATURE 0x454E
#define IMAGE_OS2_SIGNATURE_LE 0x454C
#define IMAGE_VXD_SIGNATURE 0x454C
#define IMAGE_NT_SIGNATURE 0x00004550 #include "pshpack2.h"
//这里就是IMAGE_DOS_HEADER的结构了。
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; // DOS可执行文件标记“MZ”
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip; //DOS代码入口IP
WORD e_cs; //DOS代码的入口CS
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[];
LONG e_lfanew; // 指向PE文件头, “PE”,0,0
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;

LONG e_lfanew是指向PE文件头的一个地址,它的文件偏移地址是0x3C--也就是60字节开始,然后占据了4个字节,指向PE文件头,具体看下图

我们可以看到0x000000F8在偏移60字节的地方,看到PE文件头在0x000000F8,具体可以自己找一个文件来测试(加深印象)

DOS文件头就到这里了,接下来继续介绍PE头,也就是IMAGE_NT_HEADER,下面的代码是对于定义32还是64的PE头,我们可以看到相应的宏语句

和对应的数据结构定义。

#ifdef _WIN64             //如果采用64的架构
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC
#else /* _WIN64 */ //如果不是采用64而是32位的架构
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC
#endif /* _WIN64 */ //上面的typedef都是改变结构体的名称 typedef struct _IMAGE_NT_HEADERS64 {//这里是64位的PE头的结构体的定义
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; typedef struct _IMAGE_NT_HEADERS {//这里是32位的PE头的结构体的定义
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;

在PE的文件头中,第一个DWORD Signature, 被定义为了0x00004550h,也就是"PE\0\0"这四个字符。这个标志没有什么作用。(DOS中指向的地方)。

主要是IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER这两个结构体中的几个字段重要。

我么接下来观看PE文件头中的IMAGE FILE_HEADER FileHeader这个结构体

typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //这里定义的是运行平台,i386= 0x014Ch这个值,还有其他平台,看书吧。。
WORD NumberOfSections;       //这个是标识区块的数目,紧跟在PE头的后面,也就是IMAGE_NT_HEADERS的后面
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;     //这里表明了IMAGE_NT_HEADERS中的大小(RAW SIZE),32位一般是0x00E0, 64位PE+一般是0x00F0
WORD Characteristics;       //普通的EXE是0x010fh, DLL文件是0x210Eh
} IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;

接下来我们看一下IMAGE_OPTIONAL_HEADER这个结构体,一样下面的是这个结构体在winnt.h中的定义,下面这个是32位的,还有64位的,但是差不多的,可以看winnt.htypedef struct _IMAGE_OPTIONAL_HEADER

typedef struct _IMAGE_OPTIONAL_HEADER {

      WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;           //这里定义了包含代码区块的大小
DWORD SizeOfInitializedData;    //这里定义了已经初始化的变量的区块的大小
DWORD SizeOfUninitializedData;   //这里是未初始化的变量的区块的大小
DWORD AddressOfEntryPoint;     //这里是程序入口的RVA(相对虚拟地址)
DWORD BaseOfCode;          //这里是程序代码块的起始RVA
DWORD BaseOfData;          //这里是数据块起始RVA
DWORD ImageBase;           //这里是程序默认装入的基地址(ImageBase)
DWORD SectionAlignment;       //内存中区块的对齐值,非常重要
DWORD FileAlignment;        //文件中区块的对齐值,非常重要
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;          //这里定义了文件的子系统,图形接口子系统,字符子系统,具体可以看具体的定义
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;   //这里定义了数据目录表的项数,一直保持为16
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //这个是数据目录表,指向输入、输出表、资源块等数据,很重要
} IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

这个IMAGE_OPTIONAL_HEADER只需要关注一些关键字段就行了,记住。。

接下来我么就看一看这个数据目录表,数据目录表简单点说就是一个长度为16的IMAGE_DATA_DIRECTORY结构体数组而已

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //数据块的其实RVA,很重要
DWORD Size;             //数据块的长度
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

这是一个16位的数组,最有一个数组元素作为保留,全部为0,其他的从开头一直到倒数第二个数据都是已经规定好了的,我们看一下这个数据目录表成员

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0              //Export Table
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1        //Import Table 输入表这里比较重要
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
#define IMAGE_DIRECTORY_ENTRY_TLS 9
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
#define IMAGE_DIRECTORY_ENTRY_IAT 12          //IAT (import address table), 这里也很重要
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14

还有也可以使用LordPE的PE editor来查看这个目录,现在的查看目录表的工具很多。。。。。

PE的第一阶段到这里,接下来会继续学习,增加熟悉度。。。。。。。。。。-----------好好学习,天天向上!

PE文件格式(加密与解密3)(一)的更多相关文章

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

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

  2. PE文件格式详解(六)

    0x00 前言 前面两篇讲到了输出表的内容以及涉及如何在hexWorkShop中找到输出表及输入DLL,感觉有几个地方还是没有理解好,比如由数据目录表DataDirectory[16]找到输出表表后以 ...

  3. PE文件格式偏移参考

    在进行PE文件格式病毒分析的时候,经常要使用到PE文件格式的解析,尤其是对LoadPE形式的病毒的分析,经常要查看PE文件格式的偏移,特地从博客<PE文件格式的偏移参考>中转载收录一份,之 ...

  4. 如何对web.config进行加密和解密

    http://blog.csdn.net/jf_jifei/article/details/6527390 在WEB网站开发过程中,如果我们将数据库连接字符串封装到.DLL文件中,将会给数据库和程序的 ...

  5. 关于《加密与解密》的读后感----对dump脱壳的一点思考

    偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能在大三的时候遇到ISCC, ...

  6. (译)利用ASP.NET加密和解密Web.config中连接字符串

    介绍 这篇文章我将介绍如何利用ASP.NET来加密和解密Web.config中连接字符串 背景描述 在以前的博客中,我写了许多关于介绍 Asp.net, Gridview, SQL Server, A ...

  7. 利用ASP.NET加密和解密Web.config中连接字符串

    摘自:博客园 介绍 这篇文章我将介绍如何利用ASP.NET来加密和解密Web.config中连接字符串 背景描述 在以前的博客中,我写了许多关于介绍 Asp.net, Gridview, SQL Se ...

  8. PE文件格式

    以下内容摘录自<加密与解密>: 为了在PE文件中避免有确定的内存地址,出现了相对虚拟地址(RVA)的概念.RVA只是内存中的一个简单的相对于PE文件装入地址的偏移位置.它是一个“相对”地址 ...

  9. Php AES加密、解密与Java互操作的问题

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

随机推荐

  1. Eclipse集成Tomcat:6个常见的”how to”问题

    学习一门新技术通常是一个很困难的过程,当你想要同时学习两门有交叉的新技术的时候,这个过程会变得更困难.Tomcat和Eclipse是Java EE开发中最流行的2个必备神器,因此,为了成为一个专业的开 ...

  2. 【jQuery】初始化的三种方法

    JQ初始化方法实际上有两种,由于美元符号可以定义 jQuery,那么就有三种方法可以进行初始化操作,根据个人习惯来选择吧! 第一种 $(document).ready(function(){ // j ...

  3. 集中日志服务器Rsyslog

    http://www.gaizaoren.org/archives/408 基于主机的管理一般需要收集服务器的日志信息用于及时发现错误,处理故障. 搭建linux下的集中日志服务器的程序一般可以用sy ...

  4. 【学习笔记】load-on-startup Servlet

    创建Servlet实例有两个时机:用户请求之时和应用启动之时.应用启动之时创建的通常用于某些后台服务的Servlet.配置load-on-startup的Servlet有两种方式: 在web.xml文 ...

  5. SQL Server数据库SP命令祥解

    1.数据库: (1)sp_helpdb:报告有关指定数据库或所有数据库的信息.例:sp_helpdb   --显示所有数据库信息(名称.大小等)例:sp_helpdb Recruitment   -- ...

  6. SQL Server 积累

    2016-11-24 sql语句修改某表某字段的数据类型和字段长度: 问题是在修改老功能中暴露出来的,我修改了图片上传功能,结果报图片路径超出数据库字段规定长度,我检查数据库后发现之前设计数据库的人将 ...

  7. php下载远程文件方法~

    直接上代码: getFile("http://easyread.ph.126.net/N8gDl6ayo5wLgKbgT21NZQ==/7917056565549478184.jpg&quo ...

  8. Eclipse导出插件工程

    一.Feature Projecties工程设置 1. 新建一个Feature Projecties 2. 选择我们的插件工程,finish 3. 在目录下新建一个Category definitio ...

  9. iOS SpriteKit 问题

    今天偶然发现 向SKShapeNode添加子 node时,子node参考的是 SKShapeNode的parent的坐标系,但是如果使用SKSpriteNode却是使用自己的坐标系,带研究.而且sha ...

  10. printf和scanf

    一 printf和scanf(printf和scanf是c语言中的输入输出库函数) printf(”格式控制“,输出列表) <1>格式控制 其中包含 格式声明(%+相应格式对应字母).转义 ...