zoukankan      html  css  js  c++  java
  • DelphiHookApi(经典)

    论坛里有关于HOOK API的贴子, 但其实现在方式显示得麻烦, 其实现在拦截API一般不用那种方式, 大都采用inline Hook API方式。其实也就是直接修改了要拦截的API源码的头部,让它无条件跳转到我们自己的处理过程。

       不多说别的了,开始我们自己的Hook API吧。

       我们今天要拦截的API如下:

       MessageBoxA、MessageBoxW、MessageBeep 和 OpenProcess 。

       首先,大家都知道要在整个系统范围中拦截,需要使用Dll来完成。现在我们打开Delphi 2009,新建一个Dll工程:hookDll。需要说明的是,Delphi是完全面向对象的编程语言,所以我们不要浪费,这个Dll打算用类的方式完成。于是,在新建的DLL工程中在添加一个Unit Pas,命名为unitHook, 用来写拦截类的处理。unitHook.pas中的代码如下:

    unit unitHook;

    interface

    uses
      Windows, Messages, Classes, SysUtils;

    type

      //NtHook类相关类型
      TNtJmpCode=packed record  //8字节
        MovEax:Byte;
        Addr:DWORD;
        JmpCode:Word;
        dwReserved:Byte;
      end;

      TNtHookClass=class(TObject)
      private
        hProcess:THandle;
        NewAddr:TNtJmpCode;
        OldAddr:array[0..7] of Byte;
        ReadOK:Boolean;
      public
        BaseAddr:Pointer;
        constructor Create(DllName,FuncName:string;NewFunc:Pointer);
        destructor Destroy; override;
        procedure Hook;
        procedure UnHook;
      end;

    implementation

    //==================================================
    //NtHOOK 类开始
    //==================================================
    constructor TNtHookClass.Create(DllName: string; FuncName: string;NewFunc:Pointer);
    var
      DllModule:HMODULE;
      dwReserved:DWORD;
    begin
      //获取模块句柄
      DllModule:=GetModuleHandle(PChar(DllName));
      //如果得不到说明未被加载
      if DllModule=0 then DllModule:=LoadLibrary(PChar(DllName));
      //得到模块入口地址(基址)
      BaseAddr:=Pointer(GetProcAddress(DllModule,PChar(FuncName)));
      //获取当前进程句柄
      hProcess:=GetCurrentProcess;
      //指向新地址的指针
      NewAddr.MovEax:=$B8;
      NewAddr.Addr:=DWORD(NewFunc);
      NewAddr.JmpCode:=$E0FF;
      //保存原始地址
      ReadOK:=ReadProcessMemory(hProcess,BaseAddr,@OldAddr,8,dwReserved);
      //开始拦截
      Hook;
    end;

    //释放对象
    destructor TNtHookClass.Destroy;
    begin
      UnHook;
      CloseHandle(hProcess);

      inherited;
    end;

    //开始拦截
    procedure TNtHookClass.Hook;
    var
      dwReserved:DWORD;
    begin
      if (ReadOK=False) then Exit;
      //写入新的地址
      WriteProcessMemory(hProcess,BaseAddr,@NewAddr,8,dwReserved);
    end;

    //恢复拦截
    procedure TNtHookClass.UnHook;
    var
      dwReserved:DWORD;
    begin
      if (ReadOK=False) then Exit;
      //恢复地址
      WriteProcessMemory(hProcess,BaseAddr,@OldAddr,8,dwReserved);
    end;

    end.
    至此,unitHook.pas的代码OK了,其中加了详细的注释,在此就不再多做解释。现在切换到Dll的代码页,
    写入以下代码:
     
    library hookdll;

    uses
      SysUtils, Windows,
      Classes,
      unitHook in 'unitHook.pas';

    {$R *.res}

    const
      HOOK_MEM_FILENAME  =  'tmp.hkt';

    var
      hhk: HHOOK;
      Hook: array[0..3] of TNtHookClass;

      //内存映射
      MemFile: THandle;
      startPid: PDWORD;   //保存PID

    {--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}

    //拦截 MessageBoxA
    function NewMessageBoxA(_hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT):
    Integer; stdcall;
    type
      TNewMessageBoxA = function (_hWnd: HWND; lpText, lpCaption: PAnsiChar; uType:
    UINT): Integer; stdcall;
    begin
      lpText := PAnsiChar('已经被拦截 MessageBoxA');
      Hook[0].UnHook;
      Result := TNewMessageBoxA(Hook[0].BaseAddr)(_hWnd, lpText, lpCaption, uType);
      Hook[0].Hook;
    end;

    //拦截 MessageBoxW
    function NewMessageBoxW(_hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT):
    Integer; stdcall;
    type
      TNewMessageBoxW = function (_hWnd: HWND; lpText, lpCaption: PWideChar; uType:
    UINT): Integer; stdcall;
    begin
      lpText := '已经被拦截 MessageBoxW';
      Hook[2].UnHook;
      Result := TNewMessageBoxW(Hook[2].BaseAddr)(_hWnd, lpText, lpCaption, uType);
      Hook[2].Hook;
    end;

    //拦截 MessageBeep
    function NewMessageBeep(uType: UINT): BOOL; stdcall;
    type
      TNewMessageBeep = function (uType: UINT): BOOL; stdcall;
    begin
      Result := True;
    end;

    //拦截 OpenProcess , 防止关闭
    function NewOpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId:
    DWORD): THandle; stdcall;
    type
      TNewOpenProcess = function (dwDesiredAccess: DWORD; bInheritHandle: BOOL;
    dwProcessId: DWORD): THandle; stdcall;
    begin
      if startPid^ = dwProcessId then begin
        result := 0;
        Exit;
      end;
      Hook[3].UnHook;
      Result := TNewOpenProcess(Hook[3].BaseAddr)(dwDesiredAccess, bInheritHandle,
    dwProcessId);
      Hook[3].Hook;
    end;

    {--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}

    //安装API Hook
    procedure InitHook;
    begin
      Hook[0] := TNtHookClass.Create('user32.dll', 'MessageBoxA', @NewMessageBoxA);
      Hook[1] := TNtHookClass.Create('user32.dll', 'MessageBeep', @NewMessageBeep);
      Hook[2] := TNtHookClass.Create('user32.dll', 'MessageBoxW', @NewMessageBoxW);
      Hook[3] := TNtHookClass.Create('kernel32.dll', 'OpenProcess', @NewOpenProcess);
    end;

    //删除API Hook
    procedure UninitHook;
    var
      I: Integer;
    begin
      for I := 0 to High(Hook) do
      begin
        FreeAndNil(Hook[I]);
      end;
    end;

    {--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}

    //内存映射共想
    procedure MemShared();
    begin
      MemFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS,False, HOOK_MEM_FILENAME);
    if MemFile = 0 then begin  //打开失败则衉c2建内存映射文件
        MemFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
                                  4, HOOK_MEM_FILENAME);
      end;
      if MemFile <> 0 then
        //映射文件到变量
        startPid := MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0);
    end;

    //传递消息
    function HookProc(nCode, wParam, lParam: Integer): Integer; stdcall;
    begin
      Result := CallNextHookEx(hhk, nCode, wParam, lParam);
    end;

    //开始HOOK
    procedure StartHook(pid: DWORD); stdcall;
    begin
      startPid^ := pid;
      hhk := SetWindowsHookEx(WH_CALLWNDPROC, HookProc, hInstance, 0);
    end;

    //结束HOOK
    procedure EndHook; stdcall;
    begin
      if hhk <> 0 then
        UnhookWindowsHookEx(hhk);
    end;

    //环境处理
    procedure DllEntry(dwResaon: DWORD);
    begin
      case dwResaon of
        DLL_PROCESS_ATTACH: InitHook;   //DLL载入
        DLL_PROCESS_DETACH: UninitHook; //DLL删除
      end;
    end;

    exports
      StartHook, EndHook;

    begin
      MemShared;

      { 分配DLL程序到 DllProc 变量 }
      DllProc := @DllEntry;
      { 调用DLL加载处理 }
      DllEntry(DLL_PROCESS_ATTACH);
    end.

         这样,我们用来hook API 的 Dll 就完工了。 在Dll中,我们还使用到了内存映射,用来实现在拦

    截全局时的内存共享,如这个例子中需要保存调用此hook的进程句柄,以防止通过任务管理器关闭示例程序。

       编译生成 hookdll.dll 文件,就可以使用了。现在我们再来建立一个测试用的程序。

       如附图所示,画3个按钮,分别为"Hook"、"UnHook"、"MessageBox",前两个用来

    安装和删除钩子,第三个用来显示一个消息框,你将会看到被Hook后的情况。测试工程的代码如下:


    unit FMain;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;

    type
      TfrmMain = class(TForm)
        btnHook: TButton;
        btnUnhook: TButton;
        Button1: TButton;
        procedure btnHookClick(Sender: TObject);
        procedure btnUnhookClick(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;

    var
      frmMain: TfrmMain;

      procedure StartHook(pid: DWORD); stdcall; external 'hookdll.dll';
      procedure EndHook; stdcall; external 'hookdll.dll';

    implementation

    {$R *.dfm}

    procedure TfrmMain.btnHookClick(Sender: TObject);
    begin
      StartHook(GetCurrentProcessId);
    end;

    procedure TfrmMain.btnUnhookClick(Sender: TObject);
    begin
      EndHook;
    end;

    procedure TfrmMain.Button1Click(Sender: TObject);
    begin
      MessageBox(0, 'abdfadfasdf', nil, 0);
    end;

    procedure TfrmMain.FormCreate(Sender: TObject);
    begin

    end;

    end.
     
          完成后运行,先不点击"hook"按钮,直接点击MessageBox,你会发现现在已经被拦截了
    。为什么我们还没有安装钩子就被拦截了呢?程序出错了吗?呵呵。当然没有出错。反过来看看DLL中
    的一处代码:
    .............

    //环境处理
    procedure DllEntry(dwResaon: DWORD);
    begin
      case dwResaon of
        DLL_PROCESS_ATTACH: InitHook;   //DLL载入
        DLL_PROCESS_DETACH: UninitHook; //DLL删除
      end;
    end;

    ............

    begin
      MemShared;

      { 分配DLL程序到 DllProc 变量 }
      DllProc := @DllEntry;
      { 调用DLL加载处理 }
      DllEntry(DLL_PROCESS_ATTACH);
    end.
     
         可以看到,在DLL装入内存的时候其实就已经调用了InitHook,将要拦截的API拦截了
    。这时候看看任务管理器能不能关闭我们的程序,试一下就知道还可以,因为我们还没有调用
    StartHook来传入我们程序的PID,所以还可以被关闭。       到此这篇文章就结束了, 本人从小语文没及过格(^_^),文章写的不太好,不过源代码都贴上了,
    有详细的注释,相信大家也能看明白。如果你发现有什么错误的地方,要记得告诉我哦!     最后感谢 cxwr(菜新)大大的支持,能完成这篇文章少不了他的功劳。

  • 相关阅读:
    An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling
    Multi-attention Network for One Shot Learning
    Visual Question Answering with Memory-Augmented Networks
    Tutorial on word2vector using GloVe and Word2Vec
    论文笔记:Tracking by Natural Language Specification
    论文笔记:Semantic Segmentation using Adversarial Networks
    论文笔记:Attention Is All You Need
    论文笔记:Capsules for Object Segmentation
    美国签证申请流程
    论文笔记:Diffusion-Convolutional Neural Networks (传播-卷积神经网络)
  • 原文地址:https://www.cnblogs.com/linyawen/p/1995624.html
Copyright © 2011-2022 走看看