delphi-學用鉤子函數

編者按:在計算機病毒氾濫的今天,我們正使用着各種殺毒軟件,你知道這些殺毒軟件和病毒是怎麼編寫的嗎?其實,這些殺毒軟件和病毒都用到了一種重要的函數——鉤子函數。
使用鉤子函數並不是什麼高深的技術,很早在Microsoft的Win32 SDK手冊上就有記載。不過很可惜要看懂Microsoft的手冊,可是不容易的事!而且它的例子是使用SDK寫的,又不完整!這就讓我們這些只會Delphi的程序員更看不懂了。
前段時間我研究了一下鉤子函數,現在我把我幾周的研究成果寫出來,希望對大家有所幫助。
鉤子函數一共有12種,分爲全局鉤子和線程鉤子兩種。線程鉤子就只監視某個線程,全局鉤子可以監視Windows的所有線程。具體的你可以看看Delphi 帶的Win32 SDK(說實話有些鉤子我也沒有用過^_^),全局鉤子是必須用DLL加載,也就是說鉤子函數必須包裝爲一個DLL文件,然後再在主程序中調用鉤子DLL中函數纔可以!而且有些鉤子是必須使用DLL加載爲全局鉤子,其他的鉤子就可以分爲全局和進程兩種。
再解釋設置鉤子的Api函數:
function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK; stdcall;
其中第一個參數是鉤子的類型;第二個參數是鉤子函數的地址;第三個參數是包含鉤子函數的模塊句柄;第四個參數指定監視的線程;返回鉤子句柄。如果指定了某個確定的線程就只監視那個線程,即是線程鉤子;如果爲空,即是監視所有線程的全局鉤子。
如果你只想使用進程鉤子的話,有一個現成的控件可以用,就是Rx的RxWindowHook控件。拖到窗體上,設置Active爲True就可以了。然後它只有BeforeMessage(消息從消息隊列取走前)和AfterMessage(消息從消息隊列取走後)兩個事件,響應它就可以了,怎麼用就看你的了。
下面我說說全局鉤子的使用!我用最簡單的鼠標全局鉤子講解,我假定你懂如何寫DLL。來,看一個最簡單的源程序:
##1一、DLL的工程文件
library hookprj;
uses
SysUtils,
Classes,
hkprocunit in 'hkprocunit.pas';
{$R *.RES}
exports //只要把這兩個函數輸出就可以了,EnableMouseHook,DisableMouseHook;//不會不懂函數的意思吧^_^
begin
end.
##1二、DLL輸出函數的實現單元
unit hkprocunit;
interface
uses
Windows,Messages;
var
hHk: HHOOK;//鉤子的句柄值。
function MouseHookProc(nCode: Integer;WParam: WPARAM;LParam: LPARAM): LRESULT;stdcall;
//鼠標鉤子的回調函數,即用它來處理得到消息後要幹什麼。這裏我只是發送一個//WM_PASTE消息。
//nCode參數是Hook的標誌,一般只關心小於0時。看下面的詳細說明
//WParam參數表示鼠標消息的類型
//LParam參數是一個指向 TMOUSEHOOKSTRUCT 結構的指針。結構包含了鼠標消息的狀態,我只用了hwnd一個
//即鼠標消息要傳遞給的窗口句柄。
//返回值如果不是0的話Windows就把這個消息丟掉,其它的程序就不會再收到這個消息了。
function EnableMouseHook:Boolean; stdcall; export;
function DisableMouseHook:Boolean; stdcal; export;//兩個函數都是Boolean類型,成功都是返回True
implementation
function MouseHookProc(nCode: Integer;WParam: WPARAM;LParam:LPARAM): LRESULT;stdcall;
var
MouseHookStruct: ^TMOUSEHOOKSTRUCT;//這個結構Delphi在Windows單元有定義,直接用就可以了。
nState: SHORT;//得到鍵盤狀態的GetKeyState函數的返回值。這是一個16位的數。
begin
Result := 0; //最好首先給它一個返回值,不然會有警告的!記住這可不是C語言。
//當nCode小於0時表示還有其它的Hook必須把參數傳給它。
//此時就要用Api函數CallNextHookEx讓它調用下一個Hook!!!當然不用好像也可以。
if nCode < 0 then
Result := CallNextHookEx(hHk,nCode,WParam,LParam)//參數是現成的,直接用就可以了。
//詳細的說明可以參考Win32 SDK
else if wParam = WM_LBUTTONDBLCLK then //判斷是不是鼠標左鍵雙擊事件
begin
nState := GetKeyState(VK_CONTROL);//這個函數只有一個參數,就是要得到的鍵的//鍵值,這裏用Windows的虛擬鍵值表示ctrl鍵。
if (nState and $80000000) = $80000000 then//如果按下了,那麼返回值的最高位爲1
begin //即是16進制的80000000,如果沒有按下就返回0
MouseHookStruct := Pointer(LParam);//轉換指針並付值給MouseHookStruct變量。
SendMessage(MouseHookStruct.hwnd,WM_PASTE,0,0);//如果條件都滿足了就發送WM_PASTE(粘貼)消息
end;
end;
end;
function EnableMouseHook:Boolean; stdcall; export;
begin
if hHk = 0 then //爲了安全,必須判斷一下再設置鉤子。
Begin
//第三個參數的Hinstance 在Delphi中有定義,用就可以了。第四個參數必須爲0
hHk := SetWindowsHookEx(WH_MOUSE,@MouseHookProc,Hinstance,0);
Result := True;
end
else
Result := False;
end;
function DisableMouseHook:Boolean; stdcall; export;
begin
if hHk <> 0 then //如果有鉤子就卸掉它。
begin
UnHookWindowsHookEx(hHk);
hHk := 0;
Result := True;
end
else
Result := False;
end;
end.
##1三、使用鉤子的應用程序的工程文件
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
...
##1四、使用鉤子的應用程序代碼
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, RxHook;
type
TForm1 = class(TForm)
Button1: TButton;//放上兩個Button和一個Edit控鍵用來試用我們的鉤子函數。
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
//下面是調用hookprj.dll中的函數。
function EnableMouseHook:Boolean; stdcall; external 'Hookprj.dll' name 'EnableMouseHook';
function DisableMouseHook:Boolean; stdcall; external 'Hookprj.dll' name 'DisableMouseHook';
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
if EnableMouseHook then
ShowMessage('啓動鉤子成功');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if DisableMouseHook then
ShowMessage('停止鉤子成功');
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//這裏調用是必需的,否則有可能沒有卸載鉤子就退出了,那就不好了。
DisableMouseHook;
end;
end;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章