您的位置:首页 > 其它

Detours使用说明

2010-02-04 13:57 190 查看

1介绍

Apihook包括两部分:api调用的截取和api函数的重定向。通过apihook可以修改函数的参数和返回值。关于原理的详细内容参见《windows核心编程》第19章和第22章。

2DetoursAPIhook

"DetoursisalibraryforinterceptingarbitraryWin32binaryfunctionsonx86machines.Interceptioncodeisapplieddynamicallyatruntime.Detoursreplacesthefirstfewinstructionsofthetargetfunctionwithanunconditionaljumptotheuser-provideddetourfunction.Instructionsfromthetargetfunctionareplacedinatrampoline.Theaddressofthetrampolineisplacedinatargetpointer.Thedetourfunctioncaneitherreplacethetargetfunction,orextenditssemanticsbyinvokingthetargetfunctionasasubroutinethroughthetargetpointertothetrampoline."
在Detours库中,驱动detours执行的是函数DetourAttach(…).
LONGDetourAttach(
PVOID*ppPointer,
PVOIDpDetour
);
这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是我们定义的替代函数的地址。但是,在挂接开始之前,还有以下几件事需要完成:

需要对detours进行初始化.

需要更新进行detours的线程.

这些可以调用以下函数很容的做到:

DetourTransactionBegin()

DetourUpdateThread(GetCurrentThread())

在这两件事做完以后,detour函数才是真正地附着到目标函数上。在此之后,调用DetourTransactionCommit()是detour函数起作用并检查函数的返回值判断是正确还是错误。

2.1hookDLL中的函数

在这个例子中,将要hookwinsock中的函数send(…)和recv(…).在这些函数中,我将会在真正调用send或者recv函数前,把真正说要发送或者接收的消息写到一个日志文件中去。注意:我们自定义的替代函式一定要与被hook的函数具有相同的参数和返回值。例如,send函数的定义是这样的:
intsend(
__inSOCKETs,
__inconstchar*buf,
__inintlen,
__inintflags
);
因此,指向这个函数的指针看起来应该是这样的:
int(WINAPI*pSend)(SOCKET,constchar*,int,int)=send;
把函数指针初始化成真正的函数地址是ok的;另外还有一种方式是把函数指针初始化为NULL,然后用函数DetourFindFunction(…)指向真正的函式地址.把send(…)和recv(…)初始化:
int(WINAPI*pSend)(SOCKETs,constchar*buf,intlen,intflags)=send;
intWINAPIMySend(SOCKETs,constchar*buf,intlen,intflags);
int(WINAPI*pRecv)(SOCKETs,char*buf,intlen,intflags)=recv;
intWINAPIMyRecv(SOCKETs,char*buf,intlen,intflags);
现在,需要hook的函数和重定向到的函数已经定义好了。这里使用WINAPI是因为这些函数是用__stdcall返回值的导出函数,现在开始hook:
INTAPIENTRYDllMain(HMODULEhDLL,DWORDReason,LPVOIDReserved)
{
switch(Reason)
{
caseDLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hDLL);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)pSend,MySend);
if(DetourTransactionCommit()==NO_ERROR)
OutputDebugString("send()detouredsuccessfully");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)pRecv,MyRecv);
if(DetourTransactionCommit()==NO_ERROR)
OutputDebugString("recv()detouredsuccessfully");
break;
.
.
.
它基本上是用上面介绍的步骤开始和结束——初始化,更新detours线程,用DetourAttach(…)开始hook函数,最后调用DetourTransactionCommit()函数,当调用成功时返回NO_ERROR,失败是返回一些错误码.下面是我们的函数的实现,我发送和接收的信息写入到一个日志文件中:
intWINAPIMySend(SOCKETs,constchar*buf,intlen,intflags)
{
fopen_s(&pSendLogFile,"C://SendLog.txt","a+");
fprintf(pSendLogFile,"%s/n",buf);
fclose(pSendLogFile);
returnpSend(s,buf,len,flags);
}

intWINAPIMyRecv(SOCKETs,char*buf,intlen,intflags)
{
fopen_s(&pRecvLogFile,"C://RecvLog.txt","a+");
fprintf(pRecvLogFile,"%s/n",buf);
fclose(pRecvLogFile);
returnpRecv(s,buf,len,flags);
}

2.2hook自定义c函数

举例来说明,假如有一个函数,其原型为
intRunCmd(constchar*cmd);
如果要hook这个函数,可以按照以下几步来做:
a)include声明这个函数的头文件
b)定义指向这个函数的函数指针,int(*RealRunCmd)(constchar*)=RunCmd;
c)定义detour函数,例如:intDetourRunCmd(constchar*);
d)实现detour函数,如:
IntDetourRunCmd(constchar*cmd)
{
//extendthefunction,addwhatyouwant:)
ReturnRealRunCme(cmd);
}
这样就完成了hookRunCmd函数的定义,所需要的就是调用DetourAttack
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)RealRunCmd,DetourRunCmd);
if(DetourTransactionCommit()==NO_ERROR)
{
//error
}

2.3hook类成员函数

Hook类成员函数通过在static函数指针来实现
还是举例说明,假如有个类定义如下:
classCData
{
public:
CData(void);
virtual~CData(void);
intRun(constchar*cmd);
};
现在需要hookintCData::Run(constchar*)这个函数,可以按照以下几步:
a)声明用于hook的类
classCDataHook
{
public:
intDetourRun(constchar*cmd);
staticint(CDataHook::*RealRun)(constchar*cmd);
};
b)初始化类中的static函数指针
int(CDataHook::*CDataHook::RealRun)(constchar*cmd)=(int(CDataHook::*)(constchar*))&CData::Run;
c)定义detour函数
intCDataHook::DetourRun(constchar*cmd)
{
//添加任意你想添加的代码
intiRet=(this->*RealRun)(cmd);
returniRet;
}
e)调用detourAttach函数
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)CDataHook::RealRun,(PVOID)(&(PVOID&)CDataHook::DetourRun));
if(DetourTransactionCommit()==NO_ERROR)
{
//error
}

2.4DetourCreateProcessWithDll

使用这个函数相当于用
CREATE_SUSPENDED
标志调用函数
CreateProcess
.新进程的主线程处于暂停状态,因此DLL能在函数被运行钱被注入。注意:被注入的DLL最少要有一个导出函数.如用testdll.dll注入到notepad.exe中:

#undefUNICODE

#include<cstdio>

#include<windows.h>

#include<detours/detours.h>


intmain()

{

STARTUPINFOsi;

PROCESS_INFORMATIONpi;

ZeroMemory(&si,sizeof(STARTUPINFO));

ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));

si.cb=sizeof(STARTUPINFO);

char*DirPath=newchar[MAX_PATH];

char*DLLPath=newchar[MAX_PATH];//testdll.dll

char*DetourPath=newchar[MAX_PATH];//detoured.dll

GetCurrentDirectory(MAX_PATH,DirPath);

sprintf_s(DLLPath,MAX_PATH,"%s//testdll.dll",DirPath);

sprintf_s(DetourPath,MAX_PATH,"%s//detoured.dll",DirPath);

DetourCreateProcessWithDll(NULL,"C://windows//notepad.exe",NULL,

NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,NULL,NULL,

&si,&pi,DetourPath,DLLPath,NULL);

delete[]DirPath;

delete[]DLLPath;

delete[]DetourPath;

return0;

}

2.5DetouringbyAddress

假如出现这种情况怎么办?我们需要hook的函数既不是一个标准的WIN32API,也不是导出函数。这时我们需要吧我们的程序和被所要注入的程序同事编译,或者,把函数的地址硬编码:

#undefUNICODE

#include<cstdio>

#include<windows.h>

#include<detours/detours.h>


typedefvoid(WINAPI*pFunc)(DWORD);

voidWINAPIMyFunc(DWORD);


pFuncFuncToDetour=(pFunc)(0x0100347C);//Setitataddresstodetourin

//theprocess

INTAPIENTRYDllMain(HMODULEhDLL,DWORDReason,LPVOIDReserved)

{

switch(Reason)

{

caseDLL_PROCESS_ATTACH:

{

DisableThreadLibraryCalls(hDLL);

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

DetourAttach(&(PVOID&)FuncToDetour,MyFunc);

DetourTransactionCommit();

}

break;

caseDLL_PROCESS_DETACH:

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

DetourDetach(&(PVOID&)FuncToDetour,MyFunc);

DetourTransactionCommit();

break;

caseDLL_THREAD_ATTACH:

caseDLL_THREAD_DETACH:

break;

}

returnTRUE;

}


voidWINAPIMyFunc(DWORDsomeParameter)

{

//Somemagiccanhappenhere

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: