实现拦截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.钩子可以加工处理该消息,即钩子机制允许应 ...
随机推荐
- Android动画的深入分析
一.AnimationDrawable的使用 详见:Drawable类及XMLDrawable的使用 补充:通过Animation的setAnimationListener()可以给View动画添加监 ...
- 七夕节(hd1215)干嘛今天做这题T_T
七夕节 Problem Description 七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们的另一半是谁吗?那就按照告示上的方法去找吧!&q ...
- 什么是Activity、生命周期
1.什么是Activity 1.当程序第一次运行时用户就会看这个Activity,这个Activity可以通过启动其他的Activity进行相关的操作. 2.当启动其他的Activty时这个当前的这个 ...
- QT多重继承的时候,要把QObject放在最前面,否则报错——C++认为人性本恶,默认都是私有的,这点和Delphi的世界观不一样
在买来的控件(没有源码)的基础上,想加入QObject的一些特性,不得不多继承: class MyProgress : public CProgress, public QObject 但总是报错: ...
- 简单方便又实用的在线作图工具:ProcessOn
说到Visio大家都不陌生,虽然没有Word那么火,但很多业内朋友都在用,一用就是好多年,Visio是相对比较传统和专业的工具,新手在没人指导的情况下一般很难上手,下载和安装以及“授权”都是个问题,很 ...
- VC实现图片拖拽及动画
基础知识 1.PictureBox控件的使用 2.加载位图文件 1.通过文件路径获得位图句柄 //获得位图句柄 void CMovePictureDlg::GetHandleFromPath(CSt ...
- IT技术 | 让程序员抓狂的排序算法教学视频
点击「箭头所指处」可快速关注传智特刊微信号:CZTEKAN 原文地址:http://mp.weixin.qq.com/s?__biz=MjM5OTM4NDMyMg==&mid=20056820 ...
- SonarQube代码质量管理平台工具
1.Sonar轮廓介绍 Sonar (SonarQube)是一个开源平台,用于管理源代码的质量.Sonar 不只是一个质量数据报告工具,更是代码质量管理平台.支持的语言包括:Java.PHP.C#.C ...
- rpath 与runpath
- 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .
3.2. “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模 ...