Windows安全之PE結構(二)之 IMAGE_NT_HEADER(NT頭) 以及其成員(IMAGE_FILE_HEADER / IMAGE_OPTIONAL_HEADER32)

上章Windows安全之PE結構(一)

重溫一下上章節已經講了幾個的PE結構的區域, 如IMAGE_DOS_HEADER,DOS頭所有都是一整字(word)或雙字(dword),只要記住上一章提及兩個重要的成員變量就行了。當然也可以看一下其他的成員變量,知多也沒壞處。
然而IMAGE_NT_HEADER,就講了幾個IMAGE_NT_HEADER裡面的成員的結構體,IMAGE_FILE_HEADER ,IMAGE_OPTIONAL_HEADER32 這兩個
兩個在PE裡頭不可或缺的結構體,沒了IMAGE_OPTIONAL_HEADER32 整個PE結構體都崩壞了,導出表,導入表,重定位表等等的重要信息都不能被保存了,這些表會在以後的章節詳細講解。

今章將會講一下 節表 或稱 區塊表, 不同地區的譯名而已 英文為 IMAGE_SECTION_HEADER, 其實PE結構經過上一章發現 就是一個線性結構的

------------------------------------------------------------------------------------------------------
節 / 區塊 (SECTION) :
存在目的 就是為了將同類的數據歸納在一起。

第一部份 除了節 / 區塊 (SECTION)
PE加載器不會做任何預處理

節 / 區塊 會做以下處理:

- 內存頁的屬性(只讀/可讀寫)
- 節的偏移地址
- 節的尺寸
- 不進行映射的節(.reloc)

重定位(Relocation) 的意義
- 對於DLL檔的加載來說
------------------------------------------------------------------------------------------------------------

區塊表 / 節表

區塊表的位置定位??
沒有一個地方存放區塊表中的地址
但是我們可以透過一些方法知道在IMAGE_OPTIONAL_HEADER後面就是區塊表的起始位置了;

獲取 IMAGE_OPTIONAL_HEADER的基地址(這裡是00000100H)
獲取 IMAGE_FILE_HEADER->FileHeader->SizeOfOptionalHeader(這裡是00E0H)
從OptionalHeader的大小 我們可以知道IMAGE_OPTIONAL_HEADER最後一個字節是哪裡,從而推斷出節表的位置

找到了IMAGE_SECTION_HEADER的基址
typedef struct _IMAGE_SECTION_HEADER
{

BYTE name[IMAGE_SIZEOF_SHORT_NAME]
//節表名稱,如“的.text”
//IMAGE_SIZEOF_SHORT_NAME=8

union
{
DWORD PhysicalAddress; //物理地址
DWORD VirtualSize; //聯合結構可以使用任意一個,他們會互相取替, 不懂可參考有關C語言書藉
}Misc;
DWORD VirtualAddress; //節區的RVA地址
DWORD SizeOfRawData; //在文件中對齊後的尺寸
DWORD PointerToRawData; //在文件中的偏移量
DWORD PointerToRelocations; //在OBJ文件中使用,重定位的偏移
DWORD PointerToLinenumbers; //行號表的偏移(供調試使用地)
WORD NumberOfRelocations; //在OBJ文件中使用,重定位項數目
WORD NumberOfLinenumbers; //行號表中行號的數目
DWORD Characteristics; //節屬性如可讀,可寫,可執行等
} IMAGE_SECTION_HEADER,* PIMAGE_SECTION_HEADER;

_IMAGE_SECTION_HEADER 大小為40個字節(byte)

Name : 區塊名,限於8個字節的,大於8個字節的話會以0結束,一定要加.符號在區塊名,一定是要唯一的
VirtualSize : 虛擬內存對齊前的大小
VirtualAddress : 虛擬內存對齊後的位置
SizeOfRawData : 區塊的數據大小
PointerToRawData : 指向區塊的偏移

假如PointerToRawData 第一段指向00001000H 那我們可以透過SizeOfRawData獲取第一段區塊大小 那就知道了第二區塊的初始位置
當取得了第二塊區塊的初始位置,再獲取數據的大小,加起來就獲取第三塊區塊的,那可以一直推斷下去
Characteristics : 該區塊的屬性(如代碼/數據/可讀/可寫/共享區塊....等等)

說來這麼多 來一張圖片給大家分析一下
其實只要一直的數下去按照成員變量大小一直見到節表的所有成員




















這裡圈住了000001E0H 這個就是基址 因為偏移的問題 首八個字節是沒有值的然後就是順次序能看到的
.text節/區塊的屬性等
VirtualSize = 0000C73FH //這裡可以看到union只會選擇一個變量
VirtualAddress = 00001000H//這個十分十分重要 是虛擬空間中對齊後的位置
SizeOfRawData = 0000C800H //這個是數據大小(一定能被FileAlignment整除)
PointerToRawData = 00000400 //段在文件中的偏移
最後較為重要的是Characteristics = 60000020h
然後就下一張節的名,成員變量等等...直至終於所有節



以下是一些MSDN可以設置內存的一些屬性
0x00000020 表示這是代碼
0x00000040 表示此區域含有已初始化的變量,幾乎所有節/區塊都有這個設置,除了可執行區塊和.bss節
0x00000080 含有未被初始化的變量,如.bss節
0x00000200 表示節中含有注譯等的內容,一般用於.drectve節
0x00000800 他部分的內容不應該放在最後EXE文件。這些部分所使用的編譯器/彙編程序將信息傳遞給鏈接器。
0x02000000 此部分可以被丟棄,因為它不是所需要的過程一旦它被加載。最常見的可丟棄的部分是基重定位(.reloc節)。
0x10000000 處這一部分是共享的。當與一個DLL使用時,在此部分中的數據將使用DLL的所有進程之間共享。默認值是用於數據段進行非共享,這意味著使用DLL的每個進程都有自己的這一部分的數據副本。在更多的技術術語中,共享部分告訴內存管理器來設置這個部分,使得使用DLL的所有進程指代相同的物理頁存儲器中的頁的映射。為了使部分共享,使用鏈接時將SHARED屬性。例如
LINK/ SECTION:MYDATA,RWS...
告訴連接器調用MYDATA的部分應該是可讀,可寫和共享。

0x20000000處這部分是可執行的。每當“包含代碼”標誌(0x00000020)設置該標誌通常設置。
0x40000000的這一部分是可讀的。該標誌是幾乎總是設置為EXE文件的部分。
0x80000000的該部分寫入。如果該標誌不是一個EXE的部分設置,裝載機應
透過OR運算 可以得出最終的屬性



本節完

Comments

Post a Comment

Popular posts from this blog

Android Kernel Development - Kernel compilation and Hello World

How does Nested-Virtualization works?

Understanding ACPI and Device Tree