实现拦截API的钩子(Hook)

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

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

Hook.DLL主工程文件代码

[delphi] view plaincopy

  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地址的替换

[c-sharp] view plaincopy

  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

[delphi] view plaincopy

  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.

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

[delphi] view plaincopy

  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

时间: 2024-10-12 22:19:02

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

windows钩子 Hook示例

1.首先编写一个 win32 dll工程. #include "stdafx.h" int WINAPI add(int a,int b) { return a+b; } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } 在def文件添加显式导出: (没找到def文件需要添加) LIBRARY DESCRIPTION "AD

android 上的API函数钩子,利用CydiaHook实现

android 上的API函数钩子,利用CydiaHook实现 发布将近一年了,最近发现还是有些人需要的,github上也有些人fork了. 例子代码,发布在github上,地址:https://github.com/zencodex/cydia-android-hook CydiaHook 利用Cydia Substrate SDK 开发,可以HOOK java层或NATIVE层 API接口. 本代码功能 写代码的初衷是因为有个app,需要保存数据到SD卡上,并且app里面有判断SD挂载的状态

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

windows 下实现函数打桩:拦截API方式 最近因为工作需要,开始研究函数打桩的方法.由于不想对工程做过多的修改,于是放弃了使用Google gmock的想法.但是也足足困扰另外我一天一宿.经过奋战,终于有所收获.闲话少说,开始看看有什么方法. 一.基础准备 1. 函数调用的原理:通过函数名(函数的入口地址)对函数进行访问,假设我们能够改变函数首地址指向的内存的话,使其跳转到另一个函数去执行的话,那么就可以实现函数打桩了. 2. 方法:对函数首地址出写入一条汇编语言 jmp xxx (其中x

拦截API 注入进程

本文详细的介绍了在Visual Studio(以下简称VS)下实现API钩子的编程方法,阅读本文需要基础:有操作系统的基本知识(进程管理,内存管理),会在VS下编写和调试Win32应用程序和动态链接库(以下简称DLL). API钩子是一种高级编程技巧,常常用来完成一些特别的功能,比如词典软件的屏幕取词,游戏修改软件的数据修改等.当然,此技术更多的是被黑客或是病毒用来攻击其它程序,截获需要的数据或改变目标程序的行为.本文不探讨此技术的应用,只讲实现.同时希望掌握此技术的人都能够合法的应用它,不要去

钩子(hook)编程

一.钩子介绍 1.1钩子的实现机制 钩子英文名叫Hook,是一种截获windows系统中某应用程序或者所有进程的消息的一种技术.下图是windows应用程序传递消息的过程: 如在键盘中按下一键,操作系统将收到键按下消息,把消息放入消息队列,然后消息队列对消息进行派发,发给相应的应用程序,经过应用程序处理后发给操作系统,操作系统再调用相应的应用程序的创建的窗口过程. 我们可能通过钩子截获这些消息,让消息不再往下传递,或者说截获到感兴趣的消息后做点什么. 1.2钩子分类与实现 钩子分进程内钩子与全局

WordPress中函数钩子hook的作用及基本用法

WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它.钩子分类 钩子分为两种,一种叫做动作(action),还有一种叫做过滤器(filter).这两种钩子实现原理基本一样,后边会讲到,使用上的区别在于过滤器有返回值,而动作没有. 动作的理念是让你在一种情况或者一个特别的位置执行一些函数,比如发送一封邮件等:过滤器则是让你修改 WordPress 核心需要用到的一个值,然后 Wo

php中的钩子(hook插件机制)

对"钩子"这个概念其实不熟悉,最近看到一个php框架中用到这种机制来扩展项目,所以大概来了解下. hook插件机制的基本思想: 在项目代码中,你认为要扩展(暂时不扩展)的地方放置一个钩子函数,等需要扩展的时候,把需要实现的类和函数挂载到这个钩子上,就可以实现扩展了. 思想就是这样听起来比较笼统,看一个网上的实现的例子. 整个插件机制包含三个部分: 1.hook插件经理类:这个是核心文件,是一个应用程序全局Global对象.它主要有三个职责 1>监听已经注册了的所有插件,并实例化这

CI框架源代码阅读笔记6 扩展钩子 Hook.php

CI框架同意你在不改动系统核心代码的基础上加入或者更改系统的核心功能(如重写缓存.输出等). 比如,在系统开启hook的条件下(config.php中$config['enable_hooks'] = TRUE;).通过加入特定的钩子,能够让系统在特定的时刻触发特定的脚本: $hook['post_system'] = array( 'class' => 'frameLog', 'function' => 'postLog', 'filename' => 'post_system.php

CI框架源码阅读笔记6 扩展钩子 Hook.php

CI框架允许你在不修改系统核心代码的基础上添加或者更改系统的核心功能(如重写缓存.输出等).例如,在系统开启hook的条件下(config.php中$config['enable_hooks'] = TRUE;),通过添加特定的钩子,可以让系统在特定的时刻触发特定的脚本: $hook['post_system'] = array( 'class' => 'frameLog', 'function' => 'postLog', 'filename' => 'post_system.php'