windows hook (转)

http://blog.csdn.net/friendan/article/details/12226201

 

原文地址:http://blog.sina.com.cn/s/blog_628821950100xmuc.html

初稿对我的帮忙极大,正是因为看了初稿,我才学会了HOOK,鉴于原文的排版不是杀好,

再者无原来工程例子源码下载,因此自控制对其重新整理,文章尾附有本人测试时的工程源码下载地址。

流淌:我测试的环境也Win7+VS2008+MFC

初稿出处,好像是当下首:http://blog.csdn.net/glliuxueke/article/details/2702608 
    //后来才来看底


前言
       本文主要介绍了安贯彻替换Windows上之API函数,实现Windows API
Hook

(当然,对于socket的Hook只是里面的同一栽特例)。这种Hook
API技术让大的施用以局部领域被,

要屏幕取词,个人防火墙等。这种API
Hook技术并无是深新,但是涉及的世界较常见,

倘惦记办好有自然之技术难度。本文是集了无数达人的先资料并成自己的尝试得出的心得体会,

每当这里开展总结发表,希望能被大的读者提供参考,达到抛砖引玉的结果。


问题
     
 最近以及同班讨论哪边构建一个Windows上的简要的私家防火墙。后来讨论事关到了何等为过程关联套接字端口,

轮换windows API,屏幕取词等技巧。其中要的题材来:

1) 采用何种机制来收获socket的调用?

诚如的话,实现截获socket的计有无数森,最基本的,可以描绘驱动,驱动也产生成千上万种,TDI驱动,
NDIS驱动,Mini port驱动…

鉴于自家以的凡Win2000体系,所以截获socket也可就此Windows
SPI来开展。另外一种植就是Windows API Hook技术。

鉴于自家没什么硬件基础,不见面刻画驱动,所以率先栽办法无设想,而因此SPI相对比较简单。

可是后来以为Windows API Hook适应面更广泛,而且认为温馨下手能模拟到广大东西,

即决定用Windows API Hook来品尝做socket Hook.

2) API Hook的兑现方式?

     
 实际上就是是指向网函数的交替,当然实现替换的方大概不产5,6种植吧,可以参见《Windows核心编程》第22回。

而我下的艺术与其不近相同,应该相对比较简单易亮。

原理

     
 我们清楚,系统函数都是以DLL封装起来的,应用程序应用至网函数时,应首先将该DLL加载到即之经过空间中,

调用的体系函数的输入地址,可以经
GetProcAddress函数进行得。当系统函数进行调用的时节,

率先将所不可或缺的信保存下来(包括参数和归地址,等有别的信息),然后便跨反至函数的进口地址,继续执行。

事实上函数地址,就是系统函数“可实施代码”的开端地址。那么怎么才能够为函数首先实施我们的函数呢?

呵呵,应该懂得了咔嚓,把开的那段可实施代码替换为我们团结定制的一模一样有点截可实施代码,这样系统函数调用时,

匪就仍我们的打算乖乖行事了啊?其实,就如此简单。Very very简单。 :P

     
 实际的游说,就好改系统函数入口的地方,让他调转至我们的函数的入口点就实行了。

使用汇编代码就会简单的落实Jmp XXXX, 其中XXXX就是一旦跳转的相对地址。

俺们的做法是:把系统函数的进口地方的始末替换为同漫漫Jmp指令,目的就是超到我们的函数进行实施。

要Jmp后面要求的凡相对偏移,也即是咱的函数入口地址及系统函数入口地址间的差距,再减去我们这长达指令的大小。

于是公式表达如下:(1)int nDelta = UserFunAddr – SysFunAddr –
(我们定制的立条指令的分寸);(2)Jmp nDleta;

为保持原来程序的健壮性,我们的函数里举行扫尾必要的处理后,要回调原来的体系函数,然后回。

用调用原来系统函数之前须事先管本来修改的网函数入口地方叫回复,否则,

系统函数地方为我们转移成为了Jmp XXXX就会见又跳到我们的函数里,死循环了。

那么说一下程序执行的长河。
       我们的dll“注射”入于hook的经过 -> 保存体系函数入口处的代码
-> 替换掉进程面临的体系函数入口指为我们的函数 -> 当系统函数被

调用,立即跳反到我们的函数 -> 我们函数进行拍卖 ->
恢复系统函数入口的代码 -> 调用本的体系函数 ->
再修改系统函数入口指向

咱俩的函数(为了下次hook)-> 返回。于是,一次等完整的Hook就到位了。

       
好,这个题目掌握之后,讲一下产只问题,就是什么样开展dll“注射”?即将我们的dll注射到要是Hook的历程中失呢?

酷简单哦,这里我们运用调用Windows提供于咱的有些现的Hook来开展注射。举个例子,鼠标钩子,

键盘钩子大家还懂吧?我们可以为系统装一个鼠标钩子,然后所有响应到鼠标事件的经过,

即使见面“自动”(其实是系处理了)载入我们的dll然后安相应的钩函数。其实我们的目的只是需要为吃注射进程

载入我们的dll就可以了,我们可以再dll实例化的时节进行函数注射的,我们的此鼠标钩子什么还非关乎的。


简的例子OneAddOne

     
讲了端的规律,现在我们应该实战一下了。先甭考虑windows系统那些乱七八糟的函数,

咱俩好编排一个API函数来进行Hook与给Hook的练吧,哈哈。

第一步,首先编写一个Add.dll,很简短,这个dll只输出一个API函数,就是add啦。
新建一个win32 dll工程,

图片 1

dllmain.cpp的内容:

[cpp] view
plain copy print?

  1. //千万别忘声明WINAPI,否则调用的上回有声明错误啊!  
  2. int WINAPI add(int a,int b)  
  3. {    
  4.     return a+b;  
  5. }  
  6.   
  7. BOOL APIENTRY DllMain( HANDLE hModule,   
  8.                       DWORD  ul_reason_for_call,   
  9.                       LPVOID lpReserved  
  10.                       )  
  11. {  
  12.     return TRUE;  
  13. }  

接下来转忘了于add.def里面输出函数add:
LIBRARY  Add
DESCRIPTION “ADD LA”
EXPORTS
 add  @1;

图片 2

修筑了工程后,你晤面发现没Add.def文件,这时我们友好新建一个Add.def文件,然后上加到工程被即可,

添加Add.def文件及工程后,我们尚待安装工程的性能,将Add.def添加到【项目】–>【Add属性】–>

【链接器】–>【输入】–>【模块定义文件】,如下图所著,不这样设置的话,我们添加的Add.def文件是

不起作用的啊。

图片 3

设置好后,编译,ok,我们得了Add.dll


获Add.dll后,我们好用一个多少器【dll函数查看器】来打开我们的Add.dll文件,如果函数导出成之说话,我们尽管足以

当内部来看导出的函数名字了,如下图所示:

图片 4

拖欠工具下载地址:http://download.csdn.net/detail/friendan/6347455     
 //dll函数查看器


产生矣dll文件后,接下我们新建一个MFC对话框程序来调动用该dll中导出的函数add,

程序界面即运行效果截图如下:

图片 5

重大代码如下:

[cpp] view
plain copy print?

  1. //调用dll函数 add(int a,int b)  
  2. void CCallAddDlg::OnBnClickedBtnCallAdd()  
  3. {  
  4.     HINSTANCE hAddDll=NULL;  
  5.     typedef int (WINAPI*AddProc)(int a,int b);//函数原型定义  
  6.     AddProc add;  
  7.     if (hAddDll==NULL)  
  8.     {  
  9.         hAddDll=::LoadLibrary(_T(“Add.dll”));//加载dll  
  10.     }  
  11.     add=(AddProc)::GetProcAddress(hAddDll,”add”);//获取函数add地址  
  12.   
  13.     int a=1;  
  14.     int b=2;  
  15.     int c=add(a,b);//调用函数  
  16.     CString tem;  
  17.     tem.Format(_T(“%d+%d=%d”),a,b,c);  
  18.     AfxMessageBox(tem);  
  19. }  

 


紧接下我们开展HOOK,即HOOK我们的Add.dll文件被之函数int add(int a,int b)

新建一个MFC的
dll工程,工程称为也Hook,然后我们在Hook.cpp文件之中编写代码如下:

率先以首声明如下变量:

[cpp] view
plain copy print?

  1. //变量定义  
  2. //不同Instance共享的拖欠变量  
  3. #pragma data_seg(“SHARED”)  
  4. static HHOOK  hhk=NULL; //鼠标钩子句柄  
  5. static HINSTANCE hinst=NULL; //本dll的实例句柄 (hook.dll)  
  6. #pragma data_seg()  
  7. #pragma comment(linker, “/section:SHARED,rws”)  
  8. //以上之变量共享哦!  
  9.   
  10. CString temp; //用于展示错误的旋变量  
  11. bool bHook=false; //是否Hook了函数  
  12. bool m_bInjected=false; //是否对API进行了Hook  
  13. BYTE OldCode[5]; //老的网API入口代码  
  14. BYTE NewCode[5]; //要跳转的API代码 (jmp xxxx)  
  15. typedef int (WINAPI*AddProc)(int a,int b);//add.dll中之add函数定义  
  16. AddProc add; //add.dll中的add函数  
  17. HANDLE hProcess=NULL; //所处进程的词柄  
  18. FARPROC pfadd;  //指向add函数的远指针  
  19. DWORD dwPid;  //所处进程ID  
  20. //end of 变量定义  

编纂鼠标钩子安装、卸载和处理函数:

[cpp] view
plain copy print?

  1. //鼠标钩子过程,什么为不开,目的是流dll到程序中  
  2. LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam)  
  3. {  
  4.     return CallNextHookEx(hhk,nCode,wParam,lParam);  
  5. }  
  6.   
  7. //鼠标钩子安装函数:  
  8. BOOL InstallHook()  
  9. {  
  10.   
  11.     hhk=::SetWindowsHookEx(WH_MOUSE,MouseProc,hinst,0);  
  12.   
  13.     return true;  
  14. }  
  15.   
  16. //卸载鼠标钩子函数  
  17. void UninstallHook()  
  18. {  
  19.     ::UnhookWindowsHookEx(hhk);  
  20. }  

 


于dll实例化函数InitInstance()中,初始化变量和展开注入:

[cpp] view
plain copy print?

  1. //在dll实例化中获取有参数  
  2. BOOL CHookApp::InitInstance()  
  3. {  
  4.     CWinApp::InitInstance();  
  5.   
  6.     //获得dll 实例,进程句柄  
  7.     hinst=::AfxGetInstanceHandle();  
  8.     DWORD dwPid=::GetCurrentProcessId();  
  9.     hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);   
  10.     //调用注射函数  
  11.     Inject();  
  12.     return TRUE;  
  13. }  

 


编辑注射函数,即HOOK函数Inject()了:

[cpp] view
plain copy print?

  1. //好,最重点之HOOK函数:  
  2. void Inject()  
  3. {  
  4.   
  5.     if (m_bInjected==false)  
  6.     { //保证只调用1软  
  7.         m_bInjected=true;  
  8.   
  9.         //获取add.dll中的add()函数  
  10.         HMODULE hmod=::LoadLibrary(_T(“Add.dll”));  
  11.         add=(AddProc)::GetProcAddress(hmod,”add”);  
  12.         pfadd=(FARPROC)add;  
  13.   
  14.         if (pfadd==NULL)  
  15.         {  
  16.             AfxMessageBox(L”cannot locate add()”);  
  17.         }  
  18.   
  19.         // 将add()中之进口代码保存入OldCode[]  
  20.         _asm   
  21.         {   
  22.             lea edi,OldCode   
  23.                 mov esi,pfadd   
  24.                 cld   
  25.                 movsd   
  26.                 movsb   
  27.         }  
  28.   
  29.         NewCode[0]=0xe9;//实际上0xe9就一定于jmp指令  
  30.         //获取Myadd()的对立地址  
  31.         _asm   
  32.         {   
  33.             lea eax,Myadd  
  34.                 mov ebx,pfadd   
  35.                 sub eax,ebx   
  36.                 sub eax,5   
  37.                 mov dword ptr [NewCode+1],eax   
  38.         }   
  39.         //填充完毕,现在NewCode[]里的下令相当于Jmp Myadd  
  40.         HookOn(); //可以被钩子了  
  41.     }  
  42. }  

 


编排HOOK开启同住函数HookOn()和HookOff()

[cpp] view
plain copy print?

  1. //开启钩子的函数  
  2. void HookOn()   
  3. {   
  4.     ASSERT(hProcess!=NULL);  
  5.   
  6.     DWORD dwTemp=0;  
  7.     DWORD dwOldProtect;  
  8.   
  9.     //将内存保护模式改变也而写,老模式保存入dwOldProtect  
  10.     VirtualProtectEx(hProcess,pfadd,5,PAGE_READWRITE,&dwOldProtect);   
  11.     //将所属进程中add()的眼前5只字节改吧Jmp Myadd   
  12.     WriteProcessMemory(hProcess,pfadd,NewCode,5,0);  
  13.     //将内存保护模式改回为dwOldProtect  
  14.     VirtualProtectEx(hProcess,pfadd,5,dwOldProtect,&dwTemp);  
  15.   
  16.     bHook=true;   
  17. }  
  18. //关闭钩子的函数  
  19. void HookOff()//将所属进程中add()的入口代码恢复  
  20. {   
  21.     ASSERT(hProcess!=NULL);  
  22.   
  23.     DWORD dwTemp=0;  
  24.     DWORD dwOldProtect;  
  25.   
  26.     VirtualProtectEx(hProcess,pfadd,5,PAGE_READWRITE,&dwOldProtect);   
  27.     WriteProcessMemory(hProcess,pfadd,OldCode,5,0);   
  28.     VirtualProtectEx(hProcess,pfadd,5,dwOldProtect,&dwTemp);   
  29.     bHook=false;   
  30. }  

 


编制我们团结一心之Myadd函数()

[cpp] view
plain copy print?

  1. //然后,写我们协调之Myadd()函数  
  2. int WINAPI Myadd(int a,int b)  
  3. {  
  4.     //截获了对add()的调用,我们于a,b都加1  
  5.     a=a+1;  
  6.     b=b+1;  
  7.   
  8.     HookOff();//关掉Myadd()钩子防止死循环  
  9.   
  10.     int ret;  
  11.     ret=add(a,b);  
  12.   
  13.     HookOn();//开启Myadd()钩子  
  14.   
  15.     return ret;  
  16. }  

然后生成忘在hook.def里面导出我们的少单函数 :

InstallHook  
UninstallHook 

图片 6


通下去便好拓展HOOK的测试了,给前的对话框程序,再补充加点儿只按钮,一个用以安装钩子,另一个用于卸载钩子,

先后与周转效果截图如下:

图片 7

//未HOOK之前

图片 8

//HOOK之后

图片 9


安装钩子和卸载钩子主要代码如下:

[cpp] view
plain copy print?

  1. HINSTANCE hinst=NULL;  
  2. //安装鼠标钩子,进行HOOK  
  3. void CCallAddDlg::OnBnClickedBtnStartHook()  
  4. {  
  5.     typedef BOOL (CALLBACK *inshook)(); //函数原型定义  
  6.     inshook insthook;  
  7.       
  8.     hinst=LoadLibrary(_T(“Hook.dll”));//加载dll文件  
  9.     if(hinst==NULL)  
  10.     {  
  11.         AfxMessageBox(_T(“no Hook.dll!”));  
  12.         return;  
  13.     }  
  14.     insthook=::GetProcAddress(hinst,”InstallHook”);//获取函数地址  
  15.     if(insthook==NULL)  
  16.     {  
  17.         AfxMessageBox(_T(“func not found!”));  
  18.         return;  
  19.     }  
  20.     insthook();//开始HOOK  
  21. }  
  22.   
  23. //卸载鼠标钩子,停止HOOK  
  24. void CCallAddDlg::OnBnClickedBtnStopHook()  
  25. {  
  26.     if (hinst==NULL)  
  27.     {  
  28.         return;  
  29.     }  
  30.     typedef BOOL (CALLBACK *UnhookProc)(); //函数原型定义  
  31.     UnhookProc UninstallHook;  
  32.   
  33.     UninstallHook=::GetProcAddress(hinst,”UninstallHook”);//获取函数地址  
  34.     if(UninstallHook!=NULL)   
  35.     {  
  36.         UninstallHook();  
  37.     }  
  38.     if (hinst!=NULL)  
  39.     {  
  40.         ::FreeLibrary(hinst);  
  41.     }  
  42. }  

 


上述就是是前我看之那篇文章的重中之重内容了,关于HOOK系统API,我会以任何的文章里进行验证。

这边更说一下原稿的瑕疵,我当那有零星单短:

1.住HOOK时,没有过来吃HOOK函数的输入。

2.尚未拍卖dll退出事件,没有在dll退出事件被还原为HOOK函数入口。

上述两单缺陷,很易招程序的倒,因此当自身的例证程序中,都指向它们进行了拍卖:

[cpp] view
plain copy print?

  1. //卸载鼠标钩子函数  
  2. void UninstallHook()  
  3. {  
  4.     if (hhk!=NULL)  
  5.     {  
  6.         ::UnhookWindowsHookEx(hhk);  
  7.     }  
  8.     HookOff();//记得恢复原函数进口  
  9. }  
  10.   
  11. //dll退出时  
  12. int CHookApp::ExitInstance()  
  13. {  
  14.     HookOff();//记得恢复原函数输入  
  15.     return CWinApp::ExitInstance();  
  16. }  

 


如上自之事例工程的下载地址:hook
dll文件被的函数add.zip

http://download.csdn.net/detail/friendan/6348209

友谊提示:我当Debug模式运行程序时,HOOK会砸,在Release模式运作程序则HOOK成功。

 

相关文章