分享
 
 
 

关于PE可执行文件的修改

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

在windows 9x、NT、2000下,所有的可执行文件都是基于Microsoft设计的一种新的文件格式Portable Executable File Format(可移植的执行体),即PE格式。有一些时候,我们需要对这些可执行文件进行修改,下面文字试图详细的描述PE文件的格式及对PE格式文件的修改。

1、PE文件框架构成

DOS MZ header

DOS stub

PE header

Section table

Section 1

Section 2

Section ...

Section n

上表是PE文件结构的总体层次分布。所有 PE文件(甚至32位的 DLLs) 必须以一个简单的 DOS MZ header 开始,在偏移0处有DOS下可执行文件的“MZ标志”,有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随 MZ header 之后的 DOS stub。DOS stub实际上是个有效的EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串 " This program cannot run in DOS mode " 或者程序员可根据自己的意图实现完整的 DOS代码。通常DOS stub由汇编器/编译器自动生成,对我们的用处不是很大,它简单调用中断21h服务9来显示字符串"This program cannot run in DOS mode"。

紧接着 DOS stub 的是 PE header。 PE header 是PE相关结构 IMAGE_NT_HEADERS 的简称,其中包含了许多PE装载器用到的重要域。可执行文件在支持PE文件结构的操作系统中执行时,PE装载器将从 DOS MZ header的偏移3CH处找到 PE header 的起始偏移量。因而跳过了 DOS stub 直接定位到真正的文件头 PE header。

PE文件的真正内容划分成块,称之为sections(节)。每节是一块拥有共同属性的数据,比如“.text”节等,那么,每一节的内容都是什么呢?实际上PE格式的文件把具有相同属性的内容放入同一个节中,而不必关心类似“.text”、“.data”的命名,其命名只是为了便于识别,所有,我们如果对PE格式的文件进行修改,理论上讲可以写入任何一个节内,并调整此节的属性就可以了。

PE header 接下来的数组结构 section table(节表)。 每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。如果PE文件里有5个节,那么此结构数组内就有5个成员。

以上就是PE文件格式的物理分布,下面将总结一下装载一PE文件的主要步骤:

1、 PE文件被执行,PE装载器检查 DOS MZ header 里的 PE header 偏移量。如果找到,则跳转到 PE header。

2、PE装载器检查 PE header 的有效性。如果有效,就跳转到PE header的尾部。

3、紧跟 PE header 的是节表。PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时付上节表里指定的节属性。

4、PE文件映射入内存后,PE装载器将处理PE文件中类似 import table(引入表)逻辑部分。

上述步骤是一些前辈分析的结果简述。

2、PE文件头概述

我们可以在winnt.h这个文件中找到关于PE文件头的定义:

typedef struct _IMAGE_NT_HEADERS {

DWORD Signature;

//PE文件头标志 :“PE\0\0”。在开始DOS header的偏移3CH处所指向的地址开始

IMAGE_FILE_HEADER FileHeader; //PE文件物理分布的信息

IMAGE_OPTIONAL_HEADER32 OptionalHeader; //PE文件逻辑分布的信息

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_FILE_HEADER {

WORD Machine; //该文件运行所需要的CPU,对于Intel平台是14Ch

WORD NumberOfSections; //文件的节数目

DWORD TimeDateStamp; //文件创建日期和时间

DWORD PointerToSymbolTable; //用于调试

DWORD NumberOfSymbols; //符号表中符号个数

WORD SizeOfOptionalHeader; //OptionalHeader 结构大小

WORD Characteristics; //文件信息标记,区分文件是exe还是dll

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_OPTIONAL_HEADER {

WORD Magic; //标志字(总是010bh)

BYTE MajorLinkerVersion; //连接器版本号

BYTE MinorLinkerVersion; //

DWORD SizeOfCode; //代码段大小

DWORD SizeOfInitializedData; //已初始化数据块大小

DWORD SizeOfUninitializedData; //未初始化数据块大小

DWORD AddressOfEntryPoint; //PE装载器准备运行的PE文件的第一个指令的RVA,若要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。(许多文章都有介绍RVA,请去了解)

DWORD BaseOfCode; //代码段起始RVA

DWORD BaseOfData; //数据段起始RVA

DWORD ImageBase; //PE文件的装载地址

DWORD SectionAlignment; //块对齐

DWORD FileAlignment; //文件块对齐

WORD MajorOperatingSystemVersion;//所需操作系统版本号

WORD MinorOperatingSystemVersion;//

WORD MajorImageVersion; //用户自定义版本号

WORD MinorImageVersion; //

WORD MajorSubsystemVersion; //win32子系统版本。若PE文件是专门为Win32设计的

WORD MinorSubsystemVersion; //该子系统版本必定是4.0否则对话框不会有3维立体感

DWORD Win32VersionValue; //保留

DWORD SizeOfImage; //内存中整个PE映像体的尺寸

DWORD SizeOfHeaders; //所有头+节表的大小

DWORD CheckSum; //校验和

WORD Subsystem; //NT用来识别PE文件属于哪个子系统

WORD DllCharacteristics; //

DWORD SizeOfStackReserve; //

DWORD SizeOfStackCommit; //

DWORD SizeOfHeapReserve; //

DWORD SizeOfHeapCommit; //

DWORD LoaderFlags; //

DWORD NumberOfRvaAndSizes; //

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

//IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等

} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_DATA_DIRECTORY {

DWORD VirtualAddress; //表的RVA地址

DWORD Size; //大小

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

PE文件头后是节表,在winnt.h下如下定义

typedef struct _IMAGE_SECTION_HEADER {

BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名称,如“.text”

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;

以上结构就是在winnt.h中关于PE文件头的定义,如何我们用C/C++来进行PE可执行文件操作,就要用到上面的所有结构,它详细的描述了PE文件头的结构。

3、修改PE可执行文件

现在让我们把一段代码写入任何一个PE格式的可执行文件,代码如下:

-- test.asm --

.386p

.model flat, stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib

.code

start:

INVOKE MessageBoxA,0,0,0,MB_ICONINFORMATION or MB_OK

ret

end start

以上代码只显示一个MessageBox框,编译后得到二进制代码如下:

unsigned char writeline[18]={

0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0

};

好,现在让我们看看该把这些代码写到那。现在用Tdump.exe显示一个PE格式得可执行文件信息,可以发现如下描述:

Object table:

# Name VirtSize RVA PhysSize Phys off Flags

-- -------- -------- -------- -------- -------- --------

01 .text 0000CCC0 00001000 0000CE00 00000600 60000020 [CER]

02 .data 00004628 0000E000 00002C00 0000D400 C0000040 [IRW]

03 .rsrc 000003C8 00013000 00000400 00010000 40000040 [IR]

Key to section flags:

C - contains code

E - executable

I - contains initialized data

R - readable

W - writeable

上面描述此文件中存在3个段及每个段得信息,实际上我们的代码可以写入任何一个段,这里我选择“.text”段。

用如下代码得到一个PE格式可执行文件的头信息:

//writePE.cpp

#include <windows.h

#include <stdio.h

#include <io.h

#include <fcntl.h

#include <time.h

#include <SYS\STAT.H

unsigned char writeline[18]={

0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0

};

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有