iczelion pe tut5

原创 2001年08月29日 16:28:00

 

Tutorial 5: Section Table

 

Theory:

Up to this tutorial, we learned about the DOS header, the PE header. What remains is the section table. A section table is actually an array of structure immediately following the PE header. The number of the array members is determined by NumberOfSections field in the file header (IMAGE_FILE_HEADER) structure. The structure is called 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

Again, not all members are useful. I'll describe only the ones that are really important.

Field Meanings
Name1 Actually the name of this field is "name" but the word "name" is an MASM keyword so we have to use "Name1" instead. This member contains the name of the section. Note that the maximum length is 8 bytes. The name is just a label, nothing more. You can use any name or even leave this field blank. Note that there is no mention of the terminating null. The name is not an ASCIIZ string so don't expect it to be terminated with a null.
VirtualAddress The RVA of the section. The PE loader examines and uses the value in this field when it's mapping the section into memory. Thus if the value in this field is 1000h and the PE file is loaded at 400000h, the section will be loaded at 401000h.
SizeOfRawData The size of the section's data rounded up to the next multiple of file alignment. The PE loader examines the value in this field so it knows how many bytes in the section it should map into memory.
PointerToRawData The file offset of the beginning of the section. The PE loader uses the value in this field to find where the data in the section is in the file.
Characteristics Contains flags such as whether this section contains executable code, initialized data, uninitialized data, can it be written to or read from.

Now that we know about IMAGE_SECTION_HEADER structure, let's see how we can emulate the PE loader's job:

  1. Read NumberOfSections in IMAGE_FILE_HEADER so we know how many sections there are in the file.
  2. Use the value in SizeOfHeaders as the file offset of the section table and moves the file pointer to that offset.
  3. Walk the structure array, examining each member.
  4. For each structure, we obtain the value in PointerToRawData and move the file pointer to that offset. Then we read the value in SizeOfRawData so we know how many bytes we should map into memory. Read the value in VirtualAddress and add the value in ImageBase to it to get the virtual address the section should start from. And then we are ready to map the section into memory and mark the attribute of the memory according to the flags in Characteristics.
  5. Walk the array until all the sections are processed.

Note that we didn't make use the the name of the section: it's not really necessary.

Example:

This example opens a PE file and walks the section table, showing the information about the sections in a listview control.

.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

Analysis:

This example reuses the code of the example in PE tutorial 2. After it verifies that the file is a valid PE, it calls a function, 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

We use edi as the pointer to the data in the PE file. At first, we initialize it to the value of pMapping which is the address of the DOS header. Then we add the value in e_lfanew to it so it now contains the address of the PE header.

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

Since we need to walk the section table, we must obtain the number of sections in this file. That's the value in NumberOfSections member of the file header. Don't forget that this member is of word size.

   add edi,sizeof IMAGE_NT_HEADERS

Edi currently contains the address of the PE header. Adding the size of the PE header to it will make it point at the section table.

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

Call DialogBoxParam to show the dialog box containing the listview control. Note that we pass the address of the section table as its last parameter. This value will be available in lParam during WM_INITDIALOG message.

In the dialog box procedure, in response to WM_INITDIALOG message, we store the value of lParam (address of the section table) in esi, the number of sections in edi and then dress up the listview control. When everything is ready, we enter a loop which will insert the info about each section into the listview control. This part is very simple.

      .while edi>0
         mov lvi.iSubItem,0

Put this string in the first column.

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

We will display the name of the section but we must convert it to an ASCIIZ string first.

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

Then we display it in the first column.
We continue with this scheme until the last value we want to display for this section is displayed. Then we must move to the next structure.

         dec edi
         add esi, sizeof IMAGE_SECTION_HEADER
      .endw

We decrement the value in edi for each section processed. And we add the size of IMAGE_SECTION_HEADER to esi so it contains the address of the next IMAGE_SECTION_HEADER structure.

The steps in walking the section table are:

  1. Verify that the file is a valid PE
  2. Go to the beginning of the PE header
  3. Obtain the number of sections from NumberOfSections field in the file header.
  4. Go to the section table either by adding ImageBase to SizeOfHeaders or by adding the address of the PE header to the size of the PE header. (The section table immediately follows the PE header). If you don't use file mapping, you need to move the file pointer to the section table using SetFilePointer. The file offset of the section table is in SizeOfHeaders.(SizeOfHeaders is a member of IMAGE_OPTIONAL_HEADER)
  5. Process each IMAGE_SECTION_HEADER structure.

[Iczelion's Win32 Assembly Homepage]

 

iczelion tut5

Tutorial 5: More about TextTheory:Windows color system is based on RGB values, R=red, G=Green, B=Blu...
  • jimgreen
  • jimgreen
  • 2001年08月28日 12:22
  • 552

PE文件概述

 前言 PE格式,是Windows的可执行文件的格式。Windows中的 exe文件,dll文件,都是PE格式。PE 就是Portable Executable 的缩写。Portable 是指对于不同...
  • hpxcx
  • hpxcx
  • 2007年05月06日 15:06
  • 393

iczelion Vxd tut5

 VxD Example: MessageBoxIn the previous tutorials, you learn about mechanics of VxD programming. Now...
  • jimgreen
  • jimgreen
  • 2001年08月30日 12:03
  • 488

iczelion pe tutcn4

 PE教程4: Optional Header我们已经学习了关于 DOS header 和 PE header 中部分成员的知识。这里是 PE header 中最后、最大或许也是最重要的成员,opti...
  • jimgreen
  • jimgreen
  • 2001年08月29日 17:45
  • 545

iczelion pe tutcn5

 PE教程5: Section Table(节表) 理论:到本课为止,我们已经学了许多关于 DOS header 和 PE header 的知识。接下来就该轮到 section table(节表)了。...
  • jimgreen
  • jimgreen
  • 2001年08月29日 17:47
  • 704

iczelion pe tut4

 Tutorial 4: Optional HeaderWe have learned about the DOS header and some members of the PE header. ...
  • jimgreen
  • jimgreen
  • 2001年08月29日 16:26
  • 426

iczelion pe tut1

 Tutorial 1: Overview of PE file formatThis is the complete rewrite of the old PE tutorial no1 which...
  • jimgreen
  • jimgreen
  • 2001年08月29日 16:23
  • 593

iczelion pe tutcn7

 PE教程7: Export Table(引出表)上一课我们已经学习了动态联接中关于引入表那部分知识,现在继续另外一部分,那就是引出表。 理论:当PE装载器执行一个程序,它将相关DLLs都装入该进程的...
  • jimgreen
  • jimgreen
  • 2001年08月29日 17:50
  • 636

iczelion pe tut3

 Tutorial 3: File HeaderIn this tutorial, we will study the file header portion of the PE header. Le...
  • jimgreen
  • jimgreen
  • 2001年08月29日 16:25
  • 469

iczelion pe tutcn1

 PE教程1: PE文件格式一览考虑到早期写的PE教程1是自己所有教程中最糟糕的一篇,此番决心彻底重写一篇以飨读者。PE 的意思就是 Portable Executable(可移植的执行体)。它是 W...
  • jimgreen
  • jimgreen
  • 2001年08月29日 17:23
  • 755
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:iczelion pe tut5
举报原因:
原因补充:

(最多只允许输入30个字)