PE文件格式分析及修改Word下载.docx

上传人:b****8 文档编号:22265318 上传时间:2023-02-03 格式:DOCX 页数:20 大小:522.72KB
下载 相关 举报
PE文件格式分析及修改Word下载.docx_第1页
第1页 / 共20页
PE文件格式分析及修改Word下载.docx_第2页
第2页 / 共20页
PE文件格式分析及修改Word下载.docx_第3页
第3页 / 共20页
PE文件格式分析及修改Word下载.docx_第4页
第4页 / 共20页
PE文件格式分析及修改Word下载.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

PE文件格式分析及修改Word下载.docx

《PE文件格式分析及修改Word下载.docx》由会员分享,可在线阅读,更多相关《PE文件格式分析及修改Word下载.docx(20页珍藏版)》请在冰豆网上搜索。

PE文件格式分析及修改Word下载.docx

在SectionTable后,Section数目的多少是不定的。

二、程序的装入

当我们在explorer.exe(资源管理器)中双击某文件,执行一个可执行程序,系统会根据文件扩展名启动一个程序装载器,称之为Loader。

Loader会首先检查DOSMZHeader,如果存在,就继续寻找PEheader,如果这两项都不存在,就认为是DOS16位代码,如果只存在DOSMZHeader,而其中又指示了而其中又指示了PEHeader的位置,那么Loader就判定此文件不一个有效的PE文件,拒绝执行。

如果DOSHeader和PEHeader都正常有效,那么Loader就会根据PEHeader及SectionTable的指示,将相应的代码和数据映射到内存中,然后根据不同的Section进行数据的初始化,最后开始执行程序段代码。

三、PE格式高级分析

下面我们以一个真实的程序为例详细分析PE格式,分析PE格式最好有PE分析器,常用的软件是LordPE,也有其它的分析工具和软件如PEEditor、StudPE等。

先分析一下磁盘文件的内容,这里我们使用UltraEdit32(UE)工具,这是一个实用的文件编辑器,可以编辑文本和二进制文件。

图4PE文件开始的磁盘数据

在文件的一开始有两位16进制数据4D5A,其对应的ASCII字符是MZ,这个标志就是DOSMZHeader的标志。

下面是通过LoadPE列出的DOSMZHeader

1.DOSHeader

数据结构名称

e_magic:

0x5A4D->

‘MZ’

e_cblp:

0x0090

e_cp:

0x0003

e_crlc:

0x0000

e_cparhdr:

0x0004

e_minalloc:

e_maxalloc:

0xFFFF

e_ss:

e_sp:

0x00B8

e_csum:

e_ip:

e_cs:

e_lfarlc:

0x0040

e_ovno:

e_res:

0x0000000000000000

e_oemid:

e_oeminfo:

e_res2:

0x0000000000000000000000000000000000000000

e_lfanew:

0x000000F8

这是一个PE文件的DOSHeader,其中我们最关心的就是e_lfanew这个字段的值,它指向了PEHeader在磁盘文件中相对于文件开始的偏移地址,这里是F8。

在本文件00F8h处果然找到了“PE”两个字符,那么在00F8h处就是PEHeader的有效头载荷。

2.PEHeader

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

typedefstruct_IMAGE_NT_HEADERS

{

DWORDSignature;

//PE文件头标志:

PE\0\0。

在开始DOSheader的偏移3CH(e_lfanew)处所指向的地址开始

IMAGE_FILE_HEADERFileHeader;

//PE文件物理分布的信息

IMAGE_OPTIONAL_HEADER32OptionalHeader;

//PE文件逻辑分布的信息

}IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;

2.1IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER

typedefstruct_IMAGE_FILE_HEADER

WORDMachine;

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

WORDNumberOfSections;

//文件的节数目

DWORDTimeDateStamp;

//文件创建日期和时间

DWORDPointerToSymbolTable;

//用于调试

DWORDNumberOfSymbols;

//符号表中符号个数

WORDSizeOfOptionalHeader;

//OptionalHeader结构大小

WORDCharacteristics;

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

}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;

重要的Characteristics值

#defineIMAGE_FILE_RELOCS_STRIPPED0001h//文件中是否存在重定位信息

#defineIMAGE_FILE_EXECUTABLE_IMAGE0002h//文件是可执行的

#defineIMAGE_FILE_LARGE_ADDRESS_AWARE0020h//程序可以触及大于2G的地址

#defineIMAGE_FILE_BYTES_REVERSED_LO0080h//保留的机器类型低位

#defineIMAGE_FILE_32BIT_MACHINE0100h//32位机器

#defineIMAGE_FILE_REMOVABLE_RUN_FROM_SWAP0400h//不可在可移动介质上运行

#defineIMAGE_FILE_NET_RUN_FROM_SWAP0800h//不可在网络上运行

#defineIMAGE_FILE_SYSTEM1000h//系统文件

#defineIMAGE_FILE_DLL2000h//文件是一个DLL

#defineIMAGE_FILE_UP_SYSTEM_ONLY4000h//只能在单处理器计算机上运行

#defineIMAGE_FILE_BYTES_REVERSED_HI8000h//保留的机器类型高位

typedefstruct_IMAGE_OPTIONAL_HEADER

WORDMagic;

//标志字(总是010bh)

BYTEMajorLinkerVersion;

//连接器高版本号

BYTEMinorLinkerVersion;

//连接器低版本号

DWORDSizeOfCode;

//代码段大小

DWORDSizeOfInitializedData;

//已初始化数据块大小

DWORDSizeOfUninitializedData;

//未初始化数据块大小

DWORDAddressOfEntryPoint;

//PE装载器准备运行的PE文件的第一个指令的RVA,若要改变整个执行的流程,

可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。

DWORDBaseOfCode;

//代码段起始RVA

DWORDBaseOfData;

//数据段起始RVA

DWORDImageBase;

//PE文件的装载地址

DWORDSectionAlignment;

//块对齐因子

DWORDFileAlignment;

//文件块对齐因子

WORDMajorOperatingSystemVersion;

//所需操作系统高位版本号

WORDMinorOperatingSystemVersion;

//所需操作系统低位版本号

WORDMajorImageVersion;

//用户自定义高位版本号

WORDMinorImageVersion;

//用户自定义低位版本号

WORDMajorSubsystemVersion;

//win32子系统版本。

若PE文件是专门为Win32设计的

WORDMinorSubsystemVersion;

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

DWORDWin32VersionValue;

//保留值,系统没用到的,一般被作为是否感染的标志

DWORDSizeOfImage;

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

DWORDSizeOfHeaders;

//所有头+节表的大小

DWORDCheckSum;

//校验和

WORDSubsystem;

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

WORDDllCharacteristics;

//用来表示一个DLL映像是否为进程和线程的初始化及终止包含入口点的标记

DWORDSizeOfStackReserve;

//

DWORDSizeOfStackCommit;

DWORDSizeOfHeapReserve;

DWORDSizeOfHeapCommit;

//堆栈大小这些域控制要保留的地址空间数量,并且负责栈和默认堆的申请。

在默认情况下,

栈和堆都拥有1个页面的申请值以及16个页面的保留值

DWORDLoaderFlags;

//告知装载器是否在装载时中止和调试,或者默认地正常运行

DWORDNumberOfRvaAndSizes;

//该字段标识了接下来的DataDirectory数组个数。

IMAGE_DATA_DIRECTORYDataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

//IMAGE_DATA_DIRECTORY结构数组。

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

}IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

2.2IMAGE_DATA_DIRECTORY

typedefstruct_IMAGE_DATA_DIRECTORY

DWORDVirtualAddress;

//表的RVA地址

DWORDSize;

//大小

}IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

图5LoadPE读取的PEHeader的重要部分数据

图6Subsystem类型

图7LoadPe读取的IMAGE_DATA_DIRECTORY信息

在IMAGE_OPTIONAL_HEADER32后部一般是16项IMAGE_DATA_DIRECTORY数据,其中最后一项是保留数据。

每一项数据都有其固定的含义,并且位置不可改变。

ExportTable 

导出函数表,主要用于DLL中的导出函数

ImportTable 

导入函数表,使用外部函数的数据表

Resource 

资源数据表

Exception 

异常处理表

Security 

安全处理数据表

Relocation 

重定位信息表,一般和DLL相关

Debug 

调试信息表

Copyright 

版权信息表

Globalptr 

机器值(MIPSGP)

Tls 

Table 

线程信息表

LoadConfig 

装配信息表

BoundImport 

输入函数绑定信息表

IAT 

也ImportTable对应,由Loader填写的输入函数地址

DelayImport 

延迟装入的函数信息

COM 

公用组件信息表

Reserved 

保留信息,系统没有使用,为以后扩展使用

这16项数据,其所在位置由RVA指定,大小由Size指定。

对于一般的一个可执行程序(.exe),

最重要的是导入表(ImportTable和IAT)、资源数据表(Resoruce)。

2.3IMAGE_SECTION_HEADER

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

typedefstruct_IMAGE_SECTION_HEADER{

BYTEName[IMAGE_SIZEOF_SHORT_NAME];

//节表名称,如“.text”

//IMAGE_SIZEOF_SHORT_NAME=8

union{

DWORDPhysicalAddress;

//物理地址

DWORDVirtualSize;

//真实长度,这两个值是一个联合结构,可以使用其中的任何一个,

//一般是节的数据大小

}Misc;

//RVA

DWORDSizeOfRawData;

//物理长度

DWORDPointerToRawData;

//节基于文件的偏移量

DWORDPointerToRelocations;

//重定位的偏移

DWORDPointerToLinenumbers;

//行号表的偏移

WORDNumberOfRelocations;

//重定位项数目

WORDNumberOfLinenumbers;

//行号表的数目

DWORDCharacteristics;

//节属性如可读,可写,可执行等

}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;

图8LoadPE读取的IMAGE_SECTION_HEADER信息

Name:

节名称 

VOffset:

相对于ImageBase的虚拟偏移

VSize:

实际大小

ROffset:

相对于文件起始处的偏移

RSize所占的文件空间大小

Flags:

节属性

图9LoadPE读取的.text节的属性

重要的节属性定义:

#defineIMAGE_SCN_CNT_CODE00000020h//节中包含代码

#defineIMAGE_SCN_CNT_INITIALIZED_DATA00000040h//节中包含已初始化数据

#defineIMAGE_SCN_CNT_UNINITIALIZED_DATA00000080h//节中包含未初始化数据

#defineIMAGE_SCN_MEM_DISCARDABLE02000000h//是一个可丢弃的节,即节中的数据在进程开始后将被丢弃

#defineIMAGE_SCN_MEM_NOT_CACHED04000000h//节中数据不经过缓存

#defineIMAGE_SCN_MEM_NOT_PAGED08000000h//节中数据不被交换出内存

#defineIMAGE_SCN_MEM_SHARED10000000h//节中数据可共享

#defineIMAGE_SCN_MEM_EXECUTE20000000h//可执行节

#defineIMAGE_SCN_MEM_READ40000000h//可读节

#defineIMAGE_SCN_MEM_WRITE80000000h//可写节

[注]

RVA:

虚拟偏移地址。

RAV是指的某一处由Loader装入内存后,这一处应该在虚拟内存的什么地方,RAV也称为虚拟偏移地址。

Alignment:

对齐因子。

与对齐因子相关的值有2个地方,一处是文件对齐因子,另一处是内存对齐因子。

对齐因子指示出某一类型的对齐方式,以文件对齐为例,如果Alignment为200h,说明文件中的内容是以200h为单位的,如果数据大小正好是200h的整数倍,则不存在对齐问题,如果数据大小是非200h的整数倍,则要使用Alignment对数据所占的空间进行修正,取其上限数值(如310h->

400h),使其所占的空间是200h的整数倍。

2.3ImprotTable和IAT

IMAGE_DATA_DIRECTORY的第2项和第13项,指示导入表和导入函数地址表的位置。

这部分对于一个PE文件相当重要,很多系统函数都是由此导入。

ImportTable的VirtualAddress指向了一个RVA,他是一个导入表结构数组,数组以全0作为结束标记,该结构定义如下:

typedefstruct_IMAGE_IMPORT_DESCRIPTOR{

DWORDOriginalFirstThunk;

//指向一个IMAGE_THUNK_DATA结构数组的RVA

}

//文件生成的时间

DWORDForwarderChain;

//这个数据一般为0,可以不关心

DWORDName1;

//RVA,指向DLL名字的指针,ASCII字符串

DWORDFirstThunk;

//指向一个IMAGE_THUNK_DATA结构数组的RVA,这个数据与IAT所指向的地址一致

}IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR

IMAGE_THUNK_DATA这是一个DWORD类型的集合。

通常我们将其解释为指向一个IMAGE_IMPORT_BY_NAME结构的指针,其定义如下:

IMAGE_THUNK_DATA{

PBYTEForwarderString;

PDWORDFunction;

DWORDOrdinal;

//判定当前结构数据是不是以序号为输出的,如果是的话该值为0x800000000,此时PIMAGE_IMPORT_BY_NAME不可做为名称使用

PIMAGE_IMPORT_BY_NAMEAddressOfData;

}u1;

}IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;

typedefstruct_IMAGE_IMPORT_BY_NAME{

WORDHint;

//函数输出序号

BYTEName1[1];

//输出函数名称

}IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME

3.IMP和IAT的关系

静态分析时,OriginalFirstThunk与FirstThunk指向的数据是同一组IMAGE_IMPROT_BY_NAME。

OriginalFirstThunk

IMAGE_IMPORT_BY_NAME

FirstThunk

IMAGE_THUNK_DATA

...

--->

Function1

Function2

Function3

Function4

Functionn

<

---

IMAGE_THUNK_DATA

Loader在装入一个可执行的代码时,会分析该文件的导入表(IMP),然后通过导入表的指引,修改IAT指向的数据,这们在装载完成后,数据会变成如下形式

 

AddressofFunction1

AddressofFunction2

AddressofFunction3

AddressofFunction4

AddressofFunctionn

可以看出,OriginalFirstThunk与FirstThunk所指向的数据分离。

FirstThunk指向的不再是IMAGE_IMPORT_BY_NAME,而是指向了函数的真实地址。

代码段对于一个外部函数的引用始终使用的是FirstThunk处的RVA。

当程序真正执行时,就可以跳到真正的函数入口了

四、修改PE文件

PE文件是由源代码经由编译器编译、链接后形成的可执行文件,由系统加载执行。

通过对PE文件的分析,给理论上修改PE文件提供了可能。

下面我们分几个步骤修改PE文件。

这些步骤不是修改PE的必须步骤,但从中我们可以讨论如何修改PE文件。

1.给PE文件增加一个新节

PE文件节的信息保存在文件头的最后部分,如果预留磁盘空间足够大(大于或等于了个节的结构数据大小)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1