我的应用程序或VCL本身调用了API函数,但是我想在不改变VCL源码或本身应用程序的情况下,写一个钩子,这个钩子只对我这个应用程序有效。
如我想我的程序在调用:CreateBitmap API函数时先调用我的函数。
谢谢各位高手。

解决方案 »

  1.   

    http://www.xfocus.net/articles/200205/392.html
      

  2.   

    按照楼上提供的地址,改了,但是没有Hook成功。
    代码如下:
    unit uHook;interface
    uses
       Windows, Messages, SysUtils, Classes;
    type               
      TlmportCode =
      packed record
        Jumplnstruction: Word;               //是$25FF,JUMP指令
        AddressOfPointerToFunction: PPointer;//真正开始的地址
      end;
      PlmportCode = ^TlmportCode;var
       FuncMessageboxA, FuncMessageboxW: PlmportCode;
    //静态挂接
    procedure API_Hookup;
    procedure Un_API_Hook;implementation
    type
       TmessageA = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;
       TmessageW = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;var
       OldMessageBoxA: TmessageA;
       OldMessageBoxW: TmessageW;function TrueFunctionAddress(func: Pointer): Pointer;
    var
      Code: PlmportCode;
    Begin
      //返回指定函数的真正地址
      Result:= func;
      if func = nil then exit;  try
       Code := func;
       if (Code.jumplnstruction = $25FF) then
         Result := Code.AddressOfPointerToFunction^;
      except
        Result :=nil;
      end;
    end;Procedure PermuteFunction(OldFunc: pointer; NewFunc: pointer);
    var
      Written: DWORD;                            
    begin
      //写地址函数
      WriteProcessMemory(GetCurrentProcess, @OldFunc, @NewFunc, 4, Written)
        // raise Exception.Create('Hook OK');
    end;function MyBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;
    begin
      //新函数
      result :=OldMessageBoxA(hWnd, 'Succes Hook MessageBoxA!', lpCaption, uType);
    end;function MyBoxW(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;
    begin
      //新函数
      result :=OldMessageBoxW(hWnd, 'Succes Hook MessageBoxW!', lpCaption, uType);
    end;procedure API_Hookup;
    begin
      //在旧函数的地址写上自己的函数
      PermuteFunction(@FuncMessageboxA, @MyBoxA);
      PermuteFunction(@FuncMessageboxW, @MyBoxW);
    end;procedure Un_API_Hook;
    begin
      //在旧的函数地址写旧的函数
      PermuteFunction(@FuncMessageboxA, @OldMessageboxA);
      PermuteFunction(@FuncMessageboxW, @OldMessageboxW);
    end;initialization
      //记住旧函数的跳转的指令位置.
      FuncMessageboxA:= @MessageBoxA;
      FuncMessageboxW:= @MessageBoxW;
      //从旧函数指针返回旧函数的真实地址,便于将来写回.
      @OldMessageBoxA:= TrueFunctionAddress(@MessageBoxA);
      @OldMessageBoxW:= TrueFunctionAddress(@MessageBoxW);
    end.Form
    uses uhook;
    procedure TForm1.btn2Click(Sender: TObject);
    begin
       API_Hookup;
    end;procedure TForm1.btn4Click(Sender: TObject);
    begin
      MessageBoxA(Form1.Handle,'NO HOOK UP A','MessageBoxA',MB_OK);
      MessageBoxW(Form1.Handle,'NO HOOK UP W','MessageBoxW',MB_OK);
      MessageBox (Form1.Handle,'NO HOOK UP BOX','MessageBox',MB_OK);
    end;procedure TForm1.btn3Click(Sender: TObject);
    begin
      Un_API_Hook;
    end;
      

  3.   

    呵呵,就是API Hook了
    例子很多的:)http://lysoft.7u7.net
      

  4.   

    xthmpro_cn(安徽农民*在外打工) 的可以
      

  5.   

    sephil老大 那个 统计个数 问题还没帮我呢!
      

  6.   

    这样即可,请大家解释一下RepointAddrInModule递归函数的意思,我具体还不是很明白。
    以下主要代码来自CSDN:
    unit uhook;interfaceuses
      Windows, Messages, Classes;type
      TmessageA = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;
      TmessageW = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): integer; stdcall;  //入口结构
      Image_Import_Entry = record
        Characteristics: DWORD;
        TimeDateStamp: DWORD;
        MajorVersion: Word;
        MinorVersion: Word;
        Name: DWORD;
        LookupTable: DWORD;
      end;
      PImage_Import_Entry = ^Image_Import_Entry;
      
      //函数跳转的结构
      TImportCode = packed record
        JumpInstruction: Word;                //定义跳转指令jmp,是$25FF,JUMP指令
        AddressOfPointerToFunction: ^Pointer; //定义要跳转到的函数,//真正开始的地址
      end;
      PImportCode = ^TImportCode;procedure API_Hookup;
    procedure Un_API_Hook;implementationvar
       OldMessageBoxA: TmessageA;
       OldMessageBoxW: TmessageW;function GetFunctionAddress(PFunction: PImportCode): Pointer;
    begin
      Result:= PFunction;
      if PFunction = nil then exit;
      
      if (PFunction.JumpInstruction = $25FF) then
        Result:= PFunction.AddressOfPointerToFunction^;
    end;function RepointFunction(OldFunc, NewFunc: Pointer): Integer;
    var
      ProcessList: TList;
      function RepointAddrInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
      var
        f: Pointer;
        RVA: DWORD;
        InportDLL: string;
        written: DWORD;
        Func: ^Pointer;
        NT: PImageNTHeaders;
        Dos: PImageDosHeader;
        ImportDesc: PImage_Import_Entry;
      begin
        //HOOK的数量
        Result:= 0;    //判断当前Module是否已经处理过
        Dos:= Pointer(hModule);
        if ProcessList.IndexOf(Dos) >= 0 then exit;
        ProcessList.Add(Dos);    if IsBadReadPtr(Dos, SizeOf(TImageDosHeader)) then exit;
        if Dos.e_magic <> IMAGE_DOS_SIGNATURE then exit;
        NT:= Pointer(Integer(Dos) + dos._lfanew);
        RVA:= NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
        if RVA = 0 then exit;
        ImportDesc:= Pointer(Integer(Dos) + Integer(RVA));    //取旧的函数地址
        OldFunc:= GetFunctionAddress(OldFunc);
        while (ImportDesc^.Name <> 0) do
        begin
          //递归处理函数包含的所有InprotDll
          InportDLL:= PChar(Integer(Dos) + Integer(ImportDesc^.Name));
          RepointAddrInModule(GetModuleHandle(PChar(InportDLL)), OldFunc, NewFunc);
          //处理当前Dll导入的函数
          Func:= Pointer(Integer(DOS) + Integer(ImportDesc.LookupTable));
          while Func^ <> nil do
          begin
            f:= GetFunctionAddress(Func^);
            if f = OldFunc then
            begin
              WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
              if Written > 0 then Inc(Result);
            end;
            Inc(Func);
          end;
          Inc(ImportDesc);
        end;
      end;begin
      ProcessList:= TList.Create;
      try
        Result:= RepointAddrInModule(GetModuleHandle(nil), OldFunc, NewFunc); //这可以HOOK到“我的程序的代码”
      finally
        ProcessList.Free;
      end;
    end;function MyBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
    begin
      //新函数
      result:=OldMessageBoxA(hWnd, 'Succes Hook MessageBoxA!', lpCaption, uType);
    end;function MyBoxW(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
    begin
      //新函数
      // result:=OldMessageBoxW(hWnd, '成功HOOK!', lpCaption, uType);
      result:=OldMessageBoxA(hWnd, 'Succes Hook MessageBoxW!', lpCaption, uType);
    end;procedure API_Hookup;
    begin
      if @OldMessageBoxA = nil then
        @OldMessageBoxA:= GetFunctionAddress(@MessageBoxA);
      RepointFunction(@OldMessageBoxA, @MyBoxA);  if @OldMessageBoxW = nil then
        @OldMessageBoxW:= GetFunctionAddress(@MessageBoxW);
      RepointFunction(@OldMessageBoxW, @MyBoxW);
    end;procedure Un_API_Hook;
    begin
      if @OldMessageBoxA <> nil then
        RepointFunction(@MyBoxA, @OldMessageBoxA);  if @OldMessageBoxW <> nil then
        RepointFunction(@MyBoxW, @OldMessageBoxW);
    end;
    end.
      

  7.   

    另外这个代码编译的Exe文件不能用Aspack压缩,压缩后就钩不住了。还请大家帮忙!
      

  8.   

    原贴内容:
    关于API的钩子,我已经可以在进程内钩住了,但是如果将Exe文件用Aspack压缩后就又钩不住了,不知有没有高招?谢谢!Re:可以通过动态挂接技术,不使用Import Table的,直接就LoadLibrary后,修改由GetProcAddress获得的地址的前5Bytes为JMP XXX流程为:
    复制前+5Bytes(可能是6Bytes等,需要代码对齐)到某区域(可执行可写的区域)
    修改为JMP到地址
    新建立的区域中Call你的Hook过程,然后JMP到API入口+5后的地址http://lysoft.7u7.net
      

  9.   

    谢谢:ly_liuyang(Liu Yang) 
    目前我不使用Import Table,直接修改内存@MessageBoxA内存可以HOOK了,不受ASPACK等加壳软件的影响,但是,我HOOK不住控件对该API函数的调用,请指点一下,如果有源代码更好!
      

  10.   

    基本思路是按照这个文章,但是这个文章是错误的,文章是不完整的。
    http://www.xfocus.net/articles/200205/392.html
      

  11.   

    任务完成!
    导入表HOOK
    内存修改HOOK 空间无效
    内存修改HOOK 控件有效