API钩挂技术

什么是API钩挂技术:

API挂钩技术的目的就是:用自己的函数替换别人程序里的函数。当程序试图调用它原来应该使用的函数A的时候,我们将函数A替换成函数B,让程序调用B去进行我们想要的处理。

一个例子就是我们经常使用的屏幕取词软件,例如金山词霸和博雅等等。当鼠标指向一个英文或者中文单词的时候,就会在旁边给出相应的翻译。实现该类软件的一个方法就是使用API钩挂技术。当鼠标在屏幕上移动时系统会产生重画消息,相应的程序就会调用TextOut,DrawText等API函数重画屏幕,翻译软件使用自己的函数代替系统提供的重画函数,在屏幕重画前进行自己的处理,显示翻译等等

API钩挂和Windows事件消息钩挂有什么不同:

 

  实现目标(相同点)

 技术本质(不同点)

消息钩挂

在别人的程序试图做某事前,先进行我们的处理

消息挂钩截获消息,在调用程序的函数前先调用我们的钩子函数

API钩挂

 

API钩挂替换程序原来的函数,使得程序对原函数的调用最终都变成对我们自己的函数的调用

 

我们知道,当有消息发送到程序的时候,程序肯定是通过调用某个函数进行处理的:但是程序调用某个函数的时候,却不一定是处理消息,我们可以调用函数进行任何处理,和Windows消息没有必然的联系。在非消息处理的情况下,消息钩子就起不了任何作用了。所以说,API钩挂技术比事件消息钩挂功能更加强大,使用更广泛,但是它的实现也更加多样化,更加复杂。


有哪些API钩挂的方法:

 

API钩挂是一个很灵活的技术,没有一个固定的方法,只要能达到我们的目的就行。但是API钩挂的方法有难有易,效果也有好有坏,下面我们来看看两种方法:

 

Ø  方法1:通过改写原函数的代码来进行API钩挂:

① 获得我们想要挂接的函数在内存中的地址。这一步比想象的要复杂,很多意外的情况都要考虑。

② 将该函数的头几个字节保存起来。

③ 用一个JUMP指令改写函数的头几个字节,跳转到我们的替换函数的地址,在我们的函数内进行处理。当然了,我们的函数必须和原函数的格式一样,有一样的输入输出参数。

④ 当你完成自己的处理后,则跳转回到原来保存的那几个头字节,执行原函数的代码。

 


 

这种方法在16位Windows编程中使用的非常普遍,而且效果很好,但在32位Windows程序里存在严重的问题:首先它对CPU的依赖性很大,X86,Alpha等各种CPU上JUMP等指令是不同的,必须使用手工地编写机器码;其次,在抢占式的多线程系统环境中,这种方法是很脆弱的,万一代码在替换的过程中另一个线程又调用了该函数,那样将会造成严重后果。

所以,在32位Windows操作系统中,我们不推荐这种方法。

Ø  方法2:通过修改模块的引入表来挂接API

在前面的章节中我们已经介绍过PE文件的引入表的概念。这种方法的关键就是修改模块引入表里函数对应的地址。在内存里模块的引入表包含了一组该模块运行时需要的DLL,而且还包含了从每个DLL引入的符号的列表。当程序调用DLL里的某个函数时,它实际上是从引入表里读出该函数在内存里的地址,然后跳转到该地址执行函数的代码。

如果我们修改了引入表里函数A对应的地址,把我们自己的函数B的地址替换上去,那么当程序调用该函数A时,实际上从引入表里查出来的是函数B的地址,从而执行函数B的代码。

如何进行API的简单钩挂:

我们先来看一个简单的例子。该程序的功能很简单,它有一个函数ShowDlg,调用该函数的时候就弹出一个对话框;当我们使用API钩挂技术把原来的对话框函数用新函数NewFunction替换掉后,程序再来调用该函数时,就会执行NewFunction的代码,弹出另一个对话框。

 


修改引入表函数

void ReplaceIATEntry(PCSTR pszDLLName,PROCpfnOld,PROC pfnNew,HMODULE hmodCaller)
{
       ULONGsize;
 
       PIMAGE_IMPORT_DESCRIPTORpImportDesc=(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
 
       if(pImportDesc==NULL)
       {
              return ;
       }
       for(;pImportDesc->Name;pImportDesc++)
       {
              PSTRpszModName=(PSTR)((PBYTE)hmodCaller+pImportDesc->Name);
              if(lstrcmpiA(pszModName,pszDllName)==0)
                     break;
       }
       if(pImportDesc->Name==0)
              return ;
       PIMAGE_THUNK_DATApThunk=(PIMAGE_THUNK_DATA)((PBYTE)hmodCaller+pImportDesc->FirstThunk);
 
       for(;pThunk->u1;pThunk++)
       {
              PROC *ppfn=(PROC*)&pThunk->u1.Function;
              BOOL fFound=(* ppfn==pfnOld);
              if(fFound)
              {
                     WriteProcessMemory(GetCurrentProcess(),ppfn,&pfnNew,sizeof(pfnNew),NULL);
                     return;
              }
       }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值