手工構造一個超微型的 PE 檔案 (轉)
;==================================
; 標題:手工構造一個超微型的 PE
; 作者:一塊三毛錢
; 日期:.12.18
;==================================
最近構造了一個微型的 PE 檔案,下面把構造的方法和一點心得寫出來和大家交流,也算是
對 PE 格式的一個複習吧。
最終構造好的檔案大小是 180 位元組,可以在 下執行,執行後會彈出一個訊息框。
來看看最後生成的檔案的內容:
00000000 4D 5A 00 00 50 45 00 00 4C 01 01 00 75 73 65 72 MZ..PE..L...user
00000010 33 32 2E 64 6C 6C 00 00 70 00 0F 01 0B 01 6A 00 32.dll..p.....j.
00000020 B8 8C 00 40 00 50 50 6A 00 EB 05 00 1E 00 00 00 to:...@.PPj">...@.PPj........
00000030 FF 15 78 00 40 00 C3 00 00 00 40 00 04 00 00 00 ..x.@.....@.....
00000040 04 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 ................
00000050 00 00 00 00 B4 00 00 00 00 00 00 00 00 00 00 00 ................
00000060 02 00 00 00 00 00 10 00 00 00 00 00 00 00 10 00 ................
00000070 00 10 00 00 00 00 00 00 C4 01 00 80 00 00 00 00 ................
00000080 00 00 00 00 9C 00 00 00 28 00 00 00 5A 54 53 B1 ........(...ZTS.
00000090 E0 D0 B4 00 B4 00 00 00 00 00 00 00 B4 00 00 00 ................
000000A0 00 00 00 00 00 00 00 00 0C 00 00 00 78 00 00 00 ............x...
000000B0 E0 00 00 E0 ....
用 dumpbin 顯示檔案結構如下:
FILE HEADER VALUES
14C machine (i386)
1 number of sections
72657375 time date stamp Sat Oct 26 21:21:57 2030
642E3233 file pointer to symbol table
6C6C number of symbols
70 size of optional header
10F characteristics
Relocations stripped
Executable
Line numbers stripped
Symbols stripped
32 bit machine
OPTIONAL HEADER VALUES
10B magic #
106.00 linker version
40008CB8 size of code
6A505000 size of initialized data
5EB00 size of uninitialized data
1E RVA of entry point 7815FF base of code
C30040 base of data
400000 image base
4 section alignment
4 file alignment
4.00 operating system version
0.00 image version
4.00 subsystem version
0 version
B4 size of image
0 size of headers
0 checksum
2 subsystem ( GUI)
0 DLL characteristics
100000 size of stack reserve
0 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
800001C4 number of directories
0 [ 0] RVA [size] of Export Directory
9C [ 28] RVA [size] of Import Directory 0 [ 0] RVA [size] of Re Directory
0 [ 0] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
0 [ 0] RVA [size] of Base Relocation Directory
0 [ 0] RVA [size] of De Directory
0 [ 0] RVA [size] of Architecture Directory
0 [ 0] RVA [size] of Special Directory
0 [ 0] RVA [size] of Thread Storage Directory
0 [ 0] RVA [size] of Load Configuration Directory
0 [ 0] RVA [size] of Bound Import Directory
0 [ 0] RVA [size] of Import Address Table Directory
0 [ 0] RVA [size] of Delay Import Directory
0 [ 0] RVA [size] of Reserved Directory
0 [ 0] RVA [size] of Reserved Directory
現在開始具體的步驟
1. DHeader
IMAGE_DOS_HEADER STRUCT
e_magic ... e_lfanew IMAGE_DOS_HEADER ENDS
為了把檔案做得儘可能的小,所以 PE Header 準備放在檔案偏移 4 的地方,本來還可以
往前放,由於 Dos Header 的 e_lfanew 必須指向 PE Header 的偏移位置。當放在偏移
4 的地方,Dos Header 的 e_lfanew 正好對應著 PE Header 的 SectionAlignment,
我們只需要把 SectionAlignment 設為 4 就可以達到兩個目的。
2. PE Header
IMAGE_NT_HEADERS STRUCT
Signature FileHeader
OptionalHeader
IMAGE_NT_HEADERS ENDS
下面打了 * 標誌的意味著不能隨便填資料,具體的資料可以參考上面 dumpbin 顯示的數
據。凡是沒有打 * 標誌的可以填入任意資料,我們的程式碼就準備塞在這些結構裡面。
IMAGE_FILE_HEADER STRUCT
Machine *
NumberOfSections *
TimeDateStamp
PointerToSymbolTable
NumberOfSymbols
SizeOfOptionalHeader *
Characteristics *
IMAGE_FILE_HEADER ENDS
IMAGE_OPTIONAL_HEADER32 STRUCT
Magic *
MajorLinkerVersion
MinorLinkerVersion
SizeOfCode
SizeOfInitializedData
SizeOfUninitializedData
AddressOfEntryPoint *
BaseOfCode
BaseOfData
ImageBase *
SectionAlignment *
FileAlignment *
MajorOperatingSystemVersion *
MinorOperatingSystemVersion *
MajorImageVersion *
MinorImageVersion *
MajorSubsystemVersion *
MinorSubsystemVersion *
Win32VersionValue *
SizeOfImage *
SizeOfHeaders *
CheckSum
Subsystem *
DllCharacteristics *
SizeOfStackReserve *
SizeOfStackCommit *
SizeOfHeapReserve *
SizeOfHeapCommit *
LoaderFlags
NumberOfRvaAndSizes *
DataDirectory
IMAGE_OPTIONAL_HEADER32 ENDS
對於 DataDirectory 中不需要的成員可以不要,只留下 Export Directory 和 Import Directory。
整個 PE Header 的大小為 88h 位元組,其中 Optional Header 的大小為 70h 位元組。
3. Section Table
IMAGE_SECTION_HEADER STRUCT
Name1 union Misc
PhysicalAddress
VirtualSize ends
VirtualAddress SizeOfRawData PointerToRawData PointerToRelocations PointerToLinenumbers NumberOfRelocations NumberOfLinenumbers Characteristics IMAGE_SECTION_HEADER ENDS
整個檔案的內容就是節的內容,最後檔案的全部內容會被完整的對映到 400000h 的地址處。
因為對映到中後檔案的內容後面都是 0,所以相當於節表以一個全 0 元素結束。
4. Import
檔案只需要從 user32.dll 中輸入一個 MessageBoxA,所以輸入表中有一個非 0 成員
和一個結束的全 0 成員。就因為要保證有一個全 0 成員來結束輸入表,所以也把輸入表放
在檔案的末尾,和節的情況一樣,當檔案被對映到記憶體中後,檔案後面的內容都是 0,就相當
於有一個全 0 成員。
一個輸入表成員的大小是 20 位元組,在節表當中找出沒有被利用的域用來放輸入表,找到了從
SizeOfRawData 開始的位置。輸入表中的 OriginalFirstThunk ,TimeDateStamp 和
ForwarderChain 都是沒用的域,不用管他們是什麼值,所以不會因為在節表中插入輸入表而
改變節表中有用的域:SizeOfRawData 和 PointerToRawData 。
還有的就是 Name 和 FirstThunk 啦,在檔案中找到偏移 0Ch 的地方寫入 user32.dll,然
後把 Name 指向偏移 0Ch,這個偏移就是檔案頭中 TimeDateStamp 的偏移位置。在檔案中再
找到一個偏移位置 78h 來放 IAT,然後把 FirstThunk 指向偏移 78h,這個偏移是檔案頭中
NumberOfRvaAndSizes 的偏移位置。在上面雖然說了 NumberOfRvaAndSizes 域不能隨便填
資料(打了 * 標誌),但這個域只要不填 2 以下的值就可以,所以我們可以利用。
填好的樣子如下:
00000070 C4 01 00 80 00 00 00 00 ................
00000080
00000090 B4 00 00 00 ................
000000A0 00 00 00 00 00 00 00 00 0C 00 00 00 78 00 00 00 ............x...
為了減少檔案的大小,輸入 MessageBoxA 函式是透過序號的方式引入的。
手工寫好輸入表之後把輸入表的偏移和大小填到 DataDirectory 陣列的 Import Directory
成員中去,偏移為 9Ch,大小為 28h。
5. 程式碼
所有準備工作做完就開始寫程式碼,程式碼也需要從檔案頭中間找沒用的域來存放。找找檔案頭發現
還有兩個地方沒有被使用,一個是 MajorLinkerVersion 開始的 14 個位元組,偏移為 1Eh,另
一個是 BaseOfCode 開始的 8 個位元組,偏移為 30h。
需要的程式碼寫好就是下面的樣子:
0000001E: 6A00 push 0
00000020: B88C004000 mov eax,40008C
00000025: 50 push eax
00000026: 50 push eax
00000027: 6A00 push 0
00000029: EB05 jmp 000000030
00000030: FF1578004000 call dword ptr [00400078]
00000036: C3 ret
把程式碼對應的 16 進位制值填到偏移 1Eh 和 30h 處就行了。
儲存檔案,所有的工作就結束了。最後把注意事項再總結一下:
1. 如果 FileAlignment 小於 200h,則要求 FileAlignment == SectionAlignment >= 2
2. 如果 FileAlignment 小於 200h,則要求 VirtualAddress == PointerToRawData
3. VirtualSize <= SizeOfRawData
4. SizeOfHeaders < SizeOfImage
5. NumberOfRvaAndSizes >= 2 資料目錄結構的數量要求不小於 2
6. 節表和輸入表都要求有一個結束的全 0 成員
胡亂寫了一點,希望不會浪費大家太多時間,如果有錯誤還望各位大俠指點指點,也好讓象我這
樣的菜鳥能多學一些東西。
/pediybbs/.?id=696&sid=43a348bf4f599d7be75756d1086b1703">
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-963776/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PE 檔案結構圖
- PE檔案結構(二) 區塊,檔案偏移與RVA轉換
- PE檔案結構複習
- PE檔案結構解析3
- PE檔案結構解析1
- PE檔案結構解析2
- 可能是最小的 pe 程式 -- 我手工構造了一個 pe 程式, 只 305 個位元組, 可正確執行(Win9x). .. (5千字)
- win32 PE 檔案格式 (轉)Win32
- PE檔案結構(五)基址重定位
- PE檔案結構(四) 輸出表
- 再探.NET的PE檔案結構(安全篇)
- PE檔案格式
- PE檔案格式詳細解析(一)
- 如何設計一個微型分散式架構?分散式架構
- 深入剖析PE檔案
- PE檔案格式的RVA概念
- PE教程2: 檢驗PE檔案的有效性
- 譯:如何構造我的JavaScript檔案?JavaScript
- 如何設計一個麻雀般的微型分散式架構?分散式架構
- windows載入PE檔案的流程Windows
- 手工建立控制檔案
- [轉載]淺析.NET Framework對PE檔案格式的擴充套件Framework套件
- 一個簡單的檔案管理程式 (轉)
- 一個最簡單的XML檔案(轉)XML
- 手工建庫---控制檔案
- 手工恢復控制檔案
- 初步瞭解PE檔案格式(上)
- 通過koa2和Promise.race()構造一個超時取消的ajax。Promise
- jOrgChart橫向的組織機構樹--手工構造json資料GCJSON
- 推薦一個yaml檔案轉json檔案的線上工具YAMLJSON
- 手工定製Win2000應答檔案(轉)
- ODBC檔案DSN 的結構 (轉)
- PE學習筆記(一) (轉)筆記
- PE檔案格式詳細解析(二)--IAT
- 惡意軟體PE檔案重建指南
- 21.1 Python 使用PEfile分析PE檔案Python
- PE檔案檢測DOS頭\NT頭
- PE教程3: File Header (檔案頭)Header