论坛里有关于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(菜新)大大的支持,能完成这篇文章少不了他的功劳。

DelphiHookApi(经典)的更多相关文章

  1. 回首经典的SQL Server 2005

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com SQL Server是我使用时间最长的数据库,算起来已经有10年了.上世纪90年代,微软在软件开发的所有领域高歌猛 ...

  2. 微软Azure 经典模式下创建内部负载均衡(ILB)

    微软Azure 经典模式下创建内部负载均衡(ILB) 使用之前一定要注意自己的Azure的模式,老版的为cloud service模式,新版为ARM模式(资源组模式) 本文适用于cloud servi ...

  3. Express 教程 01 - 入门教程之经典的Hello World

    目录: 前言 一.Express?纳尼?! 二.开始前的准备工作 三.测试安装之经典的Hello World 四.使用express(1)来生成一个应用程序 五.说明 前言: 本篇文章是建立在Node ...

  4. 赠书:HTML5 Canvas 2d 编程必读的两本经典

    赠书:HTML5 Canvas 2d 编程必读的两本经典 这两年多一直在和HTML5 Canvas 打交道,也带领团队开发了世界首款基于HTML5 Canvas 的演示文档工具---AxeSlide( ...

  5. 虚拟机体验之 VirtualBox 篇 —— 性能强大的经典架构

    前两篇体验了 QEMU 和经过 KVM 加速的 QEMU,并体验了第三方虚拟机管理工具 virt-manager,让我们见识了开源社区的强大和开源虚拟机软件的高质量和高性能.这一篇,我来剖析一下 Vi ...

  6. Atitit MATLAB 图像处理 经典书籍attilax总结

    Atitit MATLAB 图像处理 经典书籍attilax总结 1.1. MATLAB数字图像处理1 1.2. <MATLAB实用教程(第二版)>((美)穆尔 著)[简介_书评_在线阅读 ...

  7. 在Windows Server 2012中如何快速开关桌面上经典的“计算机、我的文档”等通用图标

    我们都知道,在Windows Server 2012系列的服务器版本中都已经引入了Modern的现代界面作为默认的用户交互界面,同时满足视觉一致化,新版的服务器管理程序也做成了扁平化.因此传统的计算机 ...

  8. Apworks框架实战(四):使用Visual Studio开发面向经典分层架构的应用程序:从EasyMemo案例开始

    时隔一年,继续我们的Apworks框架之旅.在接下来的文章中,我将逐渐向大家介绍如何在Visual Studio中结合Apworks框架,使用ASP.NET Web API和MVC来开发面向经典分层架 ...

  9. 【十大经典数据挖掘算法】PageRank

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 我特地把PageRank作为[十大经 ...

随机推荐

  1. add a characteristic in enovia PLM

    Problem: add a new Char. name D_COI6 that the description is Injected coloration #7 (COI6) in the D_ ...

  2. ttytype - 终端设备映射的默认终端类型

    DESCRIPTION(描述) /etc/ttytype 文件把termcap/terminfo中的终端类型名与tty行关联起来.每行包括一种终端类型,后面跟着空格,然后是tty名(不带 /dev/ ...

  3. day05 mysql pymysql的使用 (前端+flask+pymysql的使用) 索引 解释执行 慢日志 分页性能方案

    day05 mysql pymysql   一.pymysql的操作     commit(): 在数据库里增删改的时候,必须要进行提交,否则插入的数据不生效       1.增, 删, 改  #co ...

  4. K8S命令的梳理

    kubectl是一个基础的K8S集群管理命令,可以实现对K8S资源的查询,创建,删除,更新,回退等各种各样的操作.由于其复杂的功能体系,命令灵活度又高,因此需要进行常见的一些命令和使用场景的梳理. 1 ...

  5. 使用canvas绘制6X6调色盘

    <canvas id="canvas" height="150" width="150"></canvas> var ...

  6. Delphi流

      一.流的概念 流简单说是建立在面向对象基础上的一种抽象的处理数据的工具,它定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员只需掌握对流进行操作,而不用关心流的另一头数据的真正流向.其实 ...

  7. StringUtils工具类常用api <转>

    该工具类是用于操作Java.lang.String类的. StringUtils类与String类的区别在于:此类是null安全的,即如果输入参数String为null,则不会抛出NullPointe ...

  8. NX二次开发-创建直线UF_CURVE_create_line与NXOpen->CreateLine

    NX11+VS2013 #include <uf.h> #include <uf_curve.h> #include <NXOpen/CurveCollection.hx ...

  9. ShellExecute打开文件打开文件夹的用法

    1 #include <uf.h> 2 #include <uf_part.h> 3 #include <atlstr.h> 4 #include <iost ...

  10. 图像直方图均衡化(C#)

    关于图像直方图均衡化的原理和步骤先不作讨论,我就看看代码吧. private Bitmap picequalization(Bitmap basemap, int width, int height) ...