PE文件和COFF文件格式分析——节信息
? ? ? ? 在《PE文件和COFF文件格式分析——簽名、COFF文件頭和可選文件頭3》中,我們看到一些區塊的信息都有偏移指向。而我們本文討論的節信息是沒有任何偏移指向的,所以它是緊跟在可選文件頭后面的。(轉載請注明來源于breaksoftware的csdn博客)于是該節的起始位置要如此計算
size_t unDwordSize = sizeof(DWORD); // PE\0\0
size_t unImgFileHeaderSize = sizeof(IMAGE_FILE_HEADER);
LPVOID lpSectionHeaderStart = (LPBYTE)m_lpPEStart + unDwordSize + unImgFileHeaderSize + m_FileHeader.SizeOfOptionalHeader;
? ? ? ? 有了起始地址,那么結束地址呢?在《PE文件和COFF文件格式分析——簽名、COFF文件頭和可選文件頭1》中,我們描述過,IMAGE_FILE_HEADER::NumberOfSections就是用于指定該節信息的個數的。這樣我們便可以得到節信息
size_t unSectionHeaderSize = sizeof( IMAGE_SECTION_HEADER );
for ( int i = 0; i < m_FileHeader.NumberOfSections; i++ ) {IMAGE_SECTION_HEADER SectionHeader;if ( FALSE == SafeCopy( &SectionHeader, lpSectionHeaderStart, unSectionHeaderSize ) ) {break;}// 不夠嚴謹哦!不要這么用! m_vecSectionHeaders.push_back( SectionHeader );lpSectionHeaderStart = (LPBYTE)(lpSectionHeaderStart) + unSectionHeaderSize;
}
? ? ? ? 像Stud_PE和PE Explorer等都是這么做的。但是我這兒說一下,這樣做是不嚴謹的,我會在之后論述這樣草率的做法為什么不對。
? ? ? ? 我先拿我電腦上notepad.exe為例,看看它的節信息
? ? ? ? 再看下保存節信息的結構體IMAGE_SECTION_HEADER ,和上圖對照看就容易理解了。
#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是使用UTF-8編碼,以\0結尾,大小為8Byte的字符串。它是節的名稱,如上圖中的.text、.data和.rsrc。看到Name的長度為8,你是不是在想到:小于,等于和大于?現在我們就討論下如果節名長度小于、等于和大于8的情況。
? ? ? ? 節名長度小于8 的情況。這個場景最簡單了,不足的位用\0填充。
? ? ? ? 節名長度等于8的情況。因為結構大小是固定的,所以我們不可能找到一個空余的位置放置\0,那么這8byte就全部填充名字了。
? ? ? ? 以下是我收集的節名信息
IMAGESETCTIONNAME g_ImageSectionName[] = {{'.','b','s','s','\0','\0','\0','\0'},{'.','c','o','r','m','e','t','a'},{'.','d','a','t','a','\0','\0','\0'},{'.','d','e','b','u','g','$','F'},{'.','d','e','b','u','g','$','P'},{'.','d','e','b','u','g','$','S'},{'.','d','e','b','u','g','$','T'},{'.','d','r','e','c','t','v','e'},{'.','e','d','a','t','a','\0','\0'},{'.','i','d','a','t','a','\0','\0'},{'.','i','d','l','s','y','m','\0'},{'.','p','d','a','t','a','\0','\0'},{'.','r','d','a','t','a','\0','\0'},{'.','r','e','l','o','c','\0','\0'},{'.','r','s','r','c','\0','\0','\0'},{'.','s','b','s','s','\0','\0','\0'},{'.','s','d','a','t','a','\0','\0'},{'.','s','r','d','a','t','a','\0'},{'.','s','x','d','a','t','a','\0'},{'.','t','e','x','t','\0','\0','\0'},{'.','t','l','s','\0','\0','\0','\0'},{'.','t','l','s','$','\0','\0','\0'},{'.','v','s','d','a','t','a','\0'},{'.','x','d','a','t','a','\0','\0'}
};
? ? ? ? ?像.debug$F這樣的就是占用了8個byte的
? ? ? ? 節名長度大于8的情況。這個場景怎么辦?結構體大小固定,我們不能越界寫!那我們只能在其他地方去寫了,然后在這個位置保存我們寫入數據的偏移即可!是的,PE規范就是采用的這樣的思想,只是稍微有點不同:以/開始,其后跟著一個表示偏移量的十進制數字字符串,如/4(0x2f 0 0x34 0x00 0x00?0x00?0x00?0x00?0x00)。這個數字是相對字符串表起始位置的偏移RA,我們的真實的節名就保存在字符串表中。我在我電腦上找到一個這樣的文件avcodec-52.dll。我們先看Stud_PE的分析結果
? ? ? ? 可以看到Stud_PE對第5節的名字的解析是錯的的,那正確的是什么?現在我們要回顧《PE文件和COFF文件格式分析——簽名、COFF文件頭和可選文件頭1》,該文中我埋了一個伏筆,我把段提出來
? ? ? ? PointerToSymbolTable是0x00000000,該字段記錄了該PE文件中調試信息符號表。由于符號表信息是在程序運行時不需要加載進入內存的,所以這個偏移使用的是相對文件頭偏移RA。目前微軟推薦是:將映像文件調試符號表信息獨立的放在PDB文件中,所以不會在PE文件中再保存調試符號表信息,于是這個字段應該為0。當然這并不是硬性要求,我發現我電腦上就存在很多該字段不為0的文件。剛開始時我也不是很明白它們為什么要使用這個字段,特別是其指向的字符表個數(NumberOfSymbols)為0!!你說既然大小為0,那你指向有什么意思呢?其實這種設計是非常有深意的,我會在之后的章節中介紹這種深意。
? ? ? ? NumberOfSymbols是0x00000000,該字段記錄了該PE文件中調試信息符號表元素個數。對于映像文件,該字段為0(非硬性要求),,理由在PointerToSymbolTable中已經說明。通過NumberOfSymbols和PointerToSymbolTable,我們可以找到字符串表起始位置,因為字符串表緊跟在符號表之后。 ?
? ? ? ? 看了這段后,我想你應該對那個伏筆有了解答。想想也挺有意思,微軟不推薦在文件中包含調試信息,于是PointerToSymbolTable和NumberOfSymbols就是應該廢棄的??墒沁@兩個數據卻關聯著字符串表。字符串表大部分時候可以不使用,但是如果DLL中存在超過8byte的節名時又不得不用,于是只好讓PointerToSymbolTable指向字符串表開始,而NumberOfSymbols為0。
? ? ? ? 現在我們來看下上面那個Stud_PE分析出錯的文件的文件頭信息
? ? ? ? 我們去0x001c1600+4的位置去尋找該節名字,該節名位.eh_frame,長度是9byte。
? ? ? ? 這兒要特別說明一點,可執行文件的節名長度是不會超過8的。即使obj文件中節名存在超過8的,也會在鏈接進入可執行文件時被截斷。
? ? ? ? VirtualSize屬性是節加載進入內存后,節在內存中的大小。如果它比SizeOfRawData大,則多余的部分是用0x00填充的。這個性質非常重要,它是關系到RVA和RA之間換算的一個基礎。
? ? ? ??
? ? ? ? VirtualAddress屬性是節加載進入內存后其第一個字節相對于映像基址的偏移(RVA)。
? ? ? ? SizeOfRawData是磁盤映像文件中該節的已初始化數據的大小。對于可執行文件來說,它必須是IMAGE_OPTIONAL_HEADER32(64)::FileAlignment的倍數。.如果該節中僅包含未初始化的數據,則該字段為0。
? ? ? ? PointerToRawData是磁盤映像文件中該節相對于映像基址的偏移(RA)。對于可執行文件來說,它的值要是IMAGE_OPTIONAL_HEADER32(64)::FileAlignment的倍數。如果該節中僅包含未初始化的數據,則該字段為0。
? ? ? ??PointerToRelocations指向節中重定位項開頭的相對映像基址的偏移(RA)??蓤绦形募蛘卟荒苤囟ㄏ虻奈募撟侄螒摓?。
? ? ? ? PointerToLinenumbers指向節中行號項的相對映像基址偏移(RA)。因為已經不推薦在PE文件中包含調試信息,所以該字段一般為0。
? ? ? ? NumberOfRelocations是節中重定位項的個數??蓤绦形募筒豢梢灾囟ㄎ坏奈募撟侄螢?。
? ? ? ? NumberOfLinenumbers是節中行號項的個數。因為已不推薦PE文件中包含調試信息,所以該字段一般為0。
? ? ? ? Characteristics描述節的特征。
?
| Flag | Value | Description |
| ? | 0x00000000 | Reserved for future use. |
| ? | 0x00000001 | Reserved for future use. |
| ? | 0x00000002 | Reserved for future use. |
| ? | 0x00000004 | Reserved for future use. |
| IMAGE_SCN_TYPE_NO_PAD | 0x00000008 | The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. |
| ? | 0x00000010 | Reserved for future use. |
| IMAGE_SCN_CNT_CODE | 0x00000020 | The section contains executable code. |
| IMAGE_SCN_CNT_INITIALIZED_DATA | 0x00000040 | The section contains initialized data. |
| IMAGE_SCN_CNT_UNINITIALIZED_ DATA | 0x00000080 | The section contains uninitialized data. |
| IMAGE_SCN_LNK_OTHER | 0x00000100 | Reserved for future use. |
| IMAGE_SCN_LNK_INFO | 0x00000200 | The section contains comments or other information. The .drectve section has this type. This is valid for object files only. |
| ? | 0x00000400 | Reserved for future use. |
| IMAGE_SCN_LNK_REMOVE | 0x00000800 | The section will not become part of the image. This is valid only for object files. |
| IMAGE_SCN_LNK_COMDAT | 0x00001000 | The section contains COMDAT data. For more information, see section 5.5.6, “COMDAT Sections (Object Only).” This is valid only for object files. |
| IMAGE_SCN_GPREL | 0x00008000 | The section contains data referenced through the global pointer (GP). |
| IMAGE_SCN_MEM_PURGEABLE | 0x00020000 | Reserved for future use. |
| IMAGE_SCN_MEM_16BIT | 0x00020000 | For ARM machine types, the section contains Thumb code.? Reserved for future use with other machine types. |
| IMAGE_SCN_MEM_LOCKED | 0x00040000 | Reserved for future use. |
| IMAGE_SCN_MEM_PRELOAD | 0x00080000 | Reserved for future use. |
| IMAGE_SCN_ALIGN_1BYTES | 0x00100000 | Align data on a 1-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_2BYTES | 0x00200000 | Align data on a 2-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_4BYTES | 0x00300000 | Align data on a 4-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_8BYTES | 0x00400000 | Align data on an 8-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_16BYTES | 0x00500000 | Align data on a 16-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_32BYTES | 0x00600000 | Align data on a 32-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_64BYTES | 0x00700000 | Align data on a 64-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_128BYTES | 0x00800000 | Align data on a 128-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_256BYTES | 0x00900000 | Align data on a 256-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_512BYTES | 0x00A00000 | Align data on a 512-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_1024BYTES | 0x00B00000 | Align data on a 1024-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_2048BYTES | 0x00C00000 | Align data on a 2048-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_4096BYTES | 0x00D00000 | Align data on a 4096-byte boundary. Valid only for object files. |
| IMAGE_SCN_ALIGN_8192BYTES | 0x00E00000 | Align data on an 8192-byte boundary. Valid only for object files. |
| IMAGE_SCN_LNK_NRELOC_OVFL | 0x01000000 | The section contains extended relocations. |
| IMAGE_SCN_MEM_DISCARDABLE | 0x02000000 | The section can be discarded as needed. |
| IMAGE_SCN_MEM_NOT_CACHED | 0x04000000 | The section cannot be cached. |
| IMAGE_SCN_MEM_NOT_PAGED | 0x08000000 | The section is not pageable. |
| IMAGE_SCN_MEM_SHARED | 0x10000000 | The section can be shared in memory. |
| IMAGE_SCN_MEM_EXECUTE | 0x20000000 | The section can be executed as code. |
| IMAGE_SCN_MEM_READ | 0x40000000 | The section can be read. |
| IMAGE_SCN_MEM_WRITE | 0x80000000 | The section can be written to. |
? ? ? ??IMAGE_SCN_LNK_NRELOC_OVFL 標志表明節中重定位項的個數超出了節頭中為每個節保留的16 位所能表示的范圍。如果設置了此標志并且節頭中的NumberOfRelocations 域的值是0xffff,那么實際的重定位項個數被保存在第一個重定位項的VirtualAddress 域(32 位)中。如果設置了IMAGE_SCN_LNK_NRELOC_OVFL
標志但節中的重定位項的個數少于0xffff,則表示出現了錯誤。
? ? ? ? 最后貼一下Section節的獲取算法
BOOL CGetPEInfo::GetSectionHeaders()
{GETPESTART();BOOL bSuc = FALSE;do {size_t unDwordSize = sizeof(DWORD); // PE\0\0size_t unImgFileHeaderSize = sizeof(IMAGE_FILE_HEADER);LPVOID lpSectionHeaderStart = (LPBYTE)m_lpPEStart + unDwordSize + unImgFileHeaderSize + m_FileHeader.SizeOfOptionalHeader;size_t unSectionHeaderSize = sizeof( IMAGE_SECTION_HEADER );for ( int i = 0; i < m_FileHeader.NumberOfSections; i++ ) {IMAGE_SECTION_HEADER SectionHeader;if ( FALSE == SafeCopy( &SectionHeader, lpSectionHeaderStart, unSectionHeaderSize ) ) {break;}IMAGE_SECTION_HEADERINFO SectionHeaderInfo;if ( '/' == SectionHeader.Name[0]) {std::string szOffsetStringTable;szOffsetStringTable.assign( &SectionHeader.Name[1], &SectionHeader.Name[IMAGE_SIZEOF_SHORT_NAME-1]);int nOffsetString = atoi( szOffsetStringTable.c_str() );LPSTR lpSetcionNameStart = (LPSTR)m_lpFileStart + m_FileHeader.PointerToSymbolTable;lpSetcionNameStart += (DWORD)(sizeof(IMAGE_SYMBOL) * m_FileHeader.NumberOfSymbols);lpSetcionNameStart += nOffsetString;SectionHeaderInfo.szSectionName = lpSetcionNameStart;if ( 0 != m_FileHeader.NumberOfSymbols ) {//_ASSERT(FALSE); }}m_vecSectionHeaders.push_back( SectionHeader );SectionHeaderInfo.ImgSecHD = SectionHeader;m_vecSetcionHeaderInfo.push_back(SectionHeaderInfo);lpSectionHeaderStart = (LPBYTE)(lpSectionHeaderStart) + unSectionHeaderSize;}bSuc = TRUE;} while (0);return bSuc;
}
?
總結
以上是生活随笔為你收集整理的PE文件和COFF文件格式分析——节信息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PE文件和COFF文件格式分析——签名、
- 下一篇: PE文件和COFF文件格式分析——RVA