php 解析pe版本号,PE格式解析

一、区段名及其含义

二、区段类别及分布

三、区段表解析

四、导入表解析

一、区段名及其含义

.text

默认的代码区块,它的内容全是指令代码,链接器把所有目标文件的text块连接成一个大的.text块,使用Borland C++,编译器产生的代码存放在CODE的区域里

.data

默认的读/写数据块,全局变量,静态变量一般放在这个区段

.rdata

默认只读数据区块,但程序中很少用到该块中的数据,一般两种情况用到,一是MS 的链接器产生EXE文件中用于存放调试目录,二是用于存放说明字符串,如果程序的DEF文件中指定了DESCRIPTION,字符串就会出现在rdata中

.idata

包含其他外来的DLL的函数及数据信息,即输入表,将.idata区块合并成另一个区块已成为一种惯例,典型的是.rdata区块,默认的,链接器只在创建一个Release模式的可执行文件时才能将idata合并到另外一个区块中

.edata

输出表,当创建一个输出API或数据的可执行文件时,连接器会创建一个.EXP文件,这个.EXP文件包含一个.edata区块,其会被加载到可执行文件中,经常被合并到.text或.rdata 区块中

.rsrc

资源,包括模块的全部资源,如图标,菜单,位图等,这个区块是只读的,无论如何不应该把它命名为.rsrc以外的名字,也不能合并到其他的区块里

.bss

未初始化的数据,很少在用,取而代之的是执行文件的.data区块的的VirtualSize被扩展大的空间里用来装未初始化的数据.

.crt

用于C++ 运行时(CRT)所添加的数据

.tls

TLS的意思是线程局部存储器,用于支持通过_declspec(thread)声明的线程局部存储变量的数据,这包括数据的初始化值,也包括运行时所需要的额外变量

.reloc

可执行文件的基址重定位,基址重定位一般仅Dll需要的

.sdata

相对于全局指针的可被定位的 短的读写数据

.pdata

异常表,包含CPU特定的IAMGE_RUNTIME_FUNTION_ENTRY结构数组,DataDirectory中的IMAGE_DIRECTORY_ENTRY_EXCEPTION指向它.

.didat

延迟装入输入数据,在非Release模式下可以找到

二、区段类别及分布

1、Stud_PE 加载的区段示例(图一)

157532352_1_20190328074206410

Name:区段的名称

VirtualSize:区段在内存中的大小

VirtualOffset:区段在内存中的相对虚拟地址RVA

RawSize:区段在文件中的大小

RawOffset:区段在文件中的偏移地址

Characteristics:特征值(下图中我们可以看到.text特征值600000020)

从区段表不难发现:.text段的RVA为1000,大小为4B48,也就是说.text区段在内存中的位置是从1000~5B48。其他区段也不难得出

2、通过区段图,得出程序加载到内存后的分布以及文件在硬盘的分布(图二)

157532352_2_20190328074206707

程序加载到内存之后,都会分配4GB的内存地址空间(注:并不是内存大小)

在区段与区段之间并不是紧挨着的,因为内存会进行0x1000的内存对齐(不懂的可以参见该篇文章:PE格式解析-NT头与地址换算),空出来的空间进行填充0字节的数据。例如5B4B~6000的空间都是填充的0字节数据

3、如何正确识别一个区段为代码段

注:代码段的真正识别并不是根据.text名来判断,后面我们会知道,将.text修改后是不会影响到我们程序的真正运行的

方法一:通过Image_Option_Header中代码块起始RVA(BaseOfCode)中的地址

方法二:通过区段的特征值标志(属性)MEM_EXECUTE(可执行)、MEM_READ(可读),判断这个是代码段

例如 .text 区段(通过右击区段行,选择Edit Header即可查看):

157532352_3_20190328074206847

注:并没有勾选MEN_WRITE标志,因为程序运行的一般情况下是不允许代码进行变化的。当然,我们也可以进行改变属性为可写,此时可称之为SMC(Self Modify Code 可变代码),程序在运行的时候,可能会对自身的代码进行修改,实现一些功能上的变化,比如产生偏移量的变化。当然如果实现自变形的功能,必须添加MEM_WRITE属性,否则会程序的崩溃。

三、区段表解析

1、Section Table(区段表) 中,每0x28个字节保存一个区段的信息

区段表示意图(另存图片浏览更清晰):

157532352_4_20190328074206925

如下:从黑色标识的开始的每0x28字节表示一个区段的信息

157532352_5_20190328074207144

内存中块大小(VirtualSize):0x4B48(大小端的转换)

内存中块RVA值(VirtualAddress):0x1000

文件中块大小(SizeOfRawSize):0x4C00

文件中块偏移(PointerToRawRelocations):0x400

块属性(Characteristics):0x60000020

格式中的块名(0x08字节):表示的一个字符串(区段的名称),可以修改!

例如(修改 .text 为 .zhangy):

157532352_6_20190328074207254

修改之后是依旧可以正常运行的,再用Stud_PE打开exe文件:

157532352_7_20190328074207332

不难发现,此时 .text 变成了 .zhangy,所以判断一个区段是不是代码段,不是根据名称来判断,而是根据区段的属性来判断的。

2、手动解析的时候如何判断一个区段表是否正确?区段表的数量

区段表的数量在上篇关于NT头中有两个字节(NumberOfSection 块数目)表示的就是区段的数量。在校验区段时,我们可以根据VA,RVA值以及文件偏移值换算的计算方式进行校验。

跳转到文件的0x400后,前面有一大片的0,这是因为要实现文件对齐而填充的0。同样,在区段与区段之间,你也会发现填充0的部分,这也是为了实现文件对齐。

四、导入表解析

1、本示例中的程序是没有输出表的(此文就只讲解输入表),往往在Dll文件(具有导出函数)中才有输出表。

157532352_8_20190328074207394

前四个字节表示输入输出表的RVA值,后四个字节表示输入输出表的大小

解析出输入表的八个字节

RVA:0x000091B8

大小:0x00000050

我们接下来提到的输入表,你可以理解为程序调用的一个Dll中的一些函数所形成的列表,PE文件分别为每一个所调用的Dll都添加了一个输入表。

相反的,输出表就是所需要导出的函数所形成的表。

注:输入表中可能是系统的kernel32.dll中的API,也可能是自己书写的Dll中的函数,所以输入表中不一定是API,接下来对输入表的形容我会尽量用函数来替代,而不是API

2、将输入表的RVA转换成文件的偏移地址0x91BB对应的区段为.idata(0x9000~0x9A7D)

列表内容

.idata对应的文件偏移位置为0x7200

输入表的文件偏移:0x91B8-0x9000+0x7200=0x73B8(以下就不写计算过程了)

157532352_9_20190328074207488

3、OS是如何解析输入表中的这些字节数据的呢?

一个输入表的平面结构示意图

157532352_10_20190328074207660

注:这里讲到的输入表

输入表中,每20个字节(一个Image_Import_Directory)对应一个动态链接库Dll的调用数据

例如:我们要调用kernel32里面的的10个API,此时这10个API的数据都会保存在这20个字节中。但是是怎么保存这10个API的呢?其实它根据一个数组的指针来保存的所要调用的API(下面会讲到)

4、了解了输入表的结构,现在来分析下输入表

第一个输入表示意图(红色部分 20字节):

157532352_11_20190328074207832

1)Dll名字符串的RVA值(Name):0x9452->对应的文件偏移:0x7652

此时我们就能在文件偏移0x7652的地方找到Dll的名字

157532352_12_20190328074207941

2)Import Thunk Data数组的RVA值(Original First Thunk):0x92A0->对应的文件偏移:74A0

157532352_13_2019032807420866

每四个字节代表了一个导入的函数,所以24个字节正好对应VCRUNTIME140D.Dll中的6个函数(24个字节后为四个字节的0,所以判断到此结束)

其实这四个字节也是一个RVA值,我们可以再看一下输入表的示意图

0x9420是上图的第一个函数RVA,0x93C0是上图的最后一个函数的RVA

157532352_14_20190328074208191

0x9420的文件偏移:0x7620

157532352_15_20190328074208410

此时就得到了我们调用VCRUNTIME140D.Dll中的第一个函数的名字__vcrt_GetModuleHandleW,和Stud_PE中解析的相同

0x93C0的文件偏移:0x75C0

157532352_16_20190328074208519

此时就得到了我们调用VCRUNTIME140D.Dll中的最后一个函数的名字__std_type_info_destroy_list,和Stud_PE中解析的相同

综上小结:PE文件里面,通过前四个字节一个多级的数组指针,指向一个数组HNT,OS通过HNT中保存的RVA值就能找到对应API的地址

3)IAT(Import address table):导入表函数地址表(保存API实际地址的数组),每四个字节表示一个函数的地址。当我们应用程序加载起来的时候,OS的PE文件加载器就会将我们所需要导入的动态链接库(Dll)的函数(不一定是API)在内存中的实际地址填写到IAT中。

我们来看下IAT的RVA:0x9098,对应的文件偏移:0x7298

157532352_17_20190328074208629

此时IAT中的这些数据并没有什么作用,主要是起到了占位的作用。因为我们要调用的函数(Dll中的函数)在内存中的实际地址是在程序运行的时候才进行填写到IAT的。也就是说,没有运行的时候,IAT这个数组中的数据并没有用,运行时OS才会把API在内存中真正的地址填写(说填写也不是很准确,应该说是修改了IAT中的数据)到IAT中,此时我们通过Import Thunk Data(数组RVA值)调用的API才是正在的API…就解释到这里吧,越说越绕

4)现在我们来验证下IAT的加载(OD加载我们的应用程序):

157532352_18_20190328074208785

(不知道大家忘没有,在0x002F9098中,前面的002F表示的是程序加载到内存的基址VA,后面的9098是相对于基址的偏移,也就是相对虚拟地址RVA)

可以看到,此时RVA0x9098位置处的值并不是文件偏移0x7298的值,这些值都是在程序运行的时候进行修改的,修改成了函数在内存中真正的地址。这6个地址,就是我们调用的VCRUNTIME140D.Dll中的6个函数的真正地址!

此时我们就可以跟进第一个函数(__vcrt_GetModuleHandleW)在内存中的地址0x72A69CE0,可以看到该函数的真正实现

157532352_19_20190328074208910

还有一个方法,通过OD右键->长型->地址来查看,效果图

157532352_20_20190328074209160

小结下IAT的作用:如果没有IAT,或者IAT中没有保存我们所需要调用的dll中的函数时,OS是无法进行相关函数调用的,可见IAT这个数据结构是很重要的。其实我们每重启操作系统的时候,API的地址都会发生变化,但是IAT的这种运行时加载真正函数地址的行为保证了地址变化也能正常运行。

因为IAT的重要,所以往往一些壳都会在对IAT进行一些修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值