前言:沒什麼好說的,發現這方面的資料全是英文的,於是我一邊研究,一邊翻譯,一邊寫出自己的心得。
希望大家尊重我的勞動成果,轉貼保持完整。
資源一般使用樹來保存,通常包含3層,在NT下,最高層是類型,然後是名字,最後是語言。一個PE文件是否包含資源文件,通常檢測塊表(Section Table)中是否含有'.rsrc',不過這個方法對有些PE文件無效。
一個類型表結構如下
―――――――――――――
| RESOURCE DIRECTORY |
―――――――――――――
| RESOURCE DATA |
―――――――――――――
資源表1(Resource File Layout)
其中的資源目錄(RESOURCE DIRECTORY)結構如下:
――――――――――――――――――――――――――
| RESOURCE FLAGS |
――――――――――――――――――――――――――
| TIME/DATE STAMP |
――――――――――――――――――――――――――
| MAJOR VERSION | MINOR VERSION |
――――――――――――――――――――――――――
| # NAME ENTRY | # ID ENTRY |
――――――――――――――――――――――――――
| RESOURCE DIR ENTRIES |
――――――――――――――――――――――――――
資源表2(Resource Table Entry)
在Delphi中的申明
{ Resources }
PIMAGE_RESOURCE_DIRECTORY = ^IMAGE_RESOURCE_DIRECTORY;
IMAGE_RESOURCE_DIRECTORY = packed record
Characteristics : DWord;
TimeDateStamp : DWord;
MajorVersion : Word;
MinorVersion : Word;
NumberOfNamedEntrIEs : Word;
NumberOfIdEntrIEs : Word;
end
其中:
RESOURCE FLAGS
通常設置為0
TIME/DATE STAMP
資源編譯器建立此資源的時間/日期,可能為0
MAJOR/MINOR VERSION
版本信息
# NAME ENTRY
使用名字的資源條目的個數,包含一個使用名字的目錄條目的數組。
# ID ENTRY
使用ID數字的資源條目的個數,包含一個32位的整數ID號,同用名字一樣。
這個目錄緊接著會是一個不定長度的目錄條目,不管用的名字還是ID,都是用升序排列。
這個不定長度的目錄結構如下:
31 0
――――――――――――――――――――――
| NAME RVA/INTEGER ID |
――――――――――――――――――――――
| E | DATA ENTRY RVA/SUBDIR RVA |
――――――――――――――――――――――
資源表3(Resource Directory Entry)
在Delphi中的申明:
PIMAGE_RESOURCE_DIRECTORY_ENTRY = ^IMAGE_RESOURCE_DIRECTORY_ENTRY;
IMAGE_RESOURCE_DIRECTORY_ENTRY = packed record
Name: DWORD; // Or ID: Word (Union)
OffsetToData: DWord;
INTEGER ID
包含一個識別資源的整數ID
如果在根目錄,這個ID表示的意義如下
資源類型
1: cursor
2: bitmap
3: icon
4: menu
5: dialog
6: string table
7: font directory
8: font
9: accelerators
10: unformatted resource data
11: message table
12: group cursor
14: group icon
16: version information
NAME RVA
名字的相對實際地址,包含一個31位的相對資源的Image Base的地址。表的形式見表4
E 一位的不可缺少的識別碼(mask 80000000h)
如果這位為0,則為Resource Data EntrIEs,其中DATA RVA = 31位的(mask 7fffffffh) 數據條目的地址。結構見表5
如果這位為1,則表示接另一個子目錄(Subdirectory Entry)。
{ 此函數檢驗 offset 是一個字符串名還是一個目錄 }
{ IMAGE_RESOURCE_NAME_IS_STRING
= IMAGE_RESOURCE_DATA_IS_DIRECTORY
= $80000000 }
function HighBitSet(L: Longint): Boolean;
begin
Result := (L and IMAGE_RESOURCE_DATA_IS_DIRECTORY) <> 0;
end;
{ 下面兩個函數用於去掉E位剩下的值或者指針 }
{IMAGE_OFFSET_STRIP_HIGH = $7FFFFFFF;}
function StripHighBit(L: Longint): Longint;
begin
Result := L and IMAGE_OFFSET_STRIP_HIGH;
end;
function StripHighPtr(L: Longint): Pointer;
begin
Result := Pointer(L and IMAGE_OFFSET_STRIP_HIGH);
end;
每一個資源目錄名為如下格式
――――――――――――――――――――――
| LENGTH | UNICODE STRING |
――――――――――――――――――――――
| LENGTH | UNICODE STRING |
――――――――――――――――――――――
表4(Resource Directory String Entry)
在Delphi中的申明
PIMAGE_RESOURCE_DIR_STRING_U = ^IMAGE_RESOURCE_DIR_STRING_U;
IMAGE_RESOURCE_DIR_STRING_U = packed record
Length : Word;
NameString : array [0..0] of WCHAR;
end;
LENGTH
就是字符串的長度
UNICODE STRING
Unicode的字符串.
資源數據表結構:
―――――――――――――
| DATA RVA |
―――――――――――――
| SIZE |
―――――――――――――
| CODEPAGE |
―――――――――――――
| RESERVED |
―――――――――――――
表5(Resource Data Entry)
在Delphi中的申明
PIMAGE_RESOURCE_DATA_ENTRY = ^IMAGE_RESOURCE_DATA_ENTRY;
IMAGE_RESOURCE_DATA_ENTRY = packed record
OffsetToData : DWord;
Size : DWord;
CodePage : DWord;
Reserved : DWord;
end;
DATA RVA
資源的相對實際地址,包含一個32位相對於資源Image Base的地址。
SIZE
資源的大小。
CODEPAGE
沒什麼說的,好像為譯碼方面設置的。
RESERVED
一定為0
好了,差不多資源這部分分析玩了,其它部分我還在研究:)