kernel32.dll默認很早加載進去,其中有函數用于加載進程,否則進程創(chuàng)建不出。
獲取kernel32.dll的基地址:
1.使用vs cmd自帶的dumpbin工具:dumpbin /headers kernel32.dll
?還有PEinfo,onlydbg
?XP OS下ntdll.dll,kernel32.dll不會被重定位。
2.從進程地址空間開始搜索
?尋找PE特征字符串,分析導出表,查找GetProcAddress"特征函數“,再對齊即可。
3.從SEH框架開始查找
?OS默認的結構化異常處理程度指向kernel32._except_handler3函數。
4.從PEB開始查找
5.直接從main函數入口時esp指向地址為kernel.dll中的一個值
?
//通過main函數入口里esp指向的返回地址為kernel32.dll里的地址.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib;數據段.data
szText db 'kernel32.dll在本程序地址空間的基地址為:%08x',0dh,0ah,0
kernel32Base dd ?
szBuffer db 256 dup(0);代碼段.code
_getKernelBase proc _dwKernelRetAddresslocal @dwRetpushadmov @dwRet,0mov edi,_dwKernelRetAddressand edi,0ffff0000h ;查找指令所在頁的邊界,以1000h對齊.repeat.if word ptr [edi]==IMAGE_DOS_SIGNATURE ;找到kernel32.dll的dos頭mov esi,ediadd esi,[esi+003ch].if word ptr [esi]==IMAGE_NT_SIGNATURE ;找到kernel32.dll的PE頭標識mov @dwRet,edi.break.endif.endifsub edi,010000h.break .if edi<070000000h.until FALSEpopadmov eax,@dwRetret
_getKernelBase endp start:mov eax,dword ptr [esp]invoke _getKernelBase,eaxinvoke wsprintf,addr szBuffer,addr szText,eaxinvoke MessageBox,NULL,addr szBuffer,NULL,MB_OKretend start
?
;------------------------
; 獲取kernel32.dll的基址
; 從PEB結構中搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib;數據段.dataszText db 'kernel32.dll的基地址為%08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0);代碼段.codestart:assume fs:nothingmov eax,fs:[30h] ;獲取PEB所在地址mov eax,[eax+0ch] ;獲取PEB_LDR_DATA 結構指針mov esi,[eax+1ch] ;獲取InInitializationOrderModuleList 鏈表頭;第一個LDR_MODULE節(jié)點InInitializationOrderModuleList成員的指針lodsd ;獲取雙向鏈表當前節(jié)點后繼的指針mov eax,[eax+8] ;獲取kernel32.dll的基地址;輸出模塊基地址invoke wsprintf,addr szBuffer,addr szText,eaxinvoke MessageBox,NULL,addr szBuffer,NULL,MB_OKretend start
?
;------------------------
; 獲取kernel32.dll的基址
; 從SEH框架空間中搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib;數據段.dataszText db 'kernel32.dll的基地址為%08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0);代碼段.codestart:assume fs:nothingmov eax,fs:[0]inc eax ; 如果eax=0FFFFFFFFh,則設置為0
loc1: dec eaxmov esi,eax ;ESI指向EXCEPTION_REGISTRATIONmov eax,[eax] ;eax=EXCEPTION_REGISTRATION.previnc eax ;如果eax=0FFFFFFFFh,則設置為0jne loc1lodsd ;跳過0FFFFFFFFhlodsd ;獲取kernel32._except_handler地址xor ax,ax ;按照10000h對齊,舍入jmp loc3loc2:sub eax,10000h
loc3:cmp dword ptr [eax],905A4Dhjne loc2;輸出模塊基地址invoke wsprintf,addr szBuffer,addr szText,eaxinvoke MessageBox,NULL,addr szBuffer,NULL,MB_OKretend start
?
;------------------------
; 獲取kernel32.dll的基址
; 從進程地址空間搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib;數據段.dataszText db 'kernel32.dll的基地址為%08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0);代碼段.codestart:call loc0db 'GetProcAddress',0 ;特征函數名loc0:pop edx ;edx中存放了特征函數名所在地址push edxmov ebx,7ffe0000h ;從高地址開始loc1:cmp dword ptr [ebx],905A4DhJE loc2 ;判斷是否為MS DOS頭標志loc5:sub ebx,00010000hpushad ;保護寄存器1invoke IsBadReadPtr,ebx,2.if eaxpopad ;恢復寄存器1jmp loc5.endifpopad ;恢復寄存器1jmp loc1loc2: ;遍歷導出表mov esi,dword ptr [ebx+3ch] add esi,ebx ;ESI指向PE頭mov esi,dword ptr [esi+78h]nop.if esi==0jmp loc5.endifadd esi,ebx ;ESI指向數據目錄中的導出表mov edi,dword ptr [esi+20h] ;指向導出表的AddressOfNamesadd edi,ebx ;EDI為AddressOfNames數組起始位置mov ecx,dword ptr [esi+18h] ;指向導出表的NumberOfNamespush esixor eax,eax
loc3:push edipush ecxmov edi,dword ptr [edi]add edi,ebx ;edi指向了第一個函數的字符串名起始mov esi,edx ;esi指向了特征函數名起始xor ecx,ecxmov cl,0eh ;特征函數名的長度repe cmpsbpop ecxpop edije loc4 ;找到特征函數,轉移add edi,4 ;edi移動到下一個函數名所在地址inc eax ;eax為計數loop loc3jmp loc5
loc4:;特征函數匹配成功,輸出模塊基地址invoke wsprintf,addr szBuffer,addr szText,ebxinvoke MessageBox,NULL,addr szBuffer,NULL,MB_OKretend start
?
;------------------------
; 無導入表的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;數據段.dataszText 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 ?;代碼段.code
;------------------------------------
; 根據kernel32.dll中的一個地址獲取它的基地址
;------------------------------------
_getKernelBase proc _dwKernelRetAddresslocal @dwRetpushadmov @dwRet,0;查找指令所在頁的邊界,以1000h對齊 mov edi,_dwKernelRetAddressand edi,0ffff0000h .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為動態(tài)鏈接庫的基址
; _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];獲取kernel32.dll的基地址invoke _getKernelBase,eaxmov hKernel32Base,eax;從基地址出發(fā)搜索GetProcAddress函數的首址invoke _getApi,hKernel32Base,addr szGetProcAddrmov lpGetProcAddr,eaxmov _getProcAddress,eax ;為函數引用賦值 GetProcAddress;使用GetProcAddress函數的首址;傳入兩個參數調用GetProcAddress函數;獲得LoadLibraryA的首址invoke _getProcAddress,hKernel32Base,addr szLoadLibmov _loadLibrary,eax;使用LoadLibrary獲取user32.dll的基地址invoke _loadLibrary,addr user32_DLLmov hUser32Base,eax;使用GetProcAddress函數的首址,獲得函數MessageBoxA的首址invoke _getProcAddress,hUser32Base,addr szMessageBoxmov _messageBox,eax ;調用函數MessageBoxAinvoke _messageBox,NULL,offset szText,NULL,MB_OKretend start
?
總結
以上是生活随笔為你收集整理的PE学习(十一)第十一章:动态加载技术的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。