道理不多讲,简单说就是将系统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. H5 progress标记

    进度条标记 示例:<progress class="processbar" id="processbar" max="100" val ...

  2. 安装4.x版本的express开发框架

    错误版本(未更新前的安装方法,更新后就不是这么安装了,好多网上的教程还是这种方法,所以这里先写明了,旧版这里是可以通过的,但是新版4.x就不行了,请用分割线下边的方法)   本文演示在Linux上安装 ...

  3. shopnc 发票项目

    ---恢复内容开始--- file_put_contents( 't.txt' , print_r($input_invoice_info ,true) ); 打印 $input_invoice_in ...

  4. jquery ajax 跨域提交(附IE浏览器解决方案)

    后台输出内容之前需要指定header("Access-Control-Allow-Origin: *"); post 之前 jQuery.support.cors = true; ...

  5. Print! Print! Print!

    print语句可以实现打印--只是对程序员友好的标准输出流的接口而已. 从技术角度来讲,这是把一个或多个对象转换为其文本表达形式,然后发送给标准输出或另一个类似文件的流. 更详细地说,在Python中 ...

  6. SQL Server 索引整理与堆重组。

    重新组织索引: alter index idx_OrderID      on dbo.OrderDetail      reorganize | reorganize;---可以rebuild 也可 ...

  7. Jquery基础之事件操作

    事件是用户操作时页面或页面加载时引发的用来完成javascript和HTML之间的交互操作.常见的元素点击事件.鼠标事件.键盘输入事件等,较传Javascript 相比JQuery增加并扩展了基本的事 ...

  8. webview的一些问题

    一些小问题. Webview 里面的网页,如果有 input ,需要输入,但是点上去却没反应,输入法不出来.这种情况是因为 webview 没有获取焦点.需要在 java 里面给 webview 设置 ...

  9. delphi 修改代码补全的快捷键(由Ctrl+Space 改为 Ctrl + alt + Space)(通过修改OpenTool生效)

    delphi 的IDE快捷键与输入法切换键中突,以往的解决方法是下载一个ImeTool修改 windows 系统的快捷键 在 xp win7 都好使,但在win 10经常是修改完后,重启又失效了. 本 ...

  10. position:absolute实现垂直居中

    一些图标通常要垂直居中 如下所示: 而css中没有直接的样式.需要我们自己调试. 我用了position:absolute;来实现. 要想使得position:absolute;有效,它的父元素必须也 ...