说到HOOK。我看了非常多的资料和教程。无奈就是学不会HOOK。不懂是我的理解能力差。还是你们说的

不够明确,直到我看了下面这篇文章,最终学会了HOOK:

http://blog.sina.com.cn/s/blog_628821950100xmuc.html    //感谢文章作者的分享,让我学会了HOOK

文章出处,好像是这篇:http://blog.csdn.net/glliuxueke/article/details/2702608     //后来才看到

----------------------------------------------------------------------------------------------------------------------------------------------

既然窝已经入门了HOOK,窝会写几篇关于HOOK的文章,让相同想入门HOOK,却难以入门的童鞋

有个參考。这篇是第一篇,希望帮助到有此须要的盆友,我測试的环境都是:Win7+VS2008+MFC

--------------------------------------------------------------------------------------------------------------------------------------------------

第一篇说的是HOOK自己程序的MessageBoxW。诚然HOOK自己程序用到的API在实际应用中没有什么

大的用处,只是我觉得对于我们理解HOOK却有莫大的帮助,因此我的HOOK文章就从HOOK自己的程序

開始。文章后面附有本样例程序的VS2008源代码下载地址。

---------------------------------------------------------------------------------------------------------------------------------------------------

//先看下我写的样例程序及执行效果截图,后面再对其进行分析

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnJpZW5kYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="border:none; max-width:100%">

//未钩MessageBoxW前

//钩MessageBoxW后

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnJpZW5kYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="border:none; max-width:100%">

---------------------------------------------------------------------------------------------------------------------

依据我的理解,先说一下HOOK API的一般思路和步骤。

HOOK API的思路就是改动原API的入口。使其跳转到我们的假API入口。

然后运行我们的假API函数。为什么说是假API函数呢?

由于我们的假API,除了函数名称和真实API的名称不一样之外,其他都是同样的。即

它们的函数參数和返回值和调用形式都是一样的。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

HOOK API的一般步骤:

1.定义假API函数

注意假API函数,除了函数名称和真实API不一样之外,其他的都要跟真实API的定义同样,如參数类型和返回值、调用形式等。

如我们能够这样定义假的MessageBoxW:

  1. int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
  2. {
  3. //定义假API时。详细的函数体代码临时可不写...
  4. return 0;
  5. }

至于我们怎样知道真实API的原型定义呢?非常easy,查看MSDN就可以,或者你也能够在VS2008开发环境中,

写下该真实API,然后选中该API。再点鼠标右键,选择【转到定义】,就能够看到其原型声明了。

...........................................................................................................................................................................

2.定义API函数类型

由于我们要动态获取原API函数的地址。获取到后,我们要将其保存起来,保存在哪里呢?

这就是定义API函数类型的原因了,有了API函数类型的定义后。我们就能够用其定义一个变量来 保存获取到的

真实API函数的地址了。比如。我定义的MessageBoxW函数类型的语句例如以下:

  1. //原函数类型定义
  2. typedef int (WINAPI* MsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

注意,原函数类型定义中的函数返回值和參数类型要跟MessageBoxW的定义同样。

上面就是定义了API函数类型MsgBoxW,这跟我们常见的int、char、float等类型。使用方法是一样的,

实际上,我们全然能够把MsgBoxW当成int类型来使用,这样一说。API函数类型也只是如此嘛。

有了API函数类型MsgBoxW,我们就能够用其来定义变量,从而为保存原API地址做准备了。

如:

有了API函数类型后,我们还须要一个远指针类型的变量,由于系统API是在dll文件里的。很多其它关于

远指针的信息,我如今也不是非常清楚,有兴趣的盆友,最好还是百度一下。系统已经给我们定义好了

远指针类型:FARPROC,我们直接拿来用就可以。如:

  1. FARPROC pfOldMsgBoxW;  //指向函数的远指针

..................................................................................................................................................................................................................

3.获取API函数入口

有了保存原API函数地址的变量OldMsgBox和指向原API函数的远指针,我们就能够获取真实API的地址了。

如:

  1. //获取原API入口地址
  2. HMODULE hmod=::LoadLibrary(_T("User32.dll"));
  3. OldMsgBoxW=(MsgBoxW)::GetProcAddress(hmod,"MessageBoxW");
  4. pfOldMsgBoxW=(FARPROC)OldMsgBoxW;

注意,上面我们将原API地址OldMsgBoxW强制转换成了远指针pfOldMsgBoxW。至于为什么要强制转换。

我如今也不是非常清楚,想知道的童鞋。能够百度一下。

................................................................................................................................................................................................................

4.保存原API入口的前5个字节

保存的目的是为了恢复用的,毕竟我们HOOK了API后,还须要调用真实的API嘛,

怎样保存一个函数入口的前5个字节呢?这里用到了汇编代码,至于不用汇编能够吗?我想是能够的。

有空时,我再试一下,不用汇编能否保存一个API入口的前5个字节。这里就先用别人写的汇编代码吧,

代码例如以下:

  1. // 将原API的入口前5个字节代码保存到OldCode[]
  2. BYTE OldCode[5];
  3. _asm
  4. {
  5. lea edi,OldCode      //获取OldCode数组的地址,放到edi
  6. mov esi,pfOldMsgBoxW //获取原API入口地址,放到esi
  7. cld    //方向标志位,为下面两条指令做准备
  8. movsd //复制原API入口前4个字节到OldCode数组
  9. movsb //复制原API入口第5个字节到OldCode数组
  10. }

....................................................................................................................................................................................................................

5.获取新入口的前5个字节

由于我们改动真实API入口的前5个字节。使其跳转到我们假API函数的入口地址。即改成Jmp xxxxxxxx,当中xxxxxxxx就是我们

假API的入口地址,那么我们怎样得到该地址呢?

前人已经总结出了一条公式:

int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);

Jmp nAddr; //我们要获取的就是nAddr的值

既然已经有了公式。我们拿来用就可以,UserFunAddr相当于我们的假API,SysFunAddr相当于真实API,这里指令的大小为5,

实现以上公式的汇编代码例如以下:

  1. //获取MyMessageBoxW的相对地址,为Jmp做准备
  2. //int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);
  3. //Jmp nAddr;
  4. //(我们定制的这条指令的大小), 这里是5。5个字节嘛
  5. BYTE NewCode[5];
  6. _asm
  7. {
  8. lea eax,MyMessageBoxW //获取我们的MyMessageBoxW函数地址
  9. mov ebx,pfOldMsgBoxW  //原系统API函数地址
  10. sub eax,ebx           //int nAddr= UserFunAddr – SysFunAddr
  11. sub eax,5             //nAddr=nAddr-5
  12. mov dword ptr [NewCode+1],eax //将算出的地址nAddr保存到NewCode后面4个字节
  13. //注:一个函数地址占4个字节
  14. }

......................................................................................................................................................................................................................

6.改动真实API入口的前5个字节

前面我们已经保存了真实API入口的前5个字节,也已经计算出了新入口的前5个字节,

可谓万事俱备,仅仅欠东风,如今能够改动真实API入口的前5个字节了。

代码例如以下:

  1. //填充完成,如今NewCode[]里的指令相当于Jmp MyMessageBoxW
  2. //既然已经获取到了Jmp MyMessageBoxW
  3. //如今该是将Jmp MyMessageBoxW写入原API入口前5个字节的时候了
  4. //知道为什么是5个字节吗?
  5. //Jmp指令相当于0xe9,占一个字节的内存空间
  6. //MyMessageBoxW是一个地址,事实上是一个整数,占4个字节的内存空间
  7. //int n=0x123;   n占4个字节和MyMessageBoxW占4个字节是一样的
  8. //1+4=5,知道为什么是5个字节了吧
  9. HookOn();

改动API入口前5个字节的HookOn()函数详细代码例如以下:

  1. //开启钩子的函数
  2. void HookOn()
  3. {
  4. ASSERT(hProcess!=NULL);
  5. DWORD dwTemp=0;
  6. DWORD dwOldProtect;
  7. //改动API函数入口前5个字节为jmp xxxxxx
  8. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);
  9. WriteProcessMemory(hProcess,pfOldMsgBoxW,NewCode,5,0);
  10. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,dwOldProtect,&dwTemp);
  11. }

以上改动API函数入口前5个字节,用到了两个系统API函数,百度百科里面对它们有具体解释,在此就不说了。

注:hProcess是进程句柄,我们能够这样获取它:

DWORD dwPid=::GetCurrentProcessId();

HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

..........................................................................................................................................................................................................

7.恢复API函数入口前5个字节

有改动。就有恢复嘛,恢复函数代码例如以下:

  1. //关闭钩子的函数
  2. void HookOff()
  3. {
  4. ASSERT(hProcess!=NULL);
  5. DWORD dwTemp=0;
  6. DWORD dwOldProtect;
  7. //恢复API函数入口前5个字节
  8. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);
  9. WriteProcessMemory(hProcess,pfOldMsgBoxW,OldCode,5,0);
  10. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,dwOldProtect,&dwTemp);
  11. }

注:hProcess是进程句柄。我们能够这样获取它:

DWORD dwPid=::GetCurrentProcessId();

HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以上就是HOOK API的大致流程了,看不明确的盆友,最好还是再看下我写的源代码。文章结合源代码,

希望有助于你们的理解。

源代码下载地址:Hook自己程序的MessageBoxW.zip

学会了HOOK自己的程序,下篇我们再接再厉。HOOK系统全部程序的MessageBoxA和MessageBoxW

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下贴一下以上这个程序的主要代码,算是有个总体印象吧:

  1. //原函数类型定义
  2. typedef int (WINAPI* MsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
  3. MsgBoxW OldMsgBoxW=NULL;//指向原函数的指针
  4. FARPROC pfOldMsgBoxW;  //指向函数的远指针
  5. BYTE OldCode[5]; //原系统API入口代码
  6. BYTE NewCode[5]; //原系统API新的入口代码 (jmp xxxxxxxx)
  7. HANDLE hProcess=NULL;//本程序进程句柄
  8. HINSTANCE hInst=NULL;//API所在的dll文件句柄
  9. void HookOn();
  10. void HookOff();
  11. int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
  12. {
  13. TRACE(lpText);
  14. HookOff();//调用原函数之前。记得先恢复HOOK呀。不然是调用不到的
  15. //假设不恢复HOOK,就调用原函数,会造成死循环
  16. //毕竟调用的还是我们的函数。从而造成堆栈溢出。程序崩溃。

  17. int nRet=::MessageBoxW(hWnd,_T("哈哈,MessageBoxW被HOOK了"),lpCaption,uType);
  18. HookOn();//调用完原函数后。记得继续开启HOOK,不然下次会HOOK不到。

  19. return nRet;
  20. }
  21. //开启钩子的函数
  22. void HookOn()
  23. {
  24. ASSERT(hProcess!=NULL);
  25. DWORD dwTemp=0;
  26. DWORD dwOldProtect;
  27. //改动API函数入口前5个字节为jmp xxxxxx
  28. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);
  29. WriteProcessMemory(hProcess,pfOldMsgBoxW,NewCode,5,0);
  30. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,dwOldProtect,&dwTemp);
  31. }
  32. //关闭钩子的函数
  33. void HookOff()
  34. {
  35. ASSERT(hProcess!=NULL);
  36. DWORD dwTemp=0;
  37. DWORD dwOldProtect;
  38. //恢复API函数入口前5个字节
  39. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);
  40. WriteProcessMemory(hProcess,pfOldMsgBoxW,OldCode,5,0);
  41. VirtualProtectEx(hProcess,pfOldMsgBoxW,5,dwOldProtect,&dwTemp);
  42. }
  43. //获取API函数入口前5个字节
  44. //旧入口前5个字节保存在前面定义的字节数组BYTE OldCode[5]
  45. //新入口前5个字节保存在前面定义的字节数组BYTE NewCode[5]
  46. void GetApiEntrance()
  47. {
  48. //获取原API入口地址
  49. HMODULE hmod=::LoadLibrary(_T("User32.dll"));
  50. OldMsgBoxW=(MsgBoxW)::GetProcAddress(hmod,"MessageBoxW");
  51. pfOldMsgBoxW=(FARPROC)OldMsgBoxW;
  52. if (pfOldMsgBoxW==NULL)
  53. {
  54. MessageBox(NULL,_T("获取原API入口地址出错"),_T("error!"),0);
  55. return;
  56. }
  57. // 将原API的入口前5个字节代码保存到OldCode[]
  58. _asm
  59. {
  60. lea edi,OldCode      //获取OldCode数组的地址,放到edi
  61. mov esi,pfOldMsgBoxW //获取原API入口地址。放到esi
  62. cld    //方向标志位,为下面两条指令做准备
  63. movsd //复制原API入口前4个字节到OldCode数组
  64. movsb //复制原API入口第5个字节到OldCode数组
  65. }
  66. NewCode[0]=0xe9;//实际上0xe9就相当于jmp指令
  67. //获取MyMessageBoxW的相对地址,为Jmp做准备
  68. //int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);
  69. //Jmp nAddr;
  70. //(我们定制的这条指令的大小), 这里是5,5个字节嘛
  71. BYTE NewCode[5];
  72. _asm
  73. {
  74. lea eax,MyMessageBoxW //获取我们的MyMessageBoxW函数地址
  75. mov ebx,pfOldMsgBoxW  //原系统API函数地址
  76. sub eax,ebx           //int nAddr= UserFunAddr – SysFunAddr
  77. sub eax,5             //nAddr=nAddr-5
  78. mov dword ptr [NewCode+1],eax //将算出的地址nAddr保存到NewCode后面4个字节
  79. //注:一个函数地址占4个字节
  80. }
  81. //填充完成,如今NewCode[]里的指令相当于Jmp MyMessageBoxW
  82. //既然已经获取到了Jmp MyMessageBoxW
  83. //如今该是将Jmp MyMessageBoxW写入原API入口前5个字节的时候了
  84. //知道为什么是5个字节吗?
  85. //Jmp指令相当于0xe9,占一个字节的内存空间
  86. //MyMessageBoxW是一个地址,事实上是一个整数。占4个字节的内存空间
  87. //int n=0x123;   n占4个字节和MyMessageBoxW占4个字节是一样的
  88. //1+4=5。知道为什么是5个字节了吧
  89. HookOn();
  90. }
  91. //開始Hook MessageBoxW
  92. void CHookMsgBoxDlg::OnBnClickedBtnStartHook()
  93. {
  94. DWORD dwPid=::GetCurrentProcessId();
  95. hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
  96. GetApiEntrance();
  97. SetDlgItemText(IDC_STATIC_INFO,_T("Hook已启动"));
  98. }
  99. //调用MessageBoxW
  100. void CHookMsgBoxDlg::OnBnClickedBtnCallMsgBox()
  101. {
  102. ::MessageBoxW(m_hWnd,_T("这是正常的MessageBoxW"),_T("Hello"),0);
  103. }
  104. //停止Hook MessageBoxW
  105. void CHookMsgBoxDlg::OnBnClickedBtnStopHook()
  106. {
  107. HookOff();
  108. SetDlgItemText(IDC_STATIC_INFO,_T("Hook未启动"));
  109. }

汇编 -- Hook API (MessageBoxW)的更多相关文章

  1. HOOK API入门之Hook自己程序的MessageBoxW(简单入门)

    说到HOOK,我看了很多的资料和教程,无奈就是学不会HOOK,不懂是我的理解能力差,还是你们说的 不够明白,直到我看了以下这篇文章,终于学会了HOOK: http://blog.sina.com.cn ...

  2. 汇编Ring 3下实现 HOOK API

    [文章标题]汇编ring3下实现HOOK API [文章作者]nohacks(非安全,hacker0058) [作者主页]hacker0058.ys168.com [文章出处]看雪论坛(bbs.ped ...

  3. HOOK API(三)—— HOOK 所有程序的 MessageBox

    HOOK API(三) —— HOOK 所有程序的 MessageBox 0x00 前言 本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与H ...

  4. HOOK API(二)—— HOOK自己程序的 MessageBox

    HOOK API(二) —— HOOK自己程序的 MessageBox 0x00 前言 以下将给出一个简单的例子,作为HOOK API的入门.这里是HOOK 自己程序的MessageBox,即将自己程 ...

  5. HOOK API(二) —— HOOK自己程序的 MessageBox

    转载来源:https://www.cnblogs.com/hookjc/ 0x00 前言 以下将给出一个简单的例子,作为HOOK API的入门.这里是HOOK 自己程序的MessageBox,即将自己 ...

  6. HOOK API(三) —— HOOK 所有程序的 MessageBox

    转载来源:https://www.cnblogs.com/hookjc/ 0x00 前言 本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与H ...

  7. HOOK API 在多线程时应该注意的问题点

    在使用INLINE HOOK API实现对系统API的拦截时,正常情况下并没有太大问题,但一旦涉及到多线程,不管是修改IAT还是JMP,2种方法均会出现不可预料的问题,特别是在HOOK一些复杂的大型系 ...

  8. HOOK API(四)—— 进程防终止

    HOOK API(四) —— 进程防终止 0x00        前言 这算是一个实战吧,做的一个应用需要实现进程的防终止保护,查了相关资料后决定用HOOK API的方式实现.起初学习HOOK API ...

  9. HOOK API (一)——HOOK基础+一个鼠标钩子实例

    HOOK API (一)——HOOK基础+一个鼠标钩子实例 0x00 起因 最近在做毕业设计,有一个功能是需要实现对剪切板的监控和进程的防终止保护.原本想从内核层实现,但没有头绪.最后决定从调用层入手 ...

随机推荐

  1. STM32F030, 使用嘀嗒定时器Systick实现LED闪烁

    本文主要解决两个问题 1 STM32的IO口要反转,怎么实现? 2 嘀嗒定时器systick的配置 解答1: 单片机的口,反转非常easy.sbit led = P1 ^6;  led = ~led; ...

  2. IT关键词,面试知识问与答

    二叉树遍历的三种方式? 遍历是指依次访问⼆叉树中的每个元素.有三种遍历⽅法,分别是前序遍历. 中序遍历和后序遍历.它们是按照访问根节点和⼦节点的先后顺序命名的. • 前序遍历:先访问根节点,然后访问左 ...

  3. lightoj--1294--Largest Box(三分)

    Largest Box Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu Submit Sta ...

  4. Ubuntu开机报错:could not update ICEauthority file /home/user/.ICEauthority(转载)

    解决方法如下: 一. 代码:sudo chown $USER:$USER /home/$USER/.ICEauthority        sudo chmod 644 /home/$USER/.IC ...

  5. 在C#中运行PowerShell

    C#中运行PowerShell需要用到System.Management.Automation.dll.在Visual Studio中可以通过NuGet添加引用,package名字为"Sys ...

  6. Linux top命令简解

    简介: top 命令是最流行的性能监视工具之一,它是一个优秀的交互式工具,用于监视性能.它提供系统整体性能,但报告进程信息才是 top 命令的长处. top 界面分为两个部份,光标上面部份显示关于系统 ...

  7. Core Java(七)

    面向对象特性整理 知识点:一. static修饰符 static修饰符可以用来修饰类的成员变量.成员方法和代码块.            . 用static修饰的成员变量表示静态变量,可以直接通过类名 ...

  8. js判断传入时间和当前时间大小

    //判断时间是否过期 function judgeTime(time){ var strtime = time.replace("/-/g", "/");//时 ...

  9. [OS][ linux ] 建立新帳號, 變更密碼, 加入 sudoer

    新增 linux , 設定預設 password, 新增 user 到 sudoers 1. 新增 User sudo useradd aa97 2. 設定 User password sudo pa ...

  10. CREATE TABLE 语句后的 ON [PRIMARY] 起什么作用

    CREATE   TABLE   [dbo].[table1]   ( [gh]   [char]   (10)   COLLATE   Chinese_PRC_CI_AS   NOT   NULL ...