ITPub博客

首页 > IT职业 > IT生活 > iczelion pe tut5 (转)

iczelion pe tut5 (转)

原创 IT生活 作者:amyz 时间:2007-11-27 16:18:09 0 删除 编辑
iczelion pe tut5 (转)[@more@]

 

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 masm32includewindows.inc
include masm32includekernel32.inc
include masm32includecomdlg32.inc
include masm32includeuser32.inc
include masm32includecomctl32.inc
includelib masm32libcomctl32.lib
includelib masm32libuser32.lib
includelib masm32libkernel32.lib
includelib masm32libcomdlg32.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.

[win32asm.cjb.NET/">Iczelion's Win32 Assembly Homepage]

 


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752019/viewspace-985422/,如需转载,请注明出处,否则将追究法律责任。

上一篇: iczelion pe tut4 (转)
下一篇: iczelion pe tut6 (转)
请登录后发表评论 登录
全部评论
  • 博文量
    3984
  • 访问量
    7363626