PE教程5: Section Table(节表)

2024-02-15 11:58
文章标签 教程 table pe section 节表

本文主要是介绍PE教程5: Section Table(节表),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PE教程5: Section Table(节表)

请下载 范例

理论:

到本课为止,我们已经学了许多关于 DOS header PE header 的知识。接下来就该轮到 section table(节表)了。节表其实就是紧挨着 PE header 的一结构数组。该数组成员的数目由 file header (IMAGE_FILE_HEADER) 结构中 NumberOfSections 域的域值来决定。节表结构又命名为 IMAGE_SECTION_HEADER

IMAGE_SIZEOF_SHORT_NAME equ 8

IMAGE_SECTION_HEADER STRUCT
   Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)
   union Misc
      PhysicalAddress dd ?
      VirtualSize dd ?
   ends
   VirtualAddress dd ?
   SizeOfRawData dd ?
   PointerToRawData dd ?
   PointerToRelocations dd ?
   PointerToLinenumbers dd ?

   NumberOfRelocations dw ?
   NumberOfLinenumbers dw ?
   Characteristics dd ?
IMAGE_SECTION_HEADER ENDS

同样,不是所有成员都是很有用的,我们只关心那些真正重要的。

FieldMeanings
Name1事实上本域的名称是"name",只是"name"已被MASM用作关键字,所以我们只能用"Name1"代替。这儿的节名长不超过8字节。记住节名仅仅是个标记而已,我们选择任何名字甚至空着也行,注意这里不用null结束。命名不是一个ASCIIZ字符串,所以不用null结尾。
VirtualAddress本节的RVA(相对虚拟地址)。PE装载器将节映射至内存时会读取本值,因此如果域值是1000h,而PE文件装在地址400000h处,那么本节就被载到401000h
SizeOfRawData经过文件对齐处理后节尺寸,PE装载器提取本域值了解需映射入内存的节字节数。(译者注: 假设一个文件的文件对齐尺寸是0x200,如果前面的 VirtualSize域指示本节长度是0x388字节,则本域值为0x400,表示本节是0x400字节长)。
PointerToRawData这是节基于文件的偏移量,PE装载器通过本域值找到节数据在文件中的位置。
Characteristics包含标记以指示节属性,比如节是否含有可执行代码、初始化数据、未初始数据,是否可写、可读等。

现在我们已知晓 IMAGE_SECTION_HEADER 结构,再来模拟一下 PE装载器的工作吧:

  1. 读取 IMAGE_FILE_HEADER NumberOfSections域,知道文件的节数目。
  2. SizeOfHeaders 域值作为节表的文件偏移量,并以此定位节表。
  3. 遍历整个结构数组检查各成员值。
  4. 对于每个结构,我们读取PointerToRawData域值并定位到该文件偏移量。然后再读取SizeOfRawData域值来决定映射内存的字节数。将VirtualAddress域值加上ImageBase域值等于节起始的虚拟地址。然后就准备把节映射进内存,并根据Characteristics域值设置属性。
  5. 遍历整个数组,直至所有节都已处理完毕。

注意我们并没有使用节名: 这其实并不重要。

示例:

本例程打开一PE文件遍历其节表,并在列表框控件显示各节的信息。

.386
.model flat,stdcall
option casemap:none
include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/comdlg32.inc
include /masm32/include/user32.inc
include /masm32/include/comctl32.inc
includelib /masm32/lib/comctl32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/comdlg32.lib

IDD_SECTIONTABLE equ 104
IDC_SECTIONLIST equ 1001

SEH struct


PrevLink dd ? ; the address of the previous seh structure
CurrentHandler dd ? ; the address of the new exception handler
SafeOffset dd ? ; The offset where it's safe to continue execution
PrevEsp dd ? ; the old value in esp
PrevEbp dd ? ; The old value in ebp
SEH ends

.data
AppName db "PE tutorial no.5",0
ofn OPENFILENAME <>
FilterString db "Executable Files (*.exe, *.dll)",0,"*.exe;*.dll",0
             db "All Files",0,"*.*",0,0
FileOpenError db "Cannot open the file for reading",0
FileOpenMappingError db "Cannot open the file for memory mapping",0
FileMappingError db "Cannot map the file into memory",0
FileInValidPE db "This file is not a valid PE",0
template db "%08lx",0
SectionName db "Section",0
VirtualSize db "V.Size",0
VirtualAddress db "V.Address",0
SizeOfRawData db "Raw Size",0
RawOffset db "Raw Offset",0
Characteristics db "Characteristics",0

.data?
hInstance dd ?
buffer db 512 dup(?)
hFile dd ?
hMapping dd ?
pMapping dd ?
ValidPE dd ?
NumberOfSections dd ?

.code
start proc
LOCAL seh:SEH
   invoke GetModuleHandle,NULL
   mov hInstance,eax
   mov ofn.lStructSize,SIZEOF ofn
   mov ofn.lpstrFilter, OFFSET FilterString
   mov ofn.lpstrFile, OFFSET buffer
   mov ofn.nMaxFile,512
   mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
   invoke GetOpenFileName, ADDR ofn
   .if eax==TRUE
      invoke CreateFile, addr buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
      .if eax!=INVALID_HANDLE_VALUE
         mov hFile, eax
         invoke CreateFileMapping, hFile, NULL, PAGE_READONLY,0,0,0
         .if eax!=NULL
            mov hMapping, eax
            invoke MapViewOfFile,hMapping,FILE_MAP_READ,0,0,0
            .if eax!=NULL
               mov pMapping,eax
               assume fs:nothing
               push fs:[0]
               pop seh.PrevLink
               mov seh.CurrentHandler,offset SEHHandler
               mov seh.SafeOffset,offset FinalExit
               lea eax,seh
               mov fs:[0], eax
               mov seh.PrevEsp,esp
               mov seh.PrevEbp,ebp
               mov edi, pMapping
               assume edi:ptr IMAGE_DOS_HEADER
               .if [edi].e_magic==IMAGE_DOS_SIGNATURE
                  add edi, [edi].e_lfanew
                  assume edi:ptr IMAGE_NT_HEADERS
                  .if [edi].Signature==IMAGE_NT_SIGNATURE
                     mov ValidPE, TRUE
                  .else
                     mov ValidPE, FALSE
                  .endif
               .else
                  mov ValidPE,FALSE
               .endif
FinalExit:
               push seh.PrevLink
               pop fs:[0]
               .if ValidPE==TRUE
                  call ShowSectionInfo
               .else
                  invoke MessageBox, 0, addr FileInValidPE, addr AppName, MB_OK+MB_ICONINFORMATION
               .endif
               invoke UnmapViewOfFile, pMapping
           .else
               invoke MessageBox, 0, addr FileMappingError, addr AppName, MB_OK+MB_ICONERROR
          .endif
          invoke CloseHandle,hMapping
       .else
          invoke MessageBox, 0, addr FileOpenMappingError, addr AppName, MB_OK+MB_ICONERROR
       .endif
       invoke CloseHandle, hFile
    .else
       invoke MessageBox, 0, addr FileOpenError, addr AppName, MB_OK+MB_ICONERROR
    .endif
  .endif
  invoke ExitProcess, 0
  invoke InitCommonControls
start endp

SEHHandler proc uses edx pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
   mov edx,pFrame
   assume edx:ptr SEH
   mov eax,pContext
   assume eax:ptr CONTEXT
   push [edx].SafeOffset
   pop [eax].regEip
   push [edx].PrevEsp
   pop [eax].regEsp
   push [edx].PrevEbp
   pop [eax].regEbp
   mov ValidPE, FALSE
   mov eax,ExceptionContinueExecution
   ret
SEHHandler endp

DlgProc proc uses edi esi hDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
   LOCAL lvc:LV_COLUMN
   LOCAL lvi:LV_ITEM
   .if uMsg==WM_INITDIALOG
      mov esi, lParam
      mov lvc.imask,LVCF_FMT or LVCF_TEXT or LVCF_WIDTH or LVCF_SUBITEM
      mov lvc.fmt,LVCFMT_LEFT
      mov lvc.lx,80
      mov lvc.iSubItem,0
      mov lvc.pszText,offset SectionName
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,0,addr lvc inc lvc.iSubItem
      mov lvc.fmt,LVCFMT_RIGHT
      mov lvc.pszText,offset VirtualSize
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,1,addr lvc
      inc lvc.iSubItem
      mov lvc.pszText,offset VirtualAddress
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,2,addr lvc
      inc lvc.iSubItem
      mov lvc.pszText,offset SizeOfRawData
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,3,addr lvc
      inc lvc.iSubItem
      mov lvc.pszText,offset RawOffset
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,4,addr lvc
      inc lvc.iSubItem
      mov lvc.pszText,offset Characteristics
      invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTCOLUMN,5,addr lvc
      mov ax, NumberOfSections
      movzx eax,ax
      mov edi,eax      
      mov lvi.imask,LVIF_TEXT
      mov lvi.iItem,0
      assume esi:ptr IMAGE_SECTION_HEADER
      .while edi>0
         mov lvi.iSubItem,0
         invoke RtlZeroMemory,addr buffer,9
         invoke lstrcpyn,addr buffer,addr [esi].Name1,8
         lea eax,buffer
         mov lvi.pszText,eax
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTITEM,0,addr lvi
         invoke wsprintf,addr buffer,addr template,[esi].Misc.VirtualSize
         lea eax,buffer
         mov lvi.pszText,eax
         inc lvi.iSubItem
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_SETITEM,0,addr lvi
         invoke wsprintf,addr buffer,addr template,[esi].VirtualAddress
         lea eax,buffer
         mov lvi.pszText,eax
         inc lvi.iSubItem
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_SETITEM,0,addr lvi
         invoke wsprintf,addr buffer,addr template,[esi].SizeOfRawData
         lea eax,buffer
         mov lvi.pszText,eax
         inc lvi.iSubItem
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_SETITEM,0,addr lvi
         invoke wsprintf,addr buffer,addr template,[esi].PointerToRawData
         lea eax,buffer
         mov lvi.pszText,eax
         inc lvi.iSubItem
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_SETITEM,0,addr lvi
         invoke wsprintf,addr buffer,addr template,[esi].Characteristics
         lea eax,buffer
         mov lvi.pszText,eax
         inc lvi.iSubItem
         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_SETITEM,0,addr lvi
         inc lvi.iItem
         dec edi
         add esi, sizeof IMAGE_SECTION_HEADER
      .endw
   .elseif
      uMsg==WM_CLOSE
         invoke EndDialog,hDlg,NULL
   .else
      mov eax,FALSE
      ret
   .endif
   mov eax,TRUE
   ret
DlgProc endp

ShowSectionInfo proc uses edi
   mov edi, pMapping
   assume edi:ptr IMAGE_DOS_HEADER
   add edi, [edi].e_lfanew
   assume edi:ptr IMAGE_NT_HEADERS
   mov ax,[edi].FileHeader.NumberOfSections
   movzx eax,ax
   mov NumberOfSections,eax
   add edi,sizeof IMAGE_NT_HEADERS
   invoke DialogBoxParam, hInstance, IDD_SECTIONTABLE,NULL, addr DlgProc, edi
   ret
ShowSectionInfo endp
end start

分析:

本例重用了PE教程2的代码,校验PE文件的有效性后,继续调用函数ShowSectionInfo显示各节信息。

ShowSectionInfo proc uses edi
   mov edi, pMapping
   assume edi:ptr IMAGE_DOS_HEADER
   add edi, [edi].e_lfanew
   assume edi:ptr IMAGE_NT_HEADERS

我们将edi用作指向PE文件数据的指针。首先,将指向DOS header地址的pMapping赋给edi,再加上e_lfanew域值等于PE header的地址。

   mov ax,[edi].FileHeader.NumberOfSections
   mov NumberOfSections,ax

因为我们要遍历节表,所以必须先获取文件的节数目。这就得靠file header里的NumberOfSections域了,切记这是个word域。

   add edi,sizeof IMAGE_NT_HEADERS

现在edi正指向PE header的起始地址,加上PE header结构大小后恰好指向节表了。

   invoke DialogBoxParam, hInstance, IDD_SECTIONTABLE,NULL, addr DlgProc, edi

调用 DialogBoxParam 显示列表对话框,注意我们已将节表地址作为最后一个参数传递过去了,该值可从WM_INITDIALOG 消息的lParam参数中提取。

在对话框过程里我们响应WM_INITDIALOG消息,将lParam(节表地址)存入esi,节数目赋给edi并设置列表控件。万事俱备后,进入循环将各节信息插入到列表控件中,这部分相当简单。

      .while edi>0
         mov lvi.iSubItem,0

字符串置入第一列。

         invoke RtlZeroMemory,addr buffer,9
         invoke lstrcpyn,addr buffer,addr [esi].Name1,8
         lea eax,buffer
         mov lvi.pszText,eax

要显示节名,当然要将其转换为ASCIIZ字符串先。

         invoke SendDlgItemMessage,hDlg,IDC_SECTIONLIST,LVM_INSERTITEM,0,addr lvi

然后显示第一列。
继续我们伟大的工程,显示完本节中最后一个欲呈现的值后,立马下一个结构。

         dec edi
         add esi, sizeof IMAGE_SECTION_HEADER
      .endw

每处理完一节就递减edi,然后将esi加上IMAGE_SECTION_HEADER 结构大小,使其指向下一个IMAGE_SECTION_HEADER 结构。

遍历节表的步骤:

  1. PE文件有效性校验。
  2. 定位到 PE header 的起始地址。
  3. file header NumberOfSections域获取节数。
  4. 通过两种方法定位节表: ImageBase+SizeOfHeaders 或者 PE header的起始地址+ PE header结构大小。 (节表紧随 PE header)。如果不是使用文件映射的方法,可以用SetFilePointer 直接将文件指针定位到节表。节表的文件偏移量存放在 SizeOfHeaders域里。(SizeOfHeaders IMAGE_OPTIONAL_HEADER 的结构成员)
  5. 处理每个 IMAGE_SECTION_HEADER 结构。

翻译:iamgufeng [Iczelion's Win32 Assembly Homepage][LuoYunBin's Win32 ASM Page]

这篇关于PE教程5: Section Table(节表)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/711329

相关文章

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

spring AMQP代码生成rabbitmq的exchange and queue教程

《springAMQP代码生成rabbitmq的exchangeandqueue教程》使用SpringAMQP代码直接创建RabbitMQexchange和queue,并确保绑定关系自动成立,简... 目录spring AMQP代码生成rabbitmq的exchange and 编程queue执行结果总结s

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地

MySQL CTE (Common Table Expressions)示例全解析

《MySQLCTE(CommonTableExpressions)示例全解析》MySQL8.0引入CTE,支持递归查询,可创建临时命名结果集,提升复杂查询的可读性与维护性,适用于层次结构数据处... 目录基本语法CTE 主要特点非递归 CTE简单 CTE 示例多 CTE 示例递归 CTE基本递归 CTE 结

电脑提示d3dx11_43.dll缺失怎么办? DLL文件丢失的多种修复教程

《电脑提示d3dx11_43.dll缺失怎么办?DLL文件丢失的多种修复教程》在使用电脑玩游戏或运行某些图形处理软件时,有时会遇到系统提示“d3dx11_43.dll缺失”的错误,下面我们就来分享超... 在计算机使用过程中,我们可能会遇到一些错误提示,其中之一就是缺失某个dll文件。其中,d3dx11_4

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本