PE节表详细分析

0x00 前言

上一篇文章我们学习了PE结构中的PE头,我之前说过PE文件结构是PE头->节表->每个节,所以我们掌握了节表后也就知道怎么去获取每个节了。(当然后面还有输入表,输出表这些比较重要的东西。这些知识在后面的文章详细介绍。)

0x01 PE节表分析

节表结构

PE节表位于PE头的下面,PE节表中记录了各个节表的起始位置、大小,以及在内存中偏移位置和属性。

其结构体如下:

  1. #define IMAGE_SIZEOF_SHORT_NAME 8
  2. typedef struct _IMAGE_SECTION_HEADER {
  3. BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//*[1]:节名
  4. union {
  5. DWORD PhysicalAddress;
  6. DWORD VirtualSize; //*[2]:对其前节大小,内存中节大小
  7. } Misc;//联合体
  8. DWORD VirtualAddress; //*[3]:内存中偏移
  9. DWORD SizeOfRawData; //*[4]:文件对其后节大小
  10. DWORD PointerToRawData; //*[5]:文件中节位置
  11. DWORD PointerToRelocations;//
  12. DWORD PointerToLinenumbers;//
  13. WORD NumberOfRelocations; //
  14. WORD NumberOfLinenumbers; //
  15. DWORD Characteristics; //*[6]:节属性的标志
  16. } 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对应下面的(该块可执行)+(该块可读)的值。所以代码段的属性就是:(包括可执行代码)、(可执行)、(可读)

  1. --> 标志(属性块) 常用特征值对照表:<--
  2. [值:00000020h](*包含可执行代码)
  3. [值:00000040h](*该块包含已初始化的数据)
  4. [值:00000080h](*该块包含未初始化的数据)
  5. [值:00000200h][Section contains comments or some other type of information.]
  6. [值:00000800h][Section contents will not become part of image.]
  7. [值:00001000h][Section contents comdat.]
  8. [值:00004000h][Reset speculative exceptions handling bits in the TLB entries for this section.]
  9. [值:00008000h][Section content can be accessed relative to GP.]
  10. [值:00500000h][Default alignment if no others are specified.]
  11. [值:01000000h][Section contains extended relocations.]
  12. [值:02000000h][Section can be discarded.]
  13. [值:04000000h][Section is not cachable.]
  14. [值:08000000h][Section is not pageable.]
  15. [值:10000000h](*该块为共享块).
  16. [值:20000000h](*该块可执行)
  17. [值:40000000h](*该块可读)
  18. [值:80000000h](*该块可写)

0x02 代码编写

在最后我们还是用代码来写个工具,之前写过解析PE头的数据了,所以继续解析就是节表的数据了。

节表解析整体思路是:

  • (1)、先得到节数量 NumberOfSections
  • (2)、循环次数=节数量
  • (3)、安装节的结构体来解析每个节的数据
  • (4)、输出相应的数据显示到控制台中
  1. vector<IMAGE_SECTION_HEADER_2> vsection_header;
  2. //解析节表
  3. for (size_t i = 0; i < IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections; i++)
  4. {
  5. IMAGE_SECTION_HEADER_2 aa;
  6. fread(&aa, sizeof(aa), 1, fp);
  7. vsection_header.push_back(aa);
  8. }
  9. //打印节中的数据
  10. printf("---------------节表数据----------------\n");
  11. cout << "节数量:" << IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections << endl;
  12. for (size_t i = 0; i < IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections; i++)
  13. {
  14. printf("--> %s段信息 <--\n", vsection_header[i].Name);
  15. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
  16. printf("*[内存中段大小]:0x%x\n", vsection_header[i].Misc.VirtualSize);
  17. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
  18. printf("*[内存中偏移]:0x%x\n", vsection_header[i].VirtualAddress);
  19. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
  20. printf("*[文件中段大小]:0x%x\n", vsection_header[i].SizeOfRawData);
  21. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
  22. printf("*[文件中偏移]:0x%x\n", vsection_header[i].PointerToRawData);
  23. SetConsoleTextAttribute(handle, 0x07);
  24. printf("[OBJ重定位偏移]:0x%x\n", vsection_header[i].PointerToRelocations);
  25. printf("[OBJ重定位项数目]:0x%x\n", vsection_header[i].NumberOfRelocations);
  26. printf("[行号表偏移]:0x%x\n", vsection_header[i].PointerToLinenumbers);
  27. printf("[行号表中的数目]:0x%x\n", vsection_header[i].NumberOfLinenumbers);
  28. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
  29. printf("*[标志|属性]:0x%x ", vsection_header[i].Characteristics);
  30. //区段的属性
  31. DWORD l_Charctieristics = (BYTE)((DWORD)(vsection_header[i].Characteristics) & 0xFF);
  32. DWORD h_Charctieristics = (BYTE)(((DWORD)(vsection_header[i].Characteristics) >> 24) & 0xFF);
  33. vector<byte> l_flag;
  34. vector<byte> h_flag;
  35. //低位
  36. l_flag.push_back((l_Charctieristics >> 7) ? 3 : 0);
  37. l_flag.push_back((l_Charctieristics >> 6) & 1 ? 2 : 0);
  38. l_flag.push_back((l_Charctieristics >> 5) & 1 ? 1 : 0);
  39. //高位
  40. h_flag.push_back((h_Charctieristics >> 7) ? 7 : 0);
  41. h_flag.push_back((h_Charctieristics >> 6) & 1 ? 6 : 0);
  42. h_flag.push_back((h_Charctieristics >> 5) & 1 ? 5 : 0);
  43. h_flag.push_back((h_Charctieristics >> 4) & 1 ? 4 : 0);
  44. //包含数据情况
  45. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
  46. for (vector<byte>::iterator iter = l_flag.begin(); iter != l_flag.end(); iter++)
  47. {
  48. switch (*iter)
  49. {
  50. case 1:
  51. cout << "(包含可执行代码),";
  52. break;
  53. case 2:
  54. cout << "(包含已初始化数据),";
  55. break;
  56. case 3:
  57. cout << "(包含未初始化数据),";
  58. break;
  59. default:
  60. break;
  61. }
  62. }
  63. //可读写执行情况
  64. for (vector<byte>::iterator iter = h_flag.begin(); iter != h_flag.end(); iter++)
  65. {
  66. switch (*iter)
  67. {
  68. case 4:
  69. cout << "(共享),";
  70. break;
  71. case 5:
  72. cout << "(可执行),";
  73. break;
  74. case 6:
  75. cout << "(可读),";
  76. break;
  77. case 7:
  78. cout << "(可写),";
  79. break;
  80. default:
  81. break;
  82. }
  83. }
  84. cout << endl << endl;;
  85. SetConsoleTextAttribute(handle, 0x07);
  86. }
  87. SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
  88. printf("--> 标志(属性块) 常用特征值对照表:<--\n");
  89. printf("[值:00000020h](*包含可执行代码)\n");//IMAGE_SCN_CNT_CODE
  90. printf("[值:00000040h](*该块包含已初始化的数据)\n");//IMAGE_SCN_CNT_INITIALIZED_DATA
  91. printf("[值:00000080h](*该块包含未初始化的数据)\n");//IMAGE_SCN_CNT_UNINITIALIZED_DATA
  92. printf("[值:00000200h][Section contains comments or some other type of information.]\n");//IMAGE_SCN_LNK_INFO
  93. printf("[值:00000800h][Section contents will not become part of image.]\n");//IMAGE_SCN_LNK_REMOVE
  94. printf("[值:00001000h][Section contents comdat.]\n");//IMAGE_SCN_LNK_COMDAT
  95. printf("[值:00004000h][Reset speculative exceptions handling bits in the TLB entries for this section.]\n");//IMAGE_SCN_NO_DEFER_SPEC_EXC
  96. printf("[值:00008000h][Section content can be accessed relative to GP.]\n");// IMAGE_SCN_GPREL
  97. printf("[值:00500000h][Default alignment if no others are specified.]\n");//IMAGE_SCN_ALIGN_16BYTES
  98. printf("[值:01000000h][Section contains extended relocations.]\n");//IMAGE_SCN_LNK_NRELOC_OVFL
  99. printf("[值:02000000h][Section can be discarded.]\n");//IMAGE_SCN_MEM_DISCARDABLE
  100. printf("[值:04000000h][Section is not cachable.]\n");//IMAGE_SCN_MEM_NOT_CACHED
  101. printf("[值:08000000h][Section is not pageable.]\n");//IMAGE_SCN_MEM_NOT_PAGED
  102. printf("[值:10000000h](*该块为共享块).\n");//IMAGE_SCN_MEM_SHARED
  103. printf("[值:20000000h](*该块可执行)\n");//IMAGE_SCN_MEM_EXECUTE
  104. printf("[值:40000000h](*该块可读)\n");//IMAGE_SCN_MEM_READ
  105. printf("[值:80000000h](*该块可写)\n\n");// IMAGE_SCN_MEM_WRITE
  106. SetConsoleTextAttribute(handle, 0x07);//IMAGE_SCN_MEM_WRITE

运行结果:

最后欢迎加群:

PE节表详细分析的更多相关文章

  1. STM32向量表详细分析

    预备知识: DCD指令:用于分配一片连续的字存储单元(32bit),并将表达式的值初始化给该字存储单元,类似于C中定义数组并初始化.比如: DCD 0 的意思是:分配一个字存储单元,并将该单元初始化为 ...

  2. PE节表

  3. 小甲鱼PE详解之区块表(节表)和区块(节)续(PE详解05)

    这一讲我们结合实例来谈谈区块表的定义以及各个属性的含义. 首先,我们先用之前学过的一点知识在二进制文件中手动翻找区块表,这样做的好处是可以使你很快的对PE结构牢记于心.学来的东西就是能用的东西,不能用 ...

  4. PE头详细分析

    目录 PE头详细分析 0x00 前言 0x01 PE文件介绍 0x02 PE头详细分析 DOS头解析 NT头解析 标准PE头解析 可选PE头解析 可选PE头结构 基址 代码段地址 数据段地址 OEP程 ...

  5. 小甲鱼PE详解之区块表(节表)和区块(节)(PE详解04)

    到此为止,小甲鱼和大家已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到SectionTable (区块表,也成节表).(视频教程:http://fishc.com ...

  6. 破解软件系列-PE文件深入浅出之Section Table节表

    我们已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到 section table(节表)了.节表其实就是紧挨着 PE header 的一结构数组.该数组成员的数目 ...

  7. PE文件格式---节和节表

    17.1.4  节表和节 从排列位置来看,PE文件在DOS部分和PE文件头部分以后就是节表和多个不同的节(如图17.1中的③和④所示).要理解什么是节表,什么是节以及它们之间的关系,那就首先要了解Wi ...

  8. PE文件格式详解,第三讲,可选头文件格式,以及节表

    PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...

  9. PE格式第五讲,手工添加节表

    PE格式第五讲,手工添加节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 首先我们要用汇编编写一段汇编代码,用来生成 ...

随机推荐

  1. webpack4一些设置

    一.sourceMap: 是一个映射关系,如果出错可以知道实际文件行数出错 在webpack.config.js设置属性 devtool: 'source-map' 在生产环境可以设置为(提醒错误比较 ...

  2. (转载)深入理解MDL元数据锁

    作者:MySQL技术本文为作者原创,转载请注明出处:https://www.cnblogs.com/kunjian/p/11993708.html 前言: 当你在MySQL中执行一条SQL时,语句并没 ...

  3. centos7 .net core 使用supervisor守护进程后台运行

    安装supervisor yum install supervisor 配置supervisor vi /etc/supervisord.conf 拉到最后,这里的意思是 /etc/superviso ...

  4. php flush() 页面缓冲及时输出 每隔一秒输出页面输出

    <?php //方案一 ob_end_clean(); echo str_pad('', 1024); // 设置足够大,大过php.ini的output_buffering设置值 for ($ ...

  5. WebMagic 爬虫技术

    WebMagic WebMagic 介绍 WebMagic基础架构 Webmagic 的结构分为 Downloader.PageProcessor.Scheduler.Pipeline四大组件,并由 ...

  6. 改头换面为哪般,最像Android的Windows——Win11升级安装体验

    在过完了十一小长假之后,各位打工人.学僧党可期待的不仅仅是新一轮的工作,Windows11也在10月5日悄悄正式发布,正式版已经面向MSDN订阅用户开放下载. 作为微软金牌合作伙伴,本葡萄已在第一时间 ...

  7. [AGC023D] Go Home 题解

    题目传送门 Solution 首先排除掉特殊情况:若 \(S\) 在两侧,肯定会顺序/逆序直接走完,答案就是边界减去出发点. 考虑到若 \(P_1\geq P_n\),那么显然 \(1\) 不到家 \ ...

  8. FastAPI 学习之路(十二)接口几个额外信息和额外数据类型

    系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...

  9. Winform同步调用异步函数死锁原因分析、为什么要用异步

    1.前言 几年前,一个开发同学遇到同步调用异步函数出现死锁问题,导致UI界面假死.我解释了一堆,关于状态机.线程池.WindowsFormsSynchronizationContext.Post.co ...

  10. Poetry(1)Poetry介绍与安装

    介绍 Poetry 是Python 中的依赖管理和打包工具,当然它也可以配置虚拟环境.它允许您声明项目所依赖的库,并为您管理(安装/更新)它们. 之前一直使用virtualenvwrapper管理虚拟 ...