您的位置:首页 > 编程语言 > Delphi

windows HOOK在delphi开发环境下的使用方法

2010-04-06 14:17 597 查看
要拦截的API如下:

MessageBoxA、MessageBoxW、MessageBeep和OpenProcess。

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

unitunitHook;

interface

uses
Windows,Messages,Classes,SysUtils;

type

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

TNtHookClass=class(TObject)
private
hProcess:THandle;
NewAddr:TNtJmpCode;
OldAddr:array[0..7]ofByte;
ReadOK:Boolean;
public
BaseAddr:Pointer;
constructorCreate(DllName,FuncName:string;NewFunc:Pointer);
destructorDestroy;override;
procedureHook;
procedureUnHook;
end;

implementation

//==================================================
//NtHOOK类开始
//==================================================
constructorTNtHookClass.Create(DllName:string;FuncName:string;NewFunc:Pointer);
var
DllModule:HMODULE;
dwReserved:DWORD;
begin
//获取模块句柄
DllModule:=GetModuleHandle(PChar(DllName));
//如果得不到说明未被加载
ifDllModule=0thenDllModule:=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;

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

inherited;
end;

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

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

end.

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


libraryhookdll;

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

{$R*.res}

const
HOOK_MEM_FILENAME='tmp.hkt';

var
hhk:HHOOK;
Hook:array[0..3]ofTNtHookClass;

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

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

//拦截MessageBoxA
functionNewMessageBoxA(_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[0].UnHook;
Result:=TNewMessageBoxA(Hook[0].BaseAddr)(_hWnd,lpText,lpCaption,uType);
Hook[0].Hook;
end;

//拦截MessageBoxW
functionNewMessageBoxW(_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[2].UnHook;
Result:=TNewMessageBoxW(Hook[2].BaseAddr)(_hWnd,lpText,lpCaption,uType);
Hook[2].Hook;
end;

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

//拦截OpenProcess,防止关闭
functionNewOpenProcess(dwDesiredAccess:DWORD;bInheritHandle:BOOL;dwProcessId:DWORD):THandle;stdcall;
type
TNewOpenProcess=function(dwDesiredAccess:DWORD;bInheritHandle:BOOL;dwProcessId:DWORD):THandle;stdcall;
begin
ifstartPid^=dwProcessIdthenbegin
result:=0;
Exit;
end;
Hook[3].UnHook;
Result:=TNewOpenProcess(Hook[3].BaseAddr)(dwDesiredAccess,bInheritHandle,dwProcessId);
Hook[3].Hook;
end;

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

//安装APIHook
procedureInitHook;
begin
Hook[0]:=TNtHookClass.Create('user32.dll','MessageBoxA',@NewMessageBoxA);
Hook[1]:=TNtHookClass.Create('user32.dll','MessageBeep',@NewMessageBeep);
Hook[2]:=TNtHookClass.Create('user32.dll','MessageBoxW',@NewMessageBoxW);
Hook[3]:=TNtHookClass.Create('kernel32.dll','OpenProcess',@NewOpenProcess);
end;

//删除APIHook
procedureUninitHook;
var
I:Integer;
begin
forI:=0toHigh(Hook)do
begin
FreeAndNil(Hook[I]);
end;
end;

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

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

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

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

//结束HOOK
procedureEndHook;stdcall;
begin
ifhhk<>0then
UnhookWindowsHookEx(hhk);
end;

//环境处理
procedureDllEntry(dwResaon:DWORD);
begin
casedwResaonof
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.


这样,我们用来hookAPI的Dll就完工了。在Dll中,我们还使用到了内存映射,用来实现在拦截全局时的内存共享,如这个例子中需要保存调用此hook的进程句柄,以防止通过任务管理器关闭示例程序。

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

如附图所示,画3个按钮,分别为"Hook"、"UnHook"、"MessageBox",前两个用来安装和删除钩子,第三个用来显示一个消息框,你将会看到被Hook后的情况。测试工程的代码如下:[/code]



unitFMain;

interface

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

type
TfrmMain=class(TForm)
btnHook:TButton;
btnUnhook:TButton;
Button1:TButton;
procedurebtnHookClick(Sender:TObject);
procedurebtnUnhookClick(Sender:TObject);
procedureButton1Click(Sender:TObject);
procedureFormCreate(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;

var
frmMain:TfrmMain;

procedureStartHook(pid:DWORD);stdcall;external'hookdll.dll';
procedureEndHook;stdcall;external'hookdll.dll';

implementation

{$R*.dfm}

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

procedureTfrmMain.btnUnhookClick(Sender:TObject);
begin
EndHook;
end;

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

procedureTfrmMain.FormCreate(Sender:TObject);
begin

end;

end.


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

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

//环境处理
procedureDllEntry(dwResaon:DWORD);
begin
casedwResaonof
DLL_PROCESS_ATTACH:InitHook;//DLL载入
DLL_PROCESS_DETACH:UninitHook;//DLL删除
end;
end;

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

begin
MemShared;

{分配DLL程序到DllProc变量}
DllProc:=@DllEntry;
{调用DLL加载处理}
DllEntry(DLL_PROCESS_ATTACH);
end.
个人觉得这篇文章极其经典,我一看跟着走了一遍,钩子马上就给会了,其实也很简单。。。。。。

[/code]
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐