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)。可执行文件或者不能重定向的文件该字段应该为0。
PointerToLinenumbers指向节中行号项的相对映像基址偏移(RA)。因为已经不推荐在PE文件中包含调试信息,所以该字段一般为0。
NumberOfRelocations是节中重定位项的个数。可执行文件和不可以重定位的文件该字段为0。
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文件格式分析——RVA和RA相互计算
之前几节一直是理论性质的东西非常多.本文将会讲到利用之前的知识得出一个一个非常有用的一个应用.(转载请指明来源于breaksoftware的csdn博客) 首先我们说下磁盘上A.exe文件和正在内存中 ...
- PE文件和COFF文件格式分析——导出表
在之前的<PE可选文件头>相关博文中我们介绍了可选文件头中很多重要的属性,而其中一个非常重要的属性是(转载请指明来源于breaksoftware的CSDN博客) IMAGE_DATA_DI ...
- PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL
通过导出表隐性加载DLL?导出表?加载DLL?还隐性?是的.如果觉得不可思议,可以先看<PE文件和COFF文件格式分析--导出表>中关于"导出地址表"的详细介绍.(转载 ...
- PE文件和COFF文件格式分析--概述
刚工作的时候,我听说某某大牛在做病毒分析时,只是用notepad打开病毒文件,就能大致猜到病毒的工作原理.当时我是佩服的很啊,同时我也在心中埋下了一个种子:我也得有这天.随着后来的工作进行,一些任务的 ...
- PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法
在日常应用中,某些程序往往会被第三方程序下钩子(hook).如果被下钩子的进程是我们的进程,并且第三方钩子严重影响了我们的逻辑和流程,我们就需要把这些钩子摘掉(Unhook).本件讲述一种在32位系统 ...
- PE文件和COFF文件格式分析——导出表的应用——一种插件模型
可能在很多人想想中,只有DLL才有导出表,而Exe不应该有导出表.而在<PE文件和COFF文件格式分析--导出表>中,我却避开了这个话题.我就是想在本文中讨论下载Exe中存在导出表的场景. ...
- PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头1
本文将讨论PE文件中非常重要的一部分信息.(转载请指明来源于breakSoftware的CSDN博客) 首先说一下VC中对应的数据结构."签名.COFF文件头和可选文件头"这三部分 ...
- PE文件和COFF文件格式分析--MS-DOS 2.0兼容Exe文件段
MS 2.0节是PE文件格式中第一个"节".其大致结构如下:(转载请指明来源于breaksoftware的csdn博客) 在VC\PlatformSDK\Include\WinNT ...
- PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3
<PE2>中介绍了一些可选文件头中重要的属性,为了全面起见,本文将会讲解那些不是那么重要的属性.虽然不重要,但是还是可以发现很多好玩的情况.首先看一下32位的可选文件头详细定义.(转载请指 ...
最新文章
- 沈阳人才市场7月精品招聘会
- 比较MongoDB在公有云上的性能:AWS、Azure和Digital Ocean
- 学完了python能做什么-学会Python后都能做什么?网友们的回答简直不要太厉害
- 图像检索系统 Image Retrieval Systems
- 农业走出去-国际农民丰收节贸易会·刘合光:走向全球思考
- python函数封装总结_python 笔记 之 函数封装成类
- Unity计划放弃支持部分图形特性
- Dynamic Clock in Terminal.
- 操作系统——Windows 控制台命令
- 高数18讲_1000题错题总结_第三四讲
- SAP ABAP开发入门-徐春波-专题视频课程
- TDD(测试驱动开发)工作流程:
- 怎样去除抖音短视频的水印,快速去除视频水印的方法
- 搜款网根据关键词取商品列表 API 返回值说明
- 简单说一下http的优点和缺点?
- XMAN misc writeup
- Sftp和ftp 区别、工作原理等(汇总ing)
- 详解sprintf()sprintf_s()
- openfire的入门学习
- Nginx服务器部署
热门文章
- MySQL如何快速插入数据
- 齐次坐标的理解(2)
- 工业物联网LCD数码屏的驱动原理及低功耗设计(华大半导体HC32L136)
- AI玩俄罗斯方块(Python实现)
- 深度学习--TensorFlow(6)神经网络 -- 拟合线性函数非线性函数
- C++中的两种绑定方式(静态绑定、动态绑定)
- CMake结合PCL库学习(2)
- 设置VSCode打开键盘快捷方式和键盘快捷方式配置JSON分别快捷键为:Ctrl+Alt+K和Shift+Alt+K
- 在Ubuntu 16.04.6 LTS上安装python3.7和pip3后出现Command '('lsb_release', '-a')' 出错问题的解决方法
- ceph 部署单机集群