道理不多讲,简单说就是将系统API的跳转地址,替换为我们自己写的API的地址,所以要求我们自定义的API函数要和被拦截的API有相同的参数。在用完后,记得恢复。

因为要挂全局的钩子,所以Hook的部分,做成DLL。   源码下载

Hook.DLL主工程文件代码

  1. library Hook;
  2. uses
  3. SysUtils,
  4. Windows,
  5. Classes,
  6. ApiDefine in 'ApiDefine.pas',
  7. APIHook in 'APIHook.pas';
  8. {$R *.res}
  9. var
  10. HookHandle: HHook;
  11. function HookProc(code:Integer;wparam:WPARAM;lparam:LPARAM):LRESULT;stdcall;
  12. begin
  13. Result := CallNextHookEx(HookHandle,code,wparam,lparam);
  14. end;
  15. procedure SetHook;stdcall;
  16. begin
  17. HookHandle := SetWindowsHookEx(WH_GETMESSAGE,@HookProc,HInstance,0);
  18. end;
  19. procedure StopHook;stdcall;
  20. begin
  21. UnhookWindowsHookEx(HookHandle);
  22. end;
  23. exports
  24. SetHook name 'SetHook',
  25. StopHook name 'StopHook';
  26. {已启动就挂上,修改API函数指向}
  27. begin
  28. API_Hook;
  29. end.

APIHook单元,这个单元实现对API地址的替换

  1. unit APIHook;
  2. interface
  3. uses
  4. Windows, SysUtils, Classes;
  5. type
  6. //引入表入口数据结构
  7. Image_Import_Entry = packed record
  8. OriginalFirstThunk:DWORD;
  9. TimeDateStamp:DWORD;
  10. ForwarderChain:DWORD;
  11. Name:DWORD;
  12. FirstThunk:DWORD;
  13. end;
  14. PImage_Import_Entry = ^Image_Import_Entry;
  15. TImportCode = packed record
  16. JmpCode: Word;
  17. AddressOfPFun: PPointer;
  18. end;
  19. PImportCode = ^TImportCode;
  20. function GetFunTrueAddress(Code:Pointer):Pointer;
  21. function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer):Integer;
  22. implementation
  23. //获得实际地址
  24. function GetFunTrueAddress(Code: Pointer): Pointer;
  25. var
  26. func: PImportCode;
  27. begin
  28. Result := Code;
  29. if Code = nil then exit;
  30. try
  31. func := code;
  32. if (func.JmpCode = $25FF) then
  33. begin
  34. Result := func.AddressOfPFun^;
  35. end;
  36. except
  37. Result := nil;
  38. end;
  39. end;
  40. //替换地址
  41. function ReplaceFunAddress(oldfun:Pointer;newfun:Pointer): Integer;
  42. var
  43. IsDone: TList;
  44. function ReplaceAddressInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
  45. var
  46. DosHeader: PImageDosHeader;
  47. NTHeader: PImageNTHeaders;
  48. ImportDesc: PImage_Import_Entry;
  49. RVA: DWORD;
  50. Func: ^Pointer;
  51. DLL: string;
  52. f: Pointer;
  53. written: DWORD;
  54. begin
  55. Result := 0;
  56. DosHeader := Pointer(hModule);
  57. //已经找过,则退出
  58. if IsDone.IndexOf(DosHeader) >= 0 then exit;
  59. IsDone.Add(DosHeader);
  60. oldfun := GetFunTrueAddress(OldFunc);
  61. if IsBadReadPtr(DosHeader, SizeOf(TImageDosHeader)) then exit;
  62. if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then exit;
  63. NTHeader := Pointer(Integer(DosHeader) + DosHeader._lfanew);
  64. //引入表的虚拟地址
  65. RVA := NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  66. if RVA = 0 then exit;
  67. ImportDesc := pointer(integer(DosHeader) + RVA);
  68. while (ImportDesc^.Name <> 0) do
  69. begin
  70. //引入文件名
  71. DLL := PChar(Integer(DosHeader) + ImportDesc^.Name);
  72. //获得该DLL的句柄,然后递归查找
  73. ReplaceAddressInModule(GetModuleHandle(PChar(DLL)), oldfun, newfun);
  74. //引入函数入口
  75. Func := Pointer(Integer(DOSHeader) + ImportDesc.FirstThunk);
  76. //如果函数指针不为空
  77. while Func^ <> nil do
  78. begin
  79. //取得真是地址
  80. f := GetFunTrueAddress(Func^);
  81. //如果和我们要拦截的Api函数地址一样
  82. if f = oldfun then
  83. begin
  84. //替换成我们自己的Api地址
  85. WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
  86. if Written > 0 then Inc(Result);
  87. end;
  88. //继续找
  89. Inc(Func);
  90. end;
  91. Inc(ImportDesc);
  92. end;
  93. end;
  94. begin
  95. IsDone := TList.Create;
  96. try
  97. //GetModuleHandle,参数nil,为获取自身的模块句柄
  98. Result := ReplaceAddressInModule(GetModuleHandle(nil), oldfun, newfun);
  99. finally
  100. IsDone.Free;
  101. end;
  102. end;
  103. end.

ApiDefine单元,这里实现我们自定义的API

  1. unit ApiDefine;
  2. interface
  3. uses
  4. Windows, SysUtils, Classes,Messages,APIHook,ShellAPI;
  5. procedure API_Hook;
  6. procedure API_UnHook;
  7. implementation
  8. //自定义Api的类型
  9. type
  10. TMsgA = function(hwn: hwnd; lptext: pchar; lpcapion: pchar; utype: cardinal):integer; stdcall;
  11. TShellExc = function(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
  12. TTextOut = function(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
  13. var
  14. oldMsgA : TMsgA;
  15. oldShellExc : TShellExc;
  16. oldTextOut : TTextOut;
  17. //自定义Api的实现
  18. function NewMsgA(hwn: hwnd; lptext: pchar; lpcaption: pchar; utype: cardinal):integer; stdcall;
  19. begin
  20. Result := oldMsgA(hwn,'成功拦截MessageBoxA','哈哈',utype);
  21. end;
  22. function NewShellExc(hwn: HWND;lpoperate: PChar;lpfilename: PChar; lpparam: PChar; lpdir:PChar;cmd:Integer):Integer;stdcall;
  23. begin
  24. Result := oldShellExc(hwn,lpoperate,'c:/2.txt',lpfilename,lpdir,cmd);
  25. end;
  26. {TextOut调用的是ExtTextOut}
  27. function NewTextOut(DC:HDC;X:Integer;Y:Integer;options:Integer;rect:PRect;str:PAnsiChar;count:Integer;dx:PInteger):Boolean;stdcall;
  28. begin
  29. {这个rect也是可以修改的,以便容纳更多的字符显示}
  30. Result := oldTextOut(DC,50,50,options,rect,'中国',count,dx);
  31. end;
  32. procedure API_Hook;
  33. begin
  34. if @oldMsgA = nil then
  35. @oldMsgA := GetFunTrueAddress(@MessageBoxA);
  36. if @oldShellExc = nil then
  37. @oldShellExc := GetFunTrueAddress(@ShellExecute);
  38. if @oldTextOut = nil then
  39. @oldTextOut := GetFunTrueAddress(@ExtTextOut);
  40. //替换
  41. ReplaceFunAddress(@oldMsgA,@NewMsgA);
  42. ReplaceFunAddress(@oldShellExc,@NewShellExc);
  43. ReplaceFunAddress(@oldTextOut,@NewTextOut);
  44. end;
  45. procedure API_UnHook;
  46. begin
  47. if @oldMsgA <> nil then
  48. ReplaceFunAddress(@NewMsgA,@oldMsgA);
  49. if @oldShellExc <> nil then
  50. ReplaceFunAddress(@NewShellExc,@oldShellExc);
  51. if @oldTextOut <> nil then
  52. ReplaceFunAddress(@NewTextOut,@oldTextOut);
  53. end;
  54. initialization
  55. //结束时恢复原Api地址
  56. finalization
  57. API_UnHook;
  58. end.

主程序代码,大家可以把,消息、打开文件、画文字的代码写到另外的程序,本程序只负责挂钩和摘钩,那样可以看到系统钩子的效果。

  1. unit TestMain;
  2. interface
  3. uses
  4. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  5. Dialogs, StdCtrls,ShellAPI;
  6. type
  7. TForm1 = class(TForm)
  8. btn_Hook: TButton;
  9. btn_Msg: TButton;
  10. btn_UnHook: TButton;
  11. btn_OpenFiel: TButton;
  12. btn_TextOut: TButton;
  13. procedure btn_HookClick(Sender: TObject);
  14. procedure btn_MsgClick(Sender: TObject);
  15. procedure btn_UnHookClick(Sender: TObject);
  16. procedure btn_OpenFielClick(Sender: TObject);
  17. procedure btn_TextOutClick(Sender: TObject);
  18. private
  19. { Private declarations }
  20. public
  21. { Public declarations }
  22. end;
  23. var
  24. Form1: TForm1;
  25. implementation
  26. procedure SetHook;stdcall;external 'Hook.dll';
  27. procedure StopHook;stdcall;external 'Hook.dll';
  28. {$R *.dfm}
  29. procedure TForm1.btn_HookClick(Sender: TObject);
  30. begin
  31. SetHook;
  32. end;
  33. procedure TForm1.btn_UnHookClick(Sender: TObject);
  34. begin
  35. StopHook;
  36. end;
  37. {被拦截后,执行我们自己的NewMsgA方法}
  38. procedure TForm1.btn_MsgClick(Sender: TObject);
  39. begin
  40. MessageBoxA(Handle,'能拦住我吗','询问',MB_OK);
  41. end;
  42. {本想打开c:/1.txt,被拦截后,打开c:/2.txt}
  43. procedure TForm1.btn_OpenFielClick(Sender: TObject);
  44. begin
  45. ShellExecute(Handle,'open','c:/1.txt',nil,nil,SW_NORMAL);
  46. end;
  47. {本想在0,0出画出'Hello',被拦截后,在50,50的位置画出'中国'}
  48. procedure TForm1.btn_TextOutClick(Sender: TObject);
  49. begin
  50. Self.Canvas.TextOut(0,0,'Hello');
  51. end;
  52. end.

下图是执行画文字代码后的效果,本想在[0,0]坐标画出'Hello',被拦截后,在[50,50]的位置画出'中国'

http://blog.csdn.net/bdmh/article/details/6104475

实现拦截API的钩子(Hook)的更多相关文章

  1. 理解钩子Hook以及在Thinkphp下利用钩子使用行为扩展

    什么是钩子函数 个人理解:钩子就像一个”陷阱”.”监听器”,当A发送一个消息到B时,当消息还未到达目的地B时,被钩子拦截调出一部分代码做处理,这部分代码也叫钩子函数或者回调函数 参考网上说法 譬如我们 ...

  2. C# 钩子HOOK专题(1)

    目录   基本概念 运行机制 钩子类型 作者 基本概念   钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程 ...

  3. 框架Thinkphp5 简单的实现行为 钩子 Hook

    这篇文章主要介绍了关于框架Thinkphp5 简单的实现行为 钩子 Hook,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 实现在一个方法开始和结束加入两个行为:api_init.ap ...

  4. windows钩子 Hook示例

    1.首先编写一个 win32 dll工程. #include "stdafx.h" int WINAPI add(int a,int b) { return a+b; } BOOL ...

  5. 钩子(hook)

    钩子(hook)编程     钩子(hook)编程 一.钩子介绍 1.1钩子的实现机制 钩子英文名叫Hook,是一种截获windows系统中某应用程序或者所有进程的消息的一种技术.下图是windows ...

  6. windows 下实现函数打桩:拦截API方式

    windows 下实现函数打桩:拦截API方式            近期由于工作须要,開始研究函数打桩的方法. 由于不想对project做过多的改动,于是放弃了使用Google gmock的想法. ...

  7. 闭包传参 余额计算 钩子hook 闭包中的this JavaScript 钩子

    闭包传参  余额计算    钩子hook 小程序 a=function(e){console.log(this)}() a=function(e){console.log(this)}() VM289 ...

  8. 《windows核心编程系列》二十二谈谈修改导入段拦截API。

    一个模块的导入段包含一组DLL.为了让模块能够运行,这些DLL是必须的.导入段还包含一个符号表.它列出了该模块从各DLL中导入的符号.当模块调用这些导入符号的时候,系统实际上会调用转换函数,获得导入函 ...

  9. Hook技术之API拦截(API Hook)

    一.实现过程 1.钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统. 2.在消息没有到达目的窗口前,钩子就捕获消息(即钩子函数先得到控制权). 3.钩子可以加工处理该消息,即钩子机制允许应 ...

随机推荐

  1. 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 ...

  2. Matlab 仿真实现TI Instaspin 的Foc 逆Clarke变换和SVPWM

    一直没搞明白TI 的Instaspin的SVPWM实现原理,最后只能在Matlab里仿真看看输出波形是不是和普通的SVPWM实现输出的波形一样,用M文件实现,下面是代码: clear all; the ...

  3. MEMS微加工技术

    MEMS的微加工有两种方法,一种是多层平面加工技术,还有一种是基于SOI的体加工技术. (一)多层平面加工技术 这种方法加工出来的结构有三层:作为主体的多晶硅层.作为暂时填充物的氧化物牺牲层以及多晶硅 ...

  4. 自己封装的一个简易的二维表类SimpleTable

    在QT中,QTableWidget处理二维表格的功能很强大(QTableView更强大),但有时我们只想让它显示少量数据(文字和图片),这时,使用QTableWidget就有点不方便了(个人感觉).所 ...

  5. let区别(关于racket和r5rs)

    R5RS is the Revised5 Report on the Algorithmic Language Scheme.参考http://www.schemers.org/Documents/S ...

  6. linux之SQL语句简明教程---ORDER BY

    到目前为止,我们已学到如何藉由 SELECT 及WHERE 这两个指令将资料由表格中抓出.不过我们尚未提到这些资料要如何排列.这其实是一个很重要的问题.事实上,我们经常需要能够将抓出的资料做一个有系统 ...

  7. linux命令之mount

    熟悉linux的同学都应该知道mount命令.在linux中,一切皆文件.硬盘分区都是以文件目录的方式存在. 如果我们想访问移动硬盘,U盘等我们必须将这些设备mount到我们linux文件系统中某个目 ...

  8. poj1050(nyoj104 zoj1074)dp问题

    To the Max Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 39913   Accepted: 21099 Desc ...

  9. python-django如何在sae中使用自带ImageField和FileField -django-上善若水小站

    python-django如何在sae中使用自带ImageField和FileField -django-上善若水小站 python-django如何在sae中使用自带ImageField和FileF ...

  10. hdu 1116 Play on Words(欧拉通路)

    Problem Description Some of the secret doors contain a very interesting word puzzle. The team of arc ...