PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3
? ? ? ? 《PE2》中介紹了一些可選文件頭中重要的屬性,為了全面起見,本文將會講解那些不是那么重要的屬性。雖然不重要,但是還是可以發現很多好玩的情況。首先看一下32位的可選文件頭詳細定義。(轉載請指明來源于breaksoftware的CSDN博客)
typedef struct _IMAGE_OPTIONAL_HEADER {//// Standard fields.//WORD Magic;BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;DWORD SizeOfInitializedData;DWORD SizeOfUninitializedData;DWORD AddressOfEntryPoint;DWORD BaseOfCode;DWORD BaseOfData;//// NT additional fields.//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;IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
? ? ? ? 64位版本和32位版本很類似:沒有BaseOfCode屬性;ImageBase、SizeofStackReserve、SizeOfStackCommit、SizeOfHeapReserve和SizeOfHeapCommit等5個屬性由32位版的DWORD改成ULONGLONG。看下詳細的64位版定義
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;
? ? ? ? Magic字段是可選文件頭幻數,0x10b是32位版,0x20b是64位版。注意該屬性不能說明這個文件是64位文件還是32位文件,至于判斷是多少位文件的方案我在《PE2》中已經有了說明。
? ? ? ??MajorLinkerVersion和MinorLinkerVersion分別對應于鏈接器的版本號,比如我電腦上VS2005編譯的文件的這兩個版本號是8.0;VS2008編譯的是9.0;VS2010編譯的是10.0。
? ? ? ??MajorOperatingSystemVersion和MinorOperatingSystemVersion是所需要的最低的系統版本號的主版本號和次版本號。我看了下我電腦上文件,基本上是4.0。
? ? ? ? MajorImageVersion和MinorImageVersion是映像文件的主版本號和次版本號。注意:我們在資源中定義的文件版本號不是通過這兩個屬性來體現的!目前我也沒找到在VC工程設置中可以設置這兩個屬性的地方。
? ? ? ??Subsystem是該文件運行于的子系統信息。一般我們在windows平臺上遇到的是2,它對應于IMAGE_SUBSYSTEM_WINDOWS_GUI。
? ? ? ??MajorSubsystemVersion和MinorSubsystemVersion是子系統的版本號。熟悉windows的朋友應該知道,微軟剛開始設計系統時,是設計成一個平臺性質——可以運行3個子系統(OS/2、POSIX和Windows)的系統。這個就是這兩個屬性的由來。
? ? ? ??SectionAlignment是當映像文件加載到內存中時節的對齊值,該大小使用字節來衡量的。它必須要大于我們之后介紹的FileAlignment。它的默認值是相應系統的頁面大小。
? ? ? ??FileAlignment 是映像文件節中的對齊值,它也是用字節來衡量的。英文文檔中說該字段的值要在2^9 ~ 2^16之間,我掃描了下我的系統,發現我系統中文件并不是如此,特別是sys文件,它們的FileAlignment小于2^9(512)。
? ? ? ? SizeOfCode是文件中代碼段的總共大小。要注意一點,這個大小和.text的大小不一定一致,因為有些代碼可能還保存在其他節中。如我電腦上AliAppLoader.exe文件,其SizeOfCode大小是0x1D600,而.text節大小只有0x1D400,另外的0x200是在.orpc這個節中。
? ? ? ??SizeOfInitializedData是文件中所有已經初始化數據節的大小。和SizeOfCode一樣,初始化數據不一定只在一個節中。
? ? ? ??SizeOfUninitializedData是文件中所有未初始化數據節的大小。和SizeOfCode一樣,未初始化數據不一定只在一個節中。
? ? ? ??Win32VersionValue是保留字段,應該為0。那么目前這個字段就是程序不關心的了,我們可以利用這個位置保存一些私密信息。
? ? ? ??SizeOfImage的官方說明是該映像文件被加載入內存時的大小,理論上它應該是SectionAlignment的倍數。但是實際并非如此,我發現我電腦上很多文件的該字段不是SectionAlignment的倍數,而有時SizeOfImage是該文件在磁盤上的大小。可以見得這個不是一個關鍵字段。
if ( m_lpFileEnd - m_lpFileStart != m_dwSizeOfImage ) {_ASSERT(FALSE);}
? ? ? ??SizeOfHeaders的官方解釋是MS-DOS占位程序、PE文件頭和節頭的總大小,且其應該是FileAlignment的倍數。但是實際上,我發現我電腦上很多文件的該字段并非FileAlignment的倍數。 ? ? ? ?
DWORD dwHeaderSize = (DWORD)(m_lpPEStart - m_lpFileStart) + (DWORD)(sizeof(IMAGE_FILE_HEADER)) + (DWORD) ( m_FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));DWORD dwTmp = m_dwFileAlignment - 1;dwHeaderSize = (dwHeaderSize + dwTmp) &~dwTmp;if ( dwHeaderSize != m_dwSizeOfHeaders ) {//_ASSERT(FALSE);}
? ? ? ??CheckSum字段是映像文件的校驗和。其計算算法保存在imagehlp.dll中,導出函數名為CheckSumMappedFile。我發現我電腦上很多文件的該PE字段和計算出來的不等。官方解釋說當驅動程序、在引導時被加載的Dll以及加載到關鍵windows進程中的DLL都需要校驗該字段以確認其合法性。
typedef PIMAGE_NT_HEADERS(WINAPI *PCheckSumMappedFile)( PVOID, DWORD, PDWORD, PDWORD );HMODULE hModule = LoadLibrary(L"imagehlp.dll");if ( NULL == hModule ) {_ASSERT(FALSE);}PCheckSumMappedFile pCheckSumMappedFile = (PCheckSumMappedFile) GetProcAddress( hModule, "CheckSumMappedFile" );if ( NULL == pCheckSumMappedFile ) {_ASSERT(FALSE);}DWORD dwHeaderSum = 0;DWORD dwCheckSum = 0;PIMAGE_NT_HEADERS lpImgNtHeader = pCheckSumMappedFile( m_lpFileStart, (DWORD)(m_lpFileEnd - m_lpFileStart), &dwHeaderSum, &dwCheckSum );if ( m_dwCheckSum != dwCheckSum ) {// 不等的很多//_ASSERT(FALSE);}if ( NULL != hModule ) {FreeLibrary(hModule);hModule = NULL;}
? ? ? ??SizeOfStackReserve、SizeOfStackCommit、SizeOfHeapReserve和SizeOfHeapCommit分別對應于保留的棧大小、提交的棧大小、保留的堆大小和提交的堆大小。
? ? ? ??LoaderFlags字段是保留字段,應該為0,當然你可以不把它設為0。
? ? ? ??NumberOfRvaAndSizes是用來指明DataDirectory元素的個數。這兒我們要說一下,我們在IMAGE_FILE_HEADER::SizeOfOptionalHeader得到了可選文件頭的大小,而影響可選文件頭大小的就是DataDirectory元素的個數(NumberOfRvaAndSizes),那么IMAGE_FILE_HEADER::SizeOfOptionalHeader和NumberOfRvaAndSizes之間應該存在著一種換算關系。的確,理論上 換算關系是:
SizeOfOptionalHeader == offsetof(IMAGE_OPTIONAL_HEADER32(64),NumberOfRvaAndSizes) + NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY)
? ? ? ? 我跑了下我電腦上的所有文件,發現這個關系是一直成立的。這應該是種強關系。
? ? ? ??DllCharacteristics是屬性字段,我們看個官方說明
| Constant | Value | Description |
| ? | 0x0001 | Reserved, must be zero. |
| ? | 0x0002 | Reserved, must be zero. |
| ? | 0x0004 | Reserved, must be zero. |
| ? | 0x0008 | Reserved, must be zero. |
| IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE | 0x0040 | DLL can be relocated at load time. |
| IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY | 0x0080 | Code Integrity checks are enforced. |
| IMAGE_DLL_CHARACTERISTICS_NX_COMPAT | 0x0100 | Image is NX compatible. |
| IMAGE_DLLCHARACTERISTICS_ NO_ISOLATION | 0x0200 | Isolation aware, but do not isolate the image. |
| IMAGE_DLLCHARACTERISTICS_ NO_SEH | 0x0400 | Does not use structured exception (SE) handling. No SE handler may be called in this image. |
| IMAGE_DLLCHARACTERISTICS_ NO_BIND | 0x0800 | Do not bind the image. |
| ? | 0x1000 | Reserved, must be zero. |
| IMAGE_DLLCHARACTERISTICS_ WDM_DRIVER | 0x2000 | A WDM driver. |
| IMAGE_DLLCHARACTERISTICS_ TERMINAL_SERVER_AWARE | 0x8000 | Terminal Server aware. |
? ? ? ? MAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE是說Dll可以在加載時被重定向,我發現我電腦上文件SDKDBLib.dll是特例,它沒有設置這個屬性,這個文件也沒有設置IMAGE_DLLCHARACTERISTICS_ NO_SEH,即該文件不使用SEH。
總結
以上是生活随笔為你收集整理的PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PE文件和COFF文件格式分析——签名、
- 下一篇: PE文件和COFF文件格式分析——节信息