- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
论坛里有关于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,所以还可以被关闭。 到此这篇文章就结束了, 本人从小语文没及过格(^_^),文章写的不太好,不过源代码都贴上了,有详细的注释,相信大家也能看明白。如果你发现有什么错误的地方,要记得告诉我哦! |
|