PE格式的资源段是比较复杂的,目前几种介绍PE格式的书籍在介绍到这部分时都是不够深入(本人认为写得比较好的有《Windows95系统程式设计奥秘》候捷译本),因此不
得不拿起工具自已研究,分析PE格式比较好的工具有:stud_PE,UltraEdit等。以下记录我在研究图标资源时的过程,请结合PE格式分析教材阅读
步骤:
1、得到资源段的偏移地址;
用Stud_PE打开PE格式文件,“sections”页中有个名称为“.rsrc”的行(如果程序有资源的话)。 查看该行的“VirtualOffset”字段,其值即是资源段的偏移,也是文件中的偏移;
2、用一款十六进制编辑软件(可使用UltraEdit)打开PE格式文件,定位到资源段;
3、资源段首先是个IMAGE_RESOURCE_DIRECTORY结构数据,该结构的NumberOf-
NamedEntries表示“使用名称的资源”的个数,NumberOfIdEntries表示“使用整数ID的资源”;
4、然后是数个IMAGE_RESOURCE_DIRECTORY_ENTRY结构,个数是NumberOfNam-
edEntries和NumberOfIdEntries的和;IMAGE_RESOURCE_DIRECTORY_ENT
RY结构只有8字节,虽然结构看起来很大。前4个字节表示资源类型,后4个字节表示位置。资源类型的值如果是3(RT_ICON)表示图标,其它值参考文档,例如,2(RT_BITMAP)表示位图,1(RT_CURSOR)表示光标;后4个字节表示资源的位置,如果高位被置位,余下的31位就是指向资源目录的偏移,这个偏移相对于资源区块开始的位置而不是RVA;
5、找到图标资源的偏移,这里又是一个IMAGE_RESOURCE_DIRECTORY结构,结构的
NumberOfIdEntries表示图标的个数;此后又是数个IMAGE_RESOURCE_DIRECTO
RY_ENTRY(与图标个数相同),前4个字节应该是图标的ID,后期个字节是图标
的位置;
6、由上步的偏移再次找到一个IMAGE_RESOURCE_DIRECTORY结构,感觉没什么有用
信息;之后又是一个IMAGE_RESOURCE_DIRECTORY_ENTRY结构(好烦),此时,
通过后4个字节(与资源区首的偏移值)可以找到另一个IMAGE_RESOURCE_DATA_
ENTRY结构,该结构的有用信息是: offsetToData表示图标数据的位置(是RVA,此时不是偏移了),size 图标数据块的大小。
7、最后注意,这里的图标信息比普通的图标文件的信息好,粗略一看,至少少了文件头和
图标头两部分数据,直接从图片数据开始,即BITMAPINFOHEADER(没写错哦)。
上面过程当RAV=RAW(在可执行文件中的偏移)情况,但多数情况下这两个值均不相等。
如何得到RAV和RAW和偏移呢(offset):
在IMAGE_OPTION_HEADER 结构之后就是数个IMAGE_SECTION_HEADER(区表),每个区表关联一种资源的信息,个数由IMAGE_NT_HEADERS.FileHeader.NumberOfSe-
ctions指定,在区表结构有一个字段是PointerToRawData, 即表示块在磁盘文件中的偏移。
记住这个RAW,并算出其与RAV的offset 。在后面给出的许多地址均是RAV,通过这个
offset就可计算出其对应的RAW。
下面的代码给出查找EXE文件中第一个图标数据所在磁盘文件的编移和大小(代码比较凌乱):
CFileDialog dlg ( TRUE ) ;
if( dlg.DoModal() != IDOK )
return ;
HANDLE hFile = CreateFile( dlg.GetPathName() , GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING ,
FILE_ATTRIBUTE_NORMAL , NULL ) ;
if( hFile == INVALID_HANDLE_VALUE )
return ;
HANDLE hMap = ::CreateFileMapping( hFile , NULL ,
PAGE_READWRITE , 0 , ::GetFileSize(hFile,NULL)+1 , NULL ) ;
if( hMap )
{
LPVOID buffer = ::MapViewOfFile( hMap , FILE_MAP_WRITE | FILE_MAP_READ , 0 , 0 , 0 ) ;
if( buffer )
{
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER *)buffer ;
IMAGE_NT_HEADERS *pNtHeader = (IMAGE_NT_HEADERS *)((DWORD)buffer
+ pDosHeader->e_lfanew ) ;
DWORD dwNumberOfSections = pNtHeader->FileHeader.NumberOfSections ;
IMAGE_SECTION_HEADER *pSectionHeader = (IMAGE_SECTION_HEADER *)
((DWORD)pNtHeader + sizeof(IMAGE_NT_HEADERS) ) ;
for( DWORD i = 0 ; i < dwNumberOfSections ; i ++ )
{
if( lstrcmp( (char *)pSectionHeader->Name , ".rsrc" ) == 0 )
break ;
pSectionHeader ++ ;
}
if( i < dwNumberOfSections )
{
DWORD dwOffsetRavToRaw = pNtHeader->OptionalHeader.DataDirectory[2].
VirtualAddress –>pSectionHeader->PointerToRawData ;
IMAGE_RESOURCE_DIRECTORY *pResourceDirect =
(IMAGE_RESOURCE_DIRECTORY *)
((DWORD)buffer + pSectionHeader->PointerToRawData ) ;
TRACE("res section rav:%x/n " , pNtHeader->OptionalHeader.
DataDirectory[2].VirtualAddress ) ;
TRACE("res raw: %x/n" , pSectionHeader->PointerToRawData ) ;
IMAGE_RESOURCE_DIRECTORY_ENTRY *pEntry =
(IMAGE_RESOURCE_DIRECTORY_ENTRY *)
( (DWORD)pResourceDirect + sizeof(IMAGE_RESOURCE_DIRECTORY) ) ;
int nRes = pResourceDirect->NumberOfIdEntries +
pResourceDirect->NumberOfNamedEntries ;
for( int i = 0 ; i < nRes ; i ++ )
{
if( pEntry->Id == 3 )
{
TRACE("icon entry is %x/n" , pEntry->OffsetToData ) ;
break;
}
pEntry ++ ;
}
int offset = pEntry->OffsetToData ;
if( offset & 0x80000000 )
offset &= 0x7FFFFFFF ;
TRACE("%x/n" , offset ) ;
IMAGE_RESOURCE_DIRECTORY *pIconDirect =
(IMAGE_RESOURCE_DIRECTORY *)((DWORD)pResourceDirect + offset ) ;
IMAGE_RESOURCE_DIRECTORY_ENTRY *pIconEntry =
(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((DWORD)pIconDirect + 16);
offset = pIconEntry->OffsetToData ;
if( offset & 0x80000000 )
offset &= 0x7FFFFFFF ;
TRACE("%x/n" , offset ) ;
pIconEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)
((DWORD)pResourceDirect + offset +16 ) ;
offset = pIconEntry->OffsetToData ;
if( offset & 0x80000000 )
offset &= 0x7FFFFFFF ;
TRACE("%x/n" , offset ) ; // offset = 0x168
pIconEntry=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((DWORD)
pResourceDirect + offset ) ;
int icon_offset = pIconEntry->Name ;
int icon_size = pIconEntry->OffsetToData ;
CString str ;
str.Format(" ICON 's RVA = %X , RAW = %X , size = %X /n" ,
icon_offset , icon_offset - dwOffsetRavToRaw,
icon_size ) ;
AfxMessageBox( str ) ;
}
::UnmapViewOfFile( buffer ) ;
}
::CloseHandle( hMap ) ;
::CloseHandle( hFile ) ;