实现拦截API的钩子(Hook)
道理不多讲,简单说就是将系统API的跳转地址,替换为我们自己写的API的地址,所以要求我们自定义的API函数要和被拦截的API有相同的参数。在用完后,记得恢复。
因为要挂全局的钩子,所以Hook的部分,做成DLL。 源码下载
Hook.DLL主工程文件代码
- library Hook;
- uses
- SysUtils,
- Windows,
- Classes,
- ApiDefine in 'ApiDefine.pas',
- APIHook in 'APIHook.pas';
- {$R *.res}
- var
- HookHandle: HHook;
- function HookProc(code:Integer;wparam:WPARAM;lparam:LPARAM):LRESULT;stdcall;
- begin
- Result := CallNextHookEx(HookHandle,code,wparam,lparam);
- end;
- procedure SetHook;stdcall;
- begin
- HookHandle := SetWindowsHookEx(WH_GETMESSAGE,@HookProc,HInstance,0);
- end;
- procedure StopHook;stdcall;
- begin
- UnhookWindowsHookEx(HookHandle);
- end;
- exports
- SetHook name 'SetHook',
- StopHook name 'StopHook';
- {已启动就挂上,修改API函数指向}
- begin
- API_Hook;
- end.
APIHook单元,这个单元实现对API地址的替换
- unit APIHook;
- interface
- uses
- Windows, SysUtils, Classes;
- type
- //引入表入口数据结构
- Image_Import_Entry = packed record
- OriginalFirstThunk:DWORD;
- TimeDateStamp:DWORD;
- ForwarderChain:DWORD;
- Name:DWORD;
- FirstThunk:DWORD;
- end;
- PImage_Import_Entry = ^Image_Import_Entry;
- TImportCode = packed record
- JmpCode: Word;
- AddressOfPFun: PPointer;
- end;
- PImportCode = ^TImportCode;
- function GetFunTrueAddress(Code:Pointer):Pointer;
- function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer):Integer;
- implementation
- //获得实际地址
- function GetFunTrueAddress(Code: Pointer): Pointer;
- var
- func: PImportCode;
- begin
- Result := Code;
- if Code = nil then exit;
- try
- func := code;
- if (func.JmpCode = $25FF) then
- begin
- Result := func.AddressOfPFun^;
- end;
- except
- Result := nil;
- end;
- end;
- //替换地址
- function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer): Integer;
- var
- IsDone: TList;
- function ReplaceAddressInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
- var
- DosHeader: PImageDosHeader;
- NTHeader: PImageNTHeaders;
- ImportDesc: PImage_Import_Entry;
- RVA: DWORD;
- Func: ^Pointer;
- DLL: string;
- f: Pointer;
- written: DWORD;
- begin
- Result := 0;
- DosHeader := Pointer(hModule);
- //已经找过,则退出
- if IsDone.IndexOf(DosHeader) >= 0 then exit;
- IsDone.Add(DosHeader);
- oldfun := GetFunTrueAddress(OldFunc);
- if IsBadReadPtr(DosHeader, SizeOf(TImageDosHeader)) then exit;
- if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then exit;
- NTHeader := Pointer(Integer(DosHeader) + DosHeader._lfanew);
- //引入表的虚拟地址
- RVA := NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
- if RVA = 0 then exit;
- ImportDesc := pointer(integer(DosHeader) + RVA);
- while (ImportDesc^.Name <> 0) do
- begin
- //引入文件名
- DLL := PChar(Integer(DosHeader) + ImportDesc^.Name);
- //获得该DLL的句柄,然后递归查找
- ReplaceAddressInModule(GetModuleHandle(PChar(DLL)), oldfun, newfun);
- //引入函数入口
- Func := Pointer(Integer(DOSHeader) + ImportDesc.FirstThunk);
- //如果函数指针不为空
- while Func^ <> nil do
- begin
- //取得真是地址
- f := GetFunTrueAddress(Func^);
- //如果和我们要拦截的Api函数地址一样
- if f = oldfun then
- begin
- //替换成我们自己的Api地址
- WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
- if Written > 0 then Inc(Result);
- end;
- //继续找
- Inc(Func);
- end;
- Inc(ImportDesc);
- end;
- end;
- begin
- IsDone := TList.Create;
- try
- //GetModuleHandle,参数nil,为获取自身的模块句柄
- Result := ReplaceAddressInModule(GetModuleHandle(nil), oldfun, newfun);
- finally
- IsDone.Free;
- end;
- end;
- end.
ApiDefine单元,这里实现我们自定义的API
- unit ApiDefine;
- interface
- uses
- Windows, SysUtils, Classes,Messages,APIHook,ShellAPI;
- procedure API_Hook;
- procedure API_UnHook;
- implementation
- //自定义Api的类型
- type
- TMsgA = function(hwn: hwnd; lptext: pchar; lpcapion: pchar; utype: cardinal):integer; stdcall;
- TShellExc = function(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
- TTextOut = function(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
- var
- oldMsgA : TMsgA;
- oldShellExc : TShellExc;
- oldTextOut : TTextOut;
- //自定义Api的实现
- function NewMsgA(hwn: hwnd; lptext: pchar; lpcaption: pchar; utype: cardinal):integer; stdcall;
- begin
- Result := oldMsgA(hwn,'成功拦截MessageBoxA','哈哈',utype);
- end;
- function NewShellExc(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
- begin
- Result := oldShellExc(hwn,lpoperate,'c:/2.txt',lpfilename,lpdir,cmd);
- end;
- {TextOut调用的是ExtTextOut}
- function NewTextOut(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
- begin
- {这个rect也是可以修改的,以便容纳更多的字符显示}
- Result := oldTextOut(DC,50,50,options,rect,'中国',count,dx);
- end;
- procedure API_Hook;
- begin
- if @oldMsgA = nil then
- @oldMsgA := GetFunTrueAddress(@MessageBoxA);
- if @oldShellExc = nil then
- @oldShellExc := GetFunTrueAddress(@ShellExecute);
- if @oldTextOut = nil then
- @oldTextOut := GetFunTrueAddress(@ExtTextOut);
- //替换
- ReplaceFunAddress(@oldMsgA,@NewMsgA);
- ReplaceFunAddress(@oldShellExc,@NewShellExc);
- ReplaceFunAddress(@oldTextOut,@NewTextOut);
- end;
- procedure API_UnHook;
- begin
- if @oldMsgA <> nil then
- ReplaceFunAddress(@NewMsgA,@oldMsgA);
- if @oldShellExc <> nil then
- ReplaceFunAddress(@NewShellExc,@oldShellExc);
- if @oldTextOut <> nil then
- ReplaceFunAddress(@NewTextOut,@oldTextOut);
- end;
- initialization
- //结束时恢复原Api地址
- finalization
- API_UnHook;
- end.
主程序代码,大家可以把,消息、打开文件、画文字的代码写到另外的程序,本程序只负责挂钩和摘钩,那样可以看到系统钩子的效果。
- unit TestMain;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls,ShellAPI;
- type
- TForm1 = class(TForm)
- btn_Hook: TButton;
- btn_Msg: TButton;
- btn_UnHook: TButton;
- btn_OpenFiel: TButton;
- btn_TextOut: TButton;
- procedure btn_HookClick(Sender: TObject);
- procedure btn_MsgClick(Sender: TObject);
- procedure btn_UnHookClick(Sender: TObject);
- procedure btn_OpenFielClick(Sender: TObject);
- procedure btn_TextOutClick(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- Form1: TForm1;
- implementation
- procedure SetHook;stdcall;external 'Hook.dll';
- procedure StopHook;stdcall;external 'Hook.dll';
- {$R *.dfm}
- procedure TForm1.btn_HookClick(Sender: TObject);
- begin
- SetHook;
- end;
- procedure TForm1.btn_UnHookClick(Sender: TObject);
- begin
- StopHook;
- end;
- {被拦截后,执行我们自己的NewMsgA方法}
- procedure TForm1.btn_MsgClick(Sender: TObject);
- begin
- MessageBoxA(Handle,'能拦住我吗','询问',MB_OK);
- end;
- {本想打开c:/1.txt,被拦截后,打开c:/2.txt}
- procedure TForm1.btn_OpenFielClick(Sender: TObject);
- begin
- ShellExecute(Handle,'open','c:/1.txt',nil,nil,SW_NORMAL);
- end;
- {本想在0,0出画出'Hello',被拦截后,在50,50的位置画出'中国'}
- procedure TForm1.btn_TextOutClick(Sender: TObject);
- begin
- Self.Canvas.TextOut(0,0,'Hello');
- end;
- end.
下图是执行画文字代码后的效果,本想在[0,0]坐标画出'Hello',被拦截后,在[50,50]的位置画出'中国'

http://blog.csdn.net/bdmh/article/details/6104475
实现拦截API的钩子(Hook)的更多相关文章
- 理解钩子Hook以及在Thinkphp下利用钩子使用行为扩展
什么是钩子函数 个人理解:钩子就像一个”陷阱”.”监听器”,当A发送一个消息到B时,当消息还未到达目的地B时,被钩子拦截调出一部分代码做处理,这部分代码也叫钩子函数或者回调函数 参考网上说法 譬如我们 ...
- C# 钩子HOOK专题(1)
目录 基本概念 运行机制 钩子类型 作者 基本概念 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程 ...
- 框架Thinkphp5 简单的实现行为 钩子 Hook
这篇文章主要介绍了关于框架Thinkphp5 简单的实现行为 钩子 Hook,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 实现在一个方法开始和结束加入两个行为:api_init.ap ...
- windows钩子 Hook示例
1.首先编写一个 win32 dll工程. #include "stdafx.h" int WINAPI add(int a,int b) { return a+b; } BOOL ...
- 钩子(hook)
钩子(hook)编程 钩子(hook)编程 一.钩子介绍 1.1钩子的实现机制 钩子英文名叫Hook,是一种截获windows系统中某应用程序或者所有进程的消息的一种技术.下图是windows ...
- windows 下实现函数打桩:拦截API方式
windows 下实现函数打桩:拦截API方式 近期由于工作须要,開始研究函数打桩的方法. 由于不想对project做过多的改动,于是放弃了使用Google gmock的想法. ...
- 闭包传参 余额计算 钩子hook 闭包中的this JavaScript 钩子
闭包传参 余额计算 钩子hook 小程序 a=function(e){console.log(this)}() a=function(e){console.log(this)}() VM289 ...
- 《windows核心编程系列》二十二谈谈修改导入段拦截API。
一个模块的导入段包含一组DLL.为了让模块能够运行,这些DLL是必须的.导入段还包含一个符号表.它列出了该模块从各DLL中导入的符号.当模块调用这些导入符号的时候,系统实际上会调用转换函数,获得导入函 ...
- Hook技术之API拦截(API Hook)
一.实现过程 1.钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统. 2.在消息没有到达目的窗口前,钩子就捕获消息(即钩子函数先得到控制权). 3.钩子可以加工处理该消息,即钩子机制允许应 ...
随机推荐
- ctype.h库函数
头文件ctype.h声明了一组用于分类和转换单个字符的函数.所有的函数都接收一个int型的参数,并返回一个int——返回的int可能代表一个字符,也可能代表的是bool值(0为假,非0为真). 你可能 ...
- 定制化Azure站点Java运行环境(5)
Java 8下PermGen及参数设置 在上一章节中,我们定制化使用了Java 8环境,使用我们的测试页面打印出了JVM基本参数,但如果我们自己观察,会发现在MXBeans中,没有出现PermGen的 ...
- OpenStack ceilometer部署安装监控,计费数据抓取测试Ok
- leetcode 326. Power of Three(不用循环或递归)
leetcode 326. Power of Three(不用循环或递归) Given an integer, write a function to determine if it is a pow ...
- sharepoint 2010 使用自定义列表模版创建列表(1)
我们在使用sharepoint的过程中,发现一个比较好用的功能,就是“将此列表另存为模版”(save list as template),这个功能的作用是,创建一个和当前列表或者文档库一模一样的配置, ...
- hdu 5569 matrix(简单dp)
Problem Description Given a matrix with n rows and m columns ( n+m ,) and you want to go to the numb ...
- SQL Server中的sysobjects
摘自:http://www.cnblogs.com/bugY/archive/2011/09/21/2184182.html 关于SQL Server数据库的一切信息都保存在它的系统表格里.我怀疑你是 ...
- jquery第三期:js与jquery对象转换
我们开始进入jquery的学习了,jquery的学习就不那么中规中矩了,我们来看一个和javascript有所区别的地方. <!DOCTYPE html PUBLIC "-//W3C/ ...
- 3-07. 求前缀表达式的值(25) (ZJU_PAT数学)
题目链接:http://pat.zju.edu.cn/contests/ds/3-07 算术表达式有前缀表示法.中缀表示法和后缀表示法等形式.前缀表达式指二元运算符位于两个运算数之前,比如2+3*(7 ...
- js仿百度文库文档上传页面的分类选择器_第二版
仿百度文库文档上传页面的多级联动分类选择器第二版,支持在一个页面同一时候使用多个分类选择器. 此版本号把HTML,CSS,以及图片都封装到"category.js"中.解决因文件路 ...