无意之中看到 Microsoft Research 里面新出了好东西,Detours,开放源代码,实现了拦截跨进程 API 函数等等功能,从它提供的例程来看,还支持 COM,DCOM 等等。。。以前 Hook API 非常麻烦,Win9X 下由于没有公开的接口,各大厂商为了实现拦截API,使用了各种魔术代码,对于外人来说,高深莫测。虽然 WinNT 平台相对容易一些,但是还是需要编写大量的代码,Detours 的出现,使得编写一个最简单的 Hook,只需要几十行代码。拿到 Detours,我最想知道它在 9X 下如何工作的,可惜最后发现,Detours 并不支持 9X。。。想来 9X 的时代已经远去了,所以也不去计较了。
API Hook 有什么用呢,比如字典软件实现屏幕取词,就是拦截 GDI 绘制文本的相关函数实现的,如果拦截注册表,可以实现一个注册表监视器。一些小说阅读器加密了内容,使得复制文字出来非常困难,但是借助于拦截 IE 内核的 HTML 解析函数,一切文本立刻现身,还可以动态调试第三方的库,甚至伪造和欺骗程序调用。。。总之用途多多。。。
下面的图显示了 Detours 的调用关系:
粗略看了下源代码,Detours 注入进程的基本原理是修改了目标进程的导入表。
下面实际说说如何实现,程序主要分为两部分,一个做钩子DLL,一个注入钩子的主程序:
首先来看钩子DLL:
#include "stdafx.h"
#include "DetourDll.h"
#include "detours.h"
#pragma comment(lib,"detours.lib")
int WINAPI CopyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
DETOUR_TRAMPOLINE(int WINAPI CopyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped), WriteFile);
int WINAPI MyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
CopyMessageBoxA(0, (LPCTSTR)lpBuffer, "hook", MB_OK);
int nResult = CopyWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); //调用原始函数
return nResult;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DetourFunctionWithTrampoline((PBYTE)CopyWriteFile, (PBYTE)MyWriteFile);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
DetourRemove((PBYTE)CopyWriteFile, (PBYTE)MyWriteFile);
break;
}
return TRUE;
}
LRESULT WINAPI MsgProc(int code, WPARAM wParam, LPARAM lParam)
{
//note :on windows 2k ,the 1st paramter to CallNextHookEx can be NULL
//On win 98 ,it must be the hook handle
return(CallNextHookEx(NULL,code,wParam,lParam));
}
在这里,我们准备好要挂钩的函数代码,然后在DllMain里面完成函数的替换就可以了。注意这个dll要导出 MsgProc。
注入程序则非常简单
使用 DetourCreateProcessWithDll() 代替 CreateProcess() 创建进程就可以了,当然也可以附加到进程,具体文档中写得很详细,需要指出的是一些老的文章里面提到的 DetourContinueProcessWithDll(),已经被 DetourCopyPayloadToProcess() 取代,不过这个我没有试。
这个程序运行后,会拦截程序写文件的操作,并且告知写入了什么。比如记事本保存文件的时候就会触发。
Detours 可以在 http://research.microsoft.com/en-us/projects/detours/ 下载。
最后还有个小问题没有解决,Detours 如何拦截 stdcall 以外的函数调用,比如 fastcall 或者 nakedcall。。。期待高手解决了。