WIN32汇编语言教程:第17章 PE文件 · 17.4 资源(2)

如果要得到 ANSI 类型的以 0 结尾的字符串,需要将 NameString 字段中包括的 UNICODE 字符串用 WideCharToMultiByte 函数转换一下,具体的方法读者可以参考后面的例子。

● OffsetToData 字段

这个字段是一个指针,当它的最高位(位13)为 1 时,低位数据指向下一层目录块的起始地址,也就是一个 IMAGE_RESOURCE_DIRECTORY 结构,这种情况一般出现在第 1 层和第 2 层目录中;当字段的位 31 为 0 时,指针指向的是用来描述资源数据块情况的 IMAGE_RESOURCE_DATA_ENTRY 指针,这种情况出现在第 3 层目录中。

当将 Name1 字段和 OffsetToData 用做指针时需要注意两点,首先是不要忘记将最高位清除(使用 7FFFFFFFH 来 and 一下);其次就是这两个资源块开始的地方算起的偏移量,也就是根目录的起始位置算起的偏移量。

注意:千万不要将这两个指针作为 RVA 来对待,否则会得到错误和地址。正确的计算方法是将指针的值加上资源块首地址,结果才是真正的地址。

最后还需要说明的是,当 IMAGE_RESUOURCE_DIRECTORY_ENTRY 用在第 1 层目录中的时候,它的 Name1 字段是作为资源类型来使用的。当资源类型以 ID 定义(最高位等于 0),并且 ID 数值在 1 到 16 之间时,表示这是系统预定义的类型,ID 与类型的对应关系请参考表 17.6 ;如果资源类型是以 ID 定义的并且数值在 16 以上,表示这是一个自定义的类型。

表 17.6 预定义的资源类型

类型 ID 值在 Windows.inc 中的预定义值资源类型
1RT_CURSOR光标(cursor)
2RT_BITMAP位图(bitmap)
3RT_ICON图标(icon)
4RT_MENU菜单(menu)
5RT_DIALOG对话框(dialog)
6RT_STRING字符串(string)
7RT_FONTDIR字体目录(font directory)
8RT_FONT字体(font)
9RT_ACCELERATOR加速键(accelerators)
10RT_RCDATA未格式化资源(unformatted)
11(无)消息表(message table)
12RT_GROUP_CURSOR光标组(group cursor)
14RT_GROUP_ICON图标组(group icon)
16RT_VERSION版本信息(version information)

3。资源数据入口

沿着资源目录树按照根目录》资源类型》资源 ID 的顺序到达第 3 层目录后,这一层目录的 IMAGE_RESOUCE_DIRECTORY_ENTRY 结构的 OffsetToData 字段指向的是一个 IMAGE_RESOURCE_DATA_ENTRY 结构(如图 17.8 中的 E1 到 E5 所示)。

IMAGE_RESOURCE_DATA_ENTRY 结构的定义如下所示:

IMAGE_RESOURCE_DATA_ENTRY struct
  OffsetToData dd ? ;资源数据的 RVA
  Size1 dd ? ;资源数据的长度
  CodePage dd ? ;代码页
  Reserved dd ? ;保留字段
IMAGE_RESOURCE_DATA_ENTRY ends

IMAGE_RESOURCE_DATA_ENTRY 结构描述了资源数据所处的位置和大小,换句话说,就是经过了这么多层结构的长途跋涉以后,终于得到了某个资源的详细信息。

结构中的 OffsetToData 字段的值是指向资源数据的指针,奇怪的是,这个指针却是一个 RVA 值,而不是以资源块的起始地址为基址的,这上读者需要特别注意的地方。Size1 字段的值是资源数据的大小。结构中的第 3 个字段是 CodePage,这个字段的名称有些奇怪,因为当前资源的代码页已经在第 3 层目录中指明了,在这里再定义一次有重复之嫌,在实际的应用中,这个字段好像未被使用,因为随便找一个 PE 文件看看就会发现这里的值总是为 0。

17.4.3 查看 PE 文件中的资源列表举例

本节中的例子遍历 PE 文件中的资源目录树并显示每个资源的详细信息,例子的源代码放在本书光盘的 Chapter17\Resource 目录中,同样,为了节省篇幅,界面代码沿用前面的 Main.asm 和 Main.rc 文件,下面是 Main.asm 中包括的 _ProcessPeFile.asm 文件的内容:

.const
szMsg    db    '文件名: %s',0dh,0ah
        db    '------------------------------------------------',0dh,0ah
        db    '资源所处的节:%s',0dh,0ah,0
szErrNoRes    db    '这个文件中没有包含资源!',0
szLevel1    db    0dh,0ah
        db    '------------------------------------------------',0dh,0ah
        db    '资源类型:%s',0dh,0ah
        db    '------------------------------------------------',0dh,0ah,0
szLevel1byID    db    '%d (自定义编号)',0
szLevel2byID    db    '  ID: %d',0dh,0ah,0
szLevel2byName    db    '  Name: %s',0dh,0ah,0
szResData    db    '     文件偏移:%08X (代码页=%04X, 长度%d字节)',0dh,0ah,0
szType    db    '光标        ',0    ;1
        db    '位图        ',0    ;2
        db    '图标        ',0    ;3
        db    '菜单        ',0    ;4
        db    '对话框      ',0    ;5
        db    '字符串      ',0    ;6
        db    '字体目录    ',0    ;7
        db    '字体        ',0    ;8
        db    '加速键      ',0    ;9
        db    '未格式化资源',0    ;10
        db    '消息表      ',0    ;11
        db    '光标组      ',0    ;12
        db    '未知类型    ',0    ;13
        db    '图标组      ',0    ;14
        db    '未知类型    ',0    ;15
        db    '版本信息    ',0    ;16
.code
    include    _RvaToFileOffset.asm
_ProcessRes    proc    _lpFile,_lpRes,_lpResDir,_dwLevel
        local    @dwNextLevel,@szBuffer[1024]:byte
        local    @szResName[256]:byte
        pushad
        mov    eax,_dwLevel
        inc    eax
        mov    @dwNextLevel,eax
; 检查资源目录表,得到资源目录项的数量
        mov    esi,_lpResDir
        assume    esi:ptr IMAGE_RESOURCE_DIRECTORY
        mov    cx,[esi].NumberOfNamedEntries
        add    cx,[esi].NumberOfIdEntries
        movzx    ecx,cx
        add    esi,sizeof IMAGE_RESOURCE_DIRECTORY
        assume    esi:ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
; 循环处理每个资源目录项
        .while    ecx >    0
            push    ecx
            mov    ebx,[esi].OffsetToData
            .if    ebx & 80000000h

上页:第17章 PE文件 · 17.4 资源(1) 下页:第17章 PE文件 · 17.4 资源(3)

第17章 PE文件

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号