用跨进程子类化技术实现对其它进程消息的拦载

原创 2003年10月09日 22:04:00

  大家都知道每个窗口都有默认的窗口函数来进行对窗口消息的处理.
  而子类化技术就是替换窗口的窗口函数为自己定义的函数的技术.例如下面的代码:
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中):
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 := 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,并调用InstallHook(目标窗口句柄, 自己窗口句柄)就可  以实现对目标窗口消息的监视了(在接收到WM_NEWMESSAGE消息时读映射的内存),调用UnHook则可以卸载掉子类化和HOOK.具休的代码还请读者自行编写.

用跨进程子类化技术实现对其它进程消息的拦载

转自 剑神一笑 的Blog http://blog.csdn.net/pankun/  大家都知道每个窗口都有默认的窗口函数来进行对窗口消息的处理.  而子类化技术就是替换窗口的窗口函数为自己定义的函...
  • passos
  • passos
  • 2005年04月18日 01:01
  • 1432

springmvc 相应静态资源,view-controler-path

的DispatcherServlet拦截 *.do这样的URL,就不存在访问不到静态资源的问题。如果你的DispatcherServlet拦截“/”,拦截了所有的请求,同时对*.js,*.jpg的访问...
  • mggwct
  • mggwct
  • 2016年04月11日 20:27
  • 182

眼见为实(2):介绍Windows的窗口、消息、子类化和超类化

http://blog.csdn.net/fmddlmyy/archive/2007/04/08/1556777.aspx这篇文章本来只是想介绍一下子类化和超类化这两个比较“生僻”的名词。为了叙述的完...
  • lqk1985
  • lqk1985
  • 2008年01月27日 15:24
  • 433

窗口子类化(SubClassing) SetWindowLong

一、什么是子类化(Subclass) 视窗系统是基于消息驱动的。因此每一个窗口都有一个函数来处理这些消息,系统管理的窗口结构中有一域记录着这个函数的地址(使用GetWindowLon...
  • chinazhd
  • chinazhd
  • 2016年01月12日 10:37
  • 2269

短信拦载

(1) 这个例子没有Activity,类SmsReceiver继承于BroadcastReceiver01public class SmsReceiver extends BroadcastRecei...
  • dahailantian1
  • dahailantian1
  • 2017年11月20日 17:42
  • 73

VC 向其他进程窗口发送自定义消息

发送端:
  • w839687571
  • w839687571
  • 2014年07月08日 12:34
  • 2840

vb调用vc的dll挂钩指定窗口,并且跨进程子类化该窗口

最后修订版本:——可以挂钩指定窗口,并且跨进程子类化该窗口,代码如下: vc-dll: // qq.cpp : Defines the entry point for the DLL applicat...
  • zhouxu21
  • zhouxu21
  • 2005年11月19日 20:12
  • 1500

android对一个ordered broadcast进行拦载的方法

所谓ordered broadcast就是指那些调用 Context.sendOrderedBroadcast去发送的广播。这种广播是按照接收者的filter顺序执行的,这个顺序:1、如果没有特权者...
  • dahailantian1
  • dahailantian1
  • 2017年11月20日 17:41
  • 9

超类化与子类化的区别?

本文转自:http://hi.baidu.com/zish/blog/item/2a4098501bef706a853524ca.html 1.子类化:改变一个已经存在的窗口实例的性质:消息处理与其他...
  • FlowShell
  • FlowShell
  • 2009年12月10日 20:59
  • 3138

关于HOOK,如何通过钩子截获指定窗口的所有消息 SetWindowsHookEx demo

SetWindowsHookEx   第三个参数为HINSTANCE,通过FindWindow找到指定窗口句柄后如何      得到该进程的HINSTANCE呢? 这个参数应该是你调用SetWind...
  • q610098308
  • q610098308
  • 2017年09月11日 21:11
  • 855
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用跨进程子类化技术实现对其它进程消息的拦载
举报原因:
原因补充:

(最多只允许输入30个字)