一、相关意义及说明
PE文件资源中的内容包括光标、图标、位图、菜单等十几种标准的类型,除此之外,还可以使用自定义的类型。每种类型的资源中可能存在多个资源项,这些资源项用不同的ID或者名称来分辨,在某个资源ID下,还可以同时存在不同代码页的版本。
这么多种类型的不同ID的资源是用类似于磁盘目录结构的方式组织起来的。也就是按照根目录→资源类型→资源ID的3层树型目录结构来组织资源,只不过在第3层目录中放置的代码页“文件”不是资源本身而是一个用来描述资源的结构罢了,通过这个结构中的指针才能最后找到资源数据。
整个组织结构如下图所示:
图17.8 PE文件中资源的组织方式
二、分析书本实例(CHA17-Resource文件夹—_ProcessPeFile、_ProcessRes)
1. _ProcessPeFile子程序
(1) 参数的意义
① 子程序参数1:已经读取到内存中的文件头的地址。通过内存映射读取到整个PE文件在内存中的起始位置。
② 子程序参数2:PE文件头在内存中的偏移地址。也就是在MAGE_DOS_HEADER 结构中取出的e_lfanew的值。
③ 子程序参数3:整个PE文件的长度。通过打开文件后拿到的句柄,用GetFileSize函数拿到文件的长度。
(2) 检查是否存在资源,如果存在,则获取资源目录的RVA值并转换为在PE文件中的偏移位置。然后显示文件名和资源所处的节的名称。最后将资源目录在PE文件中的地址存入esi作为参数调用子程序_ProcessRes。
_ProcessPeFile proc _lpFile,_lpPeHead,_dwSize
local @szBuffer[1024]:byte,@szSectionName[16]:byte
pushad
mov esi,_lpPeHead
assume esi:ptr IMAGE_NT_HEADERS
;********************************************************************
; 检测是否存在资源
;********************************************************************
mov eax,[esi].OptionalHeader.DataDirectory[8*2].VirtualAddress
.if ! eax
invoke MessageBox,hWinMain,addr szErrNoRes,NULL,MB_OK
jmp _Ret
.endif
push eax
invoke _RVAToOffset,_lpFile,eax
add eax,_lpFile
mov esi,eax
pop eax
invoke _GetRVASection,_lpFile,eax
invoke wsprintf,addr @szBuffer,addr szMsg,addr szFileName,eax
invoke SetWindowText,hWinEdit,addr @szBuffer
invoke _ProcessRes,_lpFile,esi,esi,1
2. _ProcessRes子程序
(1) 子程序参数一览
① 子程序参数1:已经读取到内存中的文件头的地址。通过内存映射读取到整个PE文件在内存中的起始位置。
② 子程序参数2:第一层资源目录表在PE文件中的地址。也就是第一层IMAGE_RESOURCE_DIRECTORY结构的起始地址。
③ 子程序参数3:每一层资源目录表在PE文件