常常见到有朋友问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.
搞两个例子就更好了 不错
代码中明晃晃的Demo目录
这个library非常好,希望可以放到github上面
你这个大概是HOOK自身内的吧,能不能HOOK其他进程
只要你能把代码注入到其它进程,自身不自身没有区别.比如你能把这个代码封装到DLL,然后注入其它进程,在DLL里面打钩子.
这个库仅仅是Hook技术.不涉及注入方式.具体怎么注入其他进程自己想办法.也可以我们底下讨论一下.
或者说不定后面我会再写一些注入技术的博客.
不过总得有点自己的东西.如果完全都用别人封装好的东西就没意思了.
呵呵,在看雪上,俺说了可以直接通过需要挂钩的函数动态获取偏移地址的。就是这种写法比较死,不灵活,不同接口下的不同的函数都需要自己算偏移,然后就可以通过算出来的这个偏移来对对应的函数进行挂钩了!今天偶然翻到了以前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;
你的D3D9PresentOffset一样要算出来的.这个D3D9PresentOffset就是我我要传输的函数Index.实际上是一样的.
偶像,偶像,2ccc上经常看到你,求个QQ 想加一下 :) see my email.
4208303
又来麻烦大侠了。我有一个音量控制软件,准备去窗口化,可是不知道怎么搞,请大侠帮忙看下。用到了hook技术。http://files.cnblogs.com/diystar/vcool_test.rar
什么叫去窗口化.没看懂啊
直接在工程文件pdr中写代码,避免forms单元的引用。因为该软件不需要窗口。
你那个是Hook跟我这个Hook是两种东西.你那个是消息钩子.这个是函数钩子.
不过你那个所谓去窗口化后没用是因为你没有主消息循环.
谢谢提醒。那我就不用瞎忙乎了。
麻烦大侠, 我想用你这个库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,不知用大侠的这个库是否能达到同样的效果
我试验了你得代码,发现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;
感谢大侠,我昨天又研究了一晚上,发现的确是你所说的原因
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 这两个函数就可以了。
再次感谢!
VirtualProtect 这个可以HOOK吗?
老大,你试一下hook VirtualProtect。会有问题的。 在myVirtualProtect中unhook.
目前的代码是不行的,因为Hook内存片段的时候用到了这个函数来恢复内存片的只读属性.
其实稍作修改可以试用你目前的要求的,问题现在是出在恢复代码段的只读属性上,你注释掉352行的VirtualProtect调用即可,实际不恢复只读也不会有影响.
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;
这个可以HOOK某个代码段么? 比如XXXXXXXX,截取寄存器的值
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就是您的文件。
HOOK后,如果HOOK不卸载,没有问题,如果一卸载就崩溃了。而且有网络连接的进程,卸载后都会崩溃。如金山,360卫士等,这个。。。
如果是火狐浏览器,会打不开的。直接崩溃。您试试。
昨天代码贴错,那是另一个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
对了,操作系统:xp3,win7 32位都测试过。
我没时间给你测试这段代码.但是上周刚刚回复盒子上的一个朋友问题,刚刚试过WIN7 64中,IE 32bit,IE64 bit HOOK Send函数完全没问题
盒子上 就是我提的问题。看到直接来这里的。代码不多,不知道问题出在那里,有空帮看看好吗?不胜感谢!我已搞了几个月了,搞不定。
我没试验你的代码.还是我自己写的Demo.没问题.
但是发现在启用了QQ电脑管家的计算机上就会有你说的崩溃问题.关了QQ电脑管家就没问题.
其他的杀软没试过.
可能是HOOK send函数太敏感了,被一些杀毒软件重点监控吧.
又来麻烦大侠了, 最近用你的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
再次感谢!!!!!
你的工程我编译不过,里面还用了什么hash的单元,编译不了.
但是上个月刚刚帮朋友弄的Webbrowser控件的Hook,也是Hook的Wininet的几乎所有函数,包括InternetConnect/HttpOpenRequest.完全没问题.
hash 的单元 uXPHashList.pas 就在打包的目录里啊, 我是 XE5 的工程, 麻烦你再看看
不好意思,刚检查了一下, 的确有个单元没打包进去, 现在已重新打包, 请在这个地址下载 : http://3.longhz.cn/vodpic/WinInet_Hook_RePack.rar
真是不好意思, 麻烦你再费时间帮忙看下, 谢谢
我只有XE5,你是啥版本
你的用法就不对啊.举个例子:
你的:
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了.
这段时间出差去了, 现在才看到, 不好意思, 的确是我自己的用法不对, 非常感谢.
源文件演示下载地址: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 钩不到。
请老师看看问题出在那儿?谢谢!
老大百忙之中请帮看看,问题出在那儿。
我搞了几个月了,就是搞不定。
这个是我一直在寻找的资料,谢谢老师了
我用了这个库,在XE5+WIN8下,hook ole32.dll 的CoCreateInstance函数,我的应用主要是基于twebbrowser的应用,然后总是不定时的出现内存异常,如果把hook屏蔽掉,就没问题。
我在家里面电脑发现英伟达有个DLL也会HOOK CoCreateInstance函数.会导致有些问题
我怀疑hook后造成了内存管理有些混乱了。
老师用你的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);
老大 使用了你的 库.
但是无法hook send recv 函数.
请求帮忙. 非常感谢. qq 964489899 求个老师
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;
Hook 网络发送和接收我这段时间一直在用,完全没问题.适用于各种浏览器.从各个版本的IE和FireFox,搜狗,360两款,傲游,Chrome,腾讯的,还有猎豹都没问题.
大哥,能发一个Hook网络发送和接收给我好吗。。研究了1个月没有搞出来,快愁死了 。 能发给我一个简单的吗 ,我的邮箱地址 382477247@qq.com。。。大哥好人。。。。
delphi 的hook能够得到c#程序里gridview的内容吗?
博主,我用这个库在HOOK一个 node-webkit程序,程序只HOOK NTDLL的 ZwQueryInformationFile时,会出现内存非法访问,请问下有时间帮忙看看吗
Pingback引用通告: more
Pingback引用通告: film
Pingback引用通告: ukraine girl kiev lviv
Pingback引用通告: ukraine girl kiev lviv 2016
Pingback引用通告: helou zis me
Pingback引用通告: helou zis me
Pingback引用通告: clic here
Pingback引用通告: clic
Pingback引用通告: illuziaobmana
Pingback引用通告: HDKINOONLINE
Pingback引用通告: 2016
Pingback引用通告: heremehazdf
Pingback引用通告: manastirski_chay
Pingback引用通告: manastirski_chay_2016
Pingback引用通告: manastirski_chay_2016ua
Pingback引用通告: online
Pingback引用通告: online
Pingback引用通告: sitemaplist
Pingback引用通告: hqpornforiphon
Pingback引用通告: hqpornforiphonlatest
Pingback引用通告: hqpornforiphonlatestmp4
Pingback引用通告: hqpornforiphonlatestmp43gp
Pingback引用通告: 18 year old noelle free mobile porn video
Pingback引用通告: PussyHerpussyissotight...
Pingback引用通告: xnxxtagssunnyleonexxxbrotherrapessister
Pingback引用通告: sister-caught-on-hiddencam-peter
Pingback引用通告: sister-helping-brother-to-masturbaste
Pingback引用通告: pornozavrnet
Pingback引用通告: hqporn2016
Pingback引用通告: Лучшие фильмы
Pingback引用通告: Лучшие фильмы2
Pingback引用通告: ТелефоновСамсунг2016
Pingback引用通告: sunnyleone
Pingback引用通告: sunnyleonelatest
Pingback引用通告: toilehtml
Pingback引用通告: tubepatrolporn
Pingback引用通告: kinoklub
Pingback引用通告: drama2016
Pingback引用通告: jpmsruvideotoppornovideo
Pingback引用通告: jpmsru
Pingback引用通告: top2017bloomingme
Pingback引用通告: mir.dikogo.zapada.ceria.sezon
Pingback引用通告: aisti.online.smotret.aisti.mult
Pingback引用通告: doktor.strendj.online.kino.
Pingback引用通告: lopoda
Pingback引用通告: gidrofob
Pingback引用通告: djekricardnetorrentonline
Pingback引用通告: mirdikogozapada
Pingback引用通告: mirdikogozapada2016
Pingback引用通告: trumpnews
Pingback引用通告: molodezhka4seria
Pingback引用通告: molodejka
Pingback引用通告: molodezhka4sezon17seriya18192
Pingback引用通告: molodezhka4sezon
Pingback引用通告: molodezjka
Pingback引用通告: molodezhka-4-sezon-18-serija-148-seria-17-seria-18-seria
Pingback引用通告: ok.rumolodezhka4sezon17seriya18192s
Pingback引用通告: Ìîëîäåæêà 4 ñåçîí 18 ñåðèÿ
Pingback引用通告: milidejka4-19-20
Pingback引用通告: molodejka4sezon19
Pingback引用通告: molodejka4sezon21222324252617
Pingback引用通告: nolodejka4sezonl332
Pingback引用通告: molodejka4s21
Pingback引用通告: molodejka4sezon21s
Pingback引用通告: link2016
Pingback引用通告: xml18112016
Pingback引用通告: xml181120167
Pingback引用通告: molodezhka4sezon212223seriya
Pingback引用通告: molodejka4sezon21seria21seria22seria23
Pingback引用通告: molodejka4seria25
Pingback引用通告: MutantNinja2016
Pingback引用通告: tiodru
Pingback引用通告: moana watch online
Pingback引用通告: lalalendfilmskachat
Pingback引用通告: liebelib.mobi
Pingback引用通告: liebelib.mobi 40plus
Pingback引用通告: liebelib.mobi latest
Pingback引用通告: liebelib.mobi bosal
Pingback引用通告: liebelib.mobi bosal principal
Pingback引用通告: androidporn
Pingback引用通告: androidporn pk
Pingback引用通告: androidporn hi
Pingback引用通告: androidporn br
Pingback引用通告: yotbub
Pingback引用通告: yiou
Pingback引用通告: hdkino720.info
Pingback引用通告: youtotobe.info
Pingback引用通告: serial
Pingback引用通告: golubaya-laguna
Pingback引用通告: articles
Pingback引用通告: Ertugrul 116-117
Pingback引用通告: News 26 04 2018
Pingback引用通告: testtesttestx
Pingback引用通告: serial online seriya smotret
Pingback引用通告: Äîìàøíèé àðåñò âñå ñåðèè
Pingback引用通告: domashnij-arest
Pingback引用通告: Venom 2018
Pingback引用通告: 2018
Pingback引用通告: hdseriionline.ru
Pingback引用通告: hdseriionline.ru/bg/
Pingback引用通告: branding
Pingback引用通告: news2
Pingback引用通告: 2019
Pingback引用通告: free bitcoin cash
Pingback引用通告: xzz111
Pingback引用通告: Ò-34 ôèëüì
Pingback引用通告: BEEF Ðóññêèé õèï-õîï
Pingback引用通告: Ìñòèòåëè 4 ìñòèòåëè 2019 ñìîòðåòü
Pingback引用通告: PUBG
Pingback引用通告: PUBG MOBILE
Pingback引用通告: 43ytr.icu
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí 2 ñåðèÿ 3 ñåðèÿ
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí Ëîñòôèëüì
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí
Pingback引用通告: glyxar.ru
Pingback引用通告: abisko.ru
Pingback引用通告: 2021
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí âñå ñåðèè
Pingback引用通告: Èãðà Ïðåñòîëîâ 8 ñåçîí 5 ñåðèÿ
Pingback引用通告: bitly.com/AzAX3
Pingback引用通告: 2020-2020-2020
Pingback引用通告: Mstiteli: Final (2019)
Pingback引用通告: ðîêåòìåí ïîëíûé ôèëüì
Pingback引用通告: wwin-tv.com
Pingback引用通告: empire-season-2-episode-3-putlocker
Pingback引用通告: Video
Pingback引用通告: Watch
Pingback引用通告: watch online
Pingback引用通告: 00-tv.com
Pingback引用通告: 4serial.com
Pingback引用通告: we-b-tv.com
Pingback引用通告: kino-m.com
Pingback引用通告: m-dnc.com
Pingback引用通告: ðûáàëêà
Pingback引用通告: kino
Pingback引用通告: hs;br
Pingback引用通告: tureckie_serialy_na_russkom_jazyke
Pingback引用通告: tureckie_serialy
Pingback引用通告: serialy
Pingback引用通告: +1+
Pingback引用通告: æóêè+2+ñåðèÿ
Pingback引用通告: Ñìîòðåòü âñå ñåðèè ïîäðÿä
Pingback引用通告: âûòîïêà âîñêà
Pingback引用通告: ++++++
Pingback引用通告: HD-720
Pingback引用通告: guardians+of+the+galaxy+2
Pingback引用通告: strong woman do bong soon
Pingback引用通告: my id is gangnam beauty
Pingback引用通告: guardians of the galaxy vol 2
Pingback引用通告: 2020
Pingback引用通告: kpop+star+season+6+ep+9
Pingback引用通告: 1 2 3 4 5 6 7 8 9 10
Pingback引用通告: dinotube hd dinotube
Pingback引用通告: Watch TV Shows
Pingback引用通告: Kinokrad 2019 Kinokrad Hd
Pingback引用通告: Kinokrad
Pingback引用通告: filmy-kinokrad
Pingback引用通告: kinokrad-2019
Pingback引用通告: filmy-2019-kinokrad
Pingback引用通告: serial 1
Pingback引用通告: cerialest.ru
Pingback引用通告: youtube2019.ru
Pingback引用通告: dorama hdrezka
Pingback引用通告: movies hdrezka
Pingback引用通告: HDrezka
Pingback引用通告: kinosmotretonline
Pingback引用通告: LostFilm HD 720
Pingback引用通告: trustedmdstorefy.com
Pingback引用通告: bofilm ñåðèàë
Pingback引用通告: bofilm
Pingback引用通告: 1 seriya
Pingback引用通告: Êîíñóëüòàöèÿ ïñèõîëîãà
Pingback引用通告: topedstoreusa.com
Pingback引用通告: hqcialismht.com
Pingback引用通告: viagramdtrustser.com
Pingback引用通告: rick and morty season 3
Pingback引用通告: See-Season-1
Pingback引用通告: Evil-Season-1
Pingback引用通告: Evil-Season-2
Pingback引用通告: Evil-Season-3
Pingback引用通告: Evil-Season-4
Pingback引用通告: Dollface-Season-1
Pingback引用通告: Queer-Eye-We-re-in-Japan-Season-1
Pingback引用通告: nileriver
Pingback引用通告: cupooftea
Pingback引用通告: serial 2020
Pingback引用通告: Dailymotion
Pingback引用通告: Watch+movies+2020
Pingback引用通告: Netflix Original Movies
Pingback引用通告: serial-video-film-online
Pingback引用通告: tvrv.ru
Pingback引用通告: 1plus1serial.site
Pingback引用通告: #1plus1
Pingback引用通告: 1plus1
Pingback引用通告: Watch Movies Online
Pingback引用通告: Film 2020
Pingback引用通告: Film 2021
Pingback引用通告: Top 10 Best
Pingback引用通告: watch online TV LIVE
Pingback引用通告: human design
Pingback引用通告: DSmlka
Pingback引用通告: viagra
Pingback引用通告: viagra online
Pingback引用通告: +
Pingback引用通告: ¯jak Son³k
Pingback引用通告: astrolog
Pingback引用通告: film-kalashnikov-watch
Pingback引用通告: generic cialis
Pingback引用通告: cialis 20mg
Pingback引用通告: kinoxaxru.ru
Pingback引用通告: pobachennya u vegas
Pingback引用通告: Proshanie so Stalinym
Pingback引用通告: strelcov 2020
Pingback引用通告: film t-34
Pingback引用通告: online pharmacy
Pingback引用通告: canadian pharmacy
Pingback引用通告: Beograd film 2020
Pingback引用通告: psiholog
Pingback引用通告: pomoshh-psihologa-online
Pingback引用通告: psixolog
Pingback引用通告: psyhelp_on_line
Pingback引用通告: coronavirus
Pingback引用通告: PSYCHOSOCIAL
Pingback引用通告: rasstanovka hellinger
Pingback引用通告: Cherekasi film 2020
Pingback引用通告: film doktor_liza
Pingback引用通告: djoker film
Baca Cara Daftar Slot Terbaru Yang Betul Biar Langsung Berbonus dan info menarik disini = http://agenslotterbesar.com/
Pingback引用通告: t.me/psyhell
Pingback引用通告: Ïñèõîëîã îíëàéí
Pingback引用通告: bitly.com
Pingback引用通告: viagra 100mg
Pingback引用通告: viagra price
Pingback引用通告: viagra generic
Pingback引用通告: viagra coupon
Pingback引用通告: cheap viagra
Pingback引用通告: cialis
Pingback引用通告: cialis coupon
Pingback引用通告: canadian pharmacy cialis
Pingback引用通告: cialis 5mg
Pingback引用通告: rlowcostmd.com
Pingback引用通告: bitly
Pingback引用通告: movies-tekstmovies-tekst
Pingback引用通告: Zemlyane 2005 smotret onlajn
Pingback引用通告: smotret onlajn besplatno v kachestve hd 1080
Pingback引用通告: gusmeasu.com
Pingback引用通告: movies-unhinged-film
Pingback引用通告: malenkie-zhenshhiny-2020
Pingback引用通告: dom 2
Pingback引用通告: zoom-psykholog
Pingback引用通告: zoom-viber-skype
Pingback引用通告: Vratar Galaktiki Film, 2020
Pingback引用通告: Vratar
Pingback引用通告: Cherkassy
Pingback引用通告: chernobyl-hbo-2019-1-sezon
Pingback引用通告: moskva-psiholog
Pingback引用通告: batmanapollo.ru
Pingback引用通告: 323
Pingback引用通告: 525
Pingback引用通告: dom2-ru
Pingback引用通告: Tenet Online
Pingback引用通告: psy psy psy psy
Pingback引用通告: krsmi.ru
Pingback引用通告: like-v.ru
Pingback引用通告: CFOSPUK
Pingback引用通告: MAMprEj
Pingback引用通告: fgu0ygW
Pingback引用通告: batmanapollo
Pingback引用通告: tsoy
Pingback引用通告: 44548
Pingback引用通告: 44549
Pingback引用通告: hod-korolevy-2020
Pingback引用通告: HD
Pingback引用通告: 158444
Pingback引用通告: groznyy-serial-2020
Pingback引用通告: 38QvPmk
Pingback引用通告: bitly.com/doctor-strange-hd
Pingback引用通告: bitly.com/eternals-online
Pingback引用通告: bitly.com/maior-grom
Pingback引用通告: matrica-film
Pingback引用通告: dzhonuikfilm4
Pingback引用通告: bitly.com/batman20212022
Pingback引用通告: bitly.com/venom-2-smotret-onlajn
Pingback引用通告: bitly.com/nevremyaumirat
Pingback引用通告: bitly.com/kingsmankingsman
Pingback引用通告: bitly.com/3zaklyatie3
Pingback引用通告: bitly.com/1dreykfilm
Pingback引用通告: bitly.com/topgunmavericktopgun
Pingback引用通告: bitly.com/flash2022
Pingback引用通告: bitly.com/fantasticheskietvari3
Pingback引用通告: bitly.com/wonderwoman1984hd
Pingback引用通告: 1444
Pingback引用通告: cleantalkorg2.ru
Pingback引用通告: 232dfsad
Pingback引用通告: cleantalkorg2.ru/sitemap.xml
Pingback引用通告: win7testxy
Pingback引用通告: join vk
Pingback引用通告: vk login
Pingback引用通告: svaty7sezon
Pingback引用通告: svaty 7
Pingback引用通告: tik tok
Pingback引用通告: 666
Pingback引用通告: The Revenant
Pingback引用通告: 2021
Pingback引用通告: D4
Pingback引用通告: 777
Pingback引用通告: link
Pingback引用通告: 4569987
Pingback引用通告: news news news
Pingback引用通告: psy
Pingback引用通告: psy2022
Pingback引用通告: projectio-freid
Pingback引用通告: kinoteatrzarya.ru
Pingback引用通告: topvideos
Pingback引用通告: afisha-kinoteatrov.ru
Pingback引用通告: Ukrainskie-serialy
Pingback引用通告: site
Pingback引用通告: top
Pingback引用通告: soderzhanki-3-sezon-2021.online