Delphi Hook Library

常常见到有朋友问Hook怎么做和COM的HOOK怎么弄.
来点干货,给Delphi业界朋友做点贡献.把我之前写的一个Delphi Hook库放到了Google Code上.方便大家.
微软官方钩子库Detours X86是免费的,X64可是要1000美刀的哦.
支持X86,X64的函数钩子.线程安全.
封装了对COM对象的Hook.在Hook COM对象的时候方法时会自动判断是Delphi还是其他语言实现的COM对象,从而进行智能处理.

其实代码加注释也就几百行.一个单元文件而已.
其中使用了开源的BeaEngine的反汇编引擎来判断代码的大小,避免机器指令被从中间切开.

Google Code
http://code.google.com/p/delphi-hook-library/

更新在
https://www.raysoftware.cn/?p=493

关键文件按内容如下:

unit HookUtils;

{
  wr960204武稀松.2012.2

  主页  https://www.raysoftware.cn

  通用Hook库.
  支持X86和X64.
  使用了开源的BeaEngine反汇编引擎.BeaEngine的好处是可以用BCB编译成OMF格式的Obj,
  被链接进Delphi的DCU和目标文件中.不需要额外带DLL.
  BeaEngin引擎
  http://www.beaengine.org/

  限制:
  1.不能Hook代码大小小于5个字节的函数.
  2.不能Hook前五个字节中有跳转指令的函数.
  希望使用的朋友们自己也具有一定的汇编或者逆向知识.
  Hook函数前请确定该函数不属于上面两种情况.


  另外钩COM对象有一个技巧,如果你想在最早时机勾住某个COM对象,
  可以在你要钩的COM对象创建前自己先创建一个该对象,Hook住,然后释放你自己的对象.
  这样这个函数已经被下钩子了,而且是钩在这个COM对象创建前的.
}
interface

{ 下函数钩子
  64位中会有一种情况失败,就是VirtualAlloc不能在被Hook函数地址正负2Gb范围内分配到内存.
  不过这个可能微乎其微.几乎不可能发生.
}
function HookProc(Func, NewFunc: Pointer): Pointer; overload;
function HookProc(DLLName, FuncName: PChar; NewFunc: Pointer): Pointer;
  overload;
{ 计算COM对象中方法的地址;AMethodIndex是方法的索引.
  AMethodIndex是接口包含父接口的方法的索引.
  例如:
  IA = Interface
  procedure A();//因为IA是从IUnKnow派生的,IUnKnow自己有3个方法,所以AMethodIndex=3
  end;
  IB = Interface(IA)
  procedure B(); //因为IB是从IA派生的,所以AMethodIndex=4
  end;
}
function CalcInterfaceMethodAddr(var AInterface; AMethodIndex: Integer)
  : Pointer;
// 下COM对象方法的钩子
function HookInterface(var AInterface; AMethodIndex: Integer;
  NewFunc: Pointer): Pointer;
// 解除钩子
function UnHook(OldFunc: Pointer): boolean;

implementation

uses
  BeaEngineDelphi, Windows, TLHelp32;

const
  PageSize = 4096;
{$IFDEF CPUX64}
{$DEFINE USELONGJMP}
{$ENDIF}
  { .$DEFINE USEINT3 }// 在机器指令中插入INT3,断点指令.方便调试.

type
  THandles = array of THandle;
  ULONG_PTR = NativeUInt;
  POldProc = ^TOldProc;

  PJMPCode = ^TJMPCode;

  TJMPCode = packed record
{$IFDEF USELONGJMP}
    JMP: Word;
    JmpOffset: Int32;
{$ELSE}
    JMP: byte;
{$ENDIF}
    Addr: UIntPtr;
  end;

  TOldProc = packed record
{$IFDEF USEINT3}
    Int3OrNop: byte;
{$ENDIF}
    BackCode: array [0 .. $20 - 1] of byte;
    JmpRealFunc: TJMPCode;
    JmpHookFunc: TJMPCode;

    BackUpCodeSize: Integer;
    OldFuncAddr: Pointer;
  end;

  PNewProc = ^TNewProc;

  TNewProc = packed record
    JMP: byte;
    Addr: Integer;
  end;

  // 计算需要覆盖的机器指令大小.借助了BeaEngin反汇编引擎.以免指令被从中间切开
function CalcHookCodeSize(Func: Pointer): Integer;
var
  ldiasm: TDISASM;
  len: longint;
begin
  Result := 0;
  ZeroMemory(@ldiasm, SizeOf(ldiasm));
  ldiasm.EIP := UIntPtr(Func);
  ldiasm.Archi := {$IFDEF CPUX64}64{$ELSE}32{$ENDIF};
  while Result < SizeOf(TNewProc) do
  begin
    len := Disasm(ldiasm);
    Inc(ldiasm.EIP, len);
    Inc(Result, len);
  end;
end;

const
  THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $3FF;

function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL;
  dwThreadId: DWORD): THandle; stdcall; external kernel32;

function SuspendOneThread(dwThreadId: NativeUInt; ACode: Pointer;
  ASize: Integer): THandle;
var
  hThread: THandle;
  dwSuspendCount: DWORD;
  ctx: TContext;
  IPReg: Pointer;
  tryTimes: Integer;
begin
  Result := INVALID_HANDLE_VALUE;
  hThread := OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
  if (hThread <> 0) and (hThread <> INVALID_HANDLE_VALUE) then
  begin
    dwSuspendCount := SuspendThread(hThread);
    // SuspendThread返回的是被挂起的引用计数,-1的话是失败.
    if dwSuspendCount <> DWORD(-1) then
    begin
      while (GetThreadContext(hThread, ctx)) do
      begin
        tryTimes := 0;
        IPReg := Pointer({$IFDEF CPUX64}ctx.Rip{$ELSE}ctx.EIP{$ENDIF});
        if (NativeInt(IPReg) >= NativeInt(ACode)) and
          (NativeInt(IPReg) <= (NativeInt(ACode) + ASize)) then
        begin
          ResumeThread(hThread);
          Sleep(100);
          SuspendThread(hThread);
          Inc(tryTimes);
          if tryTimes > 5 then
          begin
            Break;
          end;
        end
        else
        begin
          Result := hThread;
          Break;
        end;
      end;
    end;
  end;
end;

function SuspendOtherThread(ACode: Pointer; ASize: Integer): THandles;
var
  hSnap: THandle;
  te: THREADENTRY32;
  nThreadsInProcess: DWORD;
  hThread: THandle;
begin
  Exit;
  hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
  te.dwSize := SizeOf(te);

  nThreadsInProcess := 0;
  if (Thread32First(hSnap, te)) then
  begin
    while True do
    begin
      if (te.th32OwnerProcessID = GetCurrentProcessId()) then
      begin

        if (te.th32ThreadID <> GetCurrentThreadId()) then
        begin
          hThread := SuspendOneThread(te.th32ThreadID, ACode, ASize);
          if hThread <> INVALID_HANDLE_VALUE then
          begin
            Inc(nThreadsInProcess);
            SetLength(Result, nThreadsInProcess);
            Result[nThreadsInProcess - 1] := hThread;
          end;
        end
      end;
      te.dwSize := SizeOf(te);
      if not Thread32Next(hSnap, te) then
        Break;
    end;
    // until not Thread32Next(hSnap, te);
  end;

  CloseHandle(hSnap);
end;

procedure ResumOtherThread(threads: THandles);
var
  i: Integer;
begin
  Exit;
  for i := Low(threads) to High(threads) do
  begin
    ResumeThread(threads[i]);
    CloseHandle(threads[i]);
  end;
end;

{
  尝试在指定指针APtr的正负2Gb以内分配内存.32位肯定是这样的.
  64位JMP都是相对的.操作数是32位整数.所以必须保证新的函数在旧函数的正负2GB内.
  否则没法跳转到或者跳转回来.
}
function TryAllocMem(APtr: Pointer; ASize: Cardinal): Pointer;
const
  KB: Int64 = 1024;
  MB: Int64 = 1024 * 1024;
  GB: Int64 = 1024 * 1024 * 1024;
var
  mbi: TMemoryBasicInformation;
  Min, Max: Int64;
  pbAlloc: Pointer;
  sSysInfo: TSystemInfo;
begin

  GetSystemInfo(sSysInfo);
  Min := NativeUInt(APtr) - 2 * GB;
  if Min <= 0 then
    Min := 1;
  Max := NativeUInt(APtr) + 2 * GB;

  Result := nil;
  pbAlloc := Pointer(Min);
  while NativeUInt(pbAlloc) < Max do
  begin
    if (VirtualQuery(pbAlloc, mbi, SizeOf(mbi)) = 0) then
      Break;
    if ((mbi.State or MEM_FREE) = MEM_FREE) and (mbi.RegionSize >= ASize) and
      (mbi.RegionSize >= sSysInfo.dwAllocationGranularity) then
    begin
      pbAlloc :=
        PByte(ULONG_PTR((ULONG_PTR(pbAlloc) + (sSysInfo.dwAllocationGranularity
        - 1)) div sSysInfo.dwAllocationGranularity) *
        sSysInfo.dwAllocationGranularity);
      Result := VirtualAlloc(pbAlloc, ASize, MEM_COMMIT or MEM_RESERVE
{$IFDEF CPUX64}
        or MEM_TOP_DOWN
{$ENDIF}
        , PAGE_EXECUTE_READWRITE);
      if Result <> nil then
        Break;
    end;
    pbAlloc := Pointer(NativeUInt(mbi.BaseAddress) + mbi.RegionSize);
  end;

end;

function HookProc(DLLName, FuncName: PChar; NewFunc: Pointer): Pointer;
var
  h: HMODULE;
begin
  Result := nil;
  h := GetModuleHandle(DLLName);
  if h = 0 then
    h := LoadLibrary(DLLName);
  if h = 0 then
    Exit;
  Result := HookProc(GetProcAddress(h, FuncName), NewFunc);
end;

function HookProc(Func, NewFunc: Pointer): Pointer;
var
  oldProc: POldProc;
  newProc: PNewProc;
  backCodeSize: Integer;
  newProtected, oldProtected: DWORD;
  threads: THandles;
  nOriginalPriority: Integer;
  JmpAfterBackCode: PJMPCode;
begin
  Result := nil;
  if (Func = nil) or (NewFunc = nil) then
    Exit;
  newProc := PNewProc(Func);
  backCodeSize := CalcHookCodeSize(Func);
  if backCodeSize < 0 then
    Exit;
  nOriginalPriority := GetThreadPriority(GetCurrentThread());
  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  // 改写内存的时候要挂起其他线程,以免造成错误.
  threads := SuspendOtherThread(Func, backCodeSize);
  try
    if not VirtualProtect(Func, backCodeSize, PAGE_EXECUTE_READWRITE,
      oldProtected) then
      Exit;
    //

    Result := TryAllocMem(Func, PageSize);
    // VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if Result = nil then
      Exit;

    FillMemory(Result, SizeOf(TOldProc), $90);
    oldProc := POldProc(Result);
{$IFDEF USEINT3}
    oldProc.Int3OrNop := $CC;
{$ENDIF}
    oldProc.BackUpCodeSize := backCodeSize;
    oldProc.OldFuncAddr := Func;
    CopyMemory(@oldProc^.BackCode, Func, backCodeSize);
    JmpAfterBackCode := PJMPCode(@oldProc^.BackCode[backCodeSize]);
{$IFDEF USELONGJMP}
    oldProc^.JmpRealFunc.JMP := $25FF;
    oldProc^.JmpRealFunc.JmpOffset := 0;
    oldProc^.JmpRealFunc.Addr := UIntPtr(Int64(Func) + backCodeSize);

    JmpAfterBackCode^.JMP := $25FF;
    JmpAfterBackCode^.JmpOffset := 0;
    JmpAfterBackCode^.Addr := UIntPtr(Int64(Func) + backCodeSize);

    oldProc^.JmpHookFunc.JMP := $25FF;
    oldProc^.JmpHookFunc.JmpOffset := 0;
    oldProc^.JmpHookFunc.Addr := UIntPtr(NewFunc);
{$ELSE}
    oldProc^.JmpRealFunc.JMP := $E9;
    oldProc^.JmpRealFunc.Addr := (NativeInt(Func) + backCodeSize) -
      (NativeInt(@oldProc^.JmpRealFunc) + 5);

    oldProc^.JmpHookFunc.JMP := $E9;
    oldProc^.JmpHookFunc.Addr := NativeInt(NewFunc) -
      (NativeInt(@oldProc^.JmpHookFunc) + 5);
{$ENDIF}
    //
    FillMemory(Func, backCodeSize, $90);

    newProc^.JMP := $E9;
    newProc^.Addr := NativeInt(@oldProc^.JmpHookFunc) -
      (NativeInt(@newProc^.JMP) + 5);;
    // NativeInt(NewFunc) - (NativeInt(@newProc^.JMP) + 5);

    if not VirtualProtect(Func, backCodeSize, oldProtected, newProtected) then
      Exit;
    // 刷新处理器中的指令缓存.以免这部分指令被缓存.执行的时候不一致.
    FlushInstructionCache(GetCurrentProcess(), newProc, backCodeSize);
    FlushInstructionCache(GetCurrentProcess(), oldProc, PageSize);
  finally
    ResumOtherThread(threads);
    SetThreadPriority(GetCurrentThread(), nOriginalPriority);
  end;
end;

function UnHook(OldFunc: Pointer): boolean;
var
  oldProc: POldProc ABSOLUTE OldFunc;
  newProc: PNewProc;
  backCodeSize: Integer;
  newProtected, oldProtected: DWORD;
  threads: THandles;
  nOriginalPriority: Integer;
begin
  Result := FALSE;
  if (OldFunc = nil) then
    Exit;
  backCodeSize := oldProc^.BackUpCodeSize;
  newProc := PNewProc(oldProc^.OldFuncAddr);

  nOriginalPriority := GetThreadPriority(GetCurrentThread());
  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  threads := SuspendOtherThread(oldProc, SizeOf(TOldProc));
  try
    if not VirtualProtect(newProc, backCodeSize, PAGE_EXECUTE_READWRITE,
      oldProtected) then
      Exit;

    CopyMemory(newProc, @oldProc^.BackCode, oldProc^.BackUpCodeSize);

    if not VirtualProtect(newProc, backCodeSize, oldProtected, newProtected)
    then
      Exit;
    VirtualFree(oldProc, PageSize, MEM_FREE);
    // 刷新处理器中的指令缓存.以免这部分指令被缓存.执行的时候不一致.
    FlushInstructionCache(GetCurrentProcess(), newProc, backCodeSize);
  finally
    ResumOtherThread(threads);
    SetThreadPriority(GetCurrentThread(), nOriginalPriority);
  end;
end;

function CalcInterfaceMethodAddr(var AInterface; AMethodIndex: Integer)
  : Pointer;
type
  TBuf = array [0 .. $FF] of byte;
  PBuf = ^TBuf;
var
  pp: PPointer;
  buf: PBuf;
begin
  pp := PPointer(AInterface)^;
  Inc(pp, AMethodIndex);
  Result := pp^;
  { Delphi的COM对象的方法表比较特别,COM接口实际上是对象的一个成员,实际上调用到
    方法后Self是这个接口成员的地址,所以Delphi的COM方法不直接指向对象方法,而是指向
    一小段机器指令,把Self减去(加负数)这个成员在对象中的偏移,修正好Self指针后再跳转
    到真正对象的方法入口.

    所以这里要"偷窥"一下方法指针指向的头几个字节,如果是修正Self指针的,那么就是Delphi
    实现的COM对象.我们就再往下找真正的对象地址.

    下面代码就是判断和处理Delphi的COM对象的.其他语言实现的COM对象会自动忽略的.
    因为正常的函数头部都是对于栈底的处理或者参数到局部变量的处理代码.
    绝不可能一上来修正第一个参数,也就是Self的指针.所以根据这个来判断.
  }
  buf := Result;
  {
    add Self,[-COM对象相对实现对象偏移]
    JMP  真正的方法
    这样的就是Delphi生成的COM对象方法的前置指令
  }
{$IFDEF CPUX64}
  // add rcx, -COM对象的偏移, JMP 真正对象的方法地址,X64中只有一种stdcall调用约定.其他约定都是stdcall的别名
  if (buf^[0] = $48) and (buf^[1] = $81) and (buf^[2] = $C1) and (buf^[7] = $E9)
  then
    Result := Pointer(NativeInt(@buf[$C]) + PDWORD(@buf^[8])^);
{$ELSE}
  // add [esp + $04],-COM对象的偏移, JMP真正的对象地址,stdcall/cdecl调用约定
  if (buf^[0] = $81) and (buf^[1] = $44) and (buf^[2] = $24) and
    (buf^[03] = $04) and (buf^[8] = $E9) then
    Result := Pointer(NativeInt(@buf[$D]) + PDWORD(@buf^[9])^)
  else // add eax,-COM对象的偏移, JMP真正的对象地址,那就是Register调用约定的
    if (buf^[0] = $05) and (buf^[5] = $E9) then
      Result := Pointer(NativeInt(@buf[$A]) + PDWORD(@buf^[6])^);
{$ENDIF}
end;

function HookInterface(var AInterface; AMethodIndex: Integer;
  NewFunc: Pointer): Pointer;
begin
  Result := HookProc(CalcInterfaceMethodAddr(AInterface, AMethodIndex),
    NewFunc);
end;

end.

此条目发表在Delphi, 未分类分类目录。将固定链接加入收藏夹。

Delphi Hook Library》有368条回应

  1. XXOO说:

    搞两个例子就更好了 不错

  2. 匿名说:

    这个library非常好,希望可以放到github上面

  3. 匿名说:

    你这个大概是HOOK自身内的吧,能不能HOOK其他进程

    • admin说:

      只要你能把代码注入到其它进程,自身不自身没有区别.比如你能把这个代码封装到DLL,然后注入其它进程,在DLL里面打钩子.
      这个库仅仅是Hook技术.不涉及注入方式.具体怎么注入其他进程自己想办法.也可以我们底下讨论一下.
      或者说不定后面我会再写一些注入技术的博客.
      不过总得有点自己的东西.如果完全都用别人封装好的东西就没意思了.

  4. 不得闲说:

    呵呵,在看雪上,俺说了可以直接通过需要挂钩的函数动态获取偏移地址的。就是这种写法比较死,不灵活,不同接口下的不同的函数都需要自己算偏移,然后就可以通过算出来的这个偏移来对对应的函数进行挂钩了!今天偶然翻到了以前Hook D3D9中的Present函数的部分代码。
    var
    DllHandle: THandle;
    D3D: IDirect3D9;
    pVTable: Pointer;
    CreatD3d9: function(SDKVersion: LongWord): Pointer;
    d3dpp: D3DPRESENT_PARAMETERS;
    d3ddm: TD3DDisplayMode;
    pD3DDevice: IDirect3DDevice9;
    begin
    DllHandle := LoadLibrary(‘d3d9.dll’);
    CreatD3d9 := WIndows.GetProcAddress(DllHandle,’Direct3DCreate9′);
    if Assigned(CreatD3d9) then
    begin
    D3D := IDirect3D9(CreatD3d9(D3D_SDK_VERSION));
    Result := not Failed(D3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, d3ddm ));
    if Result then
    begin
    ZeroMemory( @d3dpp, sizeof(d3dpp));
    d3dpp.Windowed := true;
    d3dpp.SwapEffect := D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat := d3ddm.Format;
    ShareData^.AppHandle := frmHandle;
    Result := not Failed(D3D.CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,frmHandle,D3DCREATE_SOFTWARE_VERTEXPROCESSING,@d3dpp,pD3DDevice));
    if Result then
    begin
    //@ShareData^.MsgBackCall := @MsgCallBack;
    pVTable := Pointer(Pinteger(pD3DDevice)^+D3D9PresentOffset*sizeof(DWORD));
    ShareData^.m_nDX9_PresentOffset := phandle(pVTable)^-dllhandle;//获得偏移
    pD3DDevice := nil;
    D3D := nil;
    SendMessage(frmHandle,WM_APP_DllMSG,Integer(ShareData),0);
    end;
    end;
    end
    else Result := False;
    FreeLibrary(DllHandle);
    end;

    • admin说:

      你的D3D9PresentOffset一样要算出来的.这个D3D9PresentOffset就是我我要传输的函数Index.实际上是一样的.

  5. 爱用软件说:

    偶像,偶像,2ccc上经常看到你,求个QQ 想加一下 :) see my email.

  6. diystar说:

    又来麻烦大侠了。我有一个音量控制软件,准备去窗口化,可是不知道怎么搞,请大侠帮忙看下。用到了hook技术。http://files.cnblogs.com/diystar/vcool_test.rar

  7. beginlove说:

    麻烦大侠, 我想用你这个库HOOK wininet.dll 里的InternetSetCookie 函数,但是似乎没啥效果,我的代码如下: 麻烦你帮我看看,谢谢

    var
    original_InternetSetCookie : function(lpszUrl, lpszCookieName,
    lpszCookieData: LPCWSTR): BOOL; stdcall;

    function replaced_InternetSetCookie(lpszUrl, lpszCookieName,
    lpszCookieData: LPCWSTR): BOOL; stdcall;
    begin
    Form1.Memo1.Lines.Add(‘hook__url=’ + lpszUrl);
    Form1.Memo1.Lines.Add(‘hook__cname=’ + lpszCookieName);
    Form1.Memo1.Lines.Add(‘hook__cdata=’ + lpszCookieData);

    Result := original_InternetSetCookie(lpszUrl, lpszCookieName, lpszCookieData);
    end;

    procedure TForm1.GoClick(Sender: TObject);
    begin
    EmbeddedWB1.Go(Edit1.Text);
    end;

    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    if Assigned(original_InternetSetCookie) then
    UnHook(@original_InternetSetCookie);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    const
    {$IFDEF UNICODE}
    InternetSetCookieRealName = ‘InternetSetCookieW’;
    {$ELSE}
    InternetSetCookieRealName = ‘InternetSetCookieA’;
    {$ENDIF}
    begin
    Memo1.Clear;

    if not(Assigned(original_InternetSetCookie)) then
    begin
    @original_InternetSetCookie := HookProc(‘wininet.dll’, InternetSetCookieRealName, @replaced_InternetSetCookie);
    Memo1.Clear;
    end;
    end;

    procedure TForm1.GetCookiesClick(Sender: TObject);
    var
    buf: array[0..1024*4-1] of Char;
    size: DWORD;
    begin
    InternetGetCookie(PChar(Edit1.Text), nil, buf, size);
    Memo1.Lines.Add(string(buf));
    Memo1.Lines.Add(‘======================================’);
    end;

    PS: 非常感谢大侠的无私奉献,这个库非常好
    另搜到一片文章,不过是C#的:http://blog.csdn.net/wangjia184/article/details/4342393,不知用大侠的这个库是否能达到同样的效果

    • admin说:

      我试验了你得代码,发现WebBrowser控件似乎不是调用的InternetSetCookie 函数来设置Cookie的.
      var
      original_InternetSetCookie: function(lpszUrl, lpszCookieName,
      lpszCookieData: LPCWSTR): BOOL; stdcall;

      function replaced_InternetSetCookie(lpszUrl, lpszCookieName, lpszCookieData
      : LPCWSTR): BOOL; stdcall;
      begin
      Form1.Memo1.Lines.Add(‘ hook__url = ‘ + lpszUrl);
      Form1.Memo1.Lines.Add(‘ hook__cname = ‘ + lpszCookieName);
      Form1.Memo1.Lines.Add(‘ hook__cdata = ‘ + lpszCookieData);

      Result := original_InternetSetCookie(lpszUrl, lpszCookieName, lpszCookieData);
      end;

      procedure TForm1.Button1Click(Sender: TObject);
      begin
      //调用这个会走到replaced_InternetSetCookie中,说明Hook没问题
      InternetSetCookie(‘http://www.raysoftware.cn’,’fadfasdf’,’asdfasdfasdf’);
      end;

      procedure TForm1.Button2Click(Sender: TObject);
      begin
      //走不到,说明WebBrowser控件不是调用的InternetSetCookie方法,或者不是在本进程内调用的InternetSetCookie方法
      WebBrowser1.Navigate(‘http://www.2ccc.com’);
      end;

      procedure TForm1.FormCreate(Sender: TObject);
      const
      {$IFDEF UNICODE}
      InternetSetCookieRealName = ‘InternetSetCookieW’;
      {$ELSE}
      InternetSetCookieRealName = ‘InternetSetCookieA’;
      {$ENDIF}
      begin
      Memo1.Clear;

      if not(Assigned(original_InternetSetCookie)) then
      begin
      @original_InternetSetCookie := HookProc(‘Wininet.dll’,
      InternetSetCookieRealName, @replaced_InternetSetCookie);
      Memo1.Clear;
      end;

      end;

      • beginlove说:

        感谢大侠,我昨天又研究了一晚上,发现的确是你所说的原因

        IE控件是用
        InternetSetCookieEx : function(lpszUrl, lpszCookieName,
        lpszCookieData: LPCWSTR; dwFlags: DWORD; lpReserved: Pointer): DWORD; stdcall;

        InternetGetCookieEx : function(lpszUrl, lpszCookieName,
        lpszCookieData: LPCWSTR; var lpdwSize: DWORD; dwFlags: DWORD; lpReserved: Pointer): BOOL; stdcall;

        两个函数来操作内存的,HOOK 这两个函数就可以了。

        再次感谢!

  8. 匿名说:

    VirtualProtect 这个可以HOOK吗?

  9. 匿名说:

    老大,你试一下hook VirtualProtect。会有问题的。 在myVirtualProtect中unhook.

    • admin说:

      目前的代码是不行的,因为Hook内存片段的时候用到了这个函数来恢复内存片的只读属性.
      其实稍作修改可以试用你目前的要求的,问题现在是出在恢复代码段的只读属性上,你注释掉352行的VirtualProtect调用即可,实际不恢复只读也不会有影响.

    • admin说:

      http://www.raysoftware.cn/wp-admin/post.php?post=493&action=edit&message=1
      更新了,可以HOOK VirtualProtect了.
      用这两个函数形式
      function HookProc(Func, NewFunc: Pointer; out originalFunc: Pointer)
      : Boolean; overload;
      function HookProc(DLLName, FuncName: PChar; NewFunc: Pointer; out originalFunc: Pointer): Boolean;
      overload;

  10. 匿名说:

    这个可以HOOK某个代码段么? 比如XXXXXXXX,截取寄存器的值

  11. djsf说:

    uses
    SysUtils,
    Windows,
    Classes,
    messages,
    WinSock,

    unitHook in ‘unitHook.pas’;

    {$R *.res}
    const
    WM_HOOKKEY = WM_USER + $1000;
    LLKHF_ALTDOWN = $20;
    WH_KEYBOARD_LL = 13;
    HOOK_MEM_FILENAME = ‘tmp.hkt’;
    mycalsname=’ZwelL’;
    const
    WM_CapIp = WM_USER + 200;

    {
    type
    //要HOOK的API函数定义

    TSockProc = function (s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    TConnect =function (s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;

    PJmpCode = ^TJmpCode;
    TJmpCode = packed record
    JmpCode: BYTE;
    Address: TSockProc;
    MovEAX: Array [0..2] of BYTE;
    end;
    }
    type
    Pkeyhook=^Tkeyhook;
    Tkeyhook=record
    startPid:DWORD;
    Enabled:boolean;
    fhProcess: THandle; //保存本进程在远程进程中的句柄
    end;
    var
    hhk1: HHOOK;
    Hook: array[0..2] of TApiHookInfo; //内存映射
    MemFile: THandle;
    PstartPid:Pkeyhook=nil;
    g_hForm:integer=0;
    Oldss:string=”;
    Fbuffer:array[0..254] of char;

    function NewOpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;
    begin
    try
    Hook[0].Lock;
    if PstartPid^.startPid = dwProcessId then
    begin
    result := 0;
    OutputDebugStr(‘禁止结束1!’);
    Exit;
    end;
    try
    Hook[0].UnHook;
    Result :=OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    finally
    Hook[0].Hook;
    end;
    finally
    Hook[0].UnLock;
    end;
    end;
    {–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–}//安装API Hook
    function NewTerminateProcess(hProcess: THandle;uExitCode: UINT): BOOL; Stdcall;
    begin
    try
    Hook[1].Lock;
    result:=false;
    if (PstartPid^.fhProcess>0)and(PstartPid^.fhProcess = hProcess) then
    begin
    OutputDebugStr(‘禁止结束2!’);
    result := true;
    exit;
    end;
    try
    Hook[1].UnHook;
    Result :=TerminateProcess(hProcess, uExitCode);
    finally
    Hook[1].Hook;
    end;
    finally
    Hook[1].UnLock;
    end;
    end;

    function Newsend2(s: TSocket; const Buf; len, flags: Integer): Integer; stdcall;
    var dwSize: cardinal;iAddr,jAddr:TSockAddr;i:integer;
    ss:string;
    AsciiBuffer: string;
    hh:TSockAddrIn;
    dprot:integer;
    hProcess:THandle;
    mybuf:array[0..100] of char;
    str:array of Ansichar;
    begin
    try

    Hook[2].Lock;
    OutputDebugStr(‘拦截Newsend2!’);
    try

    try
    Hook[2].UnHook;
    Result :=send(s,buf,len,flags);
    finally
    Hook[2].Hook;
    end;
    finally
    Hook[2].UnLock;
    end;

    except

    end;
    end;

    procedure InitHook;
    begin
    g_hForm := FindWindow(‘ZwelL’,nil);
    getmodulefilename(GetModuleHandle(nil), Fbuffer, sizeof(Fbuffer));
    //try

    Hook[0]:=TApiHookInfo.Create;
    Hook[0].init(‘kernel32.dll’, ‘OpenProcess’,@NewOpenProcess);

    Hook[1]:=TApiHookInfo.Create;
    Hook[1].init(‘kernel32.dll’, ‘TerminateProcess’, @NewTerminateProcess);

    Hook[2]:=TApiHookInfo.Create;
    Hook[2].init(‘wsock32.dll’,’send’, @Newsend2);

    OutputDebugStr(strpas(Fbuffer)+’:成功!’);
    //except

    //end;
    end;//删除API Hook
    procedure UninitHook;
    var I: Integer;
    begin
    //try
    // OutputDebugStr(‘UninitHook:’+strpas(Fbuffer));
    // Hook[0].UnHook;
    // Hook[1].UnHook;
    // Hook[2].UnHook;
    // Hook[3].UnHook;
    for I := 0 to High(Hook) do
    begin
    //Hook[I].Destroy;
    if assigned(Hook[I]) then
    begin
    Hook[i].Free;
    Hook[I]:=nil;
    end;
    end;
    //except

    //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,sizeof(Tkeyhook), HOOK_MEM_FILENAME);
    end;
    if MemFile 0 then //映射文件到变量
    begin
    // startPid := MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0);
    PstartPid := Pkeyhook(MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0));
    // PstartPid^.Enabled:=true;
    //PstartPid^.fhProcess:=0;
    end;
    end;//传递消息
    function HookProc1(ncode: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
    begin
    Result := CallNextHookEx(hhk1, nCode, wParam, lParam);
    end;//开始HOOK

    procedure StartHook(pid: DWORD); stdcall;
    var dwThreadId: DWORD;
    begin
    PstartPid^.startPid:= pid;
    PstartPid^.fhProcess:=0;
    PstartPid^.Enabled:=true;
    //OutputDebugStr(‘gozi安装成!’);
    dwThreadId:=0;
    hhk1 := SetWindowsHookEx(WH_CALLWNDPROC, HookProc1, hInstance, dwThreadId);
    end;//结束HOOK
    procedure EndHook; stdcall;
    begin
    // OutputDebugStr(‘UninitHook0:’+strpas(Fbuffer));
    if hhk10 then
    begin
    UninitHook; //DLL删除
    UnhookWindowsHookEx(hhk1);
    hhk1:=0;
    end;
    end;//环境处理
    procedure DllEntry(dwResaon: DWORD);
    begin
    case dwResaon of
    DLL_PROCESS_ATTACH:
    InitHook; //DLL载入
    DLL_PROCESS_DETACH:
    begin
    if Assigned(PstartPid) then
    begin
    UnmapViewOfFile(PstartPid);
    PstartPid := nil;
    CloseHandle(MemFile);

    end;
    UninitHook; //DLL删除
    end;
    end;
    end;
    exports
    StartHook,
    EndHook;
    begin
    MemShared; { 分配DLL程序到 DllProc 变量 }
    DllProc := @DllEntry; { 调用DLL加载处理 }
    DllEntry(DLL_PROCESS_ATTACH);
    end.

    这是代码,其中 unitHook.pas就是您的文件。

    • djsf说:

      HOOK后,如果HOOK不卸载,没有问题,如果一卸载就崩溃了。而且有网络连接的进程,卸载后都会崩溃。如金山,360卫士等,这个。。。
      如果是火狐浏览器,会打不开的。直接崩溃。您试试。

  12. djsf说:

    昨天代码贴错,那是另一个HOOKAPI。
    现在这个才是使用老大的HookUtils.pas
    uses
    SysUtils,
    Windows,
    Classes,
    messages,
    WinSock2,
    HookUtils in ‘HookUtils.pas’;

    {$R *.res}
    const
    WM_HOOKKEY = WM_USER + $1000;
    LLKHF_ALTDOWN = $20;
    WH_KEYBOARD_LL = 13;
    HOOK_MEM_FILENAME = ‘tmp.hkt’;
    mycalsname=’ZwelL’;
    const
    WM_CapIp = WM_USER + 200;

    {
    type
    //要HOOK的API函数定义

    TSockProc = function (s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    TConnect =function (s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;

    PJmpCode = ^TJmpCode;
    TJmpCode = packed record
    JmpCode: BYTE;
    Address: TSockProc;
    MovEAX: Array [0..2] of BYTE;
    end;
    }
    type
    Pkeyhook=^Tkeyhook;
    Tkeyhook=record
    startPid:DWORD;
    Enabled:boolean;
    fhProcess: THandle; //保存本进程在远程进程中的句柄
    end;
    var
    hhk1: HHOOK;
    MemFile: THandle;
    PstartPid:Pkeyhook=nil;
    g_hForm:integer=0;
    Oldss:string=”;
    Fbuffer:array[0..254] of char;

    OldOpenProcess:function(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;
    OldTerminateProcess:function(hProcess: THandle;uExitCode: UINT): BOOL; Stdcall;
    Oldsend2:function(s: TSocket; const Buf; len, flags: Integer): Integer; stdcall;
    OldConnect2:function(s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;

    procedure errjilu(const ABuffer:string);
    var FileStream: TFileStream;
    aabb:TStrings;
    begin
    aabb:=TStringList.Create;
    if fileexists(‘c:\errer.txt’) then
    begin
    aabb.LoadFromFile(‘c:\errer.txt’);
    if aabb.Count>500 then
    aabb.Delete(0);
    end;
    aabb.Add(datetimetostr(now)+’:’+ABuffer);
    aabb.SaveToFile(‘c:\errer.txt’,TEncoding.Unicode);
    aabb.Free;
    end;
    procedure OutputDebugStr(const ADebugInfo: string); //输出调试信息
    begin
    OutputDebugString(PChar(ADebugInfo+#13+#10));
    end;

    //拦截MessageBoxA
    function SendMessagebufstring(buf:string;const vv:integer):integer;
    var ds: TCopyDataStruct;
    begin
    result:=0;
    if g_hForm>0 then
    begin
    ds.dwData:=vv;
    ds.cbData :=ByteLength(buf)+2;//sizeof(buf);
    getmem(ds.lpData,ds.cbData);
    ds.lpData:=pchar(buf+#0);
    result:=SendMessage (g_hForm, WM_COPYDATA,0,Cardinal(@ds)); // 向管理器发送消息
    //freemem(ds.lpData);
    end;
    end;

    function NewOpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;
    begin
    try
    if PstartPid^.startPid = dwProcessId then
    begin
    result := 0;
    OutputDebugStr(‘禁止结束1!’);
    Exit;
    end;
    try
    Result :=OldOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    finally
    end;
    finally
    end;
    end;
    {–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–}//安装API Hook
    function NewTerminateProcess(hProcess: THandle;uExitCode: UINT): BOOL; Stdcall;
    begin
    try
    result:=false;
    if (PstartPid^.fhProcess>0)and(PstartPid^.fhProcess = hProcess) then
    begin
    //showmessage(‘不准关闭我!’);
    OutputDebugStr(‘禁止结束2!’);
    result := true;
    exit;
    end;
    try
    Result :=OldTerminateProcess(hProcess, uExitCode);
    finally
    end;
    finally
    end;
    end;
    //网络===============================================================================
    //协议识别程序
    {
    function GetRemoteAddr(FSocket:TSocket): TSockAddrIn;
    var
    Size: Integer;
    begin
    try
    FillChar(Result, SizeOf(Result), 0);
    Size := SizeOf(Result);
    if getpeername(FSocket, Result, Size) 0 then
    FillChar(Result, SizeOf(Result), 0);
    finally
    end;
    end;

    }
    function Newsend2(s: TSocket; const Buf; len, flags: Integer): Integer; stdcall;
    //function Newsend2(s:TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    var dwSize: cardinal;iAddr,jAddr:TSockAddr;i:integer;
    ss:string;
    AsciiBuffer: string;
    hh:TSockAddrIn;
    dprot:integer;
    hProcess:THandle;
    mybuf:array[0..100] of char;
    str:array of Ansichar;
    begin
    try

    try
    {
    if len>10 then
    begin
    setLength(str,len);
    copymemory(str,@buf,len);
    ss:=strpas(PAnsichar(str));
    OutputDebugStr(‘拦截Newsend2!’);
    // OutputDebugStr(‘解包:’+ss);
    result:=SendMessagebufstring(ss,352);
    if result=1 then
    begin
    result:=WSAEACCES;
    OutputDebugStr(‘拦截Newsend2!’+ss);
    exit;
    end;
    end;
    hh:=GetRemoteAddr(s);
    ss:=strpas(Fbuffer)+’–‘+inet_ntoa(hh.sin_addr);
    dprot:=ntohs(hh.sin_port);
    ss:=ss+’:’+inttostr(dprot);
    if Oldssss then
    begin
    OutputDebugStr(‘拦截Newsend2!’+ss);
    result:=SendMessagebufstring(ss,351);
    if result=1 then
    begin
    result:=WSAEACCES;
    OutputDebugStr(‘拦截Newsend2!’+ss);
    exit;
    end;
    Oldss:=ss;
    end;
    }
    try
    Result :=Oldsend2(s,buf,len,flags);
    finally
    end;
    finally
    end;

    except
    on E: Exception do
    begin
    errjilu(‘Newsend2: ‘ + E.Message);
    exit;
    end;

    end;
    end;

    function NewConnect2(s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;
    var //hh:TSockAddrIn;
    dprot:integer;
    ss:string;
    begin
    try

    // ThreadID := GetWindowThreadProcessId(sWindow, nil);
    result:=0;
    OutputDebugStr(‘拦截NewConnect2!’);
    try
    {
    // hProcess:=GetCurrentProcess; //指向新地址的指针
    // hh:=GetRemoteAddr(s);
    ss:=strpas(Fbuffer)+’–‘+inet_ntoa(name.sin_addr);// hh.sin_addr);
    dprot:=ntohs(name.sin_port);// hh.sin_port);
    ss:=ss+’:’+inttostr(dprot);
    // EnumInterfaces(s,ss);
    OutputDebugStr(‘拦截NewConnect2!’+ss);
    if Oldssss then
    begin
    OutputDebugStr(‘拦截NewConnect2!’+ss);
    result:=SendMessagebufstring(ss,351);
    if result=1 then
    begin
    result:=WSAEACCES;
    OutputDebugStr(‘拦截NewConnect2!’+ss);
    exit;
    end;
    Oldss:=ss;
    end;
    }
    try
    Result :=OldConnect2(s,name,namelen);
    finally
    end;
    finally
    end;

    except
    on E: Exception do
    begin
    errjilu(‘Newsend2: ‘ + E.Message);
    exit;
    end;

    end;
    end;
    procedure InitHook;
    begin
    g_hForm := FindWindow(‘ZwelL’,nil);
    getmodulefilename(GetModuleHandle(nil), Fbuffer, sizeof(Fbuffer));
    //try
    if not Assigned(OldOpenProcess) then
    @OldOpenProcess:=HookProc(kernel32,’OpenProcess’,@NewOpenProcess);

    if not Assigned(OldTerminateProcess) then
    @OldTerminateProcess:=HookProc(kernel32, ‘TerminateProcess’, @NewTerminateProcess);

    if not Assigned(Oldsend2) then
    @Oldsend2:=HookProc(‘wsock32.dll’,’send’, @Newsend2);

    @OldConnect2:=nil;
    // if not Assigned(OldConnect2) then
    // @OldConnect2:=HookProc(‘wsock32.dll’,’connect’, @Newconnect2);

    OutputDebugStr(strpas(Fbuffer)+’:成功!’);
    //except

    //end;
    end;//删除API Hook
    procedure UninitHook;
    var I: Integer;
    begin
    //try
    OutputDebugStr(‘UninitHook:’+strpas(Fbuffer));
    if Assigned(OldOpenProcess) then
    UnHook(@OldOpenProcess);
    @OldOpenProcess := nil;

    if Assigned(OldTerminateProcess) then
    UnHook(@OldTerminateProcess);
    @OldTerminateProcess := nil;

    if Assigned(Oldsend2) then
    UnHook(@Oldsend2);
    @Oldsend2 := nil;

    if Assigned(OldConnect2) then
    UnHook(@OldConnect2);
    @OldConnect2 := nil;
    //except

    //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,sizeof(Tkeyhook), HOOK_MEM_FILENAME);
    end;
    if MemFile 0 then //映射文件到变量
    begin
    // startPid := MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0);
    PstartPid := Pkeyhook(MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0));
    // PstartPid^.Enabled:=true;
    //PstartPid^.fhProcess:=0;
    end;
    end;//传递消息
    //function HookProc1(nCode, wParam, lParam: Integer): LRESULT; stdcall;
    function HookProc1(ncode: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
    begin
    Result := CallNextHookEx(hhk1, nCode, wParam, lParam);
    end;//开始HOOK

    procedure StartHook(pid: DWORD); stdcall;
    var dwThreadId: DWORD;
    begin
    PstartPid^.startPid:= pid;
    PstartPid^.fhProcess:=0;
    PstartPid^.Enabled:=true;
    //OutputDebugStr(‘gozi安装成!’);
    dwThreadId:=0;
    hhk1 := SetWindowsHookEx(WH_CALLWNDPROC, HookProc1, hInstance, dwThreadId);
    end;//结束HOOK
    procedure EndHook; stdcall;
    begin
    // OutputDebugStr(‘UninitHook0:’+strpas(Fbuffer));
    if hhk10 then
    begin
    UninitHook; //DLL删除
    UnhookWindowsHookEx(hhk1);
    hhk1:=0;
    end;
    end;//环境处理
    procedure DllEntry(dwResaon: DWORD);
    begin
    case dwResaon of
    DLL_PROCESS_ATTACH:
    InitHook; //DLL载入
    DLL_PROCESS_DETACH:
    begin
    if Assigned(PstartPid) then
    begin
    UnmapViewOfFile(PstartPid);
    PstartPid := nil;
    CloseHandle(MemFile);

    end;
    UninitHook; //DLL删除
    end;
    end;
    end;
    exports
    StartHook,
    EndHook;
    begin
    MemShared; { 分配DLL程序到 DllProc 变量 }
    DllProc := @DllEntry; { 调用DLL加载处理 }
    DllEntry(DLL_PROCESS_ATTACH);
    end.

    HOOK后,正在运行的有网络连接的进程如IE浏览器,金山卫士、360、火狐浏览器等等就会不断崩溃退出。找了很久原因都找不到。
    老大请看看问题出在那里?如果卸载后崩溃更快。火狐浏览器启动都不能。
    希望老大指导!!谢谢!
    我的邮箱:djsf@163.com

  13. djsf说:

    对了,操作系统:xp3,win7 32位都测试过。

    • admin说:

      我没时间给你测试这段代码.但是上周刚刚回复盒子上的一个朋友问题,刚刚试过WIN7 64中,IE 32bit,IE64 bit HOOK Send函数完全没问题

  14. djsf说:

    盒子上 就是我提的问题。看到直接来这里的。代码不多,不知道问题出在那里,有空帮看看好吗?不胜感谢!我已搞了几个月了,搞不定。

    • admin说:

      我没试验你的代码.还是我自己写的Demo.没问题.
      但是发现在启用了QQ电脑管家的计算机上就会有你说的崩溃问题.关了QQ电脑管家就没问题.
      其他的杀软没试过.
      可能是HOOK send函数太敏感了,被一些杀毒软件重点监控吧.

  15. beginlove说:

    又来麻烦大侠了, 最近用你的HOOK库试图HOOK wininet.dll 以监控 TWEBBROWSER的HTTP请求, 代码写完了, 调试发现 HOOK InternetConnect/HttpOpenRequest 几个函数会导致 TOleControl 的 procedure DefaultHandler(var Message); 方法出错, 搞了好几天实在是不知道问题出在哪里, 我的系统是 WIN 8 X64, IE10, 大侠如果有空麻烦帮我看下, 测试工程和所有代码都已打包, 可以在这个地址下载: http://3.longhz.cn/vodpic/WinInet_Hook.rar
    再次感谢!!!!!

    • admin说:

      你的工程我编译不过,里面还用了什么hash的单元,编译不了.
      但是上个月刚刚帮朋友弄的Webbrowser控件的Hook,也是Hook的Wininet的几乎所有函数,包括InternetConnect/HttpOpenRequest.完全没问题.

  16. beginlove说:

    hash 的单元 uXPHashList.pas 就在打包的目录里啊, 我是 XE5 的工程, 麻烦你再看看

    • beginlove说:

      不好意思,刚检查了一下, 的确有个单元没打包进去, 现在已重新打包, 请在这个地址下载 : http://3.longhz.cn/vodpic/WinInet_Hook_RePack.rar
      真是不好意思, 麻烦你再费时间帮忙看下, 谢谢

      • admin说:

        我只有XE5,你是啥版本

      • admin说:

        你的用法就不对啊.举个例子:
        你的:
        if not(Assigned(original_InternetConnectW)) then
        HookProc(PChar(‘wininet.dll’), PChar(‘InternetConnectW’),
        @replaced_InternetConnectW);
        改成:
        if not(Assigned(original_InternetConnectW)) then
        @original_InternetConnectW:=HookProc(PChar(‘wininet.dll’), PChar(‘InternetConnectW’),
        @replaced_InternetConnectW);
        其他以此类推.修改后完全没问题.
        另外这些函数有A和W后缀的你都HOOK了,没有后缀的函数其实是不存在的,你不需要Hook了.

        • beginlove说:

          这段时间出差去了, 现在才看到, 不好意思, 的确是我自己的用法不对, 非常感谢.

  17. djsf说:

    源文件演示下载地址:http://pan.baidu.com/s/1pJJKcYJ
    win7SP1 32位系统,我用的是DELPHI XE5编译的。
    FireFox 26.0 可以钩得到,但会崩溃,错误为:
    2014-01-05 08:35:36:Newsend2: Access violation at address 92B1F44F. Write of address 92B1F44F
    2014-01-05 08:35:41:Newsend2: Access violation at address 92B1F44F. Write of address 92B1F44F

    IE11 钩不到。

    请老师看看问题出在那儿?谢谢!

  18. djsf说:

    老大百忙之中请帮看看,问题出在那儿。
    我搞了几个月了,就是搞不定。

  19. 908418235@qq.com说:

    这个是我一直在寻找的资料,谢谢老师了

  20. 码农一枚说:

    我用了这个库,在XE5+WIN8下,hook ole32.dll 的CoCreateInstance函数,我的应用主要是基于twebbrowser的应用,然后总是不定时的出现内存异常,如果把hook屏蔽掉,就没问题。

  21. 码农一枚说:

    我怀疑hook后造成了内存管理有些混乱了。

  22. ppc371说:

    老师用你的Hook库做禁止关闭某个进程怎么不启作用。
    麻烦给个例子,谢谢!
    这是我的代码:
    function NewOpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;
    begin
    try
    if GetCurrentProcessId = dwProcessId then
    begin
    result := 0;
    Exit;
    end;
    try
    Result :=OldOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    finally
    end;
    finally
    end;
    end;
    function NewTerminateProcess(hProcess: THandle;uExitCode: UINT): BOOL; Stdcall;
    begin
    try
    result:=false;
    if (GetCurrentProcessId>0)and(GetCurrentProcessId = hProcess) then
    begin
    result := true;
    exit;
    end;
    try
    Result :=OldTerminateProcess(hProcess, uExitCode);
    finally
    end;
    finally
    end;
    end;

    if not Assigned(OldOpenProcess) then
    @OldOpenProcess:=HookProc(kernel32,’OpenProcess’,@NewOpenProcess); // 测试API钩子,DrawtextEx,因为我是Unicode版本Delphi
    if not Assigned(OldTerminateProcess) then
    @OldTerminateProcess:=HookProc(kernel32, ‘TerminateProcess’, @NewTerminateProcess);

  23. 匿名说:

    老大 使用了你的 库.

    但是无法hook send recv 函数.

    请求帮忙. 非常感谢. qq 964489899 求个老师

  24. GodPan说:

    Hook不到呢?????????
    Hook Recv和 Send 都有问题 ,长度都为1 。。。

    uses
    HookUtils, WinSock;

    var
    Old_Recv: function(s: TSocket; var Buf; len, flags: Integer)
    : Integer; stdcall;
    { ————————————— }
    { 函数功能:Recv函数的HOOK
    {函数参数:同Recv
    {函数返回值:integer
    {————————————— }
    function MyRecv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
    begin

    Form4.mmo1.Lines.Add(‘Sockets长度为:’ + IntToStr(len));
    //Form4.mmo1.Lines.Add(‘长度为:’ + TemStr);
    end;

    procedure TForm4.chk1Click(Sender: TObject);
    begin
    if chk1.Checked then
    begin
    // 测试API钩子,DrawtextEx,因为我是Unicode版本Delphi
    if not Assigned(Old_Recv) then
    begin
    {武稀松的APIHook函数}
    @Old_Recv := HookProc(‘ws2_32.dll’, ‘recv’, @MyRecv);
    end
    else
    begin
    ShowMessage(‘钩过了!’);
    end;
    end
    else
    begin
    if Assigned(Old_Recv) then
    UnHook(@Old_Recv);
    @Old_Recv := nil;
    end;
    end;

    • admin说:

      Hook 网络发送和接收我这段时间一直在用,完全没问题.适用于各种浏览器.从各个版本的IE和FireFox,搜狗,360两款,傲游,Chrome,腾讯的,还有猎豹都没问题.

      • 田攀说:

        大哥,能发一个Hook网络发送和接收给我好吗。。研究了1个月没有搞出来,快愁死了 。 能发给我一个简单的吗 ,我的邮箱地址 382477247@qq.com。。。大哥好人。。。。

  25. 智慧说:

    delphi 的hook能够得到c#程序里gridview的内容吗?

  26. Cai说:

    博主,我用这个库在HOOK一个 node-webkit程序,程序只HOOK NTDLL的 ZwQueryInformationFile时,会出现内存非法访问,请问下有时间帮忙看看吗

  27. Pingback引用通告: more

  28. Pingback引用通告: film

  29. Pingback引用通告: ukraine girl kiev lviv

  30. Pingback引用通告: ukraine girl kiev lviv 2016

  31. Pingback引用通告: helou zis me

  32. Pingback引用通告: helou zis me

  33. Pingback引用通告: clic here

  34. Pingback引用通告: clic

  35. Pingback引用通告: illuziaobmana

  36. Pingback引用通告: HDKINOONLINE

  37. Pingback引用通告: 2016

  38. Pingback引用通告: heremehazdf

  39. Pingback引用通告: manastirski_chay

  40. Pingback引用通告: manastirski_chay_2016

  41. Pingback引用通告: manastirski_chay_2016ua

  42. Pingback引用通告: online

  43. Pingback引用通告: online

  44. Pingback引用通告: sitemaplist

  45. Pingback引用通告: hqpornforiphon

  46. Pingback引用通告: hqpornforiphonlatest

  47. Pingback引用通告: hqpornforiphonlatestmp4

  48. Pingback引用通告: hqpornforiphonlatestmp43gp

  49. Pingback引用通告: 18 year old noelle free mobile porn video

  50. Pingback引用通告: PussyHerpussyissotight...

  51. Pingback引用通告: xnxxtagssunnyleonexxxbrotherrapessister

  52. Pingback引用通告: sister-caught-on-hiddencam-peter

  53. Pingback引用通告: sister-helping-brother-to-masturbaste

  54. Pingback引用通告: pornozavrnet

  55. Pingback引用通告: hqporn2016

  56. Pingback引用通告: Лучшие фильмы

  57. Pingback引用通告: Лучшие фильмы2

  58. Pingback引用通告: ТелефоновСамсунг2016

  59. Pingback引用通告: sunnyleone

  60. Pingback引用通告: sunnyleonelatest

  61. Pingback引用通告: toilehtml

  62. Pingback引用通告: tubepatrolporn

  63. Pingback引用通告: kinoklub

  64. Pingback引用通告: drama2016

  65. Pingback引用通告: jpmsruvideotoppornovideo

  66. Pingback引用通告: jpmsru

  67. Pingback引用通告: top2017bloomingme

  68. Pingback引用通告: mir.dikogo.zapada.ceria.sezon

  69. Pingback引用通告: aisti.online.smotret.aisti.mult

  70. Pingback引用通告: doktor.strendj.online.kino.

  71. Pingback引用通告: lopoda

  72. Pingback引用通告: gidrofob

  73. Pingback引用通告: djekricardnetorrentonline

  74. Pingback引用通告: mirdikogozapada

  75. Pingback引用通告: mirdikogozapada2016

  76. Pingback引用通告: trumpnews

  77. Pingback引用通告: molodezhka4seria

  78. Pingback引用通告: molodejka

  79. Pingback引用通告: molodezhka4sezon17seriya18192

  80. Pingback引用通告: molodezhka4sezon

  81. Pingback引用通告: molodezjka

  82. Pingback引用通告: molodezhka-4-sezon-18-serija-148-seria-17-seria-18-seria

  83. Pingback引用通告: ok.rumolodezhka4sezon17seriya18192s

  84. Pingback引用通告: Ìîëîäåæêà 4 ñåçîí 18 ñåðèÿ

  85. Pingback引用通告: milidejka4-19-20

  86. Pingback引用通告: molodejka4sezon19

  87. Pingback引用通告: molodejka4sezon21222324252617

  88. Pingback引用通告: nolodejka4sezonl332

  89. Pingback引用通告: molodejka4s21

  90. Pingback引用通告: molodejka4sezon21s

  91. Pingback引用通告: link2016

  92. Pingback引用通告: xml18112016

  93. Pingback引用通告: xml181120167

  94. Pingback引用通告: molodezhka4sezon212223seriya

  95. Pingback引用通告: molodejka4sezon21seria21seria22seria23

  96. Pingback引用通告: molodejka4seria25

  97. Pingback引用通告: MutantNinja2016

  98. Pingback引用通告: tiodru

  99. Pingback引用通告: moana watch online

  100. Pingback引用通告: lalalendfilmskachat

  101. Pingback引用通告: liebelib.mobi

  102. Pingback引用通告: liebelib.mobi 40plus

  103. Pingback引用通告: liebelib.mobi latest

  104. Pingback引用通告: liebelib.mobi bosal

  105. Pingback引用通告: liebelib.mobi bosal principal

  106. Pingback引用通告: androidporn

  107. Pingback引用通告: androidporn pk

  108. Pingback引用通告: androidporn hi

  109. Pingback引用通告: androidporn br

  110. Pingback引用通告: yotbub

  111. Pingback引用通告: yiou

  112. Pingback引用通告: hdkino720.info

  113. Pingback引用通告: youtotobe.info

  114. Pingback引用通告: serial

  115. Pingback引用通告: golubaya-laguna

  116. Pingback引用通告: articles

  117. Pingback引用通告: Ertugrul 116-117

  118. Pingback引用通告: News 26 04 2018

  119. Pingback引用通告: testtesttestx

  120. Pingback引用通告: serial online seriya smotret

  121. Pingback引用通告: Äîìàøíèé àðåñò âñå ñåðèè

  122. Pingback引用通告: domashnij-arest

  123. Pingback引用通告: Venom 2018

  124. Pingback引用通告: 2018

  125. Pingback引用通告: hdseriionline.ru

  126. Pingback引用通告: hdseriionline.ru/bg/

  127. Pingback引用通告: branding

  128. Pingback引用通告: news2

  129. Pingback引用通告: 2019

  130. Pingback引用通告: free bitcoin cash

  131. Pingback引用通告: xzz111

  132. Pingback引用通告: Ò-34 ôèëüì

  133. Pingback引用通告: BEEF Ðóññêèé õèï-õîï

  134. Pingback引用通告: Ìñòèòåëè 4 ìñòèòåëè 2019 ñìîòðåòü

  135. Pingback引用通告: PUBG

  136. Pingback引用通告: PUBG MOBILE

  137. Pingback引用通告: 43ytr.icu

  138. Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí 2 ñåðèÿ 3 ñåðèÿ

  139. Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí Ëîñòôèëüì

  140. Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí

  141. Pingback引用通告: glyxar.ru

  142. Pingback引用通告: abisko.ru

  143. Pingback引用通告: 2021

  144. Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí âñå ñåðèè

  145. Pingback引用通告: Èãðà Ïðåñòîëîâ 8 ñåçîí 5 ñåðèÿ

  146. Pingback引用通告: bitly.com/AzAX3

  147. Pingback引用通告: 2020-2020-2020

  148. Pingback引用通告: Mstiteli: Final (2019)

  149. Pingback引用通告: ðîêåòìåí ïîëíûé ôèëüì

  150. Pingback引用通告: wwin-tv.com

  151. Pingback引用通告: empire-season-2-episode-3-putlocker

  152. Pingback引用通告: Video

  153. Pingback引用通告: Watch

  154. Pingback引用通告: watch online

  155. Pingback引用通告: 00-tv.com

  156. Pingback引用通告: 4serial.com

  157. Pingback引用通告: we-b-tv.com

  158. Pingback引用通告: kino-m.com

  159. Pingback引用通告: m-dnc.com

  160. Pingback引用通告: ðûáàëêà

  161. Pingback引用通告: kino

  162. Pingback引用通告: hs;br

  163. Pingback引用通告: tureckie_serialy_na_russkom_jazyke

  164. Pingback引用通告: tureckie_serialy

  165. Pingback引用通告: serialy

  166. Pingback引用通告: +1+

  167. Pingback引用通告: æóêè+2+ñåðèÿ

  168. Pingback引用通告: Ñìîòðåòü âñå ñåðèè ïîäðÿä

  169. Pingback引用通告: âûòîïêà âîñêà

  170. Pingback引用通告: ++++++

  171. Pingback引用通告: HD-720

  172. Pingback引用通告: guardians+of+the+galaxy+2

  173. Pingback引用通告: strong woman do bong soon

  174. Pingback引用通告: my id is gangnam beauty

  175. Pingback引用通告: guardians of the galaxy vol 2

  176. Pingback引用通告: 2020

  177. Pingback引用通告: kpop+star+season+6+ep+9

  178. Pingback引用通告: 1 2 3 4 5 6 7 8 9 10

  179. Pingback引用通告: dinotube hd dinotube

  180. Pingback引用通告: Watch TV Shows

  181. Pingback引用通告: Kinokrad 2019 Kinokrad Hd

  182. Pingback引用通告: Kinokrad

  183. Pingback引用通告: filmy-kinokrad

  184. Pingback引用通告: kinokrad-2019

  185. Pingback引用通告: filmy-2019-kinokrad

  186. Pingback引用通告: serial 1

  187. Pingback引用通告: cerialest.ru

  188. Pingback引用通告: youtube2019.ru

  189. Pingback引用通告: dorama hdrezka

  190. Pingback引用通告: movies hdrezka

  191. Pingback引用通告: HDrezka

  192. Pingback引用通告: kinosmotretonline

  193. Pingback引用通告: LostFilm HD 720

  194. Pingback引用通告: trustedmdstorefy.com

  195. Pingback引用通告: bofilm ñåðèàë

  196. Pingback引用通告: bofilm

  197. Pingback引用通告: 1 seriya

  198. Pingback引用通告: Êîíñóëüòàöèÿ ïñèõîëîãà

  199. Pingback引用通告: topedstoreusa.com

  200. Pingback引用通告: hqcialismht.com

  201. Pingback引用通告: viagramdtrustser.com

  202. Pingback引用通告: rick and morty season 3

  203. Pingback引用通告: See-Season-1

  204. Pingback引用通告: Evil-Season-1

  205. Pingback引用通告: Evil-Season-2

  206. Pingback引用通告: Evil-Season-3

  207. Pingback引用通告: Evil-Season-4

  208. Pingback引用通告: Dollface-Season-1

  209. Pingback引用通告: Queer-Eye-We-re-in-Japan-Season-1

  210. Pingback引用通告: nileriver

  211. Pingback引用通告: cupooftea

  212. Pingback引用通告: serial 2020

  213. Pingback引用通告: Dailymotion

  214. Pingback引用通告: Watch+movies+2020

  215. Pingback引用通告: Netflix Original Movies

  216. Pingback引用通告: serial-video-film-online

  217. Pingback引用通告: tvrv.ru

  218. Pingback引用通告: 1plus1serial.site

  219. Pingback引用通告: #1plus1

  220. Pingback引用通告: 1plus1

  221. Pingback引用通告: Watch Movies Online

  222. Pingback引用通告: Film 2020

  223. Pingback引用通告: Film 2021

  224. Pingback引用通告: Top 10 Best

  225. Pingback引用通告: watch online TV LIVE

  226. Pingback引用通告: human design

  227. Pingback引用通告: DSmlka

  228. Pingback引用通告: viagra

  229. Pingback引用通告: viagra online

  230. Pingback引用通告: +

  231. Pingback引用通告: ¯jak Son³k

  232. Pingback引用通告: astrolog

  233. Pingback引用通告: film-kalashnikov-watch

  234. Pingback引用通告: generic cialis

  235. Pingback引用通告: cialis 20mg

  236. Pingback引用通告: kinoxaxru.ru

  237. Pingback引用通告: pobachennya u vegas

  238. Pingback引用通告: Proshanie so Stalinym

  239. Pingback引用通告: strelcov 2020

  240. Pingback引用通告: film t-34

  241. Pingback引用通告: online pharmacy

  242. Pingback引用通告: canadian pharmacy

  243. Pingback引用通告: Beograd film 2020

  244. Pingback引用通告: psiholog

  245. Pingback引用通告: pomoshh-psihologa-online

  246. Pingback引用通告: psixolog

  247. Pingback引用通告: psyhelp_on_line

  248. Pingback引用通告: coronavirus

  249. Pingback引用通告: PSYCHOSOCIAL

  250. Pingback引用通告: rasstanovka hellinger

  251. Pingback引用通告: Cherekasi film 2020

  252. Pingback引用通告: film doktor_liza

  253. Pingback引用通告: djoker film

  254. dewa slot说:

    Baca Cara Daftar Slot Terbaru Yang Betul Biar Langsung Berbonus dan info menarik disini = http://agenslotterbesar.com/

  255. Pingback引用通告: t.me/psyhell

  256. Pingback引用通告: Ïñèõîëîã îíëàéí

  257. Pingback引用通告: bitly.com

  258. Pingback引用通告: viagra 100mg

  259. Pingback引用通告: viagra price

  260. Pingback引用通告: viagra generic

  261. Pingback引用通告: viagra coupon

  262. Pingback引用通告: cheap viagra

  263. Pingback引用通告: cialis

  264. Pingback引用通告: cialis coupon

  265. Pingback引用通告: canadian pharmacy cialis

  266. Pingback引用通告: cialis 5mg

  267. Pingback引用通告: rlowcostmd.com

  268. Pingback引用通告: bitly

  269. Pingback引用通告: movies-tekstmovies-tekst

  270. Pingback引用通告: Zemlyane 2005 smotret onlajn

  271. Pingback引用通告: smotret onlajn besplatno v kachestve hd 1080

  272. Pingback引用通告: gusmeasu.com

  273. Pingback引用通告: movies-unhinged-film

  274. Pingback引用通告: malenkie-zhenshhiny-2020

  275. Pingback引用通告: dom 2

  276. Pingback引用通告: zoom-psykholog

  277. Pingback引用通告: zoom-viber-skype

  278. Pingback引用通告: Vratar Galaktiki Film, 2020

  279. Pingback引用通告: Vratar

  280. Pingback引用通告: Cherkassy

  281. Pingback引用通告: chernobyl-hbo-2019-1-sezon

  282. Pingback引用通告: moskva-psiholog

  283. Pingback引用通告: batmanapollo.ru

  284. Pingback引用通告: 323

  285. Pingback引用通告: 525

  286. Pingback引用通告: dom2-ru

  287. Pingback引用通告: Tenet Online

  288. Pingback引用通告: psy psy psy psy

  289. Pingback引用通告: krsmi.ru

  290. Pingback引用通告: like-v.ru

  291. Pingback引用通告: CFOSPUK

  292. Pingback引用通告: MAMprEj

  293. Pingback引用通告: fgu0ygW

  294. Pingback引用通告: batmanapollo

  295. Pingback引用通告: tsoy

  296. Pingback引用通告: 44548

  297. Pingback引用通告: 44549

  298. Pingback引用通告: hod-korolevy-2020

  299. Pingback引用通告: HD

  300. Pingback引用通告: 158444

  301. Pingback引用通告: groznyy-serial-2020

  302. Pingback引用通告: 38QvPmk

  303. Pingback引用通告: bitly.com/doctor-strange-hd

  304. Pingback引用通告: bitly.com/eternals-online

  305. Pingback引用通告: bitly.com/maior-grom

  306. Pingback引用通告: matrica-film

  307. Pingback引用通告: dzhonuikfilm4

  308. Pingback引用通告: bitly.com/batman20212022

  309. Pingback引用通告: bitly.com/venom-2-smotret-onlajn

  310. Pingback引用通告: bitly.com/nevremyaumirat

  311. Pingback引用通告: bitly.com/kingsmankingsman

  312. Pingback引用通告: bitly.com/3zaklyatie3

  313. Pingback引用通告: bitly.com/1dreykfilm

  314. Pingback引用通告: bitly.com/topgunmavericktopgun

  315. Pingback引用通告: bitly.com/flash2022

  316. Pingback引用通告: bitly.com/fantasticheskietvari3

  317. Pingback引用通告: bitly.com/wonderwoman1984hd

  318. Pingback引用通告: 1444

  319. Pingback引用通告: cleantalkorg2.ru

  320. Pingback引用通告: 232dfsad

  321. Pingback引用通告: cleantalkorg2.ru/sitemap.xml

  322. Pingback引用通告: win7testxy

  323. Pingback引用通告: join vk

  324. Pingback引用通告: vk login

  325. Pingback引用通告: svaty—7—sezon

  326. Pingback引用通告: svaty 7

  327. Pingback引用通告: tik tok

  328. Pingback引用通告: 666

  329. Pingback引用通告: The Revenant

  330. Pingback引用通告: 2021

  331. Pingback引用通告: D4

  332. Pingback引用通告: 777

  333. Pingback引用通告: link

  334. Pingback引用通告: 4569987

  335. Pingback引用通告: news news news

  336. Pingback引用通告: psy

  337. Pingback引用通告: psy2022

  338. Pingback引用通告: projectio-freid

  339. Pingback引用通告: kinoteatrzarya.ru

  340. Pingback引用通告: topvideos

  341. Pingback引用通告: afisha-kinoteatrov.ru

  342. Pingback引用通告: Ukrainskie-serialy

  343. Pingback引用通告: site

  344. Pingback引用通告: top

  345. Pingback引用通告: soderzhanki-3-sezon-2021.online

评论已关闭。