拦截网络数据封包的方法有三种,一是将网卡设为混杂模式,这次就可以监视到局域网上所有的数据包,二是HOOK目标进程的发送和接收的API函数,第三种方法是自己实现一个代理的DLL.在这里我们使用HOOK API的方法,这样易于实现,而且也不会得到大量的无用数据(如第一种方法就会监视到所有的网络数据).
下面是一个尽量简化了的API HOOK的模版,原理是利用消息钩子将DLL中的代码注入到目标进程中,再用GetProcAddress得到API函数入口地址,将函数入口址改为自己定义的函数入口,这样就得到了API函数的相应参数,处理完后,再改回真实API函数入口地址,并调用它.
编译通过,简单起见,调试中首先打开一个IE窗口,找到其句柄,直接给TmpWndHandle,
然后运行程序,按下BUTTON1,显示Hook OK,并且可以监视收发数据包,一切正常。
然后按Button2,卸载HOOK,然后在IE窗口中随便打个地址,
IE会报错“Microsoft Internet Explorer 遇到问题需要关闭。我们对此引起的不便表示抱歉”
估计是卸载HOOK时,地址还原错了,但是代码看上去没有问题啊,所以我不敢肯定(我接触DELPHI才2个月拉),
请各位高手看看,怎么样才能改好,谢谢了。

解决方案 »

  1.   

    HOOK.DLL的代码:
    library Hook;uses
      SysUtils,
      windows,
      Messages,
      APIHook in 'APIHook.pas';type
      PData = ^TData;
      TData = record
        Hook: THandle;
        Hooked: Boolean;
      end;
      
    var
      DLLData: PData;{------------------------------------}
    {过程名:HookProc
    {过程功能:HOOK过程
    {过程参数:nCode, wParam, lParam消息的相
    {         关参数
    {------------------------------------}
    procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
    begin
      if not DLLData^.Hooked then
      begin
        HookAPI;
        DLLData^.Hooked := True;
      end;
      //调用下一个Hook
      CallNextHookEx(DLLData^.Hook, nCode, wParam, lParam);
    end;
    {------------------------------------}
    {函数名:InstallHook
    {函数功能:在指定窗口上安装HOOK
    {函数参数:sWindow:要安装HOOK的窗口
    {返回值:成功返回TRUE,失败返回FALSE
    {------------------------------------}
    function InstallHook(SWindow: LongWORD):Boolean;stdcall;
    var
      ThreadID: LongWORD;
    begin
      Result := False;
      DLLData^.Hook := 0;
      ThreadID := GetWindowThreadProcessId(sWindow, nil);
      //给指定窗口挂上钩子
      DLLData^.Hook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, ThreadID);
      if DLLData^.Hook > 0 then
        Result := True  //是否成功HOOK
      else
        exit;
    end;{------------------------------------}
    {过程名:UnHook
    {过程功能:卸载HOOK
    {过程参数:无
    {------------------------------------}
    procedure UnHook;stdcall;
    begin
      UnHookAPI;
      //卸载Hook
      UnhookWindowsHookEx(DLLData^.Hook);
    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, $ffff, '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:
        begin
          if Assigned(DLLData) then
          begin
            UnmapViewOfFile(DLLData);
            DLLData := nil;
          end;
        end;
      end;
    end;{$R *.res}
    exports
      InstallHook, UnHook, HookProc;begin
      DLLProc := @MyDLLHandler;
      MyDLLhandler(DLL_PROCESS_ATTACH);
      DLLData^.Hooked := False;
    end.----------------------------------------------------------------------------------------
    APIHook.Pas的代码:unit APIHook;interfaceuses
      SysUtils,
      Windows, WinSock;type
      //要HOOK的API函数定义
      TSockProc = function (s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;  PJmpCode = ^TJmpCode;
      TJmpCode = packed record
        JmpCode: BYTE;
        Address: TSockProc;
        MovEAX: Array [0..2] of BYTE;
      end;  //--------------------函数声明---------------------------
      procedure HookAPI;
      procedure UnHookAPI;var
      OldSend, OldRecv: TSockProc;      //原来的API地址
      JmpCode: TJmpCode;
      OldProc: array [0..1] of TJmpCode;
      AddSend, AddRecv: pointer;        //API地址
      TmpJmp: TJmpCode;
      ProcessHandle: THandle;
    implementation{---------------------------------------}
    {函数功能:Send函数的HOOK
    {函数参数:同Send
    {函数返回值:integer
    {---------------------------------------}
    function MySend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    var
      dwSize: cardinal;
    begin
      //这儿进行发送的数据处理
      MessageBeep(1000);           //简单的响一声
      //调用直正的Send函数
      WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
      Result := OldSend(S, Buf, len, flags);
      JmpCode.Address := @MySend;
      WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize);
    end;{---------------------------------------}
    {函数功能:Recv函数的HOOK
    {函数参数:同Recv
    {函数返回值:integer
    {---------------------------------------}
    function MyRecv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    var
      dwSize: cardinal;
    begin
      //这儿进行接收的数据处理
      MessageBeep(1000);         //简单的响一声
      //调用直正的Recv函数
      WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
      Result := OldRecv(S, Buf, len, flags);
      JmpCode.Address := @MyRecv;
      WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize);
    end;{------------------------------------}
    {过程功能:HookAPI
    {过程参数:无
    {------------------------------------}
    procedure HookAPI;
    var
      DLLModule: THandle;
      dwSize: cardinal;
    begin
      ProcessHandle := GetCurrentProcess;
      DLLModule := LoadLibrary('ws2_32.dll');        
      AddSend := GetProcAddress(DLLModule, 'send');  //取得API地址
      AddRecv := GetProcAddress(DLLModule, 'recv');
      JmpCode.JmpCode := $B8;
      JmpCode.MovEAX[0] := $FF;
      JmpCode.MovEAX[1] := $E0;
      JmpCode.MovEAX[2] := 0;
      ReadProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
      JmpCode.Address := @MySend;
      WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize);   //修改Send入口
      ReadProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
      JmpCode.Address := @MyRecv;
      WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize);   //修改Recv入口
      OldSend := AddSend;   /////////////////////这里类型不一样也能这样?看不懂
      OldRecv := AddRecv;
    end;{------------------------------------}
    {过程功能:取消HOOKAPI
    {过程参数:无
    {------------------------------------}
    procedure UnHookAPI;
    var
      dwSize: Cardinal;
    begin
      WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);   //////看上去应该恢复了原来的地址了呀
      WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
    end;end.---------------------------------------------------------------------------------------------
    编译这个DLL后,再新建一个程序调用这个DLL的InstallHook并传入目标进程的主窗口句柄就可:
    unit fmMain;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
      
    var
      Form1: TForm1;
      InstallHook: function (SWindow: THandle):Boolean;stdcall;
      UnHook: procedure;stdcall;
    implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      ModuleHandle: THandle;
      TmpWndHandle: THandle;
    begin
      TmpWndHandle := 0;
      TmpWndHandle := FindWindow(nil, '目标窗口的标题');
      if not isWindow(TmpWndHandle) then
      begin
        MessageBox(self.Handle, '没有找到窗口', '!!!', MB_OK);
        exit;
      end;
      ModuleHandle := LoadLibrary('Hook.dll');
      @InstallHook := GetProcAddress(ModuleHandle, 'InstallHook');
      @UnHook := GetProcAddress(ModuleHandle, 'UnHook');
      if InstallHook(TmpWndHandle) then
        ShowMessage('Hook OK');
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      UnHook
    end;end.
      

  2.   

    OldProc 初始化一下;
    应该不需要吧,因为我先点BUTTON1的呀,里面有赋值。如果不点BUTTON1,直接点BUTTON2(卸载HOOK) 会报地址错了,这个我知道
      

  3.   

    自由界面和报表的完美解决方案!
    http://www.anylib.com
      

  4.   

    好想是RECV错了,因为我在打开任何网页的时候,从来没有RECV,光有SENT这个不对吧
      

  5.   


    我这里有madcodehook一套例程
      

  6.   

    TO;naughtyboy如果可以的话发一份给我吧,谢谢了[email protected]