用跨程式子類化技術實現對其它程式訊息的攔載 (轉)
大家都知道每個視窗都有預設的視窗來進行對視窗訊息的處理.
而子類化技術就是替換視窗的視窗函式為自己定義的函式的技術.例如下面的程式碼:
var
Form1: TForm1;
OldWndProc: Pointer;
implementation
{$R *.dfm}
function NewWndProc(hHwnd, Msg, wParam, lParam: Long): Longint; stdcall;
begin
if Msg=WM_CLOSE then
exit;
Result := CallWindowProc(OldWndProc, hHwnd, Msg, wParam, lParam);
end;
procedure TForm1.FormCreate(Sender: T);
begin
{儲存舊的視窗函式地址}
OldWndProc := Pointer(GetWindowLong(Self.Handle, GWL_WNDPROC));
{設定新的視窗函式為自定義函式}
SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(@NewWndProc));
end;
這樣在視窗建立時就對視窗實現了子類化,這時按下視窗的關閉按鈕就會發現關不了視窗,因為新的視窗處理函式把WM_CLOSE訊息過濾掉了,要取消子類化,只需要簡單的把以前的視窗函式恢復過來就可以了.SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(OldWndProc));
現在看來似乎很簡單,只要對其它程式中的目標視窗進行子類化就可以實現對其訊息的攔載監視了.但是在下,每一個程式都有自己獨立的空間,新的視窗函式必須和目標視窗在同一個程式內,直接使用SetWindowLong(其它程式中視窗的控制程式碼, GWL_WNDPROC, 新視窗函式)就會失敗,所以就要想辦法把我們的視窗函式程式碼放到目標程式內,這兒有二個辦法,一是使用CreateRemoteThread在目標程式內建立執行緒,但這函式只在NT及以上操作實現,而且還要涉及到地址重定位等問題,很麻煩(請參考/develop/Read_Article.?Id=21079">http://www.csdn.net/develop/Read_Article.asp?Id=21079).另一個方法就是使用HOOK技術(SetHookEx,如果不知道,請先參考HOOK技術方面的文章),大家都知道,對其它程式進行HOOK時,此程式會自動載入HOOK過程所在的DLL,如果我們把視窗函式也放在DLL中,那視窗函式就相當於載入到了目標程式的地址空間中了,這方法簡單易行.在這裡我們就採用HOOK技術來實現跨程式子類化.
最後一個問題是如何在DLL中實現全域性變數,因為DLL中的變數在每個程式載入這個DLL時都申請新的空間來存放變數,所以DLL中的變數在各個程式內不一樣,可以利用記憶體對映,WM_COPYDATA等方法來實現全域性變數.這兒採用記憶體檔案對映.
現在需要的知識都已瞭解了,就讓我們來看具體的程式碼吧(這兒是把所有函式放在一個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; {要HOOK的視窗及用於接收訊息的視窗}
hHook: LongWORD; {HOOK控制程式碼}
OldWndProc: pointer; {舊的視窗過程}
MsgHwnd: LongWORD;
Msg: TMessage;
end;
var
DLLData: PMyDLLVar;
{---------------------------------------}
{函式名:NewWndProc
{函式功能:新的視窗過程
{函式引數:hHwnd:視窗控制程式碼 Msg:訊息ID
{ wParam, lParam:訊息引數
{函式返回值:下一個視窗過程的返回值
{---------------------------------------}
function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall;
begin
if Msg = WM_UNSUBCLASS then {如果收到解除安裝子類化訊息就恢復以前的WndProc}
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, 0, 0);
{這兒可以新增自己對目標程式訊息處理的程式碼,因為己經是在目標程式的地址空間內,現在可以為所
欲為 ^_^)
Result := CallWindowProc(DLLData^.OldWndProc, hHwnd, Msg, wParam, lParam);
end;
{------------------------------------}
{過程名:HookProc
{過程功能:HOOK過程
{過程引數:nCode, wParam, lParam訊息的相
{ 關引數
{------------------------------------}
procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
var
hEvent: THandle;
begin
if not DllData^.SubClass then {如果此視窗未子類化}
begin {儲存視窗過程地址並子類化}
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;
hEvent := OpenEvent(Synchronize, False, HOOK_EVENT_NAME);
end;
{下一個Hook}
CallNextHookEx(DLLData^.hHook, nCode, wParam, lParam);
end;
{------------------------------------}
{函式名:InstallHook
{函式功能:在指定視窗上安裝HOOK
{函式引數:HWindow:要安裝HOOK的視窗
{ SWindow:用於接收訊息的視窗
{返回值:成功返回TRUE,失敗返回FALSE
{------------------------------------}
function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;
var
ThreadID: LongWORD;
hEvent: THandle;
begin
Result := False;
DLLData^.hHook := 0;
DLLData^.HookWindow := HWindow;
DLLData^.SpyWindow := SWindow;
{得到指定視窗的執行緒ID}
ThreadID := GetWindowThreadProcessId(HWindow, nil);
{給指定視窗掛上鉤子}
hEvent := CreateEvent(nil, True, False, HOOK_EVENT_NAME);
DLLData^.hHook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, ThreadID);
SetEvent(hEvent);
CloseHandle(hEvent);
if DLLData^.hHook > 0 then Result := True; {是否成功HOOK}
end;
{------------------------------------}
{過程名:UnHook
{過程功能:解除安裝HOOK
{過程引數:無
{------------------------------------}
procedure UnHook;stdcall;
begin
{傳送解除安裝子類化訊息給指定視窗}
SendMessage(DLLData^.HookWindow, WM_UNSUBCLASS, 0, 0);
DLLData^.SubClass := False;
{解除安裝Hook}
UnhookWindowsHookEx(DLLData^.hHook);
end;
{------------------------------------}
{過程名:DLL入口函式
{過程功能:進行DLL初始化,釋放等
{過程引數:DLL狀態
{------------------------------------}
procedure MyDLLHandler(Reason: Integer);
var
FHandle: LongWORD;
begin
case Reason of
DLL_PROCESS_ATTACH:
begin {建立檔案對映,以實現DLL中的全域性變數}
FHandle := CreateFileMap($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,並呼叫InstallHook(目標視窗控制程式碼, 自己視窗控制程式碼)就可 以實現對目標視窗訊息的監視了(在接收到WM_NEWMESSAGE訊息時讀對映的記憶體),呼叫UnHook則可以解除安裝掉子類化和HOOK.具休的程式碼還請讀者自行編寫.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-962356/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談MFC中超類化技術的實現 (轉)
- 自己實現一個Electron跨程式訊息元件元件
- ORACLE同步軟體技術實現對比(轉載)Oracle
- Red Hat虛擬化技術Xen訊息透露(轉)
- motorola手機中在主類中響應其它類中的按鈕訊息 (轉)
- uni-app技術分享| uni-app轉小程式-實時訊息APP
- 再談訊息佇列技術-轉佇列
- [WPF]用HtmlTextBlock實現訊息對話方塊的內容高亮和跳轉HTMLBloC
- 佩羅的技術分類(轉載)
- 超實用:實現負載均衡技術的方式負載
- IPsec_VPN實現技術【轉載】
- 【漫畫技術】Android跨程式通訊Android
- 使用 NSProxy 實現訊息轉發
- MFC抽象類之動態實現技術 (轉)抽象
- 用程式碼理解 ObjC 中的傳送訊息和訊息轉發OBJ
- 用程式碼理解ObjC中的傳送訊息和訊息轉發OBJ
- framework外掛化技術-類載入Framework
- 詳解 CmProcess 跨程式通訊的實現
- 在VC++ 6.0下利用訊息實現內部程式通訊 (轉)C++
- VB中子分類技術的應用 (轉)
- 用postMessage實現跨域通訊跨域
- 使用GraphQL對資料模型和訊息格式實現類似XML的DTD驗證模型XML
- 用 Laravel 自帶訊息模組搭建小程式實時推送訊息Laravel
- 技術分享| 小程式實現音視訊通話
- 程式間通訊的另類實現
- VC++訊息對映的思考 (轉)C++
- Android訊息推送技術原理分析和實踐Android
- [轉]:多程式等待的跨平臺實現
- 如何對Kafka 中的訊息實現優先分級?Kafka
- SysListView控制元件類的訊息常量 (轉)View控制元件
- 用Java程式碼實現區塊鏈技術Java區塊鏈
- 【轉載】SAP 系統中STO+VC 技術實現
- 技術教程網 -- 實用技術參考 (轉)
- mfc中的訊息的應用 (轉)
- 微信小程式 傳送模板訊息的功能實現微信小程式
- 我對C++中THUNK一種實現技術的分析 (轉)C++
- Delphi中停靠技術的實現 (轉)
- 剖析Unreal Engine超真實人類的渲染技術Part 3 - 毛髮渲染及其它Unreal