前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DelphiHookApi(经典)

DelphiHookApi(经典)

作者头像
战神伽罗
发布2019-07-24 10:20:30
9940
发布2019-07-24 10:20:30
举报

论坛里有关于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[0..7] 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[0..3] 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[0].UnHook; Result := TNewMessageBoxA(Hook[0].BaseAddr)(_hWnd, lpText, lpCaption, uType); Hook[0].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[2].UnHook; Result := TNewMessageBoxW(Hook[2].BaseAddr)(_hWnd, lpText, lpCaption, uType); Hook[2].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[3].UnHook; Result := TNewOpenProcess(Hook[3].BaseAddr)(dwDesiredAccess, bInheritHandle, dwProcessId); Hook[3].Hook; end;

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

//安装API Hook procedure InitHook; 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;

//删除API Hook procedure UninitHook; var I: Integer; begin for I := 0 to High(Hook) do begin FreeAndNil(Hook[I]); 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拦截了 。这时候看看任务管理器能不能关闭我们的程序,试一下就知道还可以,因为我们还没有调用 StartHook来传入我们程序的PID,所以还可以被关闭。 到此这篇文章就结束了, 本人从小语文没及过格(^_^),文章写的不太好,不过源代码都贴上了, 有详细的注释,相信大家也能看明白。如果你发现有什么错误的地方,要记得告诉我哦! 最后感谢 cxwr(菜新)大大的支持,能完成这篇文章少不了他的功劳。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档