PE节表详细分析
PE节表详细分析
0x00 前言
上一篇文章我们学习了PE结构中的PE头,我之前说过PE文件结构是PE头->节表->每个节,所以我们掌握了节表后也就知道怎么去获取每个节了。(当然后面还有输入表,输出表这些比较重要的东西。这些知识在后面的文章详细介绍。)
0x01 PE节表分析
节表结构
PE节表位于PE头的下面,PE节表中记录了各个节表的起始位置、大小,以及在内存中偏移位置和属性。
其结构体如下:
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//*[1]:节名
union {
DWORD PhysicalAddress;
DWORD VirtualSize; //*[2]:对其前节大小,内存中节大小
} Misc;//联合体
DWORD VirtualAddress; //*[3]:内存中偏移
DWORD SizeOfRawData; //*[4]:文件对其后节大小
DWORD PointerToRawData; //*[5]:文件中节位置
DWORD PointerToRelocations;//
DWORD PointerToLinenumbers;//
WORD NumberOfRelocations; //
WORD NumberOfLinenumbers; //
DWORD Characteristics; //*[6]:节属性的标志
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
节表数量
节表数量不在节表中,而是在上一篇文章中已经介绍过,在标准PE头中。标准PE头中有一个成员是NumberOfSections
他是节表的数量。
节表名字
节表名字是各个节表的第一个成员,首先我们根据PE头大小来确定节表所在位置即DOS头+垃圾数据+NT头
,下面在010Editor演示具体数据。
节表中第一个数据是节名
,节名一共占用的数据大小是8个字节
, 演示中第一个节名是.text
。
节表大小
节表中真实的大小在VirtualAddress
中,也就是节名后的4个字节。他所代表的意思是对其前的大小也是在内存中的大小。
而在他后4四节之后的4字节数据,代表的是对其后的大小也是文件中的大小SizeOfRawData
。
节位置
节位置都是在节大小之后,占用大小也是为4字节。VirualAddress
后的4字节代表的是内存中节偏移
,SizeOfRawData
后的4字节代表的是文件中节位置
。
在内存中锁定具体的节位置需要内存地址
+节偏移
得到的地址才是真实的内存节所在的位置,而在文件中的节位置则可以根据地址直接索引到,不需要+文件地址因为文件地址开始就是0。
内存地址在可选PE头的ImageBase
中,所以我们需要先获取到ImageBase的值这里是0x00400000
,所以加上偏移位置就是0x00401000
。
一般程序在没有被修改的情况下,默认.text
段就是程序用来放代码的地方。所以我们也可以用OD直接载入程序,然后跳到.text段的位置可以看到程序的汇编代码。
(小知识:OD载入程序就是模拟了程序拉伸的过程,程序在内存中的样子。)
节表属性
节表中的最后一个数据也是最重要的,他代表了这个节是否可读
、可写
、可执行
或者是否包含可执行代码、初始化、未初始化
的数据。所以一般我们判断一个段是否是代码段就是根据这个属性的值来判断的,因为节表名是可以改的,比如我把随便一个节表名改成.text、.code。那你就觉得他是代码段了吗?
代码段的属性一般是0x60000020
,其中这4字节的数据,他每一位都对应下面表格中的数据。下面我们把0x60000020
来拆分一下,首先最后2位对应下面的包含可执行代码
的数据,然后最高位的6
对应下面的(该块可执行)+(该块可读)
的值。所以代码段的属性就是:(包括可执行代码)、(可执行)、(可读)
。
--> 标志(属性块) 常用特征值对照表:<--
[值:00000020h](*包含可执行代码)
[值:00000040h](*该块包含已初始化的数据)
[值:00000080h](*该块包含未初始化的数据)
[值:00000200h][Section contains comments or some other type of information.]
[值:00000800h][Section contents will not become part of image.]
[值:00001000h][Section contents comdat.]
[值:00004000h][Reset speculative exceptions handling bits in the TLB entries for this section.]
[值:00008000h][Section content can be accessed relative to GP.]
[值:00500000h][Default alignment if no others are specified.]
[值:01000000h][Section contains extended relocations.]
[值:02000000h][Section can be discarded.]
[值:04000000h][Section is not cachable.]
[值:08000000h][Section is not pageable.]
[值:10000000h](*该块为共享块).
[值:20000000h](*该块可执行)
[值:40000000h](*该块可读)
[值:80000000h](*该块可写)
0x02 代码编写
在最后我们还是用代码来写个工具,之前写过解析PE头的数据了,所以继续解析就是节表的数据了。
节表解析整体思路是:
- (1)、先得到节数量 NumberOfSections
- (2)、循环次数=节数量
- (3)、安装节的结构体来解析每个节的数据
- (4)、输出相应的数据显示到控制台中
vector<IMAGE_SECTION_HEADER_2> vsection_header;
//解析节表
for (size_t i = 0; i < IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections; i++)
{
IMAGE_SECTION_HEADER_2 aa;
fread(&aa, sizeof(aa), 1, fp);
vsection_header.push_back(aa);
}
//打印节中的数据
printf("---------------节表数据----------------\n");
cout << "节数量:" << IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections << endl;
for (size_t i = 0; i < IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections; i++)
{
printf("--> %s段信息 <--\n", vsection_header[i].Name);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("*[内存中段大小]:0x%x\n", vsection_header[i].Misc.VirtualSize);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("*[内存中偏移]:0x%x\n", vsection_header[i].VirtualAddress);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("*[文件中段大小]:0x%x\n", vsection_header[i].SizeOfRawData);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("*[文件中偏移]:0x%x\n", vsection_header[i].PointerToRawData);
SetConsoleTextAttribute(handle, 0x07);
printf("[OBJ重定位偏移]:0x%x\n", vsection_header[i].PointerToRelocations);
printf("[OBJ重定位项数目]:0x%x\n", vsection_header[i].NumberOfRelocations);
printf("[行号表偏移]:0x%x\n", vsection_header[i].PointerToLinenumbers);
printf("[行号表中的数目]:0x%x\n", vsection_header[i].NumberOfLinenumbers);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("*[标志|属性]:0x%x ", vsection_header[i].Characteristics);
//区段的属性
DWORD l_Charctieristics = (BYTE)((DWORD)(vsection_header[i].Characteristics) & 0xFF);
DWORD h_Charctieristics = (BYTE)(((DWORD)(vsection_header[i].Characteristics) >> 24) & 0xFF);
vector<byte> l_flag;
vector<byte> h_flag;
//低位
l_flag.push_back((l_Charctieristics >> 7) ? 3 : 0);
l_flag.push_back((l_Charctieristics >> 6) & 1 ? 2 : 0);
l_flag.push_back((l_Charctieristics >> 5) & 1 ? 1 : 0);
//高位
h_flag.push_back((h_Charctieristics >> 7) ? 7 : 0);
h_flag.push_back((h_Charctieristics >> 6) & 1 ? 6 : 0);
h_flag.push_back((h_Charctieristics >> 5) & 1 ? 5 : 0);
h_flag.push_back((h_Charctieristics >> 4) & 1 ? 4 : 0);
//包含数据情况
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
for (vector<byte>::iterator iter = l_flag.begin(); iter != l_flag.end(); iter++)
{
switch (*iter)
{
case 1:
cout << "(包含可执行代码),";
break;
case 2:
cout << "(包含已初始化数据),";
break;
case 3:
cout << "(包含未初始化数据),";
break;
default:
break;
}
}
//可读写执行情况
for (vector<byte>::iterator iter = h_flag.begin(); iter != h_flag.end(); iter++)
{
switch (*iter)
{
case 4:
cout << "(共享),";
break;
case 5:
cout << "(可执行),";
break;
case 6:
cout << "(可读),";
break;
case 7:
cout << "(可写),";
break;
default:
break;
}
}
cout << endl << endl;;
SetConsoleTextAttribute(handle, 0x07);
}
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
printf("--> 标志(属性块) 常用特征值对照表:<--\n");
printf("[值:00000020h](*包含可执行代码)\n");//IMAGE_SCN_CNT_CODE
printf("[值:00000040h](*该块包含已初始化的数据)\n");//IMAGE_SCN_CNT_INITIALIZED_DATA
printf("[值:00000080h](*该块包含未初始化的数据)\n");//IMAGE_SCN_CNT_UNINITIALIZED_DATA
printf("[值:00000200h][Section contains comments or some other type of information.]\n");//IMAGE_SCN_LNK_INFO
printf("[值:00000800h][Section contents will not become part of image.]\n");//IMAGE_SCN_LNK_REMOVE
printf("[值:00001000h][Section contents comdat.]\n");//IMAGE_SCN_LNK_COMDAT
printf("[值:00004000h][Reset speculative exceptions handling bits in the TLB entries for this section.]\n");//IMAGE_SCN_NO_DEFER_SPEC_EXC
printf("[值:00008000h][Section content can be accessed relative to GP.]\n");// IMAGE_SCN_GPREL
printf("[值:00500000h][Default alignment if no others are specified.]\n");//IMAGE_SCN_ALIGN_16BYTES
printf("[值:01000000h][Section contains extended relocations.]\n");//IMAGE_SCN_LNK_NRELOC_OVFL
printf("[值:02000000h][Section can be discarded.]\n");//IMAGE_SCN_MEM_DISCARDABLE
printf("[值:04000000h][Section is not cachable.]\n");//IMAGE_SCN_MEM_NOT_CACHED
printf("[值:08000000h][Section is not pageable.]\n");//IMAGE_SCN_MEM_NOT_PAGED
printf("[值:10000000h](*该块为共享块).\n");//IMAGE_SCN_MEM_SHARED
printf("[值:20000000h](*该块可执行)\n");//IMAGE_SCN_MEM_EXECUTE
printf("[值:40000000h](*该块可读)\n");//IMAGE_SCN_MEM_READ
printf("[值:80000000h](*该块可写)\n\n");// IMAGE_SCN_MEM_WRITE
SetConsoleTextAttribute(handle, 0x07);//IMAGE_SCN_MEM_WRITE
运行结果:
最后欢迎加群:
PE节表详细分析的更多相关文章
- STM32向量表详细分析
预备知识: DCD指令:用于分配一片连续的字存储单元(32bit),并将表达式的值初始化给该字存储单元,类似于C中定义数组并初始化.比如: DCD 0 的意思是:分配一个字存储单元,并将该单元初始化为 ...
- PE节表
- 小甲鱼PE详解之区块表(节表)和区块(节)续(PE详解05)
这一讲我们结合实例来谈谈区块表的定义以及各个属性的含义. 首先,我们先用之前学过的一点知识在二进制文件中手动翻找区块表,这样做的好处是可以使你很快的对PE结构牢记于心.学来的东西就是能用的东西,不能用 ...
- PE头详细分析
目录 PE头详细分析 0x00 前言 0x01 PE文件介绍 0x02 PE头详细分析 DOS头解析 NT头解析 标准PE头解析 可选PE头解析 可选PE头结构 基址 代码段地址 数据段地址 OEP程 ...
- 小甲鱼PE详解之区块表(节表)和区块(节)(PE详解04)
到此为止,小甲鱼和大家已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到SectionTable (区块表,也成节表).(视频教程:http://fishc.com ...
- 破解软件系列-PE文件深入浅出之Section Table节表
我们已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到 section table(节表)了.节表其实就是紧挨着 PE header 的一结构数组.该数组成员的数目 ...
- PE文件格式---节和节表
17.1.4 节表和节 从排列位置来看,PE文件在DOS部分和PE文件头部分以后就是节表和多个不同的节(如图17.1中的③和④所示).要理解什么是节表,什么是节以及它们之间的关系,那就首先要了解Wi ...
- PE文件格式详解,第三讲,可选头文件格式,以及节表
PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...
- PE格式第五讲,手工添加节表
PE格式第五讲,手工添加节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 首先我们要用汇编编写一段汇编代码,用来生成 ...
随机推荐
- VS 2019下载、安装与注册包含MF、界面美化和安装Visual Assist
下载: 1.在搜索框中输入"微软" 2. 3. 安装: 1.双击运行-继续-等待安装完成 2. 3.安装完后,重启电脑,并创建快捷方式. 注册: 1.打开软件 2. 3. 4.网上 ...
- Redis限流
在电商开发过程中,我们很多地方需要做限流,有的是从Nginx上面做限流,有的是从代码层面限流等,这里我们就是从代码层面用Redis计数器做限流,这里我们用C#语言来编写,且用特性(过滤器,拦截器)的形 ...
- tomcat URI get 参数中文传到后台 乱码 URIEncoding
* 修改tomcat server.xml 找到这一行 <Connector connectionTimeout="20000" port="80" pr ...
- P4770-[NOI2018]你的名字【SAM,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/P4770 题目大意 给出一个长度为\(n\)的字符串\(S\).\(q\)次询问给出一个串\(T\)和一个区间\([ ...
- JDK源码阅读(4):HashMap类阅读笔记
HashMap public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, ...
- mapboxgl 纠偏百度地图
缘起 之前分享了mapboxgl 互联网地图纠偏插件,插件当时只集成了高德地图. 文章发布后,有小伙伴在后台留言,希望插件也能支持百度地图. 刚好国庆假期有时间就研究了一下. 插件加载瓦片原理 首先, ...
- Hadoop面试题总结(三)——MapReduce
1.谈谈Hadoop序列化和反序列化及自定义bean对象实现序列化? 1)序列化和反序列化 (1)序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储(持久化)和网络传输. (2) ...
- SudokuSolver 1.0:用C++实现的数独解题程序 【一】
SudokuSolver 1.0 用法与实现效果 SudokuSolver 是一个提供命令交互的命令行程序,提供的命令清单有: H:\Read\num\Release>sudoku.exe Or ...
- Windows Terminal 和 WSL
Windows Terminal ,配置启动目录为 WSL : \\wsl$\Ubuntu\home
- perl合并文件
使用Perl合并文件 有时需要将整个目录下的小文件合并到一个文件中,以便查阅检索 特性 整个目录完全遍历,自动存入单个文件顺序遍历文件 待合并的目录 合并后的文件内容 syscfg/test1 sys ...