道理不多讲,简单说就是将系统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. LogBoy logo

  2. Laravel Packages 开发

    Packages是向Laravel中添加功能最重要的途径.composer.json中require的都是包.关于包的详细说明请查看 API . 下面一起创建一个简单的Package : 1. 环境配 ...

  3. 高性能WEB开发 为什么要减少请求数,如何减少请求数!

    http请求头的数据量 [声明] 转载  原文出处:http://www.blogjava.net/BearRui/. 谢谢我们先分析下请求头,看看每次请求都带了那些额外的数据.下面是监控的googl ...

  4. webview相关链接

    http://tech.it168.com/a2011/0517/1191/000001191561_2.shtml http://www.eoeandroid.com/thread-272495-1 ...

  5. mysql perl 抓取update语句

    <pre name="code" class="html"><pre name="code" class="ht ...

  6. C++14介绍

    C++14标准是 ISO/IEC 14882:2014 Information technology -- Programming languages -- C++ 的简称[1]  .在标准正式通过之 ...

  7. MFC Attach()函数和Detach()函数

    一.Windows对象和MFC对象的区别?MFC对象实际上并没有把整个Windows对象都包装在其中.对于窗口:MFC对象它只是有一个窗口句柄而已,这个窗口句柄如果指向一个实际存在的窗口对象(窗口对象 ...

  8. Opencv下图像对鼠标事件的响应

    直接上代码: //////////////////////////////////////////////////////////////////////// // // 该程序从文件中读入一幅图像, ...

  9. java中如何将char数组转化为String

    1.直接在构造String时建立. char data[] = {'s', 'g', 'k'}; String str = new String(data); 2.String有方法可以直接转换. S ...

  10. RCTF Re300 Writeup

    发现一篇写得更好的:http://insight-labs.org/?p=2009  程序要求输入一个flag.拿ida加载后,发现是Upx壳,脱壳后加载入ida进行分析.定位到输入flag的地方,如 ...