zoukankan      html  css  js  c++  java
  • 用跨进程子类化技术实现对其它进程消息的拦载

      大家都知道每个窗口都有默认的窗口函数来进行对窗口消息的处理.
      而子类化技术就是替换窗口的窗口函数为自己定义的函数的技术.例如下面的代码:
    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
      {保存旧的窗口函数地址}
      OldWndProc := Pointer(GetWindowLong(Self.Handle, GWL_WNDPROC));
      {设置新的窗口函数为自定义函数}
      SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(@NewWndProc));
    end;
      这样在窗口建立时就对窗口实现了子类化,这时按下窗口的关闭按钮就会发现关不了窗口,因为新的窗口处理函数把WM_CLOSE消息过滤掉了,要取消子类化,只需要简单的把以前的窗口函数恢复过来就可以了.SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(OldWndProc));

      现在看来似乎很简单,只要对其它进程中的目标窗口进行子类化就可以实现对其消息的拦载监视了.但是在WIN32下,每一个进程都有自己独立的内存空间,新的窗口函数必须和目标窗口在同一个进程内,直接使用SetWindowLong(其它进程中窗口的句柄, GWL_WNDPROC, 新窗口函数)就会失败,所以就要想办法把我们的窗口函数代码放到目标进程内,这儿有二个办法,一是使用CreateRemoteThread在目标进程内建立线程,但这函数只在NT及以上操作系统实现,而且还要涉及到API地址重定位等问题,很麻烦(请参考http://www.csdn.net/develop/Read_Article.asp?Id=21079).另一个方法就是使用HOOK技术(SetWindowsHookEx,如果不知道,请先参考HOOK技术方面的文章),大家都知道,对其它进程进行HOOK时,此进程会自动加载HOOK过程所在的DLL,如果我们把窗口函数也放在DLL中,那窗口函数就相当于加载到了目标进程的地址空间中了,这方法简单易行.在这里我们就采用HOOK技术来实现跨进程子类化.

      最后一个问题是如何在DLL中实现全局变量,因为DLL中的变量在每个进程加载这个DLL时都申请新的空间来存放变量,所以DLL中的变量在各个进程内不一样,可以利用内存文件映射,WM_COPYDATA等方法来实现全局变量.这儿采用内存文件映射.

      现在需要的知识都已了解了,就让我们来看具体的代码吧(这儿是把所有函数放在一个DLL中):

    1. library Hook;     
    2. uses
    3.   SysUtils,windows, Messages;
    4. const
    5.   WM_UNSUBCLASS = WM_USER + 1001;  {卸载子类化消息}
    6.   WM_NEWMESSAGE = WM_USER + 1002;  {通知监视窗口拦到了新消息}
    7.   HOOK_EVENT_NAME = 'MyHook';
    8. type
    9.   PMyDLLVar = ^TMyDLLVar;
    10.   TMyDLLVar = record
    11.     SubClass: Boolean;                 {是否已经子类化}
    12.     HookWindow, SpyWindow: LongWORD;   {要安装HOOK的窗口及用于接收消息的窗口}
    13.     hHook: LongWORD;                   {HOOK句柄}
    14.     OldWndProc: pointer;               {旧的窗口过程}
    15.     MsgHwnd: LongWORD;
    16.     Msg: TMessage;
    17.   end;
    18. var
    19.   DLLData: PMyDLLVar;
    20. {---------------------------------------}
    21. {函数名:NewWndProc
    22. {函数功能:新的窗口过程
    23. {函数参数:hHwnd:窗口句柄 Msg:消息ID
    24. {         wParam, lParam:消息参数
    25. {函数返回值:下一个窗口过程的返回值
    26. {---------------------------------------}
    27. function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall;
    28. begin
    29.   if Msg = WM_UNSUBCLASS then   {如果收到卸载子类化消息就恢复以前的WndProc}
    30.   begin
    31.     SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, longint(DLLData^.OldWndProc));
    32.     exit;
    33.   end;
    34.   {这儿是把收到的消息放在映射的内存中,我们自己的程序可以通过读这个内存来得到监视到的消息.}
    35.   DLLData^.Msg.Msg := Msg;            
    36.   DLLData^.Msg.WParam := wParam;
    37.   DLLData^.Msg.LParam := lParam;
    38.   DLLData^.MsgHwnd := hHwnd;
    39.   {给监视窗口发送拦载新消息的消息}
    40.     SendMessage(DLLData^.SpyWindow, WM_NEWMESSAGE, wParam, lParam);
    41.   {这儿可以添加自己对目标进程消息处理的代码,因为己经是在目标进程的地址空间内,现在可以为所
    42.   欲为 ^_^}
    43.   Result := CallWindowProc(DLLData^.OldWndProc, hHwnd, Msg, wParam, lParam);
    44. end;
    45. {------------------------------------}
    46. {过程名:HookProc
    47. {过程功能:HOOK过程
    48. {过程参数:nCode, wParam, lParam消息的相
    49. {         关参数
    50. {------------------------------------}
    51. procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
    52. var
    53.   hEvent: THandle;
    54. begin
    55.   if not DllData^.SubClass then  {如果此窗口未子类化}
    56.   begin    {保存窗口过程地址并子类化}
    57.   hEvent := OpenEvent(Synchronize, False, HOOK_EVENT_NAME);
    58.     if hEvent <> 0 then
    59.     begin
    60.       WaitForSingleObject(hEvent, INFINITE);
    61.       CloseHandle(hEvent); 
    62.     end;
    63.     DLLData^.OldWndProc := pointer(GetWindowLong(DLLData^.HookWindow, GWL_WNDPROC));
    64.     SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, integer(@NewWndProc));
    65.     DLLData^.SubClass := True;
    66.     //hEvent := OpenEvent(Synchronize, False, HOOK_EVENT_NAME);
    67.   end;
    68.   {调用下一个Hook}
    69.   CallNextHookEx(DLLData^.hHook, nCode, wParam, lParam);
    70. end;
    71. {------------------------------------}
    72. {函数名:InstallHook
    73. {函数功能:在指定窗口上安装HOOK
    74. {函数参数:HWindow:要安装HOOK的窗口
    75. {         SWindow:用于接收消息的窗口
    76. {返回值:成功返回TRUE,失败返回FALSE
    77. {------------------------------------}
    78. function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;
    79. var
    80.   ThreadID: LongWORD;
    81.   hEvent: THandle;
    82. begin
    83.   Result := False;
    84.   DLLData^.hHook := 0;
    85.   DLLData^.HookWindow := HWindow;
    86.   DLLData^.SpyWindow := SWindow;
    87.   {得到指定窗口的线程ID}
    88.   ThreadID := GetWindowThreadProcessId(HWindow, nil);
    89.   {给指定窗口挂上钩子}
    90.   hEvent := CreateEvent(nil, True, False, HOOK_EVENT_NAME);
    91.   DLLData^.hHook := SetWindowsHookEx(WH_MOUSE, @HookProc, Hinstance, ThreadID);
    92.   SetEvent(hEvent);
    93.   CloseHandle(hEvent);
    94.   if DLLData^.hHook > 0 then Result := True;  {是否成功HOOK}
    95. end;
    96. {------------------------------------}
    97. {过程名:UnHook
    98. {过程功能:卸载HOOK
    99. {过程参数:无
    100. {------------------------------------}
    101. procedure UnHook;stdcall;
    102. begin
    103.   {发送卸载子类化消息给指定窗口}
    104.   SendMessage(DLLData^.HookWindow, WM_UNSUBCLASS, 00);
    105.   DLLData^.SubClass := False;
    106.   {卸载Hook}
    107.   UnhookWindowsHookEx(DLLData^.hHook);
    108. end;
    109. {------------------------------------}
    110. {过程名:DLL入口函数
    111. {过程功能:进行DLL初始化,释放等
    112. {过程参数:DLL状态
    113. {------------------------------------}
    114. procedure MyDLLHandler(Reason: Integer);
    115. var
    116.   FHandle: LongWORD;
    117. begin
    118.   case Reason of
    119.     DLL_PROCESS_ATTACH:
    120.     begin            {建立文件映射,以实现DLL中的全局变量}
    121.       FHandle := CreateFileMapping($FFFFFFFFnil, PAGE_READWRITE, 0$ff'MYDLLDATA');
    122.       if FHandle = 0 then
    123.       if GetLastError = ERROR_ALREADY_EXISTS then
    124.       begin
    125.         FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MYDLLDATA');
    126.         if FHandle = 0 then Exit;
    127.       end else Exit;
    128.       DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 000);
    129.       if DLLData = nil then
    130.         CloseHandle(FHandle);
    131.     end;
    132.     DLL_PROCESS_DETACH:
    133.       if Assigned(DLLData) then
    134.       begin
    135.         UnmapViewOfFile(DLLData);
    136.         DLLData := nil;
    137.       end;
    138.     DLL_THREAD_ATTACH:;
    139.     DLL_THREAD_DETACH:;
    140.   end;
    141. end;
    142. {$R *.res}
    143. exports
    144.   InstallHook, UnHook, HookProc;
    145. begin
    146.   DLLProc := @MyDLLHandler;
    147.   MyDLLhandler(DLL_PROCESS_ATTACH);
    148. end.

    编译这个DLL,然后在我们的程序中加载这个DLL,并调用InstallHook(目标窗口句柄, 自己窗口句柄)就可  以实现对目标窗口消息的监视了(在接收到WM_NEWMESSAGE消息时读映射的内存),调用UnHook则可以卸载掉子类化和HOOK.具休的代码还请读者自行编写.

    1. unit Unit2;
    2. interface
    3. uses
    4.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    5.   Dialogs, StdCtrls;
    6. const WM_NEWMESSAGE = WM_USER + 1002;
    7. type
    8.   TForm2 = class(TForm)
    9.     btn1: TButton;
    10.     btn2: TButton;
    11.     lst1: TListBox;
    12.     procedure btn1Click(Sender: TObject);
    13.     procedure btn2Click(Sender: TObject);
    14.   private
    15.     procedure ShowMsg(var Message:TMessage);message WM_NEWMESSAGE;
    16.   public
    17.     { Public declarations }
    18.   end;
    19.   function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;external 'Hook.dll';
    20.   procedure UnHook;stdcall;external 'Hook.dll';
    21. var
    22.   Form2: TForm2;
    23.   ListCount:Integer;
    24. implementation
    25. {$R *.dfm}
    26. procedure TForm2.ShowMsg(var Message:TMessage);
    27. begin
    28.   if Message.Msg = WM_MOUSEHOVER then
    29.   begin
    30.     ListCount:=ListCount+1;
    31.     Form2.lst1.AddItem(IntToStr(ListCount)+'.'+IntToStr(Message.WParam)+','+IntToStr(Message.lParam),nil);
    32.   end;
    33. end;
    34. function GetWindowHwnd:THandle;
    35. begin
    36.   Result:=FindWindow(nil,'ABCDE.txt - 记事本');
    37. end;
    38. procedure TForm2.btn1Click(Sender: TObject);
    39. var
    40.   TmpWndHandle: THandle;
    41. begin
    42.   TmpWndHandle := 0;
    43.   TmpWndHandle := GetWindowHwnd;
    44.   if not isWindow(TmpWndHandle) then
    45.   begin
    46.     MessageBox(self.Handle, '没有找到指定窗口''!!!', MB_OK);
    47.     exit;
    48.   end;
    49.   InstallHook(TmpWndHandle,Handle);
    50. end;
    51. procedure TForm2.btn2Click(Sender: TObject);
    52. begin
    53.   UnHook;  //下message钩子
    54. end
    55. end.
  • 相关阅读:
    python之字典方法
    python之字符串方法
    python strip()方法使用
    Airtest自动化测试工具介绍
    selenium 环境配置
    一个自定义线程池的小Demo
    简单工厂模式
    BootStrap入门_创建第一个例子
    MongoDB的索引
    MongoDB的查询
  • 原文地址:https://www.cnblogs.com/zhaoshujie/p/9594839.html
Copyright © 2011-2022 走看看