{三}簡單的訊息
spy的實現
凡寫過一些程式的人,大都用過vs的
spy++
工具,非常好用。
delphi
也有乙個類似的工具叫
winsignt32
,說實話,比
spy++
可是差遠了。這一篇將介紹如何實現乙個簡單的訊息
spy工具,其功能大概類似於
spy++
的spy message
,以此來學習全域性鉤子的用法。說點題外話,這些知識都是筆者經過實踐學習而得來,其間不乏屢遭碰壁者,因此想寫出來,幫助有興趣者更快地學習這些知識。
首先得介紹於訊息相關的幾個鉤子,主要是:
wh_getmessage
:應用程式使用
wh_getmessage hook
來監視從
getmessage
或者peekmessage
函式返回的訊息。你可以使用
wh_getmessage hook
去監視滑鼠和鍵盤輸入,以及其他傳送到訊息佇列中的訊息。
wh_callwndproc
和wh_callwndprocret
:wh_callwndproc
和wh_callwndprocret hooks
使你可以監視傳送到視窗過程的訊息。系統在訊息傳送到接收視窗過程之前呼叫
wh_callwndproc
函式過程,並且在視窗過程處理完訊息之後呼叫
wh_callwndprocret
函式過程。
上面說得很明白了,
wh_getmessage
相當於鉤住了
postmessage
傳送的訊息,而另外兩個相當於鉤住了
sendmessage
傳送的訊息。
有了這三個鉤子,已經足夠
spy所有的訊息了。至於三個鉤子的鉤子過濾函式,可以參見
msdn
的getmsgproc
和callwndproc
以及callwndretproc
的說明,相信通過上面的講解,應用容易這幾個過程的引數的含義。而這並不是這一篇的重點。
我們知道的一點常識是,全域性鉤子必須安裝在
dll中,但說到實際的應用,其實也並非這麼簡單。最好了解一下一些執行機制:
在win16
環境中,
dll的全域性資料對每個載入它的程序來說都是相同的;而在
win32
環境中,情況卻發生了變化,
dll函式中的**所建立的任何物件(包括變數)都歸呼叫它的執行緒或程序所有。當程序在載入
dll時,作業系統自動把
dll位址對映到該程序的私有空間,也就是程序的虛擬位址空間,而且也複製該
dll的全域性資料的乙份拷貝到該程序空間。也就是說每個程序所擁有的相同的
dll的全域性資料,它們的名稱相同,但其值卻並不一定是相同的,而且是互不干涉的。
好好的理解一下上面的這一段話。全域性鉤子安裝在
dll中,我們假設
dll中有乙個
api叫
starthook
,其中呼叫了
setwindowshookex
函式。當某乙個程序呼叫
dll中的
starthook
時,鉤子開始安裝,實際上它是把
dll注入到了所有的程序中(
dll注入中的乙個方法即是利用全域性鉤子的技術。詳見《
window
高階程式設計》),這樣全域性鉤子才能夠監視到系統級別的訊息。而上面的話說得很明白,每乙個程序都自己的位址空間,且互不干涉。
這就帶來了乙個難題,即資料共享。讓我來舉個例子。假設我們要監視某乙個視窗的訊息,則假設呼叫
dll中的乙個函式:
startspymessage
,向這個函式傳入將被監視的視窗的控制代碼。而
startspymessage
函式中將該控制代碼儲存在
dll中的乙個全域性變數中,接著在鉤子過程裡判斷截獲的訊息結構中的控制代碼值是否和該全域性變數相等,相等則傳送訊息通知外部。這乙個操作過程是在某乙個程序中完成的。現在問題來了,當
dll被注入到其他程序中時,儲存視窗控制代碼的變數並沒有得到共享,它是
0。因此,就形成了乙個現象:當監視自已程式的視窗時,沒有問題,因為自己程序的
dll的控制代碼變數得到賦值,所以可以判斷;但監視其他程式的視窗時,不行,因為其他程序的該變數是
0,判斷時就不對了。就好象不是全域性鉤子一樣。
說了這麼多,不知讀者是否明白。總之,我們需要一種共享技術,讓
dll中的變數在所有程序中都是一樣的。另人羨慕的是:
c++中
#pragma data_seg
預處理指令用於設定共享資料段。但
delphi
沒有,我們只能用記憶體對映檔案來達到目的。利用,
,mapviewoffile
等幾個api
取得一段共享記憶體(具體用法看幫助說明吧,這裡實在沒有篇幅來講了),讓所有程序都能共享它們。最後用完,要用
unmapviewoffile
,closehandle
等api
釋放共享記憶體。
解決了第乙個資料共享問題,還有另乙個問題等解決。當截獲了乙個訊息時,怎麼樣把這個訊息包成乙個資料報傳送到顯示的視窗呢。如果是同一程序,那倒好辦,因為都在同一位址空間中嗎,你
new了乙個記憶體,然後用乙個自定義訊息傳送過去沒有問題。但如果是截獲其他程序的訊息呢。此時
new的記憶體位址只是相對於該程序而言,而當傳送訊息到顯示的程序時,那個記憶體位址已經完成不同了。所以我們還需要乙個程序間通訊的技術。好在並不是很難。
用wm_copydata
訊息即可以完成,
wparam
表示傳遞該訊息的視窗,這個引數我們可以忽略。
lparam
是指向copydatastruct
結構的指標。看看其宣告:
typedef struct tagcopydatastruct copydatastruct;
dwdata
指定乙個
32的值傳遞過去。這個對於我們不重要。
cbdata
確定lpdata
指向的記憶體的大小
lpdata
指向一塊記憶體。
這裡最重要的無疑就是
lpdata
了,可以設定乙個訊息結構來儲存截獲得到的訊息的資訊,然後將其掛到
lpdata
上面,讓
wm_copydata
訊息載著這一塊記憶體送到顯示的視窗去。
ok了。
所有重點技術都解決了,其他的就沒有什麼了。希望讀者能夠看得懂。
鉤子應用技術
鉤子 hook 技術,以其強大的功能,被廣泛的應用於系統監視,訊息管理。他可以在訊息到達目標視窗以前截獲訊息,並任意的處理系統訊息,達到一般應用程式無法達到的功能。本文主要從鉤子的種類,作用,應用入手,概要的介紹了鉤子技術的應用和作用。並附加乙個shell鉤子的例子和過程。讀者評分 3 評分次數 1...
鉤子原理與應用
目錄 1.基本概念 2.執行機制 2.1 鉤子鍊錶與鉤子子程 2.2 鉤子安裝與釋放 2.3 一些執行機制 2.4 系統鉤子與執行緒鉤子 2.5 鉤子的不足 2.6 幾點說明 鉤子 hook 是windows訊息處理機制的乙個平台,應用程式可以在上面設定子程式以監聽指定視窗的某種訊息,而且所監聽的視...
Ember旅程系列(四) 模型鉤子
英文原版 現在呢,讓我給rentals頁面新增一些可用的租賃資訊。ember通過model物件來儲存給頁面的資料。為了簡單起見,我們暫時將model物件中的資料硬編碼。稍後,我們會使用ember data來達成這個目的。ember data 乙個給力的資料管理支援庫,內置於ember 下面這張,就是...