(转)拦截其它程序的网络数据封包

来源:互联网 发布:大数据研判 编辑:程序博客网 时间:2024/05/21 16:51

标题           拦截其它程序的网络数据封包         pankun(原作)      
       
  关键字           Hook   API   数据包   send   recv    
       
   
   
  有时候我们需要对其它应用程序发送和接收的网络数据进行拦截,比如要对IE发送的HTTP头进行分析,得到请求的地址等.这次我们可以用一些例如WPE,   Sniffer之类的工具来达到目的.但是工具功能有限,要想实现更强大的功能,还是我们自己动手来DIY吧.  
   
   
  拦截网络数据封包的方法有三种,一是将网卡设为混杂模式,这次就可以监视到局域网上所有的数据包,二是HOOK目标进程的发送和接收的API函数,第三种方法是自己实现一个代理的DLL.在这里我们使用HOOK   API的方法,这样易于实现,而且也不会得到大量的无用数据(如第一种方法就会监视到所有的网络数据).  
   
   
  下面是一个尽量简化了的API   HOOK的模版,原理是利用消息钩子将DLL中的代码注入到目标进程中,再用GetProcAddress得到API函数入口地址,将函数入口址改为自己定义的函数入口,这样就得到了API函数的相应参数,处理完后,再改回真实API函数入口地址,并调用它.  
   
  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;  
   
  interface  
   
  uses  
      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.  
   
  Top

11 楼sdzeng(大头鸟)回复于 2005-08-31 12:36:45 得分 0

---------------------------------------------------------------------------------------------  
  编译这个DLL后,再新建一个程序调用这个DLL的InstallHook并传入目标进程的主窗口句柄就可:  
  unit   fmMain;  
   
  interface  
   
  uses  
      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(FindWindow(nil,   'Untitled'))   then  
          ShowMessage('Hook   OK');  
  end;  
   
  procedure   TForm1.Button2Click(Sender:   TObject);  
  begin  
      UnHook  
  end;  
   
  end.  
   
   
     
  这段代码讲解;找到winsock   中send和Recv   地址来回替换,send和recv是封包发送,接受的函数,其中参数,buf为其中的数据封包,就是本段程序要的,自己定义myseng和myrecv来替换。处理数据就在自己定义的的这两个函数中,这个方法听说过,没想到这么简单,作者厉害呀!在myseng和myrecv中加如下代码就可以看到发送出去什么受到什么了。   var   tmp:string;   begin   setlength(tmp,len);   move(buf,tmp[1],len);   showmessage(tmp);   end;   关于hook函数就不讲了相信,能把文看完的,就回略知一   二   如果你知道怎么解密网络游戏封包的话,游戏外挂的原理你就明白了。  

原创粉丝点击