第六章 棧與重定位表
16bit OS?存在長調用 lcall push cs,ip??? 相應的iret pop ip, cs? 而call/ret only focus ip register
32bit OS 因為32寄存器可以訪問4G空間,可以長短調用被忽略,只關注eip
實模式:段地址+程序偏移地址??SS::SP= SS<<16+SP
保護模式:段選擇子+程序偏移地址?原來的段寄存器稱為段選擇子,指向是 GDT/LDT(全局描述符表/局部描述符表)
call?0xXXXXXXXX???;//push 后面的返回地址? 再 jump 0xXXXXXXXX
push ebp
mov ebp,esp??;//這兩句是masm32中偽關鍵字proc,和C中的函數一樣,翻譯為匯編時自動會加上這兩行還有leave
...
leave?等價 mov esp,ebp?pop ebp
上面這3行是 編譯器為proc做的
ret??;//pop eip
//當只有一個要訪問.text段中的數據時,需要設置段屬性
C:\testmasm\example\666>ml /coff HelloWorld1.asm /link -subsystem:windows -section:.text,ERW
window加載器發現IMAGE_OPTIONAL_HEADER32.ImageBase被占用時,會根據重定位表修改所有的重定位信息
//棧溢出導致部分代碼未執行.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib;數據段.data
szTextHelloWord db 'HelloWorld',0
szTextOverData db 'Test overwrite ret address to simulate stack overflow!',0
szShellCode db 'oneArg',0;代碼段.code
_overWrite proc _lpSrc;_lpSrc,retAddress,ebppushadmov [ebp+4],offset someAddresspopadret
_overWrite endpstart:invoke _overWrite,addr szShellCodeinvoke MessageBox,NULL,offset szTextHelloWord,NULL,MB_OK
someAddress:invoke MessageBox,NULL,offset szTextOverData,NULL,MB_OKinvoke ExitProcess,NULL
end start
?
//no_exist_import_realloc_data.asm
;------------------------
; 無導入表、無數據段、無重定位信息的HelloWorld
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc;聲明函數
_QLGetProcAddress typedef proto :dword,:dword
;聲明函數引用
_ApiGetProcAddress typedef ptr _QLGetProcAddress _QLLoadLib typedef proto :dword
_ApiLoadLib typedef ptr _QLLoadLib_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword
_ApiMessageBoxA typedef ptr _QLMessageBoxA;代碼段.codeszText db 'HelloWorldPE',0
szGetProcAddr db 'GetProcAddress',0
szLoadLib db 'LoadLibraryA',0
szMessageBox db 'MessageBoxA',0user32_DLL db 'user32.dll',0,0;定義函數
_getProcAddress _ApiGetProcAddress ?
_loadLibrary _ApiLoadLib ?
_messageBox _ApiMessageBoxA ?hKernel32Base dd ?
hUser32Base dd ?
lpGetProcAddr dd ?
lpLoadLib dd ?;------------------------------------
; 根據kernel32.dll中的一個地址獲取它的基地址
;------------------------------------
_getKernelBase proc _dwKernelRetAddresslocal @dwRetpushadmov @dwRet,0mov edi,_dwKernelRetAddressand edi,0ffff0000h ;查找指令所在頁的邊界,以1000h對齊.repeat;找到kernel32.dll的dos頭.if word ptr [edi]==IMAGE_DOS_SIGNATURE mov esi,ediadd esi,[esi+003ch];找到kernel32.dll的PE頭標識.if word ptr [esi]==IMAGE_NT_SIGNATURE mov @dwRet,edi.break.endif.endifsub edi,010000h.break .if edi<070000000h.until FALSEpopadmov eax,@dwRetret
_getKernelBase endp ;-------------------------------
; 獲取指定字符串的API函數的調用地址
; 入口參數:_hModule為動態鏈接庫的基址
; _lpApi為API函數名的首址
; 出口參數:eax為函數在虛擬地址空間中的真實地址
;-------------------------------
_getApi proc _hModule,_lpApilocal @retlocal @dwLenpushadmov @ret,0;計算API字符串的長度,含最后的零mov edi,_lpApimov ecx,-1xor al,alcldrepnz scasbmov 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.if ZERO?pop esijmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret
@@:;通過API名稱索引獲取序號索引再獲取地址索引sub ebx,[esi].AddressOfNamessub ebx,_hModuleshr ebx,1add ebx,[esi].AddressOfNameOrdinalsadd ebx,_hModulemovzx eax,word ptr [ebx]shl eax,2add eax,[esi].AddressOfFunctionsadd eax,_hModule;從地址表得到導出函數的地址mov eax,[eax]add eax,_hModulemov @ret,eax_ret:assume esi:nothingpopadmov eax,@retret
_getApi endpstart:;取當前函數的堆棧棧頂值mov eax,dword ptr [esp]push eaxcall @F ; 免去重定位
@@:pop ebxsub ebx,offset @Bpop eax;獲取kernel32.dll的基地址invoke _getKernelBase,eaxmov [ebx+offset hKernel32Base],eax;從基地址出發搜索GetProcAddress函數的首址mov eax,offset szGetProcAddradd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]invoke _getApi,ecx,eaxmov [ebx+offset lpGetProcAddr],eax;為函數引用賦值 GetProcAddressmov [ebx+offset _getProcAddress],eax ;使用GetProcAddress函數的首址;傳入兩個參數調用GetProcAddress函數,獲得LoadLibraryA的首址mov eax,offset szLoadLibadd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]mov edx,offset _getProcAddressadd edx,ebx;模仿調用 invoke GetProcAddress,hKernel32Base,addr szLoadLibpush eaxpush ecxcall dword ptr [edx] mov [ebx+offset _loadLibrary],eax;使用LoadLibrary獲取user32.dll的基地址mov eax,offset user32_DLLadd eax,ebxmov edi,offset _loadLibrarymov edx,[ebx+edi]push eaxcall edx ; invoke LoadLibraryA,addr _loadLibrarymov [ebx+offset hUser32Base],eax;使用GetProcAddress函數的首址,獲得函數MessageBoxA的首址mov eax,offset szMessageBoxadd eax,ebxmov edi,offset hUser32Basemov ecx,[ebx+edi]mov edx,offset _getProcAddressadd edx,ebx;模仿調用 invoke GetProcAddress,hUser32Base,addr szMessageBoxpush eaxpush ecxcall dword ptr [edx] mov [ebx+offset _messageBox],eax;調用函數MessageBoxAmov eax,offset szTextadd eax,ebxmov edx,offset _messageBoxadd edx,ebx;模仿調用 invoke MessageBoxA,NULL,addr szText,NULL,MB_OK push MB_OKpush NULLpush eaxpush NULLcall dword ptr [edx] retend start
?
//遍歷重定位表
;--------------------
; 獲取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].VirtualAddresscld ;//set DF=0 向高地址步增lodsd ;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学习(六)第六章 栈与重定位表 实例栈溢出、模拟加载器加载DLL、遍历重定位表的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。