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 
 
同样,不是所有成员都是很有用的,我们只关心那些真正重要的。
 
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装载器的工作吧:
 
读取 IMAGE_FILE_HEADER 的 NumberOfSections域,知道文件的节数目。
SizeOfHeaders 域值作为节表的文件偏移量,并以此定位节表。
遍历整个结构数组检查各成员值。
对于每个结构,我们读取PointerToRawData域值并定位到该文件偏移量。然后再读取SizeOfRawData域值来决定映射内存的字节数。将VirtualAddress域值加上ImageBase域值等于节起始的虚拟地址。然后就准备把节映射进内存,并根据Characteristics域值设置属性。
遍历整个数组,直至所有节都已处理完毕。
注意我们并没有使用节名: 这其实并不重要。
 
示例:
本例程打开一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 结构。
 
遍历节表的步骤:
 
PE文件有效性校验。
定位到 PE header 的起始地址。
从 file header 的 NumberOfSections域获取节数。
通过两种方法定位节表: ImageBase+SizeOfHeaders 或者 PE header的起始地址+ PE header结构大小。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值