PE教程5: Section Table(節表)
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結構大小。 (節表緊隨 PE header)。如果不是使用檔案對映的方法,可以用SetFilePointer 直接將檔案指標定位到節表。節表的檔案偏移量存放在 SizeOfHeaders域裡。(SizeOfHeaders 是 IMAGE_OPTIONAL_HEADER 的結構成員)
- 處理每個 IMAGE_SECTION_HEADER 結構。
翻譯:iamgufeng [Iczelion's Win32 Assembly Homepage][LuoYunBin's Win32 ASM Page]
相關文章
- PE節表詳細分析2021-11-06
- PE檔案格式詳細解析(六)-- 基址重定位表(Base Relocation Table)2020-03-10
- Lua table(表)2018-10-11
- PE結構-合併節(附例項程式碼)2020-10-24
- SQLAlchemy Table(表)類方式 – Table類和Column類2018-10-25SQL
- 胖爪裝機大師pe硬碟分割槽教程2022-04-15硬碟
- table表頭固定問題2018-07-27
- elementUI table 自定義表頭2018-09-25UI
- HTML <section> 標籤2019-07-30HTML
- layui將table轉化表單顯示(即table.render轉為表單展示)2018-10-11UI
- 透視表pivot_table和交叉表crosstab2020-10-03ROS
- element table 表頭顯示 tooltip2018-11-20
- (一)Superset 1.3圖表篇——Table2021-09-07
- <section>與<article> 區別2019-07-31
- A Proof of Golden Section of Fibonacci Sequence2024-06-24Go
- Xamarin圖表開發基礎教程(5)OxyPlot框架2019-11-11框架
- iOS彙編入門教程(三)彙編中的 Section 與資料存取2019-03-29iOS
- 達夢列儲存表(HUGE Table)2019-11-13
- 【TABLE】Oracle表資訊收集指令碼2021-09-08Oracle指令碼
- table/index/LOBINDEX遷移表空間2021-05-08Index
- 新增節點教程2018-07-13
- (三、四)Superset 1.3圖表篇——透視表-Pivot Table2021-09-13
- Mach-O Inside: BSS Section2023-10-29MacIDE
- artice與section的區別2020-04-05
- 【Basic Abstract Algebra】Exercises of Section 1.12024-11-16
- 【Basic Abstract Algebra】Exercises for Section 1.22024-11-22
- 【Basic Abstract Algebra】Exercises for Section 1.42024-11-24
- 【Basic Abstract Algebra】Exercises for Section 1.32024-11-23
- uefi pe下怎麼安裝win10系統【圖文教程】2019-10-09Win10
- win10系統安裝教程(U盤PE+UEFI安裝)2020-02-07Win10
- table表頭單元格斜線效果2018-10-20
- table表單製作個人簡歷2018-07-14
- table表頭分組程式碼例項2018-09-13
- Bootstrap select2 ,table, 清空表單form2021-09-09bootORM
- MySQL InnoDB File-Per-Table表空間2022-03-17MySql
- 第 5 節:常量2019-11-17
- 運維軟體PE工具箱下載附製作、安裝教程2020-11-27運維
- html標籤-HTML5精講 課時ID:6.1 【表嚴肅】#HTML教程 #HTML5教程 #html標籤2019-02-16HTML
- body標籤-HTML5精講 課時ID:6.2 【表嚴肅】#HTML教程 #HTML5教程 #body標籤2019-02-16HTML