首页
社区
课程
招聘
[原创]对PE文件头中的 NumberOfRvaAndSizes 字段分析
发表于: 2008-11-4 15:32 18519

[原创]对PE文件头中的 NumberOfRvaAndSizes 字段分析

2008-11-4 15:32
18519
【文章标题】:  对PE文件头中的NumberOfRvaAndSizes字段分析
【文章作者】: newjueqi  
【作者邮箱】: zengjiansheng1@126.com
【作者QQ号】:190678908(sdf )
【使用工具】:OD, WinHex,相关的dll文件和测试程序(见附件)
【操作平台】: xpSp2
【作者声明】: 本人水平有限,失误之处敬请诸位大侠赐教!

缘由:  

在本人发表的“手写DLL文件”(链接:http://bbs.pediy.com/showthread.php?t=75210)文章里,网友莽莽提出了如下的问题:

      DWORD   NumberOfRvaAndSizes;
(30)  NumberOfRvaAndSize:四个字节,数据目录表的数目。这个字段自从NT发布以来就是16。设置为 “00 00 00 10”, 在16进制编辑器里输入“10 00 00 00”。——可发现NumberOfRvaAndSizes不设置成16,程序也可以照样运行?在按照http://bbs.pediy.com/showthread.php?t=48590做EXE的时候,我就没把NumberOfRvaAndSizes设置成16,程序找跑不误。我发现在我做的这个EXE中,设置成0或者1都不行,大于等于2就行了,能解释一下为什么么?


       在《加密与解密3》里,对NumberOfRvaAndSize这个字段的解释是数据目录的项数,这个字段从最早的WinNt发布以来一直都是16.

        于是本人就对这个奇怪的问题进行分析,结果嘛,就是得到这份分析报告 ^-^

现象分析:

    对NumberOfRvaAndSizes的值进行试验,发现如果NumberOfRvaAndSizes的值大于5程序就能正常运行,否则的就出错。好,现在拿出调试利器OD,进行下面的三个试验。

     提示一下,如果我们能用OD直接调试这个DLL文件,就会淹没在一堆系统的API里,我们可以通过附件中的测试程序testdll.exe里的DLL函数调用来间接调试这个DLL文件,这样的好处是调试简单,直指问题的核心部分。
      
实验1:

      设置NumberOfRvaAndSizes的值为0,用OD跟踪到图1的代码后就有出错对话框

                                         图1
由图1中的红色框部分可知,GetProcAddress函数调用失败,不能调用DLL里的输出函数ShowMesBox,也就是输出表没有初始化。

实验2:

     设置NumberOfRvaAndSizes的值为1,用OD跟踪,今次没有出现实验1 的问题,可以进入到DLL的内部,

一直按F8来到图2所示的代码:


                                                图2
从图2可看到一个问题,所有的数据都没有重定位,也就是程序没有处理重定位信息。

     我们现在来看一下输入表的内容。由PE文件头区块信息可得,.text区块的RVA是1000h,idata区块的RVA是3000h,于是可以计算出输入表的内存地址为391000-1000+3000=393000h,在OD里查看393000h,

如下:

00393030  55 53 45 52 33 32 2E 64 6C 6C 00 00 00 00 00 00  USER32.dll......
00393040  50 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00  P0..............
00393050  00 00 4D 65 73 73 61 67 65 42 6F 78 41 00 00 00  ..MessageBoxA...
00393060 >50 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00  P0..............

      本来在00393060处存放的是IAT表,但我们可看到,现在的地址数值为50 30 00 00,这个数值是PE文件在磁盘里的数值,也就是说DLL的输入表没有初始化。

实验3:

      设置NumberOfRvaAndSizes的值为5,用OD跟踪,最后也来到实验2的图2所示的代码,所有的数据都没有重定位,也就是程序没有处理重定位信息。

      我们查看一下输入表的内容(输入表地址的计算方法在实验2里有讲述),在OD里查看393000h,如下:

00393030  55 53 45 52 33 32 2E 64 6C 6C 00 00 00 00 00 00  USER32.dll......
00393040  50 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00  P0..............
00393050  00 00 4D 65 73 73 61 67 65 42 6F 78 41 00 00 00  ..MessageBoxA...
00393060 >8A 05 D5 77 00 00 00 00 00 00 00 00 00 00 00 00  ?誻............

    由地址00393060h可看到,8A 05 D5 77就是MessageBoxA的系统地址,和实验2不同的是DLL的输入表已经初始化了。

推论:

     (1)观察实验1,NumberOfRvaAndSizes的值为0,而数据目录表里Export Table的序号为0,Import Table的序号为1, Base relocation Table(重定位表) 的序号为5,由实验1的结果可知,输出表没有初始化。
     (2)观察实验2,NumberOfRvaAndSizes的值为1,而数据目录表里Export Table的序号为0,Import Table的序号为1, Base relocation Table(重定位表) 的序号为5,由实验2的结果可知,Import Table,Base relocation Table(重定位表)都没有初始化。
     (3)观察实验3,NumberOfRvaAndSizes的值为5,而数据目录表里Export Table的序号为0,Import Table的序号为1, Base relocation Table(重定位表) 的序号为5,由实验3的结果可知, Base relocation Table(重定位表)都没有初始化。
     
      根据(1)(2)(3)可得出以下一个结论:

    NumberOfRvaAndSize的值是影响到应用程序是否能访问到相应的数据表。程序要访问到对应的表,不谨相应的数据表要设置值,而且NumberOfRvaAndSize的值必须大于对应表的序号。例如,程序要访问到重定位表(序号为5),NumberOfRvaAndSize的值必须大于5,程序要访问到输出表(序号为1),NumberOfRvaAndSize的值必须大于1。

       经过海风大牛的指点,对以上结论有更好的表达方法,引用如下:

   对于NumberOfRvaAndSize的值,
    0表示DATA_DIRECTORY一项也没有
    1表示DATA_DIRECTORY有1项(即:ExportTable)
    2表示DATA_DIRECTORY有2项(即:ExportTable和ImportTable)
    以此类推


     经过笨笨雄版主的指点,原来在PECOFF里早已说明了使用NumberOfRvaAndSizes的问题,幸好当时没看到,不然这份分析报告就不会诞生,对能力的培养也是一个损失
在PECOFF的3.4.3节里论述如下:
      注意目录的数目是不固定的。在查看一个特定的目录之前,先检查可选文件头中 的 NumberOfRvaAndSizes的值。


     所以,把NumberOfRvaAndSize这个字段的值设置为16就没有任何问题了。

    后记,发表这篇文章后,得到看雪众多高手指出其中的不足之处和以后的研究方向,本人不胜感激。这篇文章没有讨论到什么深奥的技术,重在阐述发现问题,解决问题的思路   

     最后借这个机会问各位大牛一个问题,是在手写DLL时发现的:
按照标准的PE结构编写,数据目录表中的输出表(108h),输入表(110h),重定位表(130h)的正常数值

如下:

00000100                            00 40 00 00 00 00 00 00           .@......
00000110   00 30 00 00 00 00 00 00  00 00 00 00 00 00 00 00   .0..............
00000120   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00000130   00 50 00 00 10 00 00 00  00 00 00 00 00 00 00 00   .P..............

这样设置没问题,调用这个DLL的输出函数可以正常运行,如下图
                           

但如果把数据目录表中的重定位表的Size字段值改变,无论是变大或者变小,都会出错,其中一个例子如下:
00000130   00 50 00 00 0F 00 00 00  00 00 00 00 00 00 00 00   .P..............

       调用这个DLL的输出函数时就会弹出下面的对话框:
      

       所以本人就觉得很奇怪,为什么改变数据目录表中的输出表和输入表的Size字段值没问题,而改变数据目录表中的重定位表的Size字段值就会问题?
     网友mavermaver的答复如下:DLL装载API函数的地址必须按重定位信息来确定,所以重定位信息不能改.
       但做完实验3后我就不同意这个答复,由实验3的观察可知,就算没有载入重定位信息DLL文件也能加载API函
数。
      请知道原因的大侠指点一个小弟,不胜感激

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (30)
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
2
输出表的SIZE某些情况是会用到的
如果你也研究NumberOfRvaAndSize大到一定程度会发生什么事,你会发现ANTI OD的一些技巧
2008-11-4 16:00
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
3
真的忘记研究NumberOfRvaAndSize大于16的情况,谢谢笨笨雄大大的指点 ,有时间再研究一下NumberOfRvaAndSize大于16的情况,等研究成果出来再补上。
2008-11-4 16:19
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
4
PE....
00 50 00 00 relocSize

假设
.reloc
5000: xxxxsizexxxx....
5010: xxxxsizexxxx....
5020: xxxxsizexxxx....
5030: 000000000000....

i:= relocSize;
p:= 5000;
while (i != 0)
  {
   重定位(p+8, [p+4]);
   p += [p+4];
   i -= [p+4];            //i-=size;
  }

这个while就是你要的答案
2008-11-4 17:14
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
5
"输出表的SIZE某些情况是会用到的" 输出表?应该是重定位表吧
2008-11-4 17:22
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
6
说不得~~~~~~~
2008-11-4 18:42
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
7
2008-11-4 19:05
0
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
8
发个demo我学习一下
看看我的插件能不能过
2008-11-4 19:36
0
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
9
DWORD NumberOfRvaAndSizes;
(30) NumberOfRvaAndSize:四个字节,数据目录表的数目。这个字段自从NT发布以来就是16。设置为 “00 00 00 10”, 在16进制编辑器里输入“10 00 00 00”。——可发现NumberOfRvaAndSizes不设置成16,程序也可以照样运行?在按照http://bbs.pediy.com/showthread.php?t=48590做EXE的时候,我就没把 NumberOfRvaAndSizes设置成16,程序找跑不误。我发现在我做的这个EXE中,设置成0或者1都不行,大于等于2就行了,能解释一下为什么么?


0表示DATA_DIRECTORY一项也没有
1表示DATA_DIRECTORY有1项(即:ExportTable)
2表示DATA_DIRECTORY有2项(即:ExportTable和ImportTable)
以此类推


真的忘记研究NumberOfRvaAndSize大于16的情况,谢谢笨笨雄大大的指点 ,再研究一下NumberOfRvaAndSize大于16的情况,等研究成果出来再补上。


大于16对系统没影响,就相当于DATA_DIRECTORY有16项(32位系统)
2008-11-4 19:44
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
10
海风大牛的语言表达能力很强,是偶的学习榜样 ^-^
另外问一句, 网友推荐海风大牛的插件StrongOD在插件区找不到,大牛把它藏在哪里?
2008-11-4 19:54
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
11
只是提出来让楼主不止步于此,充分发挥想象力
没有别的特别意思~~~
2008-11-4 20:03
0
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
12
2008-11-4 20:06
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
13
[QUOTE=海风月影;530511]http://www.unpack.cn/viewthread.php?tid=28854[/QUOTE]

海风大牛,需要Cash 11 UB ,有没有0.01折的优惠,如果有的话俺就努力去赚UB,谁叫现在嵌入了经济危机
2008-11-4 20:16
0
雪    币: 563
活跃值: (95)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
StrongOD插件 上传到这里了  http://bbs.pediy.com/showthread.php?p=530537#post530537
2008-11-4 21:17
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
你太神秘了吧?
2008-11-4 21:25
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
16
我肯定没误导,麻烦不懂别乱说,谢谢
2008-11-4 21:56
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
17
谢谢。在unpack用了灌水这个强大的武器,终于凑够UB,把这个插件下载下来
2008-11-4 22:01
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
18
    谢谢笨笨雄版主对我们这些初学者的指点,而且多发挥想象,多动手,多问对自己的技术成长是非常有用,只要自己真的动手做了,就算没有得出实际的研究成果,也会有一样宝贵的收获,那就是经验,而且不得不说的是,由于本人今晚在写一份文档,还没开始研究NumberOfRvaAndSizes的值大于16的情况,也没什么损失
2008-11-4 22:11
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
19
PECOFF,看完下面这一节

6.3.2 导出地址表

自然就知道导出表的SIZE有什么用了

至于NumberOfRvaAndSizes,既然海风的插件早PATCH了个好地方,OD不会受影响.

我也不怕说了, NumberOfRvaAndSizes改得过大,OD会认为是坏PE, 不会在EP下断点,这样你打开文件的时候停在系统断点.

15楼的同学,如果我面对前辈的谦虚让你误会我误导了后辈,我只能道歉

不过我建议你说话还是别这么随意

http://bbs.pediy.com/showthread.php?t=75702
尤其跟MJ这么说话,很容易引起争吵
2008-11-4 22:17
0
雪    币: 479
活跃值: (25)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
20
gzgzlxg大牛的《可执行文件头的变形技术》一书中有,5.1输入表的桥结构有一些楼主可能用到

// 单、单桥结构的输入表
2  <= NumberOfRvaAndSize <=16

// 双、双桥结构的输入表
13 <= NumberOfRvaAndSize <=16
2008-11-4 22:41
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
21
     感谢笨笨雄大大的指点

     原来PECOFF里早已说明了使用NumberOfRvaAndSizes的问题, 幸好当时没看到,不然这份分析报告就不会诞生,对能力的培养也是一个损失

在PECOFF的3.4.3节里论述如下:
     注意目录的数目是不固定的。在查看一个特定的目录之前,先检查可选文件头中 的 NumberOfRvaAndSizes的值。

      对于输出表的Size值问题也在PECOFF的6.3.2节里找到答案:对于Forwarder RVA(指向导出节中一个以NULL结尾的ASCII 码字符串的指针),这个字符串必须位于Export Table(导出表)数据目录项给出的范围之内,这说明会用到Size值。
2008-11-5 10:54
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
22
阿拉FTP无法打开,下载不了《可执行文件头的变形技术》这本书, dttom大侠能否发一份到邮箱190678908@qq.com
2008-11-5 11:33
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
你太神秘了吧?
2008-11-5 17:09
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
http://bbs.pediy.com/showthread.php?t=53565&highlight=RVA+%E6%84%8F%E6%80%9D,可以参看这个帖子。没全看懂,不过好像说这个值特殊情况下为0也可以,我试了一下,为 0xFFFFFFFF也照跑不误,无论是直接运行,还是用OD载入,跟设置成 0x10 一样,也没用 海风的插件。
主要是看了楼上有人说 "大于16对系统没影响,就相当于DATA_DIRECTORY有16项(32位系统),所以有感而发,不过我现在已经删掉了,呵呵。
http://bbs.pediy.com/showthread.php?t=75702,这个打不开
2008-11-5 18:27
0
雪    币: 222
活跃值: (27)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
25
支持啊,收藏了
2008-11-5 18:32
0
游客
登录 | 注册 方可回帖
返回
//