实现拦截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.钩子可以加工处理该消息,即钩子机制允许应 ...
随机推荐
- java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ex.activity/com.ex.activity.LoginActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ex.activity/com.ex.activity.L ...
- Matlab 仿真实现TI Instaspin 的Foc 逆Clarke变换和SVPWM
一直没搞明白TI 的Instaspin的SVPWM实现原理,最后只能在Matlab里仿真看看输出波形是不是和普通的SVPWM实现输出的波形一样,用M文件实现,下面是代码: clear all; the ...
- MEMS微加工技术
MEMS的微加工有两种方法,一种是多层平面加工技术,还有一种是基于SOI的体加工技术. (一)多层平面加工技术 这种方法加工出来的结构有三层:作为主体的多晶硅层.作为暂时填充物的氧化物牺牲层以及多晶硅 ...
- 自己封装的一个简易的二维表类SimpleTable
在QT中,QTableWidget处理二维表格的功能很强大(QTableView更强大),但有时我们只想让它显示少量数据(文字和图片),这时,使用QTableWidget就有点不方便了(个人感觉).所 ...
- let区别(关于racket和r5rs)
R5RS is the Revised5 Report on the Algorithmic Language Scheme.参考http://www.schemers.org/Documents/S ...
- linux之SQL语句简明教程---ORDER BY
到目前为止,我们已学到如何藉由 SELECT 及WHERE 这两个指令将资料由表格中抓出.不过我们尚未提到这些资料要如何排列.这其实是一个很重要的问题.事实上,我们经常需要能够将抓出的资料做一个有系统 ...
- linux命令之mount
熟悉linux的同学都应该知道mount命令.在linux中,一切皆文件.硬盘分区都是以文件目录的方式存在. 如果我们想访问移动硬盘,U盘等我们必须将这些设备mount到我们linux文件系统中某个目 ...
- poj1050(nyoj104 zoj1074)dp问题
To the Max Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 39913 Accepted: 21099 Desc ...
- python-django如何在sae中使用自带ImageField和FileField -django-上善若水小站
python-django如何在sae中使用自带ImageField和FileField -django-上善若水小站 python-django如何在sae中使用自带ImageField和FileF ...
- hdu 1116 Play on Words(欧拉通路)
Problem Description Some of the secret doors contain a very interesting word puzzle. The team of arc ...