寫在前面
此係列是本人一個字一個字碼出來的,包括程式碼實現和效果截圖。 如有好的建議,歡迎反饋。碼字不易,如果本篇文章有幫助你的,如有閒錢,可以打賞支援我的創作。如想轉載,請把我的轉載資訊附在文章後面,並宣告我的個人資訊和本人部落格地址即可,但必須事先通知我。
你如果是從中間插過來看的,請仔細閱讀 羽夏殼世界——序 ,方便學習本教程。
概述
在學習PE
結構之前,我們來大體看一下它的整體結構:
初步學習PE
檔案,可能看的比較頭大。如果你學習過程式語言的話,可以這麼說:PE 檔案是由一堆結構體和其他資料堆積起來的 。在學習本教程時,建議安裝010 Editor
可以更方便的學習PE
結構,不過該軟體是商用的。使用該軟體主要是用了它的模板功能,如果是指定型別的檔案,它也會主動匹配型別並提示使用相應的模板,如下所示是使用模板之後的效果:
PE
檔案有兩種狀態,一個是在磁碟以檔案的形式進行儲存,另一個就是在記憶體中,如下圖所示:
為什麼這麼說呢?是因為有對齊
這個概念,什麼是對齊如果不會建議自己進行查閱,這個無論是程式語言還是作業系統基礎中非常重要的概念,我就不在這裡絮叨了。對於為什麼有兩種狀態,之後的博文將會介紹。
在PE
結構中,有一個十分重要的概念就是RVA
和FOA
。RVA
英文全稱為Relative Virtual Address
,即相對虛擬地址;FOA
英文全稱為File Offset Address
,即檔案偏移地址。就是因為PE
有兩種狀態,所以會有這兩種偏移地址。當然還有一個VA
,英文全稱為Virtual Address
,意為絕對的虛擬地址,也就是絕對值,是幾就是幾。而RVA
需要基址才能準確定位到VA
。有關RVA
、FOA
和VA
之間的相互轉化,將會到下一篇繼續。
IMAGE_DOS_HEADER
該結構體的結構如下:
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;
這個結構體是歷史遺留的產物,因為開始的時候是DOS
系統,上面除了最後一個成員e_lfanew
,其他的都是給16位DOS
程式看的。不過第一個成員e_magic
被作為合法PE
檔案的校驗值,值為IMAGE_DOS_SIGNATURE
/0x5A4D
/"MZ"
。
e_lfanew
為檔案偏移,指向了IMAGE_NT_HEADERS
結構,這個就是我們真正可以跑在現在圖形介面的Windows
程式必須有的結構,我們來看一個程式與此部分相關的結構示意圖如下:
DosStub
接在IMAGE_DOS_HEADER
結構體後面是被稱之為DosStub
的,我們能夠看到一個字串This program cannot be run in DOS mode
,意為該程式不能夠在Dos
模式下執行。這裡面其實不是垃圾資料,而是有意義的彙編程式碼,我們用16位反彙編器來看一下:
seg000:0000 seg000 segment byte public 'CODE' use16
seg000:0000 assume cs:seg000
seg000:0000 assume es:nothing, ss:seg000, ds:nothing, fs:nothing, gs:nothing
seg000:0000
seg000:0000 ; =============== S U B R O U T I N E =======================================
seg000:0000
seg000:0000 public start
seg000:0000 start proc near
seg000:0000 push cs
seg000:0001 pop ds
seg000:0002 assume ds:seg000
seg000:0002 mov dx, 0Eh
seg000:0005 mov ah, 9
seg000:0007 int 21h ; DOS - PRINT STRING
seg000:0007 ; DS:DX -> string terminated by "$"
seg000:0009 mov ax, 4C01h
seg000:000C int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
seg000:000C start endp ; AL = exit code
seg000:000C
seg000:000C ; ---------------------------------------------------------------------------
seg000:000E aThisProgramCan db 'This program cannot be run in DOS mode.',0Dh,0Dh,0Ah
seg000:000E db '$',0
seg000:003A align 8
seg000:0040 db 0A9h, 2Ch, 93h, 71h, 0EDh, 4Dh, 0FDh, 22h, 0EDh, 4Dh
seg000:0040 db 0FDh, 22h, 0EDh, 4Dh, 0FDh, 22h, 8Fh, 35h, 0FCh, 23h
seg000:0040 db 0EEh, 4Dh, 0FDh, 22h, 8Fh, 35h, 0F8h, 23h, 0F5h, 4Dh
seg000:0040 db 0FDh, 22h, 8Fh, 35h, 0F9h, 23h, 0E7h, 4Dh, 0FDh, 22h
seg000:0040 db 8Fh, 35h, 0FEh, 23h, 0EEh, 4Dh, 0FDh, 22h, 3Eh, 3Fh
seg000:0040 db 0FCh, 23h, 0E9h, 4Dh, 0FDh, 22h, 0EDh, 4Dh, 0FCh, 22h
seg000:0040 db 0AAh, 4Dh, 0FDh, 22h, 6Dh, 34h, 0F9h, 23h, 0ECh, 4Dh
seg000:0040 db 0FDh, 22h, 6Dh, 34h, 2, 22h, 0ECh, 4Dh, 0FDh, 22h, 6Dh
seg000:0040 db 34h, 0FFh, 23h, 0ECh, 4Dh, 0FDh, 22h, 52h, 69h, 63h
seg000:0040 db 68h, 0EDh, 4Dh, 0FDh, 22h, 8 dup(0)
seg000:00A8 db 10h dup(?)
seg000:00A8 seg000 ends
seg000:00A8
seg000:00A8
seg000:00A8 end start
注意一定要使用16位
的反彙編器,否則無論是在32位是64位下,所有的程式碼都是錯誤的。
上面的程式碼如果沒有《微機原理》的基礎可能有點難懂,這裡就補充一下:int 21h
是Dos
下的中斷,類似表示我要呼叫API
了,不同的AH
暫存器的值表示呼叫的函式是不一樣的。如果是9
,表示在螢幕上列印字串,不過這個字串不是用\0
結尾的,而是$
,和我們現代作業系統的\0
的作用是一樣的。如果AH
的值為0x4C
,則表示將AL
作為返回值結束程式,和我們C語言
編寫main
函式中的return 0;
是一個道理。
有關該部分就介紹到這裡。
IMAGE_NT_HEADERS
該結構體在32位和64位程式是有所不同的,只不過是結構體的成員大小的區別,如下所示:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
Signature
是一個十分重要的成員。PE
指紋的第二部分,值為IMAGE_NT_SIGNATURE
/0x00004550
/"PE"
。如果值是錯誤的,同樣被判定為非法PE
檔案。
FileHeader
是標準PE頭,大小為20個位元組,可以通過IMAGE_SIZEOF_FILE_HEADER
巨集獲取,具體細節後面將會介紹。
OptionalHeader
是擴充套件PE頭,雖然名字帶著可選,但它是必需結構。
我們再來看看它在二進位制檔案下的位置:
IMAGE_FILE_HEADER
該結構體在32位和64位的程式是一樣的,如下所示:
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Machine
指示可以執行在什麼樣的CPU
上,它的值如下:
任意CPU
:IMAGE_FILE_MACHINE_UNKNOWN
/0x0000
;Intel 386以及後續CPU
:IMAGE_FILE_MACHINE_I386
/0x014C
;x64
:IMAGE_FILE_MACHINE_AMD64
/0x8664
。
下面是其中的所有成員:
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
NumberOfSections
指示節的數量,它十分重要。
TimeDateStamp
指示編譯器填寫的時間戳與檔案屬性裡面建立時間
/修改時間
無關,計算的是當前時間與1970年0時0點0分
差的秒數。
PointerToSymbolTable
/NumberOfSymbols
與除錯相關,不做關注。
SizeOfOptionalHeader
表示擴充套件PE頭的大小,可以修改合適的數值。在預設情況下,32位PE
檔案:0xE0
,64位PE
檔案:0xF0
。
Characteristics
指示了檔案屬性,它的值有如下:
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
我們再來看看它在二進位制檔案下的位置:
IMAGE_OPTIONAL_HEADER
這個結構體在32位和64位是有區別的,是某些成員的大小區別,它們的結構如下:
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags; //除錯相關
DWORD NumberOfRvaAndSizes; //目錄表的個數(決定DataDirectory陣列長度)
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
Magic
標識程式的位數。32位程式為值為IMAGE_NT_OPTIONAL_HDR32_MAGIC
/0x10b
,64位程式為值為IMAGE_NT_OPTIONAL_HDR64_MAGIC
/0x20b
。它是判斷程式位數的關鍵屬性。
AddressOfEntryPoint
的值表示程式入口RVA
,十分重要。
ImageBase
表示該PE
比較傾向的記憶體映象載入基址,比較重要。對於DLL
這個值通常並不被作業系統採納,如果開啟了隨機基址的EXE
也是如此。
SectionAlignment
表示記憶體對齊值,十分重要。
FileAlignment
表示檔案對齊值,十分重要。
SizeOfImage
表示記憶體中整個PE
檔案的對映的尺寸,可比實際的值大,必須是SectionAlignment
的整數倍,十分重要。
SizeOfHeaders
所有頭和節表按照檔案對齊後的大小,否則載入會出錯,這十分重要。
CheckSum
表示校驗和,一些系統檔案有要求用來判斷檔案是否被修改。
Subsystem
意為子系統,驅動程式值為1
,圖形介面值為2
,控制檯、DLL值為3
。下面是其列舉:
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 //
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17
DllCharacteristics
是檔案特性,不是針對DLL
檔案的,該成員是比較重要的,基址重定位就是從這個成員進行設定的。下面是其列舉:
// IMAGE_LIBRARY_PROCESS_INIT 0x0001 // Reserved.
// IMAGE_LIBRARY_PROCESS_TERM 0x0002 // Reserved.
// IMAGE_LIBRARY_THREAD_INIT 0x0004 // Reserved.
// IMAGE_LIBRARY_THREAD_TERM 0x0008 // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 // Image does not use SEH. No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
DataDirectory
是儲存表位置大小的陣列。不同的索引代表不同的表的資料,下面是其列舉:
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
我們再來看看它在二進位制檔案下的位置:
IMAGE_SECTION_HEADER
IMAGE_SECTION_HEADER
是節區頭,是重要的結構體,在32位和64位下的程式沒有區別。大小可通過IMAGE_SIZEOF_SECTION_HEADER
獲取,在記憶體的展開大小 = Max(Misc,SizeOfRawData)
。如果此節為已初始化的變數,則 Misc > SizeOfRawData
;若節為未初始化的變數則 Misc < SizeOfRawData
。如下是結構體成員:
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
Name
表示節區名稱,ASCII
字串,可自定義,只擷取8個。
Misc
表示該節在沒有對齊前的真實尺寸,該值可以不準確。
VirtualAddress
是在記憶體中的偏移地址,加上lmageBase
才是在記憶體中的真正地址,十分重要。
PointerToRawData
是節區在檔案中的偏移,十分重要。
PointerToRelocations
/PointerToRelocations
/NumberOfRelocations
/PointerToLinenumbers
與除錯相關,不關注。
Characteristics
是節的屬性。下面是其列舉:
// IMAGE_SCN_TYPE_REG 0x00000000 // Reserved.
// IMAGE_SCN_TYPE_DSECT 0x00000001 // Reserved.
// IMAGE_SCN_TYPE_NOLOAD 0x00000002 // Reserved.
// IMAGE_SCN_TYPE_GROUP 0x00000004 // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
// IMAGE_SCN_TYPE_COPY 0x00000010 // Reserved.
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
// IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
// 0x00002000 // Reserved.
// IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL 0x00008000 // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA 0x00008000
// IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 //
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 //
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 //
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 //
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 //
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 //
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 //
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 //
#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 //
#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 //
#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 //
#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 //
#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 //
// Unused 0x00F00000
#define IMAGE_SCN_ALIGN_MASK 0x00F00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
我們再來看看它在二進位制檔案下的位置:
IMAGE_DATA_DIRECTORY
IMAGE_DATA_DIRECTORY
是十分重要的結構體,具體重要性的體現已經在IMAGE_OPTIONAL_HEADER
介紹過了,如下是其結構:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
VirtualAddress
是指表在記憶體的RVA
,十分重要。
Size
是指IMAGE_DATA_DIRECTORY
結構體和其使用的所有資料之和,該值不會影響程式的執行。
我們再來看看它在二進位制檔案下的位置:
小結
本篇我們只介紹了基本結構體,對於後面比較複雜的幾個表和地址轉化,考慮到比較複雜,挪到下一篇進行。
看完本篇文章一定要把在16進位制下看明白結構,最好用自己熟悉的程式語言寫一個解析上面所述結構體的解析器,以鞏固自己的學習成果。