PE結構-Dos頭部

啥是PE結構?簡單來說,就是將代碼和數據按照一定的約定進行存放,爲進程的創建做準備。

微軟當初在設計PE結構時,目標是設計成多平臺的,所以裏面很多字段考慮了跨平臺因數,當然現在來看,這個跨平臺...en..就不用多說啥了。

先來了解一下PE結構的大概情況

IMAGE_DOS_HEADER //DOS頭
IMAGE_NT_HEADERS //NT頭
    DWORD Signature //PE 標誌
    IMAGE_FILE_HEADER //文件頭
    IMAGE_OPTIONAL_HEADER //選項頭
IMAGE_SECTION_HEADER //數據節區描述 多個
...
IMAGE_SECTION_HEADER
SECTION_DATA //節數據
...
SECTION_DATA
user data //附加數據 不屬於PE範疇

上面大致看看分佈即可

先來說說選項頭,有些視頻或者書籍會翻譯成可選頭,只是需要注意的是這裏的IMAGE_OPTION_HEADER是不能省略的,一個字段都不能,只是這個結構是有多種選項的

IMAGE_OPTIONAL_HEADER64 OptionalHeader; //32位
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //64位
IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; //嵌入式

然後再來說一說數據節區,位於NT頭後,有幾個節數據(理解爲數據塊即可),就會有對應多少個節區描述。那麼描述數據塊至少需要兩個信息,數據塊在哪裏(地址),多大(size),具體後面博客再寫吧。

最後面有個附加數據,這裏的附加數據相對於是用戶數據,也就是額外數據,使用vc6編譯一個debug版exe,就會發現該exe會附帶附加數據,該數據爲pdb文件位置

瞭解完大體的概貌後,下面可以動手來分析了,爲了簡單起見,這裏使用匯編來寫代碼,這樣編譯出來的exe相對學習較容易

.386
.model flat,stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

.const
	g_szHello db 'Hello World!',0
	g_szTitle db 'PE',0	
.code
START:
	invoke MessageBox,NULL,offset g_szHello,offset g_szTitle,MB_OK
	invoke ExitProcess,0
	end START

手動編譯

D:\masm32\bin\ml /c /coff hello.asm
D:\masm32\bin\link /subsystem:windows hello.obj

這樣子編譯出來的exe只有2kb大小。

這篇博客先來討論下Dos頭以及後面的Stub數據,使用WinHex打開

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // MZ 標誌
    //... 58字節
    LONG   e_lfanew;                    // 新結構(微軟定義結構)偏移地址 PE
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

上面是Dos結構,其中前面部分是完整的,總共佔0x40字節,我們只有重點關係下面部分即可(首尾),中間的是運行時基本環境中需要的一些初始化的信息(如寄存器初始值),因爲在dos程序,才需要關注配置這些相關信息,所以32位中忽略即可

剩餘的那部分數據就是stub數據,也就是Dos殘留數據,作用是當這個32位程序真的運行在Dos環境下時,那麼程序將會從40處開始執行(代碼數據混合)

seg000:0040 ; ---------------------------------------------------------------------------
seg000:0040                 push    cs
seg000:0041                 pop     ds
seg000:0042                 mov     dx, 0Eh
seg000:0045                 mov     ah, 9
seg000:0047                 int     21h             ; DOS - PRINT STRING
seg000:0047                                         ; DS:DX -> string terminated by "$"
seg000:0049                 mov     ax, 4C01h
seg000:004C                 int     21h             ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
seg000:004C                                         ; AL = exit code
seg000:004C ; ---------------------------------------------------------------------------

所以這部分地方也是沒用的,這裏的沒用是針對程序而言,事實上這部分地方解釋爲可利用的更好,至於寫啥東西就隨意了。

OK,我們可以將上面可利用處都填寫爲0xCC,剩餘都是需要特別關注的點

修改完後重新跑一下程序,測試是否能正常運行!

 

 

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