zoukankan      html  css  js  c++  java
  • 拦截其它程序的网络数据封包

    有时候我们需要对其它应用程序发送和接收的网络数据进行拦截,比如要对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.

    ---------------------------------------------------------------------------------------------
    编译这个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.

  • 相关阅读:
    SQLite数据库
    如何将大文件写入到数据库中
    Visual Studio 2008 附加进程调试
    VS2010MFC编程入门
    关于exe文件传递参数方法
    监视剪贴板数据
    Delphi快捷键
    判断一个对象是否存在, 谁更快
    全局探色器
    用DELPHI中实现RAR文件解压到指定一目录
  • 原文地址:https://www.cnblogs.com/chenjian/p/3543607.html
Copyright © 2011-2022 走看看