我们已经学了许多关于 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

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

Field

Meanings

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 结构。

破解软件系列-PE文件深入浅出之Section Table节表的更多相关文章

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

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

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

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

  3. 破解软件感悟-PE文件格式之实例总结(五)

    有很多介绍PE文件的文章,但是我打算写一篇关于输入表的文章,因为它对于破解很有用.     我想解释它的最好的方法是举一个例子,你可以跟着我逐步深入,一步一步的思考,最后你将完全明白,我选择了一个我刚 ...

  4. 分配粒度和内存页面大小(x86处理器平台的分配粒度是64K,内存页是4K,所以section都是0x1000对齐,硬盘扇区大小是512字节,所以PE文件默认文件对齐是0x200)

    分配粒度和内存页面大小 x86处理器平台的分配粒度是64K,32位CPU的内存页面大小是4K,64位是8K,保留内存地址空间总是要和分配粒度对齐.一个分配粒度里包含16个内存页面. 这是个概念,具体不 ...

  5. 打造XP下可运行的微型PE文件

    前几天和朋友交流技术,提到手工打造微型PE文件,他说现在网上流传的大部分版本在XP SP3下都不能运行,于是心血来潮,拍着胸脯说:“你放心,忙完了帮你做一个.”后来花了半天时间,终于打造出一个XP下可 ...

  6. 深入学习PE文件(转)

    PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. 基本结构. 上图便是PE文件的基本结构.(注意:DO ...

  7. 深入剖析PE文件

    不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一.   ...

  8. 解析PE文件

    最近在自学解析PE文件,根据小辣椒(CFF Explorer)以及各论坛上大佬的帖子,做了个黑屏打印PE文件的,历时7天完成,在此想跟有相关需要的同学们分享下思路,有不足之处也希望大家不吝赐教,指点出 ...

  9. PE文件的执行顺序

    当一个PE文件被执行时,PE装载器首先检查DOS MZ header里的PE header的偏移量.如果找到,则直接跳转到PE header的位置. 当PE装载器跳转到PE header后,第二步要做 ...

随机推荐

  1. css去掉a标签点击后的虚线框(转自网络)

    outline是css3的一个属性,用的很少. 声明,这是个不能兼容的css属性,在ie6.ie7.遨游浏览器都不兼容. outline控制的到底是什么呢? 当聚焦a标签的时候,在a标签的区域周围会有 ...

  2. 自行架设DNS的操作步骤及相关说明

    关于什么是DNS及相关的名词及说明,请看 http://www.wdlinux.cn/bbs/viewthread.php?tid=1081&highlight=dns这里,只是说明,在wdd ...

  3. 微软停服 XP系统到底伤害了谁?

    http://majihua.baijia.baidu.com/article/10386 微软现在成了招人恨的角色,因为其史上最成功的操作系统WINDOWS XP在4月8日就将停止服务,而社会上对X ...

  4. Swift学习笔记十一

    类与结构体 Swift中,并不要求把自定义类或结构的接口和实现写在不同的文件中.你在一个文件中定义类或结构体,那么这个类或结构体的外部接口就自动可以在其他代码中使用了. 类和结构有很多相似和区别,相同 ...

  5. 支付宝api指南

    tyle="margin:20px 0px 0px; line-height:26px; font-family:Arial"> 在这些服务中,服务类型大致可以分为以下几类: ...

  6. 【机器学习算法-python实现】决策树-Decision tree(1) 信息熵划分数据集

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 决策书算法是一种逼近离散数值的分类算法,思路比較简单,并且准确率较高.国际权威的学术组织,数据挖掘国际 ...

  7. 关于phpcmsv9更新缓存出现链接被重置的问题

    今天安装phpcmsv9后更新缓存出现链接被重置的错误,..找了半天原因. . .原来是apache配置里面的keepAlive显示的是off,,应该将其改为on...然后重新启动apache....

  8. 【JavaScript】 2013年度最强AngularJS资源合集

    http://www.iteye.com/news/28651-AngularJS-Google-resource AngularJS是Google开源的一款JavaScript MVC框架,弥补了H ...

  9. Oracle DB 管理数据库的空间

    • 描述4 KB 扇区磁盘的概念及使用 • 使用可移动表空间 • 描述可移动表空间的概念 数据库存储 数据库存储 数据库包括物理结构和逻辑结构.由于物理结构和逻辑结构是分开的,因此管理数据的物 理存储 ...

  10. iOS开发——高级UI—OC篇&退出键盘

    退出键盘 iOS开发中键盘的退出方法用很多中我们应该在合适的地方使用合适的方法才能更好的提高开发的效率和应用的性能 下面给大家介绍几种最常用的键盘退出方法,基本上iOS开发中的键盘退出方法都是这几种中 ...