• 实现拦截API的钩子(Hook)


    library Hook;
    
    uses
      SysUtils,
      Windows,
      Classes,
      ApiDefine in 'ApiDefine.pas',
      APIHook in 'APIHook.pas';
    
    {$R *.res}
    var
      HookHandle: HHook;
    
    function HookProc(code:Integer;wparam:WPARAM;lparam:LPARAM):LRESULT;stdcall;
    begin
      Result := CallNextHookEx(HookHandle,code,wparam,lparam);
    end;
    
    procedure SetHook;stdcall;
    begin
      HookHandle := SetWindowsHookEx(WH_GETMESSAGE,@HookProc,HInstance,0);
    end;
    
    procedure StopHook;stdcall;
    begin
      UnhookWindowsHookEx(HookHandle);
    end;
    
    exports
      SetHook name 'SetHook',
      StopHook name 'StopHook';
    
    {已启动就挂上,修改API函数指向}
    begin
      API_Hook;
    end.
    View Code
    unit APIHook;
    
    interface
    
    uses
      Windows, SysUtils, Classes;
    
    type
      //引入表入口数据结构
      Image_Import_Entry = packed record
        OriginalFirstThunk:DWORD;
        TimeDateStamp:DWORD;
        ForwarderChain:DWORD;
        Name:DWORD;
        FirstThunk:DWORD;
      end;
      PImage_Import_Entry = ^Image_Import_Entry;
      TImportCode = packed record
        JmpCode: Word;
        AddressOfPFun: PPointer;
      end;
      PImportCode = ^TImportCode;
    
      function GetFunTrueAddress(Code:Pointer):Pointer;
      function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer):Integer;
    
    implementation
    
    //获得实际地址
    function GetFunTrueAddress(Code: Pointer): Pointer;
    var
       func: PImportCode;
    begin
       Result := Code;
       if Code = nil then exit;
       try
          func := code;
          if (func.JmpCode = $25FF) then
          begin
             Result := func.AddressOfPFun^;
          end;
       except
          Result := nil;
       end;
    end;
    
    //替换地址
    function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer): Integer;
    var
       IsDone: TList;
       function ReplaceAddressInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
       var
          DosHeader: PImageDosHeader;
          NTHeader: PImageNTHeaders;
          ImportDesc: PImage_Import_Entry;
          RVA: DWORD;
          Func: ^Pointer;
          DLL: string;
          f: Pointer;
          written: DWORD;
       begin
          Result := 0;
          DosHeader := Pointer(hModule);
          //已经找过,则退出
          if IsDone.IndexOf(DosHeader) >= 0 then exit;
          IsDone.Add(DosHeader);
    
          oldfun := GetFunTrueAddress(OldFunc);
    
          if IsBadReadPtr(DosHeader, SizeOf(TImageDosHeader)) then exit;
          if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then exit;
          NTHeader := Pointer(Integer(DosHeader) + DosHeader._lfanew);
          //引入表的虚拟地址
          RVA := NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    
          if RVA = 0 then exit;
          ImportDesc := pointer(integer(DosHeader) + RVA);
          while (ImportDesc^.Name <> 0) do
          begin
            //引入文件名
             DLL := PChar(Integer(DosHeader) + ImportDesc^.Name);
             //获得该DLL的句柄,然后递归查找
             ReplaceAddressInModule(GetModuleHandle(PChar(DLL)), oldfun, newfun);
             //引入函数入口
             Func := Pointer(Integer(DOSHeader) + ImportDesc.FirstThunk);
             //如果函数指针不为空
             while Func^ <> nil do
             begin
               //取得真是地址
                f := GetFunTrueAddress(Func^);
                //如果和我们要拦截的Api函数地址一样
                if f = oldfun then
                begin
                  //替换成我们自己的Api地址
                   WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
                   if Written > 0 then Inc(Result);
                end;
                //继续找
                Inc(Func);
             end;
             Inc(ImportDesc);
          end;
       end;
    
    begin
       IsDone := TList.Create;
       try
         //GetModuleHandle,参数nil,为获取自身的模块句柄
          Result := ReplaceAddressInModule(GetModuleHandle(nil), oldfun, newfun);
       finally
          IsDone.Free;
       end;
    end;
    end.
    View Code
    unit ApiDefine;
    
    interface
    
    uses
      Windows, SysUtils, Classes,Messages,APIHook,ShellAPI;
    
      procedure API_Hook;
      procedure API_UnHook;
    
    implementation
    
    //自定义Api的类型
    type
      TMsgA = function(hwn: hwnd; lptext: pchar; lpcapion: pchar; utype: cardinal):integer; stdcall;
      TShellExc = function(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
      TTextOut = function(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
    var
      oldMsgA : TMsgA;
      oldShellExc : TShellExc;
      oldTextOut : TTextOut;
    
    //自定义Api的实现
    function NewMsgA(hwn: hwnd; lptext: pchar; lpcaption: pchar; utype: cardinal):integer; stdcall;
    begin
      Result := oldMsgA(hwn,'成功拦截MessageBoxA','哈哈',utype);
    end;  
    
    function NewShellExc(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
    begin
      Result := oldShellExc(hwn,lpoperate,'c:/2.txt',lpfilename,lpdir,cmd);
    end;
    
    {TextOut调用的是ExtTextOut}
    function NewTextOut(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
    begin
      {这个rect也是可以修改的,以便容纳更多的字符显示}
      Result := oldTextOut(DC,50,50,options,rect,'中国',count,dx);
    end;
    
    procedure API_Hook;
    begin
      if @oldMsgA = nil then
        @oldMsgA := GetFunTrueAddress(@MessageBoxA);
      if @oldShellExc = nil then
        @oldShellExc := GetFunTrueAddress(@ShellExecute);
      if @oldTextOut = nil then
        @oldTextOut := GetFunTrueAddress(@ExtTextOut);
      //替换  
      ReplaceFunAddress(@oldMsgA,@NewMsgA);
      ReplaceFunAddress(@oldShellExc,@NewShellExc);
      ReplaceFunAddress(@oldTextOut,@NewTextOut);
    end;
    
    procedure API_UnHook;
    begin
      if @oldMsgA <> nil then
        ReplaceFunAddress(@NewMsgA,@oldMsgA);
      if @oldShellExc <> nil then
        ReplaceFunAddress(@NewShellExc,@oldShellExc);
      if @oldTextOut <> nil then
        ReplaceFunAddress(@NewTextOut,@oldTextOut);
    end;
    
    initialization
    //结束时恢复原Api地址
    finalization
      API_UnHook;
    
    end.
    View Code
  • 相关阅读:
    Forrester:开源APM发展势头强劲
    Forrester:开源APM发展势头强劲
    canvas 绘图api的位置问题
    canvas 绘图api的位置问题
    canvas 绘图api的位置问题
    canvas 绘图api的位置问题
    Android应用层View绘制流程与源码分析
    Android应用层View绘制流程与源码分析
    Android应用层View绘制流程与源码分析
    未来5年到底是做什么生意最好?
  • 原文地址:https://www.cnblogs.com/key-ok/p/3428912.html
Copyright © 2020-2023  润新知