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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ windows 平台的 Hook

發布時間:2024/7/23 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ windows 平台的 Hook 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

From:https://www.jianshu.com/p/1cbde2276752

Windows Hook(鉤子)函數詳解:https://wenku.baidu.com/view/fd9088aaf46527d3250ce059.html

?

環境:vs 2019,添加Windows.h頭文件。

核心函數:SetWindowsHookEx(),UnhookWindowsHookEx(),CallNextHookEx()
你可能在其他api文檔看到SetWindowsHookExA、SetWindowsHookExW這兩個函數,他們是編碼上的區別,A指ASCII,W指wide-char也就是unicode編碼,但系統已經幫我們用宏處理好,只需調用 SetWindowsHookEx 就行了,自動選擇對應編碼那個函數。

Hook:建議先百度自行稍微了解

HINSTANCE、HMODULE、HANDLE、HWND是一樣的東西,都是各種 typedef 繞來繞去,區別只在于人類使用時附加的語義,實際上都是一串數字。下面就混著用了。
下面僅以最基本的控制臺應用示例。

?

非常簡單的一個例子,運行后鼠標移動即可看到效果:

LRESULT CALLBACK mymouse(int nCode, WPARAM wParam, LPARAM lParam) {cout<<"yes"<<endl;return CallNextHookEx(NULL, nCode, wParam, lParam); }int main() {HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mymouse, 0, 0);MSG msg;while (GetMessage(&msg, NULL, NULL, NULL)){}UnhookWindowsHookEx(mouseHook);return 0; }

?

1.mymouse函數:
LRESULT:long result,實際就是個宏,當long(長整數)就行。
CALLBACK:也是宏,實際上是__stdcall,函數修飾關鍵字,詳細自行可百度。
WPARAM、LPARAM:還是宏,當整數就行。不同的值有不同含義,具體看msdn。

為什么這樣定義?
因為SetWindowsHookEx()的第二個參數就是接受這樣的一個函數指針。簡單了解使用函數指針
該函數返回0時,消息繼續往下傳遞;返回1時消息不再往下傳遞。

為什么是return CallNextHookEx()而不是直接return 0或1?
SetWindowsHookEx()把這個鉤子放在Hook鏈頭,不調用這個方法其他鏈節點的Hook不執行。另外該函數的第一個參數沒用,直接null就行。

2.HHOOK類型:
代表加進去的鉤子,后面解除鉤子的函數UnhookWindowsHookEx(),參數就是這個的對象。

3.MSG、while:
為了不讓程序結束,用一個while卡住它。

為什么不用while(true)?
看第5點

4.SetWindowsHookEx函數:
原型:

HHOOK WINAPI SetWindowsHookEx(_In_ int idHook,_In_ HOOKPROC lpfn,_In_ HINSTANCE hMod,_In_ DWORD dwThreadId );

看到陌生的不用頭大,都是關鍵字和宏罷了,直接講4個參數。
idHook:一個int值,不同的值對應不同的鉤子(鼠標or鍵盤之類的)。vs中打出WH_后,看自動補全顯示的名字,你就能了解了,不用死記硬背。WH就是window hook的意思。
lpfn:函數指針,類型就是mymouse函數那個類型。每當鉤子獲取到消息,就會調用該函數指針。
hMod:用于幫助找到真正的地址,下面會講。
dwThreadId:DWORD也是一個宏,當整數就行。這里指你要把鉤子掛到哪個線程中,所有進程的所有線程都可以選擇,只不過其他進程的線程不一定掛的上,需要其他手段,不作細說。填0就是嘗試把所有線程都給掛上,成了所謂的全局鉤子(只是嘗試,拒絕掛鉤子的線程還是掛不上)。

當掛鉤子失敗時,該函數返回null。另外msdn講解參數這段一定要看:
lpfn [in]
Type: HOOKPROC

A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
如果dwThreadId指定的線程并不是由當前進程創建的,那么子程(就是那個函數,如示例的mymouse)一定要寫在dll里(動態鏈接庫)。
原因:由于lpfn是指針和邏輯地址的機制,當前進程的函數地址不適用于其他進程。系統一般需要借助dll模塊以確定函數入口地址(low-level除外,只有此時可以不寫dll)。

hMod [in]
Type: HINSTANCE

A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
當 dwThreadId指定的線程是當前進程創建的線程 子程的代碼是在當前進程(非dll)寫的,那么這個hMod必須填0(也就是null)。
值得一提,在dll中時,這個參數要填為該dll的句柄,可以有兩種方法獲取來填:
(1)把入口DllMain的參數hModule(HMODULE和HINSTANCE一樣的)保存下來,填進去(推薦)
(2)通過函數GetModuleHandle(L"dll name")來獲取(加L代表為unicode編碼,不用加dll后綴)(不推薦)

絕大多數情況下會寫成動態鏈接庫(建議)。上面示例能算上特例,不寫在dll中就要:首先是鉤子類型不是WH_MOUSE而是WH_MOUSE_LL(LL代表low-level,另一種回調機制,寫在dll中則兩種都可以),不然沒反應,其次第三個參數hMod寫成0。

5.GetMessage函數:從線程消息隊列獲取消息,沒有消息將進入等待態直至有消息被插入隊列
(1)系統獲取消息-----系統分發消息---(Hook鏈)-----消息抵達線程消息隊列。(這下搞懂第一點說的消息是否繼續傳遞和CallNextHookEx了吧)
(2)我們示例的控制臺程序創建時默認是沒有消息隊列的,但調用相關函數時就自動創建消息隊列,如GetMessage函數
(3)子程是由系統通過回調機制,把執行SetWindowsHookEx函數的線程叫回來去執行的,也就是示例中的mymouse函數是由主線程去執行的。因此,如果寫成while(true),那么線程將無限運行,系統沒有機制能夠中斷它的執行來把它叫過來執行子程。但是,調用GetMessage函數后,線程有了消息隊列,而且我們沒有往里面插入消息,線程就進入等待態,此時系統便能夠控制該線程,讓它去執行子程。也就是說,我們需要把這個線程弄成等待態去讓系統獲取控制權,所以你還可以使用while(true){ Sleep(100); }達到相同目的。
(4)由于上述原因,對于掛Hook的線程來說,這樣一個循環查詢消息隊列是有必要的。
(5)如果系統發現hook的子程長期得不到執行(你的線程正在繁忙),那么系統會自動刪除掉這個hook。這里就要注意了,不要安排耗時任務在該線程上。

?

?

?

總結

以上是生活随笔為你收集整理的C++ windows 平台的 Hook的全部內容,希望文章能夠幫你解決所遇到的問題。

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