最近在学习分解PE文件,第一步便是熟悉pe文件的结构。在看到了罗云杉的win32汇编教程的第17章的PEInfo例子时,运行了一下,顺便根据提示做了一定的试验。结果发现了一定的问题。这些问题主要集中在对win32汇编中的.data段和.data?段上。
首先,按照书中(大概是第三章)的说法,.data?段在磁盘上不会预留空间,只有当PE文件被装载(注意是装载,而不是简单的内存映射)的时候,.data?段才会被填充为真正的占有内存的节。于是,我编写了一个非常简单的程序,如下:
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data?
number dd ?
.const
text db 'hello',0
.code
start:
invoke MessageBox, NULL, addr text, addr text, MB_OK
invoke ExitProcess, 0
end start
使用PEInfo程序(书中所带代码,基本上就是查看PE文件内容的程序)查看到如下信息
----------------------------------------------------------
节区名称 节区大小 虚拟地址 Raw_尺寸 Raw_偏移 节区属性
----------------------------------------------------------
.text 00000026 00001000 00000200 00000400 60000020
.rdata 0000009A 00002000 00000200 00000600 40000040
.data 00000004 00003000 00000000 00000000 C0000040
.rsrc 00000010 00004000 00000200 00000800 40000040
简单解释一下,“Raw_尺寸”表示该节在磁盘中以磁盘粒度调整后的所占大小,“节区大小”是没有经过对齐调整的,正真所占空间的大小。
很显然,.const段被解释位.rdata,.data?也被解释为.data(注意区别程序结果中的.data和程序中的.data其实所带意义不同,根据以后的试验可知,在PE文件中,被命名为.data的节实际上是源程序中的.data和.data?的统称), 而程序里由于没有.data,所以Raw_尺寸为0。
当我修改程序如下之后(只是简单的加了一个.data段),程序如下
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data?
number dd ?
.data
number2 dd 0
.const
text db 'hello',0
.code
start:
invoke MessageBox, NULL, addr text, addr text, MB_OK
invoke ExitProcess, 0
end start
再次查看,可以看到如下结果,
----------------------------------------------------------
节区名称 节区大小 虚拟地址 Raw_尺寸 Raw_偏移 节区属性
----------------------------------------------------------
.text 00000026 00001000 00000200 00000400 60000020
.rdata 0000009A 00002000 00000200 00000600 40000040
.data 00000008 00003000 00000200 00000800 C0000040
.rsrc 00000010 00004000 00000200 00000A00 40000040
再次修改程序,将number2的定义改成2*16*16个byte大小,即
.data
number2 db 2*16*16 dup(0)
得到结果
----------------------------------------------------------
节区名称 节区大小 虚拟地址 Raw_尺寸 Raw_偏移 节区属性
----------------------------------------------------------
.text 00000026 00001000 00000200 00000400 60000020
.rdata 0000009A 00002000 00000200 00000600 40000040
.data 00000204 00003000 00000200 00000800 C0000040
.rsrc 00000010 00004000 00000200 00000A00 40000040
如果在上次修改的那个程序里再在.data中再加一个number3 db 0 ,即
.data
number2 db 2*16*16 dup(0)
number3 db 0
----------------------------------------------------------
节区名称 节区大小 虚拟地址 Raw_尺寸 Raw_偏移 节区属性
----------------------------------------------------------
.text 00000026 00001000 00000200 00000400 60000020
.rdata 0000009A 00002000 00000200 00000600 40000040
.data 00000208 00003000 00000400 00000800 C0000040
.rsrc 00000010 00004000 00000200 00000C00 40000040
总结:
有上面的一系列的测试结果可知,
1. 在PE文件中,被命名为.data的节实际上是源程序中的.data和.data?的统称,只是.data?不占用磁盘,而.data却实实在在地占用了磁盘
2. 从"节区大小"这里可以看出来,源程序中在没有.data,但是有.data?的情况下,确实在磁盘上没有预留空间,但是在PE文件被装载进内存之后,就会被扩展出来
3. 磁盘的对齐粒度是200h,这其实是一笔不小的开销。远远高于内存的4h的对齐粒度。