分類: Delphi 2008-10-03 13:25 189人閱讀 收藏 舉報
大家都知道每個窗口都有默認(rèn)的窗口函數(shù)來進(jìn)行對窗口消息的處理. 而子類化技術(shù)就是替換窗口的窗口函數(shù)為自己定義的函數(shù)的技術(shù).例如下面的代碼: var Form1: TForm1; OldWndProc: Pointer; implementation
{$R *.dfm} function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall; begin if Msg=WM_CLOSE then exit; Result := CallWindowProc(OldWndProc, hHwnd, Msg, wParam, lParam); end;
procedure TForm1.FormCreate(Sender: TObject); begin {保存舊的窗口函數(shù)地址} OldWndProc := Pointer(GetWindowLong(Self.Handle, GWL_WNDPROC)); {設(shè)置新的窗口函數(shù)為自定義函數(shù)} SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(@NewWndProc)); end; 這樣在窗口建立時就對窗口實現(xiàn)了子類化,這時按下窗口的關(guān)閉按鈕就會發(fā)現(xiàn)關(guān)不了窗口,因為新的窗口處理函數(shù)把WM_CLOSE消息過濾掉了,要取消子類化,只需要簡單的把以前的窗口函數(shù)恢復(fù)過來就可以了.SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(OldWndProc));
現(xiàn)在看來似乎很簡單,只要對其它進(jìn)程中的目標(biāo)窗口進(jìn)行子類化就可以實現(xiàn)對其消息的攔載監(jiān)視了.但是在WIN32下,每一個進(jìn)程都有自己獨立的內(nèi)存空間,新的窗口函數(shù)必須和目標(biāo)窗口在同一個進(jìn)程內(nèi),直接使用SetWindowLong(其它進(jìn)程中窗口的句柄, GWL_WNDPROC, 新窗口函數(shù))就會失敗,所以就要想辦法把我們的窗口函數(shù)代碼放到目標(biāo)進(jìn)程內(nèi),這兒有二個辦法,一是使用CreateRemoteThread在目標(biāo)進(jìn)程內(nèi)建立線程,但這函數(shù)只在NT及以上操作系統(tǒng)實現(xiàn),而且還要涉及到API地址重定位等問題,很麻煩(請參考http://www.csdn.net/develop/Read_Article.asp?Id=21079).另一個方法就是使用HOOK技術(shù)(SetWindowsHookEx,如果不知道,請先參考HOOK技術(shù)方面的文章),大家都知道,對其它進(jìn)程進(jìn)行HOOK時,此進(jìn)程會自動加載HOOK過程所在的DLL,如果我們把窗口函數(shù)也放在DLL中,那窗口函數(shù)就相當(dāng)于加載到了目標(biāo)進(jìn)程的地址空間中了,這方法簡單易行.在這里我們就采用HOOK技術(shù)來實現(xiàn)跨進(jìn)程子類化.
最后一個問題是如何在DLL中實現(xiàn)全局變量,因為DLL中的變量在每個進(jìn)程加載這個DLL時都申請新的空間來存放變量,所以DLL中的變量在各個進(jìn)程內(nèi)不一樣,可以利用內(nèi)存文件映射,WM_COPYDATA等方法來實現(xiàn)全局變量.這兒采用內(nèi)存文件映射.
現(xiàn)在需要的知識都已了解了,就讓我們來看具體的代碼吧(這兒是把所有函數(shù)放在一個DLL中):
- library Hook;
-
- uses
- SysUtils,windows, Messages;
-
- const
- WM_UNSUBCLASS = WM_USER + 1001;
- WM_NEWMESSAGE = WM_USER + 1002;
- HOOK_EVENT_NAME = 'MyHook';
-
- type
- PMyDLLVar = ^TMyDLLVar;
- TMyDLLVar = record
- SubClass: Boolean;
- HookWindow, SpyWindow: LongWORD;
- hHook: LongWORD;
- OldWndProc: pointer;
- MsgHwnd: LongWORD;
- Msg: TMessage;
- end;
-
- var
- DLLData: PMyDLLVar;
-
-
-
-
-
-
-
-
- function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall;
- begin
- if Msg = WM_UNSUBCLASS then
- begin
- SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, longint(DLLData^.OldWndProc));
- exit;
- end;
-
- DLLData^.Msg.Msg := Msg;
- DLLData^.Msg.WParam := wParam;
- DLLData^.Msg.LParam := lParam;
- DLLData^.MsgHwnd := hHwnd;
-
- SendMessage(DLLData^.SpyWindow, WM_NEWMESSAGE, wParam, lParam);
-
-
- Result := CallWindowProc(DLLData^.OldWndProc, hHwnd, Msg, wParam, lParam);
- end;
-
-
-
-
-
-
-
- procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
- var
- hEvent: THandle;
- begin
- if not DllData^.SubClass then
- begin
- hEvent := OpenEvent(Synchronize, False, HOOK_EVENT_NAME);
- if hEvent <> 0 then
- begin
- WaitForSingleObject(hEvent, INFINITE);
- CloseHandle(hEvent);
- end;
- DLLData^.OldWndProc := pointer(GetWindowLong(DLLData^.HookWindow, GWL_WNDPROC));
- SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, integer(@NewWndProc));
- DLLData^.SubClass := True;
-
- end;
-
- CallNextHookEx(DLLData^.hHook, nCode, wParam, lParam);
- end;
-
-
-
-
-
-
-
-
-
- function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;
- var
- ThreadID: LongWORD;
- hEvent: THandle;
- begin
- Result := False;
- DLLData^.hHook := 0;
- DLLData^.HookWindow := HWindow;
- DLLData^.SpyWindow := SWindow;
-
- ThreadID := GetWindowThreadProcessId(HWindow, nil);
-
- hEvent := CreateEvent(nil, True, False, HOOK_EVENT_NAME);
- DLLData^.hHook := SetWindowsHookEx(WH_MOUSE, @HookProc, Hinstance, ThreadID);
- SetEvent(hEvent);
- CloseHandle(hEvent);
- if DLLData^.hHook > 0 then Result := True;
- end;
-
-
-
-
-
-
- procedure UnHook;stdcall;
- begin
-
- SendMessage(DLLData^.HookWindow, WM_UNSUBCLASS, 0, 0);
- DLLData^.SubClass := False;
-
- UnhookWindowsHookEx(DLLData^.hHook);
- end;
-
-
-
-
-
-
- procedure MyDLLHandler(Reason: Integer);
- var
- FHandle: LongWORD;
- begin
- case Reason of
- DLL_PROCESS_ATTACH:
- begin
- FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, $ff, 'MYDLLDATA');
- if FHandle = 0 then
- if GetLastError = ERROR_ALREADY_EXISTS then
- begin
- FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MYDLLDATA');
- if FHandle = 0 then Exit;
- end else Exit;
- DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
- if DLLData = nil then
- CloseHandle(FHandle);
- end;
- DLL_PROCESS_DETACH:
- if Assigned(DLLData) then
- begin
- UnmapViewOfFile(DLLData);
- DLLData := nil;
- end;
- DLL_THREAD_ATTACH:;
- DLL_THREAD_DETACH:;
- end;
- end;
-
- {$R *.res}
- exports
- InstallHook, UnHook, HookProc;
-
- begin
- DLLProc := @MyDLLHandler;
- MyDLLhandler(DLL_PROCESS_ATTACH);
- end.
編譯這個DLL,然后在我們的程序中加載這個DLL,并調(diào)用InstallHook(目標(biāo)窗口句柄, 自己窗口句柄)就可 以實現(xiàn)對目標(biāo)窗口消息的監(jiān)視了(在接收到WM_NEWMESSAGE消息時讀映射的內(nèi)存),調(diào)用UnHook則可以卸載掉子類化和HOOK.具休的代碼還請讀者自行編寫.
- unit Unit2;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls;
-
- const WM_NEWMESSAGE = WM_USER + 1002;
-
- type
- TForm2 = class(TForm)
- btn1: TButton;
- btn2: TButton;
- lst1: TListBox;
- procedure btn1Click(Sender: TObject);
- procedure btn2Click(Sender: TObject);
- private
- procedure ShowMsg(var Message:TMessage);message WM_NEWMESSAGE;
- public
-
- end;
- function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;external 'Hook.dll';
- procedure UnHook;stdcall;external 'Hook.dll';
- var
- Form2: TForm2;
- ListCount:Integer;
-
- implementation
-
- {$R *.dfm}
-
- procedure TForm2.ShowMsg(var Message:TMessage);
- begin
- if Message.Msg = WM_MOUSEHOVER then
- begin
- ListCount:=ListCount+1;
- Form2.lst1.AddItem(IntToStr(ListCount)+'.'+IntToStr(Message.WParam)+','+IntToStr(Message.lParam),nil);
- end;
- end;
-
-
- function GetWindowHwnd:THandle;
- begin
- Result:=FindWindow(nil,'ABCDE.txt - 記事本');
- end;
-
- procedure TForm2.btn1Click(Sender: TObject);
- var
- TmpWndHandle: THandle;
- begin
- TmpWndHandle := 0;
- TmpWndHandle := GetWindowHwnd;
- if not isWindow(TmpWndHandle) then
- begin
- MessageBox(self.Handle, '沒有找到指定窗口', '!!!', MB_OK);
- exit;
- end;
- InstallHook(TmpWndHandle,Handle);
- end;
-
- procedure TForm2.btn2Click(Sender: TObject);
- begin
- UnHook;
- end;
-
- end.
|