第五章 導出表
typedef struct _IMAGE_NT_HEADERS
{
+00h DWORD Signature
+04h IMAGE_FILE_HEADER FileHeader
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader
} IMAGE_NT_HEADERS ENDS, *PIMAGE_NT_HEADERS32;
?
IMAGE_NT_HEADERS=4BYTEPE標識符 + IMAGE_FILE_HEADER + IMAGE_OPTIONAL_HEADER32 總共240字節 = 4 + 20 + FileHeader.SizeOfOptionalHeader
Windows加載器將與進程相關的DLL加載到虛擬地址空間以后,會根據導入表中登記的與該動態鏈接庫相關的由INT指向的名稱或編號來編譯DLL所在虛擬地址空間,
通過函數名或編號查找導出表結構,從而確定該導出函數在虛擬地址空間中起始地址VA,并將該VA覆蓋導入表的IAT相關項。
IMAGE_EXPORT_DIRECTORY STRUCT{
?Characteristics?DWORD ?
?TimeDateStamp??DWORD ?
?MajorVersion??WORD??
?MinorVersion??WORD? ?
?nName??????DWORD ???;000ch - 指向該導出表的文件名字字符串
?nBase??????DWORD ???;10導出函數的起始序號
?NumberOfFunctions?DWORD ? ;14所有的導出函數個數
?NumberOfNames??DWORD ???;18以函數名導出的函數個數
?AddressOfFuctions DWORD ? ;1c導出函數地址表RVA?指向全部導出函數的入口地址的起始
?AddressOfNames??DWORD ???;20函數名稱地址表RVA
?AddressOfNameOrdinal DWORD ??;24函數序號地址表 AddressOfNameOrdinals指向的是單字數組
}
AddressOfFuctions DWORD ? ;導出函數地址表RVA?指向全部導出函數的入口地址的起始
nBase?并不是從0開始
AddressOfName 指向的位置是一連串的雙字值,這些值指向對應定義了函數名的函數的字符串地址。
AddressOfNameOrdinal 與AddressOfName一一對應,指向AddressOfName中對應函數在AddressOfNameOrdinal的索引值 分別的偏移相等
編寫DLL
1.winResult.asm?// ml /c /coff winResult.asm
2.winResult.def
// link -dll -subsystem:widnows -def:winResult.def winResult.obj
上面生成 winResult.dll? winResult.lib
使用上面的DLL
1.winResult.inc
現在就可以用1.winResult.inc;2. winResult.dll? winResult.lib
2.FistWindow.asm?
//include??? winResult.inc
//includelib winResult.lib
操作導出表內容可以覆蓋、調整導出函數,還可以增加導出信息來導出dll中出導出的私有數據。
?
?
;------------------------
; DLL動態鏈接庫
; 提供了幾個窗口效果
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.libMAX_XYSTEPS equ 50
DELAY_VALUE equ 50 ; 動畫效果使用的步長
X_STEP_SIZE equ 10
Y_STEP_SIZE equ 9
X_START_SIZE equ 20
Y_START_SIZE equ 10LMA_ALPHA equ 2
LMA_COLORKEY equ 1
WS_EX_LAYERED equ 80000h;數據段.data
dwCount dd ?
Value dd ?
Xsize dd ?
Ysize dd ?
sWth dd ?
sHth dd ?
Xplace dd ?
Yplace dd ?
counts dd ?
pSLWA dd ?
User32 db 'user32.dll',0
SLWA db 'SetLayeredWindowAttributes',0
;代碼段.code
;------------------
; DLL入口
;------------------
DllEntry proc _hInstance,_dwReason,_dwReservedmov eax,TRUEret
DllEntry endp;-------------------------------
; 私有函數
;-------------------------------
TopXY proc wDim:DWORD,sDim:DWORDshr sDim,1 shr wDim,1mov eax,wDimsub sDim,eaxmov eax,sDimret
TopXY endp
;-----------------------------------------------------------
; 窗口抖動進入效果
;-----------------------------------------------------------
AnimateOpen proc hWin:DWORDLOCAL Rct:RECTinvoke GetWindowRect,hWin,ADDR Rctmov Xsize,X_START_SIZEmov Ysize,Y_START_SIZEinvoke GetSystemMetrics,SM_CXSCREENmov sWth,eaxinvoke TopXY,Xsize,eaxmov Xplace,eaxinvoke GetSystemMetrics,SM_CYSCREENmov sHth,eaxinvoke TopXY,Ysize,eaxmov Yplace,eaxmov counts,MAX_XYSTEPS
aniloop:invoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,FALSEinvoke ShowWindow,hWin,SW_SHOWNAinvoke Sleep,DELAY_VALUEinvoke ShowWindow,hWin,SW_HIDEadd Xsize,X_STEP_SIZEadd Ysize,Y_STEP_SIZEinvoke TopXY,Xsize,sWthmov Xplace,eaxinvoke TopXY,Ysize,sHthmov Yplace,eaxdec countsjnz aniloopmov eax,Rct.leftmov ecx,Rct.rightsub ecx,eaxmov Xsize,ecxmov eax,Rct.topmov ecx,Rct.bottomsub ecx,eaxmov Ysize,ecxinvoke TopXY,Xsize,sWthmov Xplace,eaxinvoke TopXY,Ysize,sHthmov Yplace,eaxinvoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,TRUE invoke ShowWindow,hWin,SW_SHOWret
AnimateOpen endp;-------------------------
; 窗口抖動退出效果
;-------------------------
AnimateClose proc hWin:DWORDLOCAL Rct:RECTinvoke ShowWindow,hWin,SW_HIDEinvoke GetWindowRect,hWin,ADDR Rctmov eax,Rct.leftmov ecx,Rct.rightsub ecx,eaxmov Xsize,ecxmov eax,Rct.topmov ecx,Rct.bottomsub ecx,eaxmov Ysize,ecxinvoke GetSystemMetrics,SM_CXSCREENmov sWth,eaxinvoke TopXY,Xsize,eaxmov Xplace,eaxinvoke GetSystemMetrics,SM_CYSCREENmov sHth,eaxinvoke TopXY,Ysize,eaxmov Yplace,eaxmov counts,MAX_XYSTEPS
aniloop:invoke MoveWindow,hWin,Xplace,Yplace,Xsize,Ysize,FALSE invoke ShowWindow,hWin,SW_SHOWNAinvoke Sleep,DELAY_VALUEinvoke ShowWindow,hWin,SW_HIDEsub Xsize,X_STEP_SIZEsub Ysize,Y_STEP_SIZEinvoke TopXY,Xsize,sWthmov Xplace,eaxinvoke TopXY,Ysize,sHthmov Yplace,eaxdec countsjnz aniloopret AnimateClose endp;--------------------------------------------
; 窗口淡入效果,僅運行在2000/XP以上操作系統
;--------------------------------------------
FadeInOpen proc hWin:DWORDinvoke GetWindowLongA,hWin,GWL_EXSTYLEor eax,WS_EX_LAYEREDinvoke SetWindowLongA,hWin,GWL_EXSTYLE,eaxinvoke GetModuleHandleA,ADDR User32invoke GetProcAddress,eax,ADDR SLWAmov pSLWA,eaxpush LMA_ALPHApush 0 push 0push hWincall pSLWAmov Value,90invoke ShowWindow,hWin,SW_SHOWNA
doloop:push LMA_COLORKEY + LMA_ALPHApush Valuepush Valuepush hWincall pSLWAinvoke Sleep,DELAY_VALUEadd Value,15cmp Value,255jne dolooppush LMA_ALPHApush 255push 0push hWincall pSLWAret FadeInOpen endp;--------------------------------------------
; 窗口淡出效果,僅運行在2000/XP以上操作系統
;--------------------------------------------
FadeOutClose proc hWin:DWORDinvoke GetWindowLongA,hWin,GWL_EXSTYLEor eax,WS_EX_LAYEREDinvoke SetWindowLongA,hWin,GWL_EXSTYLE,eaxinvoke GetModuleHandleA,ADDR User32invoke GetProcAddress,eax,ADDR SLWAmov pSLWA,eaxpush LMA_ALPHApush 255push 0push hWincall pSLWAmov Value,255
doloop:push LMA_COLORKEY + LMA_ALPHApush Valuepush Valuepush hWincall pSLWAinvoke Sleep,DELAY_VALUEsub Value,15cmp Value,0jne doloopret
FadeOutClose endpEnd DllEntry
?
//inc file
AnimateOpen proto :dword
AnimateClose proto :dword
FadeInOpen proto :dword
FadeOutClose proto :dword
?
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include winResult.inc
includelib winResult.lib;數據段.data?
hInstance dd ?
hWinMain dd ?
;常量定義.const
szClassName db 'MyClass',0
szCaptionMain db '窗口特效演示',0
szText db '你好,認識我嗎?^_^',0;代碼段.code
;------------------
; 窗口消息處理子程序
;------------------
_ProcWinMain proc uses ebx edi esi,hWnd,uMsg,wParam,lParamlocal @stPs:PAINTSTRUCTlocal @stRect:RECTlocal @hDcmov eax,uMsg.if eax==WM_PAINTinvoke BeginPaint,hWnd,addr @stPsmov @hDc,eaxinvoke GetClientRect,hWnd,addr @stRectinvoke DrawText,@hDc,addr szText,-1,\addr @stRect,\DT_SINGLELINE or DT_CENTER or DT_VCENTERinvoke EndPaint,hWnd,addr @stPs.elseif eax==WM_CLOSE ;關閉窗口invoke FadeOutClose,hWinMaininvoke DestroyWindow,hWinMaininvoke PostQuitMessage,NULL.elseinvoke DefWindowProc,hWnd,uMsg,wParam,lParamret.endifxor eax,eaxret
_ProcWinMain endp;----------------------
; 主窗口程序
;----------------------
_WinMain proclocal @stWndClass:WNDCLASSEXlocal @stMsg:MSGinvoke GetModuleHandle,NULLmov hInstance,eaxinvoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass;注冊窗口類invoke LoadCursor,0,IDC_ARROWmov @stWndClass.hCursor,eaxpush hInstancepop @stWndClass.hInstancemov @stWndClass.cbSize,sizeof WNDCLASSEXmov @stWndClass.style,CS_HREDRAW or CS_VREDRAWmov @stWndClass.lpfnWndProc,offset _ProcWinMainmov @stWndClass.hbrBackground,COLOR_WINDOW+1mov @stWndClass.lpszClassName,offset szClassNameinvoke RegisterClassEx,addr @stWndClass;建立并顯示窗口invoke CreateWindowEx,WS_EX_CLIENTEDGE,\offset szClassName,offset szCaptionMain,\WS_OVERLAPPEDWINDOW,\100,100,600,400,\NULL,NULL,hInstance,NULLmov hWinMain,eaxinvoke FadeInOpen,hWinMain;invoke ShowWindow,hWinMain,SW_SHOWNORMALinvoke UpdateWindow,hWinMain ;更新客戶區,即發送WM_PAINT消息;消息循環.while TRUEinvoke GetMessage,addr @stMsg,NULL,0,0.break .if eax==0invoke TranslateMessage,addr @stMsginvoke DispatchMessage,addr @stMsg.endwret
_WinMain endpstart:call _WinMaininvoke ExitProcess,NULLend start
?
;-------------------------------
; 獲取指定字符串的API函數的調用地址
; 入口參數:_hModule為動態鏈接庫的基址,_lpApi為API函數名的首址
; 出口參數:eax為函數在虛擬地址空間中的真實地址
;-------------------------------
_getApi proc _hModule,_lpApilocal @retlocal @dwLenpushadmov @ret,0;計算API字符串的長度,含最后的零mov edi,_lpApimov ecx,-1xor al,alcld ;set DF=0(向高地址增長) std is set DF=1repnz scasb ;scasb 在edi向高地址增長方向找al字符,找到設置ZF=1mov ecx,edisub ecx,_lpApimov @dwLen,ecx;從pe文件頭的數據目錄獲取導出表地址mov esi,_hModuleadd esi,[esi+3ch]assume esi:ptr IMAGE_NT_HEADERSmov esi,[esi].OptionalHeader.DataDirectory.VirtualAddressadd esi,_hModuleassume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名稱的導出函數名mov ebx,[esi].AddressOfNamesadd ebx,_hModulexor edx,edx.repeatpush esimov edi,[ebx]add edi,_hModulemov esi,_lpApimov ecx,@dwLenrepz cmpsb ;cmpsb是用 DS:[SI] 所指的字節單元內容,減去 ES:[DI] 所指的字節單元的內容。.if ZERO?pop esi ;//if esi="fun" edi="func"感覺要比較下長度jmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret
@@:;通過API名稱索引獲取序號索引再獲取地址索引sub ebx,[esi].AddressOfNames ;AddressOfNames指向是的雙字RVA數組sub ebx,_hModule ;找到相對AddressOfNames的RVAshr ebx,1 ;DWORD 步長變為WORD步長add ebx,[esi].AddressOfNameOrdinals ;AddressOfNameOrdinals指向的是單字RVA數組add ebx,_hModulemovzx eax,word ptr [ebx] ;無符號擴展Mov 從ebx指向地址取出索引號shl eax,2 ;索引號*4變為AddressOfFunctions偏移量add eax,[esi].AddressOfFunctionsadd eax,_hModule;從地址表得到導出函數的地址mov eax,[eax]add eax,_hModulemov @ret,eax_ret:assume esi:nothingpopadmov eax,@retret
_getApi endp
?
;--------------------
; 獲取PE文件的導出表
;--------------------
_getExportInfo proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSectionName[16]:bytelocal @lpAddressOfNames,@dwIndex,@lpAddressOfNameOrdinalspushadmov esi,_lpPeHeadassume esi:ptr IMAGE_NT_HEADERSmov eax,[esi].OptionalHeader.DataDirectory[0].VirtualAddress.if !eaxinvoke _appendInfo,addr szErrNoExportjmp _Ret.endifinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov edi,eax ;計算導出表所在文件偏移位置assume edi:ptr IMAGE_EXPORT_DIRECTORYinvoke _RVAToOffset,_lpFile,[edi].nNameadd eax,_lpFilemov ecx,eax ;ecx 指向該導出表的文件名字字符串的首地址invoke _getRVASectionName,_lpFile,[edi].nNameinvoke wsprintf,addr @szBuffer,addr szMsgExport,\eax,ecx,[edi].nBase,[edi].NumberOfFunctions,\[edi].NumberOfNames,[edi].AddressOfFunctions,\[edi].AddressOfNames,[edi].AddressOfNameOrdinalsinvoke _appendInfo,addr @szBufferinvoke _RVAToOffset,_lpFile,[edi].AddressOfNamesadd eax,_lpFilemov @lpAddressOfNames,eaxinvoke _RVAToOffset,_lpFile,[edi].AddressOfNameOrdinalsadd eax,_lpFilemov @lpAddressOfNameOrdinals,eaxinvoke _RVAToOffset,_lpFile,[edi].AddressOfFunctionsadd eax,_lpFilemov esi,eax ;函數的地址表mov ecx,[edi].NumberOfFunctionsmov @dwIndex,0
@@:pushadmov eax,@dwIndexpush edimov ecx,[edi].NumberOfNamescldmov edi,@lpAddressOfNameOrdinalsrepnz scasw ;scasW 在edi向高地址增長方向找aX字符,找到設置ZF=1.if ZERO? ;找到函數名稱sub edi,@lpAddressOfNameOrdinalssub edi,2 ;lpAddressOfNameOrdinals指向是單字索引數組,減2是從零編號shl edi,1 ;AddressOfNameOrdinals單字步長變為AddressOfNames雙字步長add edi,@lpAddressOfNamesinvoke _RVAToOffset,_lpFile,dword ptr [edi]add eax,_lpFile.elsemov eax,offset szExportByOrd.endifpop edi;序號在ecx中mov ecx,@dwIndexadd ecx,[edi].nBaseinvoke wsprintf,addr @szBuffer,addr szMsg4,\ecx,dword ptr [esi],eaxinvoke _appendInfo,addr @szBufferpopadadd esi,4inc @dwIndexloop @B
_Ret:assume esi:nothingassume edi:nothingpopadret
_getExportInfo endp
?
//peinfo.asm 整個文件
.386
.model flat,stdcall
option casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include comdlg32.inc
includelib comdlg32.libICO_MAIN equ 1000
DLG_MAIN equ 1000
IDC_INFO equ 1001
IDM_MAIN equ 2000
IDM_OPEN equ 2001
IDM_EXIT equ 2002
IDM_1 equ 4000
IDM_2 equ 4001
IDM_3 equ 4002
.data
hInstance dd ?
hRichEdit dd ?
hWinMain dd ?
hWinEdit dd ?
szFileName db MAX_PATH dup(?).const
szDllEdit db 'RichEd20.dll',0
szClassEdit db 'RichEdit20A',0
szFont db '宋體',0
szExtPe db 'PE File',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0db 'All Files(*.*)',0,'*.*',0,0
szErr db '文件格式錯誤!',0
szErrFormat db '這個文件不是PE格式的文件!',0
szSuccess db '恭喜你,程序執行到這里是成功的。',0
szNotFound db '無法查找',0
szMsg db '文件名:%s',0dh,0ahdb '-----------------------------------------',0dh,0ah,0dh,0ah,0dh,0ahdb '運行平臺: 0x%04x (014c:Intel 386 014dh:Intel 486 014eh:Intel 586)',0dh,0ahdb '節的數量: %d',0dh,0ahdb '文件屬性: 0x%04x (大尾-禁止多處理器-DLL-系統文件-禁止網絡運行-禁止優盤運行-無調試-32位-小尾-X-X-X-無符號-無行-可執行-無重定位)',0dh,0ahdb '建議裝入基地址: 0x%08x',0dh,0ahdb '文件執行入口(RVA地址): 0x%04x',0dh,0ah,0dh,0ah,0
szMsgSec db '---------------------------------------------------------------------------------',0dh,0ahdb '節的屬性參考:',0dh,0ahdb ' 00000020h 包含代碼',0dh,0ahdb ' 00000040h 包含已經初始化的數據,如.const',0dh,0ahdb ' 00000080h 包含未初始化數據,如 .data?',0dh,0ahdb ' 02000000h 數據在進程開始以后被丟棄,如.reloc',0dh,0ahdb ' 04000000h 節中數據不經過緩存',0dh,0ahdb ' 08000000h 節中數據不會被交換到磁盤',0dh,0ahdb ' 10000000h 數據將被不同進程共享',0dh,0ahdb ' 20000000h 可執行',0dh,0ahdb ' 40000000h 可讀',0dh,0ahdb ' 80000000h 可寫',0dh,0ahdb '常見的代碼節一般為:60000020h,數據節一般為:c0000040h,常量節一般為:40000040h',0dh,0ahdb '---------------------------------------------------------------------------------',0dh,0ah,0dh,0ah,0dh,0ahdb '節的名稱 未對齊前真實長度 內存中的偏移(對齊后的) 文件中對齊后的長度 文件中的偏移 節的屬性',0dh,0ahdb '---------------------------------------------------------------------------------------------',0dh,0ah,0
szFmtSec db '%s %08x %08x %08x %08x %08x',0dh,0ah,0dh,0ah,0dh,0ah,0
szMsg1 db 0dh,0ah,0dh,0ah,0dh,0ahdb '---------------------------------------------------------------------------------------------',0dh,0ahdb '導入表所處的節:%s',0dh,0ahdb '---------------------------------------------------------------------------------------------',0dh,0ah,0
szMsgImport db 0dh,0ah,0dh,0ahdb '導入庫:%s',0dh,0ahdb '-----------------------------',0dh,0ah,0dh,0ahdb 'OriginalFirstThunk %08x',0dh,0ahdb 'TimeDateStamp %08x',0dh,0ahdb 'ForwarderChain %08x',0dh,0ahdb 'FirstThunk %08x',0dh,0ahdb '-----------------------------',0dh,0ah,0dh,0ah,0
szMsg2 db '%08u %s',0dh,0ah,0
szMsg3 db '%08u(無函數名,按序號導入)',0dh,0ah,0
szErrNoImport db 0dh,0ah,0dh,0ahdb '未發現該文件有導入函數',0dh,0ah,0dh,0ah,0szMsgExport db 0dh,0ah,0dh,0ah,0dh,0ahdb '---------------------------------------------------------------------------------------------',0dh,0ahdb '導出表所處的節:%s',0dh,0ahdb '---------------------------------------------------------------------------------------------',0dh,0ahdb '原始文件名:%s',0dh,0ahdb 'nBase %08x',0dh,0ahdb 'NumberOfFunctions %08x',0dh,0ahdb 'NuberOfNames %08x',0dh,0ahdb 'AddressOfFunctions %08x',0dh,0ahdb 'AddressOfNames %08x',0dh,0ahdb 'AddressOfNameOrd %08x',0dh,0ahdb '-------------------------------------',0dh,0ah,0dh,0ahdb '導出序號 虛擬地址 導出函數名稱',0dh,0ahdb '-------------------------------------',0dh,0ah,0
szMsg4 db '%08x %08x %s',0dh,0ah,0
szExportByOrd db '(按照序號導出)',0
szErrNoExport db 0dh,0ah,0dh,0ahdb '未發現該文件有導出函數',0dh,0ah,0dh,0ah,0
szMsgReloc1 db 0dh,0ah,'重定位表所處的節:%s',0dh,0ah,0
szMsgReloc2 db 0dh,0ahdb '--------------------------------------------------------------------------------------------',0dh,0ahdb '重定位基地址: %08x',0dh,0ahdb '重定位項數量: %d',0dh,0ahdb '--------------------------------------------------------------------------------------------',0dh,0ahdb '需要重定位的地址列表(ffffffff表示對齊用,不需要重定位)',0dh,0ahdb '--------------------------------------------------------------------------------------------',0dh,0ah,0
szMsgReloc3 db '%08x ',0
szCrLf db 0dh,0ah,0
szMsgReloc4 db 0dh,0ah,'未發現該文件有重定位信息.',0dh,0ah,0.code;----------------
;初始化窗口程序
;----------------
_init proclocal @stCf:CHARFORMATinvoke GetDlgItem,hWinMain,IDC_INFOmov hWinEdit,eaxinvoke LoadIcon,hInstance,ICO_MAINinvoke SendMessage,hWinMain,WM_SETICON,ICON_BIG,eax ;為窗口設置圖標invoke SendMessage,hWinEdit,EM_SETTEXTMODE,TM_PLAINTEXT,0 ;設置編輯控件invoke RtlZeroMemory,addr @stCf,sizeof @stCfmov @stCf.cbSize,sizeof @stCfmov @stCf.yHeight,9*20mov @stCf.dwMask,CFM_FACE or CFM_SIZE or CFM_BOLDinvoke lstrcpy,addr @stCf.szFaceName,addr szFontinvoke SendMessage,hWinEdit,EM_SETCHARFORMAT,0,addr @stCfinvoke SendMessage,hWinEdit,EM_EXLIMITTEXT,0,-1ret
_init endp;------------------
; 錯誤Handler
;------------------
_Handler proc _lpExceptionRecord,_lpSEH,\_lpContext,_lpDispathcerContextpushadmov esi,_lpExceptionRecordmov edi,_lpContextassume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXTmov eax,_lpSEHpush [eax+0ch]pop [edi].regEbppush [eax+8]pop [edi].regEippush eaxpop [edi].regEspassume esi:nothing,edi:nothingpopadmov eax,ExceptionContinueExecutionret
_Handler endp;---------------------
; 將內存偏移量RVA轉換為文件偏移
; lp_FileHead為文件頭的起始地址
; _dwRVA為給定的RVA地址
;---------------------
_RVAToOffset proc _lpFileHead,_dwRVAlocal @dwReturnpushadmov esi,_lpFileHeadassume esi:ptr IMAGE_DOS_HEADERadd esi,[esi].e_lfanewassume esi:ptr IMAGE_NT_HEADERSmov edi,_dwRVAmov edx,esiadd edx,sizeof IMAGE_NT_HEADERSassume edx:ptr IMAGE_SECTION_HEADERmovzx ecx,[esi].FileHeader.NumberOfSections;遍歷節表.repeatmov eax,[edx].VirtualAddressadd eax,[edx].SizeOfRawData ;計算該節結束RVA,不用Misc的主要原因是有些段的Misc值是錯誤的!.if (edi>=[edx].VirtualAddress)&&(edi<eax)mov eax,[edx].VirtualAddresssub edi,eax ;計算RVA在節中的偏移mov eax,[edx].PointerToRawDataadd eax,edi ;加上節在文件中的的起始位置jmp @F.endifadd edx,sizeof IMAGE_SECTION_HEADER.untilcxzassume edx:nothingassume esi:nothingmov eax,-1
@@:mov @dwReturn,eaxpopadmov eax,@dwReturnret
_RVAToOffset endp;------------------------
; 獲取RVA所在節的名稱
;------------------------
_getRVASectionName proc _lpFileHead,_dwRVAlocal @dwReturnpushadmov esi,_lpFileHeadassume esi:ptr IMAGE_DOS_HEADERadd esi,[esi].e_lfanewassume esi:ptr IMAGE_NT_HEADERSmov edi,_dwRVAmov edx,esiadd edx,sizeof IMAGE_NT_HEADERSassume edx:ptr IMAGE_SECTION_HEADERmovzx ecx,[esi].FileHeader.NumberOfSections;遍歷節表.repeatmov eax,[edx].VirtualAddressadd eax,[edx].SizeOfRawData ;計算該節結束RVA.if (edi>=[edx].VirtualAddress)&&(edi<eax)mov eax,edxjmp @F.endifadd edx,sizeof IMAGE_SECTION_HEADER.untilcxzassume edx:nothingassume esi:nothingmov eax,offset szNotFound
@@:mov @dwReturn,eaxpopadmov eax,@dwReturnret
_getRVASectionName endp;-------------------------------
; 獲取指定字符串的API函數的調用地址
; 入口參數:_hModule為動態鏈接庫的基址,_lpApi為API函數名的首址
; 出口參數:eax為函數在虛擬地址空間中的真實地址
;-------------------------------
_getApi proc _hModule,_lpApilocal @retlocal @dwLenpushadmov @ret,0;計算API字符串的長度,含最后的零mov edi,_lpApimov ecx,-1xor al,alcld ;set DF=0(向高地址增長) std is set DF=1repnz scasb ;scasb 在edi向高地址增長方向找al字符,找到設置ZF=1mov ecx,edisub ecx,_lpApimov @dwLen,ecx;從pe文件頭的數據目錄獲取導出表地址mov esi,_hModuleadd esi,[esi+3ch]assume esi:ptr IMAGE_NT_HEADERSmov esi,[esi].OptionalHeader.DataDirectory.VirtualAddressadd esi,_hModuleassume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名稱的導出函數名mov ebx,[esi].AddressOfNamesadd ebx,_hModulexor edx,edx.repeatpush esimov edi,[ebx]add edi,_hModulemov esi,_lpApimov ecx,@dwLenrepz cmpsb ;cmpsb是用 DS:[SI] 所指的字節單元內容,減去 ES:[DI] 所指的字節單元的內容。.if ZERO?pop esi ;//if esi="fun" edi="func"感覺要比較下長度jmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret
@@:;通過API名稱索引獲取序號索引再獲取地址索引sub ebx,[esi].AddressOfNames ;AddressOfNames指向是的雙字RVA數組sub ebx,_hModule ;找到相對AddressOfNames的RVAshr ebx,1 ;DWORD 步長變為WORD步長add ebx,[esi].AddressOfNameOrdinals ;AddressOfNameOrdinals指向的是單字RVA數組add ebx,_hModulemovzx eax,word ptr [ebx] ;無符號擴展Mov 從ebx指向地址取出索引號shl eax,2 ;索引號*4變為AddressOfFunctions偏移量add eax,[esi].AddressOfFunctionsadd eax,_hModule;從地址表得到導出函數的地址mov eax,[eax]add eax,_hModulemov @ret,eax_ret:assume esi:nothingpopadmov eax,@retret
_getApi endp;---------------------
; 往文本框中追加文本
;---------------------
_appendInfo proc _lpszlocal @stCR:CHARRANGEpushadinvoke GetWindowTextLength,hWinEditmov @stCR.cpMin,eax ;將插入點移動到最后mov @stCR.cpMax,eaxinvoke SendMessage,hWinEdit,EM_EXSETSEL,0,addr @stCRinvoke SendMessage,hWinEdit,EM_REPLACESEL,FALSE,_lpszpopadret
_appendInfo endp;--------------------
; 從內存中獲取PE文件的主要信息
;--------------------
_getMainInfo proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSecName[16]:bytepushadmov edi,_lpPeHeadassume edi:ptr IMAGE_NT_HEADERSmovzx ecx,[edi].FileHeader.Machine ;運行平臺movzx edx,[edi].FileHeader.NumberOfSections ;節的數量movzx ebx,[edi].FileHeader.Characteristics ;節的屬性invoke wsprintf,addr @szBuffer,addr szMsg,\addr szFileName,ecx,edx,ebx,\[edi].OptionalHeader.ImageBase,\ ;含建議裝入的地址[edi].OptionalHeader.AddressOfEntryPointinvoke SetWindowText,hWinEdit,addr @szBuffer;添加到編輯框中;顯示每個節的主要信息invoke _appendInfo,addr szMsgSecmovzx ecx,[edi].FileHeader.NumberOfSectionsadd edi,sizeof IMAGE_NT_HEADERSassume edi:ptr IMAGE_SECTION_HEADER.repeatpush ecx;獲取節的名稱,注意長度為8的名稱并不以0結尾invoke RtlZeroMemory,addr @szSecName,sizeof @szSecNamepush esipush edimov ecx,8mov esi,edilea edi,@szSecNamecld@@:lodsb.if !al ;如果名稱為0,則顯示為空格mov al,' '.endifstosbloop @Bpop edipop esi;獲取節的主要信息invoke wsprintf,addr @szBuffer,addr szFmtSec,\addr @szSecName,[edi].Misc.VirtualSize,\[edi].VirtualAddress,[edi].SizeOfRawData,\[edi].PointerToRawData,[edi].Characteristicsinvoke _appendInfo,addr @szBufferadd edi,sizeof IMAGE_SECTION_HEADERpop ecx.untilcxzassume edi:nothingpopadret
_getMainInfo endp;--------------------
; 獲取PE文件的導入表
;--------------------
_getImportInfo proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSectionName[16]:bytepushadmov edi,_lpPeHeadassume edi:ptr IMAGE_NT_HEADERSmov eax,[edi].OptionalHeader.DataDirectory[8].VirtualAddress.if !eaxinvoke _appendInfo,addr szErrNoImportjmp _Ret.endifinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov edi,eax ;計算引入表所在文件偏移位置assume edi:ptr IMAGE_IMPORT_DESCRIPTORinvoke _getRVASectionName,_lpFile,[edi].OriginalFirstThunkinvoke wsprintf,addr @szBuffer,addr szMsg1,eax ;顯示節名invoke _appendInfo,addr @szBuffer.while [edi].OriginalFirstThunk || [edi].TimeDateStamp ||\[edi].ForwarderChain || [edi].Name1 || [edi].FirstThunkinvoke _RVAToOffset,_lpFile,[edi].Name1add eax,_lpFileinvoke wsprintf,addr @szBuffer,addr szMsgImport,eax,\[edi].OriginalFirstThunk,[edi].TimeDateStamp,\[edi].ForwarderChain,[edi].FirstThunkinvoke _appendInfo,addr @szBuffer;獲取IMAGE_THUNK_DATA列表到EBX.if [edi].OriginalFirstThunkmov eax,[edi].OriginalFirstThunk.elsemov eax,[edi].FirstThunk.endifinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov ebx,eax.while dword ptr [ebx].if dword ptr [ebx] & IMAGE_ORDINAL_FLAG32 ;按序號導入mov eax,dword ptr [ebx]and eax,0ffffhinvoke wsprintf,addr @szBuffer,addr szMsg3,eax.else ;按名稱導入invoke _RVAToOffset,_lpFile,dword ptr [ebx]add eax,_lpFileassume eax:ptr IMAGE_IMPORT_BY_NAMEmovzx ecx,[eax].Hintinvoke wsprintf,addr @szBuffer,\addr szMsg2,ecx,addr [eax].Name1assume eax:nothing.endifinvoke _appendInfo,addr @szBufferadd ebx,4.endwadd edi,sizeof IMAGE_IMPORT_DESCRIPTOR.endw
_Ret:assume edi:nothingpopadret
_getImportInfo endp;--------------------
; 獲取PE文件的導出表
;--------------------
_getExportInfo proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSectionName[16]:bytelocal @lpAddressOfNames,@dwIndex,@lpAddressOfNameOrdinalspushadmov esi,_lpPeHeadassume esi:ptr IMAGE_NT_HEADERSmov eax,[esi].OptionalHeader.DataDirectory[0].VirtualAddress.if !eaxinvoke _appendInfo,addr szErrNoExportjmp _Ret.endifinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov edi,eax ;計算導出表所在文件偏移位置assume edi:ptr IMAGE_EXPORT_DIRECTORYinvoke _RVAToOffset,_lpFile,[edi].nNameadd eax,_lpFilemov ecx,eax ;ecx 指向該導出表的文件名字字符串的首地址invoke _getRVASectionName,_lpFile,[edi].nNameinvoke wsprintf,addr @szBuffer,addr szMsgExport,\eax,ecx,[edi].nBase,[edi].NumberOfFunctions,\[edi].NumberOfNames,[edi].AddressOfFunctions,\[edi].AddressOfNames,[edi].AddressOfNameOrdinalsinvoke _appendInfo,addr @szBufferinvoke _RVAToOffset,_lpFile,[edi].AddressOfNamesadd eax,_lpFilemov @lpAddressOfNames,eaxinvoke _RVAToOffset,_lpFile,[edi].AddressOfNameOrdinalsadd eax,_lpFilemov @lpAddressOfNameOrdinals,eaxinvoke _RVAToOffset,_lpFile,[edi].AddressOfFunctionsadd eax,_lpFilemov esi,eax ;函數的地址表mov ecx,[edi].NumberOfFunctionsmov @dwIndex,0
@@:pushadmov eax,@dwIndexpush edimov ecx,[edi].NumberOfNamescldmov edi,@lpAddressOfNameOrdinalsrepnz scasw ;scasW 在edi向高地址增長方向找aX字符,找到設置ZF=1.if ZERO? ;找到函數名稱sub edi,@lpAddressOfNameOrdinalssub edi,2 ;lpAddressOfNameOrdinals指向是單字索引數組,減2是從零編號shl edi,1 ;AddressOfNameOrdinals單字步長變為AddressOfNames雙字步長add edi,@lpAddressOfNamesinvoke _RVAToOffset,_lpFile,dword ptr [edi]add eax,_lpFile.elsemov eax,offset szExportByOrd.endifpop edi;序號在ecx中mov ecx,@dwIndexadd ecx,[edi].nBaseinvoke wsprintf,addr @szBuffer,addr szMsg4,\ecx,dword ptr [esi],eaxinvoke _appendInfo,addr @szBufferpopadadd esi,4inc @dwIndexloop @B
_Ret:assume esi:nothingassume edi:nothingpopadret
_getExportInfo endp;--------------------
; 獲取PE文件的重定位信息
;--------------------
_getRelocInfo proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSectionName[16]:bytepushadmov esi,_lpPeHeadassume esi:ptr IMAGE_NT_HEADERSmov eax,[esi].OptionalHeader.DataDirectory[8*5].VirtualAddress.if !eaxinvoke _appendInfo,addr szMsgReloc4jmp _ret.endifpush eaxinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov esi,eaxpop eaxinvoke _getRVASectionName,_lpFile,eaxinvoke wsprintf,addr @szBuffer,addr szMsgReloc1,eaxinvoke _appendInfo,addr @szBufferassume esi:ptr IMAGE_BASE_RELOCATION;循環處理每個重定位塊.while [esi].VirtualAddresscldlodsd ;eax=[esi].VirtualAddressmov ebx,eaxlodsd ;eax=[esi].SizeofBlocksub eax,sizeof IMAGE_BASE_RELOCATION ;塊總長度-兩個ddshr eax,1 ;然后除以2,得到重定位項數量;除以2是因為重定位項是wordpush eaxinvoke wsprintf,addr @szBuffer,addr szMsgReloc2,ebx,eaxinvoke _appendInfo,addr @szBufferpop ecx ;重定位項數量xor edi,edi.repeatpush ecxlodswmov cx,axand cx,0f000h ;得到高四位.if cx==03000h ;重定位地址指向的雙字的32位都需要休正and ax,0fffhmovzx eax,axadd eax,ebx ;得到修正以前的偏移,該偏移加上裝入時的基址就是絕對地址.else ;該重定位項無意義,僅用來作為對齊mov eax,-1.endifinvoke wsprintf,addr @szBuffer,addr szMsgReloc3,eaxinc edi.if edi==8 ;每顯示8個項目換行invoke lstrcat,addr @szBuffer,addr szCrLfxor edi,edi.endifinvoke _appendInfo,addr @szBufferpop ecx.untilcxz.if ediinvoke _appendInfo,addr szCrLf.endif.endw
_ret:assume esi:nothingpopadret
_getRelocInfo endp
;--------------------
; 打開PE文件并處理
;--------------------
_openFile proclocal @stOF:OPENFILENAMElocal @hFile,@dwFileSize,@hMapFile,@lpMemoryinvoke RtlZeroMemory,addr @stOF,sizeof @stOFmov @stOF.lStructSize,sizeof @stOFpush hWinMainpop @stOF.hwndOwnermov @stOF.lpstrFilter,offset szExtPemov @stOF.lpstrFile,offset szFileNamemov @stOF.nMaxFile,MAX_PATHmov @stOF.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXISTinvoke GetOpenFileName,addr @stOF ;讓用戶選擇打開的文件.if !eaxjmp @F.endifinvoke CreateFile,addr szFileName,GENERIC_READ,\FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,\OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL.if eax!=INVALID_HANDLE_VALUEmov @hFile,eaxinvoke GetFileSize,eax,NULLmov @dwFileSize,eax.if eaxinvoke CreateFileMapping,@hFile,\ ;內存映射文件NULL,PAGE_READONLY,0,0,NULL.if eaxmov @hMapFile,eaxinvoke MapViewOfFile,eax,\FILE_MAP_READ,0,0,0.if eaxmov @lpMemory,eax ;獲得文件在內存的映象起始位置assume fs:nothingpush ebppush offset _ErrFormatpush offset _Handlerpush fs:[0]mov fs:[0],esp;檢測PE文件是否有效mov esi,@lpMemoryassume esi:ptr IMAGE_DOS_HEADER.if [esi].e_magic!=IMAGE_DOS_SIGNATURE ;判斷是否有MZ字樣jmp _ErrFormat.endifadd esi,[esi].e_lfanew ;調整ESI指針指向PE文件頭assume esi:ptr IMAGE_NT_HEADERS.if [esi].Signature!=IMAGE_NT_SIGNATURE ;判斷是否有PE字樣jmp _ErrFormat.endif;到此為止,該文件的驗證已經完成。為PE結構文件;接下來分析分件映射到內存中的數據,并顯示主要參數invoke _getMainInfo,@lpMemory,esi,@dwFileSize;顯示導入表invoke _getImportInfo,@lpMemory,esi,@dwFileSize;顯示導出表invoke _getExportInfo,@lpMemory,esi,@dwFileSize;顯示重定位信息invoke _getRelocInfo,@lpMemory,esi,@dwFileSizejmp _ErrorExit_ErrFormat:invoke MessageBox,hWinMain,offset szErrFormat,NULL,MB_OK
_ErrorExit:pop fs:[0]add esp,0chinvoke UnmapViewOfFile,@lpMemory.endifinvoke CloseHandle,@hMapFile.endifinvoke CloseHandle,@hFile.endif.endif
@@: ret
_openFile endp
;-------------------
; 窗口程序
;-------------------
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParammov eax,wMsg.if eax==WM_CLOSEinvoke EndDialog,hWnd,NULL.elseif eax==WM_INITDIALOG ;初始化push hWndpop hWinMaincall _init.elseif eax==WM_COMMAND ;菜單mov eax,wParam.if eax==IDM_EXIT ;退出invoke EndDialog,hWnd,NULL .elseif eax==IDM_OPEN ;打開文件call _openFile.elseif eax==IDM_1 ;以下三個菜單是7歲的兒子完成的!!invoke MessageBox,NULL,offset szErrFormat,offset szErr,MB_ICONWARNING.elseif eax==IDM_2invoke MessageBox,NULL,offset szErrFormat,offset szErr,MB_ICONQUESTION .elseif eax==IDM_3invoke MessageBox,NULL,offset szErrFormat,offset szErr,MB_YESNOCANCEL.endif.elsemov eax,FALSEret.endifmov eax,TRUEret
_ProcDlgMain endpstart:invoke LoadLibrary,offset szDllEditmov hRichEdit,eaxinvoke GetModuleHandle,NULLmov hInstance,eaxinvoke DialogBoxParam,hInstance,\DLG_MAIN,NULL,offset _ProcDlgMain,NULLinvoke FreeLibrary,hRichEditinvoke ExitProcess,NULLend start
?
總結
以上是生活随笔為你收集整理的PE学习(五)导出表,编写DLL及查看DLL的导出信息的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。