日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

汇编Ring 3下实现 HOOK API

發布時間:2023/12/9 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 汇编Ring 3下实现 HOOK API 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【文章標題】匯編ring3下實現HOOK?API
【文章作者】nohacks(非安全,hacker0058)
【作者主頁】hacker0058.ys168.com
【文章出處】看雪論壇(bbs.pediy.com)

==================[?匯編ring3下實現HOOK?API?]=====================

?????????????????????????????????????????????????Author:?nohacks
?????????????????????????????????????????????????Emil:?kker.cn@163.com
?????????????????????????????????????????????????Version:?1.1
?????????????????????????????????????????????????Date:?7.18.2006
?????????????????????????????????????????????????

=====[?1.?內容?]=============================================

1.?內容
2.?介紹
??2.1?什么叫Hook?API?
??2.2?API?Hook的應用介紹
??2.3?API?Hook的原則
3.?掛鉤方法
??3.1?改寫IAT導入表法
??3.2?改寫內存地址JMP法
4.?匯編實現
??4.1.?代碼?
??4.2.?分析
5.?結束語


=====[?2.?介紹?]================================================

???這篇文章是有關在OS?Windows下掛鉤API函數的方法。所有例子都在基于NT技術的Windows版本NT4.0

及以上有效(Windows?NT?4.0,?Windows?2000,?Windows?XP)。可能在其它Windows系統也會有效。

???你應該比較熟悉Windows下的進程、匯編器、和一些API函數,才能明白這篇文章里的內容。


=====[2.1?什么叫Hook?API?]=================================
???
???所謂Hook就是鉤子的意思,而API是指Windows開放給程序員的編程接口,使得在用戶級別下可

以對操作系統進行控制,也就是一般的應用程序都需要調用API來完成某些功能,Hook?API的意思

就是在這些應用程序調用真正的系統API前可以先被截獲,從而進行一些處理再調用真正的API來完

成功能。

?====[2.2?API?Hook的應用介紹]=================================
????
???API?Hook技術應用廣泛,常用于屏幕取詞,網絡防火墻,病毒木馬,加殼軟件,串口紅外通訊,游戲外

掛,internet通信等領域API?HOOK的中文意思就是鉤住API,對API進行預處理,先執行我們的函數,例

如我們用API?Hook技術掛接ExitWindowsEx?API函數,使關機失效,掛接ZwOpenProcess函數(如:老王的

EncryptPE),隱藏進程等等......

====[2.3?API?Hook的原則]=====================================
???
???HOOK?API有一個原則,這個原則就是:被HOOK的API的原有功能不能受到任何影響。就象醫生救人,

如果把病人身體里的病毒殺死了,病人也死了,那么這個“救人”就沒有任何意義了。如果你HOOK?API

之后,你的目的達到了,但API的原有功能失效了,這樣不是HOOK,而是REPLACE,操作系統的正常功能

就會受到影響,甚至會崩潰。

====[?3.?掛鉤方法?]==============================================

總的來說,常用的掛鉤API方法有以下兩種:

3.1?改寫IAT導入表法

???修改可執行文件的IAT表(即輸入表)因為在該表中記錄了所有調用API的函數地址,則只需將這些

地址改為自己函數的地址即可,但是這樣有一個局限,因為有的程序會加殼,這樣會隱藏真實的IAT表

,從而使該方法失效。

3.2?改寫內存地址JMP法

????直接跳轉,改變API函數的入口或出口的幾個字節,使程序跳轉到自己的函數,該方法不受程序加殼

的限制。這種技術,說起來也不復雜,就是改變程序流程的技術。在CPU的指令里,有幾條指令可以改變

程序的流程:JMP,CALL,INT,RET,RETF,IRET等指令。理論上只要改變API入口和出口的任何機器碼

,都可以HOOK,下面我就說說常用的改寫API入口點的方法:
????
????因為工作在Ring3模式下,我們不能直接修改物理內存,只能一個一個打開修改,但具體的方法又分成

好幾種,我給大家介紹幾種操作思路:

??<1>首先改寫API首字節,要實現原API的功能需要調用API時先還原被修改的字節,然后再調用原API,調

用完后再改回來,這樣實現有點麻煩,但最簡單,從理論上說有漏HOOK的可能,因為我們先還原了API,如果

在這之前程序調用了API,就有可能逃過HOOK的可能!

??(2)把被覆蓋的匯編代碼保存起來,在替代函數里模擬被被覆蓋的功能,然后調用原函數(原地址+被覆

蓋長度).但這樣會產生一個問題,不同的匯編指令長度是不一樣的(比如說我們寫入的JMP指令占用5個字

節,而我們寫入的這5個字節占用的位置不一定正好是一個或多個完整的指令,有可能需要保存7個字節,

才不能打亂程序原有的功能,需要編寫一個龐大的判斷體系來判斷指令長度,網上已經有這樣的匯編程序

(Z0MBiE寫的LDE32),非常的復雜!

??(3)把被HOOK的函數備份一下,調用時在替代函數里調用備份函數.為了避免麻煩,可以直接備份整個

DLL缺點就是太犧牲內存,一般不推薦使用這種方法!

?
=====[?4.?匯編實現?]==============================================

本文就是建立在第2種方法之上的!本著先易后難的原則,今天我們先來說說它的第1種操作思路.
??
??我們拿API函數ExitWindowsEx來說明,下面是我在OD里攔下的ExitWindowsEx原入口部分

?????77D59E2D????????????$??8BFF??????????mov?edi,edi??
?????77D59E2F????????????.??55????????????push?ebp
?????77D59E30????????????.??8BEC??????????mov?ebp,esp
?????77D59E32????????????.??83EC?18???????sub?esp,18
??????......

??如果我們把ExitWindowsEx的入口點改為下面的,會出現什么情況?

????77D59E2D???????????????B8?00400000???mov?eax,4000
????77D59E32???????????????FFE0??????????jmp?eax
????......


??我們可想而知,程序執行到77D59E32處就會改變流程跳到00400000的地方


??如果我們的00400000處是這樣的子程:

=======================
MyAPI?proc??bs:DWORD??,dwReserved:DWORD??;和ExitWindowsEx一樣帶2個參數?????????????????

;做你想做的事

......

;這里放API入口點改回原機器碼的代碼

;如果你是備份的整個DLL,就直接調用備份API,不用改來改去了,不會有漏勾API的可能!

invoke?ExitWindowsEx,bs,dwReserved?
??????????????????????????
;這里放HOOK?API的代碼
??
.endif

mov?eax,TRUE

ret
=======================

???這里的MyAPI是和ExitWindowsEx參數一樣的的子程,因為程序是在API的入口部分跳轉的,根據

stdcall約定(參數數據從右向左依次壓棧,恢復堆棧的工作交由被調用者),此時堆棧還沒有恢復,我們

在子程里取出的參數數據依然有效,我們可以在這里執行自己的代碼,你可以決定是否繼續按原參數或改

變參數后再調用原API,也可以什么都不做,當然在調用之前,我們要先還原我們修改過的API(可以事先用

API函數ReadProcessMemory讀出原API的前幾個字節備份之),調用完后再改回來繼續HOOK?API,不過這種

方法有漏API的可能(原因前面已經說了),你如果覺得這個方法不妥,因為一般系統DLL都不大,你可以備

份整個DLL.

下面我就列出ring3下HOOK?API的幾個步驟:

1.得到要掛勾API的入口點

2.修改API的入口點所在頁的頁面保護為可讀寫模式

3.用ReadProcessMemory讀出API的入口點開始的幾字節備份

4.用WriteProcessMemory修改API的入口點象這樣的形式:
??
??mov?eax,4000
??
??jmp?eax

?其中的4000要用和原API參數一樣的子程序地址代替


??在這個子程序里我們決定用什么參數再調用原API,不過調用之前要用備份的前8字節改回來

調用之后在掛勾,如此反復.



=====[?4.1.?代碼?]==============================================

??前面所講的是本進程掛勾,我們要掛勾所有進程,可以用全局勾子,需要單獨的一個DLL,我們可

以在DLL的DLL_PROCESS_ATTACH事件里來HOOK?API

=================================hookdll.dll==========================
.486?
.model?flat,stdcall???;參數的傳遞約定是stdcall(從右到左,恢復堆棧的工作交由被調用者)
option?casemap:none?
include?\masm32\include\windows.inc?
include?\masm32\include\kernel32.inc?
includelib?\masm32\lib\kernel32.lib?
include?\masm32\include\user32.inc?
includelib?\masm32\lib\user32.lib?


HOOKAPI?struct?
a??byte???
PMyapi?DWORD?????
d?BYTE????
e?BYTE??
HOOKAPI?ends


;子程序聲明
WriteApi?proto?:DWORD?,:DWORD,:DWORD,:DWORD
MyAPI?proto??:DWORD??,:DWORD
GetApi?proto??:DWORD,:DWORD


;已初始化數據
.data?
hInstance?dd?0
WProcess?dd?0
hacker?HOOKAPI?<>?
CommandLine?LPSTR???

Papi1?DWORD???
Myapi1?DWORD??
ApiBak1?db?10?dup(?)?
DllName1??db?"user32.dll",0??????
ApiName1??db?"ExitWindowsEx",0?
mdb?db?"下面的程序想關閉計算機,要保持阻止嗎?",0


;未初始化數據

.data??
hHook?dd???
hWnd?dd???

;程序代碼段

.code?

DllEntry?proc?hInst:HINSTANCE,?reason:DWORD,?reserved1:DWORD?
???
??
?.if?reason==DLL_PROCESS_ATTACH?????;當DLL加載時產生此事件
????????push?hInst?
????????pop?hInstance?

invoke?GetCommandLine???
mov?CommandLine,eax?????????????????????????????????????????;取程序命令行

;初始化

mov?hacker.a,0B8h?????;mov?eax,
;mov?hacker.d?PMyapi??;0x000000
mov?hacker.d,0FFh?????;jmp?
mov?hacker.e,?0E0h????;eax
?

invoke???GetCurrentProcess???????????????????????????????????;取進程偽句柄

?mov?WProcess?,eax
????
invoke?GetApi,addr?DllName1,addr?ApiName1????????????????????;取API地址
??
?mov?Papi1,eax???????????????????????????????????????????????;保存API地址

invoke?ReadProcessMemory,WProcess,Papi1,addr?ApiBak1,8,NULL??;備份原API的前8字節

?mov?hacker.PMyapi,offset?MyAPI???;0x0000,這里設置替代API的函數地址

invoke?WriteApi,WProcess,Papi1,?addr?hacker?,size?HOOKAPI????;HOOK?API

.endif?

.if??reason==DLL_PROCESS_DETACH?

invoke?WriteApi,WProcess,Papi1,?addr?ApiBak1?,8???????????????;還原API

.endif?

?mov??eax,TRUE?
????ret?
DllEntry?Endp?

GetMsgProc?proc?nCode:DWORD,wParam:DWORD,lParam:DWORD?
????invoke?CallNextHookEx,hHook,nCode,wParam,lParam?
?????mov?eax,TRUE
?????
??????ret?
GetMsgProc?endp?

InstallHook?proc
???
????invoke?SetWindowsHookEx,WH_GETMESSAGE,addr?GetMsgProc,hInstance,NULL?
????mov?hHook,eax?
????ret?
InstallHook?endp?

UninstallHook?proc?
????invoke?UnhookWindowsHookEx,hHook?
???invoke?WriteApi,WProcess,Papi1,?addr?ApiBak1?,8
??ret?
UninstallHook?endp?

GetApi?proc?DllNameAddress:DWORD,ApiNameAddress:DWORD

invoke??GetModuleHandle,DllNameAddress?????;取DLL模塊句柄
???
??.if?eax==NULL
??
??invoke?LoadLibrary?,DllNameAddress????;加載DLL
??
???.endif
??
?invoke?GetProcAddress,eax,ApiNameAddress??;取API地址
???

mov?eax,eax
??
ret

GetApi?endp


;============================下面是核心部分=========================


WriteApi?proc?Process:DWORD?,Papi:DWORD,Ptype:DWORD,Psize:DWORD

LOCAL?mbi:MEMORY_BASIC_INFORMATION
LOCAL?msize:DWORD


;返回頁面虛擬信息
invoke?VirtualQueryEx,Process,?Papi,addr?mbi,SIZEOF?MEMORY_BASIC_INFORMATION

;修改為可讀寫模式

invoke?VirtualProtectEx,Process,?mbi.BaseAddress,8h,PAGE_EXECUTE_READWRITE,addr?

mbi.Protect

;開始寫內存

invoke??WriteProcessMemory,Process,?Papi,?Ptype,Psize?,NULL

PUSH?eax

;改回只讀模式

invoke?VirtualProtectEx,Process,mbi.BaseAddress,8h,PAGE_EXECUTE_READ,addr?mbi.Protect

pop?eax

ret

WriteApi?endp



;替代的API,參數要和原來一樣

MyAPI?proc??bs:DWORD??,dwReserved:DWORD??????????????????????

invoke?MessageBox,?NULL,??CommandLine,?addr?mdb,?MB_YESNO??????;彈出信息框選擇是否阻止

.if?eax==7???????????????????????????????????????????????????;如果選擇否

?invoke?WriteApi,WProcess,Papi1,?addr?ApiBak1?,8??????????????;先還原API
?
?invoke?ExitWindowsEx,bs,dwReserved???????????????????????????;再調用API
?
?invoke?WriteApi,WProcess,Papi1,?addr?hacker?,sizeof?HOOKAPI??;調用完后再改回來
??
.endif

mov?eax,TRUE?
ret

MyAPI?endp

End?DllEntry


===============================hookdll.def=============================

LIBRARY?hookdll
EXPORTS?InstallHook
EXPORTS?UninstallHook


=====[?4.2.?分析?]==============================================

HOOKAPI?struct?
a??byte???
PMyapi?DWORD?????
d?BYTE????
e?BYTE??
HOOKAPI?ends


???為了便于理解和使用,我定義了一個結構:這個結構有4個成員,第一個成員a,是個字節型,我用來放

0B8h(mov?eax),PMyapi一個整數型,用來放我們的替代API函數的地址(0X000),第3個和第4個成員我分別

用來放JMP和EAX(jmp?eax)那么連起來就是?mov,0X0000?;?jmp?eax??


?.if?reason==DLL_PROCESS_ATTACH?????
????????push?hInst?
????????pop?hInstance?

invoke?GetCommandLine???
mov?CommandLine,eax?????????????????????????????????????????

;初始化

mov?hacker.a,0B8h?????;mov?eax,
;mov?hacker.d?PMyapi??;0x0000
mov?hacker.d,0FFh?????;jmp?
mov?hacker.e,?0E0h????;eax


invoke???GetCurrentProcess???????????????????????????????????

?mov?WProcess?,eax


??當DLL加載時,我們先保存模塊句柄,讀取程序命令行,然后初始化HOOKAPI結構,寫入我們要寫到內存的

指令(PMyapi以后寫入)并調用GetCurrentProcess取出進程偽句柄方便以后寫內存.

invoke?GetApi,addr?DllName1,addr?ApiName1????????????????????
??
?mov?Papi1,eax???????????????????????????????????????????????

invoke?ReadProcessMemory,WProcess,Papi1,addr?ApiBak1,8,NULL??
?
mov?hacker.PMyapi,offset?MyAPI???;0x0000???

invoke?WriteApi,WProcess,Papi1,?addr?hacker?,size?HOOKAPI????;HOOK?API


??接下來用子程GetApi取出要掛勾API的入口點,并用ReadProcessMemory讀出入口點8字節備份之,寫入
PMyapi調用子程WriteApi改寫API的入口點,這個子程我不準備詳細說了,它非常的簡單,無非就是幾個

API的調用.它的核心就是通過WriteProcessMemory改寫內存.

.if??reason==DLL_PROCESS_DETACH?

invoke?WriteApi,WProcess,Papi1,?addr?ApiBak1?,8???????????????

.endif?

?mov??eax,TRUE?
????ret?

???如果這個DLL被卸載了,那么那個在DLL里的替代函數(MyAPI)將是無效的,如果這個時候程序再調用這

個API,將出現非法操作,因此在DLL卸載前,我們必須還原API.

???總結一下,現在只要程序加載這個DLL,這個程序的ExitWindowsEx就會被我們勾住,接下來要怎樣才能

讓所有的程序都加載這個DLL呢?這就需要安裝全局勾子:

??InstallHook?proc
???
??????invoke?SetWindowsHookEx,WH_GETMESSAGE,addr?GetMsgProc,hInstance,NULL?
????
??????invoke?WriteApi,WProcess,Papi1,?addr?hacker?,sizeof?HOOKAPI

??????mov?hHook,eax?
?????ret?
??InstallHook?endp?

???通過SetWindowsHookEx安裝勾子,最后一個參數可以決定該鉤子是局部的還是系統范圍的。如果該值

為NULL,那么該鉤子將被解釋成系統范圍內的,那它就可以監控所有的進程及它們的線程。

如果該函數調用成功的話,將在eax中返回鉤子的句柄,否則返回NULL。我們必須保存該句柄,因為后

面我們還要它來卸載鉤子,可以看出,我們創建的Hook類型是WH_CALLWNDPROC類型,該類型的Hook在進程

與系統一通信時就會被加載到進程空間,從而調用dll的初始化函數完成真正的Hook,值得一提的是:因

為要調用SetWindowsHookEx來安裝鉤子,我們GUI程序的這個DLL不會被

UnhookWidowHookEx卸載,也就只有一次DLL_PROCESS_ATTACH事件,因此這里再要

HOOK?API一次!

我們回頭來看看鉤子回調函數:

??GetMsgProc?proc?nCode:DWORD,wParam:DWORD,lParam:DWORD?
??????invoke?CallNextHookEx,hHook,nCode,wParam,lParam?
???????mov?eax,TRUE
?????
???????ret?
??GetMsgProc?endp?

???可以看到這里只是調用CallNextHookEx將消息交給Hook鏈中下一個環節處理,因為這里API函數
SetWindowsHookEx的唯一作用就是讓進程加載我們的dll。

??UninstallHook?proc?
?????invoke?UnhookWindowsHookEx,hHook?
?????invoke?WriteApi,WProcess,Papi1,?addr?ApiBak1?,8
???ret?
??UninstallHook?endp?

要卸載一個鉤子時調用UnhookWidowHookEx函數,該函數僅有一個參數,就是欲卸載的鉤子的句柄。鉤

子卸載后我們也要還原我們GUI程序的API.

??LIBRARY?hookdll
??EXPORTS?InstallHook
??EXPORTS?UninstallHook

???我們公開DLL里的InstallHook和UninstallHook函數,方便程序調用,這樣我們只要在另外的程序中調

用InstallHook便可安裝全局勾子,勾住所有程序中的API:ExitWindowsEx,執行我們自定的子程!

如果不需要了,可以調用UninstallHook卸載全局勾子.

???請注意:對于遠程鉤子,鉤子函數必須放到DLL中,它們將從DLL中映射到其它的進程空間中去。當

WINDOWS映射DLL到其它的進程空間中去時,不會把數據段也進行映射。簡言之,所有的進程僅共享DLL

的代碼,至于數據段,每一個進程都將有其單獨的拷貝。這是一個很容易被忽視的問題。您可能想當然

的以為,在DLL中保存的值可以在所有映射該DLL的進程之間共享。在通常情況下,由于每一個映射該

DLL的進程都有自己的數據段,所以在大多數的情況下您的程序運行得都不錯。但是鉤子函數卻不是如

此。對于鉤子函數來說,要求DLL的數據段對所有的進程也必須相同。這樣您就必須把數據段設成共享

的:

?一般來說,?目標文件有三個段,?分別是?text/data/bss?段.

.text?段放置代碼,?是只讀且可運行段?

.data?段放置靜態數據,?這些數據會被放置入?exe?文件.?這個段是可讀寫,?但是不能運行的.?

.bss?段放置動態數據,?這些數據不被放入?exe?文件,?在exe文件被加載入內存后才分配的空間.

你可以通過在鏈接開關中指定段的屬性來實現:

/SECTION:name,[E][R][W][S][D][K][L][P][X]

其中S表示共享,已初期化的段名是.data,未初始化的段名是.bss。假如您想要寫一個包含鉤子函數的

DLL,而且想使它的未初始化的數據段在所有進程間共享,您必須這么做:
?
link?/section:.bss[S]??/DLL??/SUBSYSTEM:WINDOWS?..........

否則,您的全局勾子將不能正常工作!

=====[?5.?結束語?]================================================

????我歡迎任何人提出更多的這里沒有提到的掛鉤方法,我肯定那會有很多。同樣歡迎補充我介紹得不

是很詳細的方法。也可以把我懶得寫的其它方法完成,把源代碼發給我。這篇文檔的目的是演示掛鉤技

術的細節,我希望我做到了。
????
============================[?End?]========================

轉載于:https://www.cnblogs.com/milantgh/p/3873191.html

總結

以上是生活随笔為你收集整理的汇编Ring 3下实现 HOOK API的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。