实现拦截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.钩子可以加工处理该消息,即钩子机制允许应 ...
随机推荐
- NPOI导出多张图片到Excel
常用NPOI导出数据到excel,但没有试过如何导出图片.NPOI最大的特点就是不依赖于Excel组件,服务端不需要安装Excel.在单元格中插入图片主要是用HSSFClientAnchor对象.他有 ...
- #pragma 预处理指令
Linux C 编程一站式学习 #pragma 预处理指示供编译器实现一些非标准的特性,C 标准没有规定 #pragma 后面应该写什么以及起什么作用,由编译器自己规定.有的编译器用 #pragma ...
- 你与优秀源码之间只差一个 Star
fir.im Weekly - 你与优秀源码之间只差一个 Star 说起开源社区,Github 是一个不可缺少的存在.作为全球最大的同性交友网站,上面有太多优秀的开源代码库和编程大神,让无数开发者 ...
- KeyEvent
http://blog.csdn.net/elfylin/article/details/8008763 一. 接口KeyEvent.Callback和View.OnKeyListener 二. 流程 ...
- 可获取公网IP的网址
由于代理检验需要,现在小站经受不住大流量测试,于是多收集了一些. http://1111.ip138.com/ic.asp, http://ip.360.cn/IPShare/info, http:/ ...
- 强烈推荐一款CSS导航菜单
强烈推荐一款CSS导航菜单,用到政府学校类网站上超级不错,有点类似站长网菜单的味道,只不过颜色不一样而已,这种菜单还不是真正意义上的“下拉”菜单,应该叫滑出菜单吧?反正比较不错,不多说了. <! ...
- 三校联考 Day3
三校联考 Day3 大水题 题目描述:给出一个圆及圆上的若干个点,问两个点间的最远距离. solution 按极角排序,按顺序枚举,显然距离最远的点是单调的,线性时间可解出答案. 大包子的束缚 题目描 ...
- 灵活使用getconf命令来获取系统信息
http://blog.chinaunix.net/uid-23105261-id-109513.html 灵活使用getconf命令来获取系统信息 我们时常需要查询系统相关的信息,比如页面大小,整数 ...
- spring 3配置文件中如何注入map list set等类型
首先写个 javabean类吧,如下 package com.bean; import java.util.List; import java.util.Map; import java.util.P ...
- HttpContext详解【转】
HttpContext 类:封装有关个别 HTTP 请求的所有 HTTP 特定的信息. 在处理请求执行链的各个阶段中,会有一个对象在各个对象之间进行传递,也即会保存请求的上下文信息,这个对象就是Htt ...