PE文件格式”1.9版 完整譯文(三)

正如你所見,我計劃只用2個節,一個用於代碼,一個用於所有剩餘的東西(數據、常量和輸入目錄等)。沒有重定位和象資源之類其它東西。我也不用BSS節並將變量“written”放入已初始化數據。文件和RAM中的節對齊都是一樣的(32字節);這將有助於使任務簡單,否則我就得來回地計算RVA很多次。

現在我們設置數據目錄,開始於0xb8字節,有0x80字節長:

地址 大小
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
???????? ???????? ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_TLS(9)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_IAT(12)
00000000 00000000 ;13
00000000 00000000 ;14
00000000 00000000 ;15

僅使用輸入目錄。

下一個使節頭。首先我們做代碼節的,代碼節將包含前面所編的彙編語句。它有32字節長,所以代碼節也就是這麼長。節頭從0x138處開始,有0x28字節長: Name 2e636f6465000000 ;".code"的ASCII碼值
VirtualSize 00000000 ;未用
VirtualAddress ???????? ;待定
SizeOfRawData 20000000 ;代碼的大小
PointerToRawData ???????? ;待定
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 20000060 ;代碼節,可執行,可讀

第二節將包含數據。節頭開始於0x160處,有0x28字節長:

Name 2e64617461000000 ;".data"的ASCII碼值
VirtualSize 00000000 ;未用
VirtualAddress ???????? ;待定
SizeOfRawData ???????? ;待定
PointerToRawData ???????? ;待定
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 400000c0 ;已初始化的,可讀,可寫

下一個字節位於0x188處,但節需要按32字節(的倍數)對齊(因爲我是這樣選擇的),所以我們需要添一些(0)字節直到0x1a0處:

000000000000 ;填充的
000000000000
000000000000
000000000000

現在第一節,就是上面所彙編的代碼節,“到”了。它開始於0x1a0處,有0x20字節長:

6A00 ;push 0x00000000
68???????? ;push offset_written
6A0D ;push 0x0000000d
68???????? ;push offsethello_string
6AF5 ;push 0xfffffff5
2EFF15???????? ;call dwordptrcs:__imp__GetStdHandle@4
50 ;push eax
2EFF15???????? ;call dwordptrcs:__imp__WriteConsoleA@20
C3 ;ret

因爲這一節的長度(剛好32字節),在下一節(數據節)前我們不需要填充任何字節。下一節到了,從0x1c0處開始:

68656C6C6F2C20776F726C640A ;"hello,world "的ASCII碼值
000000 ;填充幾個0以和_written對齊
00000000 ;_written

現在剩下的只有輸入目錄了。本文件將從"kernel32.dll"庫中輸入2個函數,輸入目錄將從本節的變量後面立即開始。首先我們先將上面的數據按32字節對齊:

000000000000000000000000 ;填充的

在0x1e0處開始輸入描述(IMAGE_IMPORT_DESCRIPTOR):

OriginalFirstThunk ???????? ;待定
TimeDateStamp 00000000 ;未綁定
ForwarderChain ffffffff ;無中轉
Name ???????? ;待定
FirstThunk ???????? ;待定

我們需要用一個0字節項來結束輸入目錄(我們現在位於0x1f4):

OriginalFirstThunk 00000000 ;結束符號
TimeDateStamp 00000000 ;
ForwarderChain 00000000 ;
Name 00000000 ;
FirstThunk 00000000 ;

現在只剩下DLL名字,還有2個換長,以及換長數據和函數名字了。但現在我們真的很快就要完成了。

DLL名字,以0結尾,開始於0x208處:

6b65726e656c33322e646c6c00 ;"kernel32.dll"的ASCII碼值
000000 ;填充到32位邊界

原始第一個換長,開始於0x218處:

AddressOfData ???????? ;"WriteConsoleA"函數名的RVA
AddressOfData ???????? ;"GetStdHandle"函數名的RVA
00000000 ;結束符號

第一個換長就是同樣的列表,開始於0x224處:

(__imp__WriteConsoleA@20,at0x224)
AddressOfData ???????? ;"WriteConsoleA"函數名的RVA
(__imp__GetStdHandle@4,at0x228)
AddressOfData ???????? ;"GetStdHandle"函數名的RVA
00000000 ;結束符號

現在剩下的只有輸入名字(IMAGE_IMPORT_BY_NAME)形式的兩個函數名了。我們現處於0x230字節。

0100 ;序數,不需要正確
5772697465436f6e736f6c654100 ;"WriteConsoleA"的ASCII碼值
0200 ;序數,不需要正確
47657453746448616e646c6500 ;"GetStdHandle"的ASCII碼值

Ok,這就全部結束了。下一個字節,我們並不真正需要,是0x24f。我們必須將節填充到0x260處:

00000000000000000000000000000000;填充的
00

------------

我們已經完成了。因爲我們已經知道了所有的字節偏移量,我們可以應用我們的修正到所有原先被用“??”符號標爲“未知”的地址和大小了。

我將不強迫你一步一步地去讀它(很好懂的),只直接給出結果來:

------------

DOS-頭,開始於0x0:

00|4d5a0000000000000000000000000000
10|00000000000000000000000000000000
20|00000000000000000000000000000000
30|00000000000000000000000040000000

簽名,開始於0x40:

50450000

文件頭,開始於0x44:

Machine 4c01 ;i386
NumberOfSections 0200 ;代碼和數據
TimeDateStamp 00000000;誰管它?
PointerToSymbolTable 00000000;未用
NumberOfSymbols 00000000;未用
SizeOfOptionalHeader e000 ;常量
Characteristics 0201 ;可執行於32位機器上

可選頭,開始於0x58:

Magic 0b01 ;常量
MajorLinkerVersion 00 ;我是0.0版:-)
MinorLinkerVersion 00 ;
SizeOfCode 20000000;32字節代碼
SizeOfInitializedData a0000000;數據節大小
SizeOfUninitializedData 00000000;我們沒有BSS節
AddressOfEntryPoint a0010000;代碼節的開始處
BaseOfCode a0010000;代碼節的RVA
BaseOfData c0010000;數據節的RVA
ImageBase 00001000;1MB,任意選擇
SectionAlignment 20000000;32字節對齊
FileAlignment 20000000;32字節對齊
MajorOperatingSystemVersion 0400 ;NT4.0
MinorOperatingSystemVersion 0000 ;
MajorImageVersion 0000 ;0.0版本
MinorImageVersion 0000 ;
MajorSubsystemVersion 0400 ;Win324.0
MinorSubsystemVersion 0000 ;
Win32VersionValue 00000000;未用?
SizeOfImage c0000000;所有節大小的總數
SizeOfHeaders a0010000;第一節的偏移量
CheckSum 00000000;非驅動程序不須用
Subsystem 0300 ;Win32控制檯程序
DllCharacteristics 0000 ;未用(不是一個DLL)
SizeOfStackReserve 00001000;1MB棧
SizeOfStackCommit 00100000;開始時4KB
SizeOfHeapReserve 00001000;1MB堆
SizeOfHeapCommit 00100000;開始時4KB
LoaderFlags 00000000;未知
NumberOfRvaAndSizes 10000000;常量

數據目錄,開始於0xb8:

地址 大小
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
e0010000 6f000000 ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_TLS(9)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_IAT(12)
00000000 00000000 ;13
00000000 00000000 ;14
00000000 00000000 ;15

節頭(代碼節),開始於0x138:

Name 2e636f6465000000 ;".code"
VirtualSize 00000000 ;未用
VirtualAddress a0010000 ;代碼節的RVA
SizeOfRawData 20000000 ;代碼的大小
PointerToRawData a0010000 ;代碼節的文件偏移量
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 20000060 ;代碼節,可執行,可讀

節頭(數據節),開始於0x160:

Name 2e64617461000000 ;".data"
VirtualSize 00000000 ;未用
VirtualAddress c0010000 ;數據節的RVA
SizeOfRawData a0000000 ;數據節的大小
PointerToRawData c0010000 ;數據節的文件偏移量
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 400000c0 ;已初始化,可讀,可寫
(填充)
000000000000 ;填充的
000000000000
000000000000
000000000000

代碼節,開始於0x1a0:

6A00 ;push 0x00000000
68d0011000 ;push offset_written
6A0D ;push 0x0000000d
68c0011000 ;push offsethello_string
6AF5 ;push 0xfffffff5
2EFF1528021000 ;call dwordptrcs:__imp__GetStdHandle@4
50 ;push eax
2EFF1524021000 ;call dwordptrcs:__imp__WriteConsoleA@20
C3 ;ret

數據節,開始於0x1c0:

68656C6C6F2C20776F726C640A ;"hello,world "
000000 ;填充到和_written對齊
00000000 ;_written

填充:

000000000000000000000000 ;填充的

輸入描述(IMAGE_IMPORT_DESCRIPTOR),開始於0x1e0:

OriginalFirstThunk 18020000 ;原始第一個換長的RVA
TimeDateStamp 00000000 ;未綁定
ForwarderChain ffffffff ;-1,無中轉
Name 08020000 ;DLL名字的RVA
FirstThunk 24020000 ;第一個換長的RVA

結束標誌(0x1f4):

OriginalFirstThunk 00000000 ;結束標誌
TimeDateStamp 00000000 ;
ForwarderChain 00000000 ;
Name 00000000 ;
FirstThunk 00000000 ;

DLL名字,開始於0x208:

6b65726e656c33322e646c6c00 ;"kernel32.dll"
000000 ;填充到32位邊界

原始第一個換長,開始於0x218:

AddressOfData 30020000 ;函數名"WriteConsoleA"的RVA
AddressOfData 40020000 ;函數名"GetStdHandle"的RVA
00000000 ;結束標誌

第一個換長,開始於0x224:

AddressOfData 30020000 ;函數名"WriteConsoleA"的RVA
AddressOfData 40020000 ;函數名"GetStdHandle"的RVA
00000000 ;結束標誌

輸入函數名稱(IMAGE_IMPORT_BY_NAME),開始於0x230:

IMAGE_IMPORT_BY_NAME,開始於0x240:

0200 ;序數,不需要正確
47657453746448616e646c6500 ;"GetStdHandle"的ASCII碼值
(填充)
00000000000000000000000000000000;填充的
00

第一個未使用字節開始於:0x260

--------------

噢,這個文件能在NT上卻不能在windows95上運行。windows95不能運行按32字節節對齊的應用程序,它要求節對齊爲4KB;並且很明顯的,文件對齊也應爲512字節。因此要想在windows95上運行,你得插入很多的0字節(爲了對齊)並調整RVA。感謝D.Binette在windows95上的(運行)試驗。

發佈了75 篇原創文章 · 獲贊 5 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章