1688 发表于 2013-9-7 18:37:03

delphi怎么HOOK指定API函数!

delphi hook鼠标键盘的例子有很多,但是没找到hook api函数的简单例子!
有没有高手给份简单的hook api函数源码!比如要hook FindWindow函数怎么实现!

小甲鱼 发表于 2013-9-7 18:37:04

转载一份:

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

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

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

   MessageBoxA、MessageBoxW、MessageBeep 和 OpenProcess 。

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

unit unitHook;

interface

uses
Windows, Messages, Classes, SysUtils;

type

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

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

implementation

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

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

inherited;
end;

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

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

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

library hookdll;

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

{$R *.res}

const
HOOK_MEM_FILENAME='tmp.hkt';

var
hhk: HHOOK;
Hook: array of TNtHookClass;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

exports
StartHook, EndHook;

begin
MemShared;

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

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

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

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

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

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


unit FMain;

interface

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

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

var
frmMain: TfrmMain;

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

implementation

{$R *.dfm}

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

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

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

procedure TfrmMain.FormCreate(Sender: TObject);
begin

end;

end.

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

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

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

begin
MemShared;

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

   可以看到,在DLL装入内存的时候其实就已经调用了InitHook,将要拦截的API拦截了

怡静 发表于 2013-9-9 00:56:02

真的谢谢小甲鱼,花这么多精力回复鱼友!

1688 发表于 2013-9-10 17:48:33

小甲鱼 发表于 2013-9-7 18:37 static/image/common/back.gif
转载一份:

{:5_110:}得到小甲鱼的解答真不容易!非常感谢!

tlwangxd 发表于 2014-10-24 09:48:05

学习

wmkforever1234 发表于 2014-10-25 22:32:59

路过学习下
页: [1]
查看完整版本: delphi怎么HOOK指定API函数!