PE教程5: Section Table(节表)
来源:互联网 发布:光盘加密软件下载 编辑:程序博客网 时间:2024/05/22 07:43
到本课为止,我们已经学了许多关于 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
同样,不是所有成员都是很有用的,我们只关心那些真正重要的。
现在我们已知晓 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结构大小。 (节表紧随 PE header)。如果不是使用文件映射的方法,可以用SetFilePointer 直接将文件指针定位到节表。节表的文件偏移量存放在 SizeOfHeaders域里。(SizeOfHeaders 是 IMAGE_OPTIONAL_HEADER 的结构成员)
- 处理每个 IMAGE_SECTION_HEADER 结构。
- PE教程5: Section Table(节表)
- PE教程5: Section Table(节表)
- PE教程5: Section Table(节表)
- PE文件学习笔记(二):Section Table解析
- PE教程6: Import Table(引入表)
- PE教程7: Export Table(引出表)(End)
- PE教程6: Import Table(引入表)
- PE教程6: Import Table(引入表)二
- PE教程7: Export Table(引出表)
- PE教程6: Import Table(引入表)
- PE教程7: Export Table(引出表)
- Tutorial 5: Section Table
- PE文件格式系列(一)——探究PE文件常见Section作用
- PE section 的标志位
- windows PE Image 文件分析(5)--- .rsrc 节与 resource table
- windows PE Image 文件分析(5)--- .rsrc 节与 resource table
- PE IMPORT TABLE
- 在PE中添加,删除SECTION
- 流云尼玛
- SpringMVC MultiActionController的使用-最简化教程
- SOA应用存在三大误区
- ultrachart的使用(一):从数据库中提取数据
- Java编程那些事儿35——while语句语法
- PE教程5: Section Table(节表)
- 《编程之美》读书笔记(六):连连看游戏设计
- spring的ParameterMethodNameResolver的使用
- ultrachart的使用(二):现成数据
- ultrachart的使用(三):给数据添加注释
- 出发
- DirectoryInfo类 按扩展名,遍历目录中所有文件
- 测试一篇文章看看
- 培训是一种乐趣