Detours使用说明
2013-12-07 23:33
274 查看
1介绍
Apihook包括两部分:api调用的截取和api函数的重定向。通过api
hook可以修改函数的参数和返回值。关于原理的详细内容参见《windows核心编程》第19章和第22章。
2DetoursAPIhook
"Detoursisalibraryforintercepting
arbitraryWin32binaryfunctionsonx86machines.Interceptioncodeisapplieddynamicallyatruntime.Detoursreplacesthefirstfewinstructionsofthetargetfunctionwithanunconditionaljumptotheuser-provideddetourfunction.Instructionsfromthe
targetfunctionareplacedinatrampoline.Theaddressofthetrampolineisplacedinatargetpointer.Thedetourfunctioncaneitherreplacethetargetfunction,orextenditssemanticsbyinvokingthetargetfunctionasasubroutinethroughthetarget
pointertothetrampoline."
在Detours库中,驱动detours执行的是函数DetourAttach(…).
LONGDetourAttach(
PVOID*ppPointer,
PVOIDpDetour
);
这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是我们定义的替代函数的地址。但是,在挂接开始之前,还有以下几件事需要完成:
需要对detours进行初始化.
需要更新进行detours的线程.
这些可以调用以下函数很容的做到:
DetourTransactionBegin()
DetourUpdateThread(GetCurrentThread())
在这两件事做完以后,detour函数才是真正地附着到目标函数上。在此之后,调用DetourTransactionCommit()是detour函数起作用并检查函数的返回值判断是正确还是错误。
在这个例子中,将要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:
它基本上是用上面介绍的步骤开始和结束——初始化,更新detours线程,用DetourAttach(…)开始hook函数,最后调用DetourTransactionCommit()函数,当调用成功时返回NO_ERROR,失败是返回一些错误码.下面是我们的函数的实现,我发送和接收的信息写入到一个日志文件中:
举例来说明,假如有一个函数,其原型为
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
}
使用这个函数相当于用
hook
2DetoursAPIhook
"Detoursisalibrary
arbitraryWin32binaryfunctionsonx86machines.Interceptioncodeisapplieddynamicallyatruntime.Detoursreplacesthefirstfewinstructionsofthetargetfunctionwithanunconditionaljumptotheuser-provideddetourfunction.Instructionsfromthe
targetfunctionareplacedinatrampoline.Theaddressofthetrampolineisplacedinatargetpointer.Thedetourfunctioncaneitherreplacethetargetfunction,orextenditssemanticsbyinvokingthetargetfunctionasasubroutinethroughthetarget
pointertothetrampoline."
在Detours库中,驱动detours
LONGDetourAttach(
PVOIDpDetour
);
这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是
需要对detours进行初始化.
需要
这些可以调用以下函数很容的做到:
DetourTransactionBegin()
DetourUpdateThr
在这两件事做完以后,detour函数才是真正地附着到目标函数上。在此之后,调用DetourTransactionCommit()是detour函数起
2.1hook
DLL中的函数
在这个例子中,将要hookwinsock中的函数send(…)和recv(…).在这些函数中,我将会在真正调用send或者recv函数前,把真正说要发送或者接收的消息写到一个intsend(
__inSOCKETs,
__inconstchar*buf,
__inintlen,
__inintflags
);
因此,指向这个函数的指针看起来应该是这样的:
int(WINAPI*pSend)(SOCKET,constchar*,int,int)=send;
把函数指针初始化成真正的函数地址是ok的;
和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:
INT APIENTRY DllMain( HMODULE hDLL, DWORD Reason, LPVOID Reserved) |
{ |
switch (Reason) |
{ |
case DLL_PROCESS_ATTACH: |
DisableThreadLibraryCalls(hDLL); |
DetourTransactionBegin(); |
DetourUpdateThread(GetCurrentThread()); |
DetourAttach(&( PVOID &)pSend, MySend); |
if (DetourTransactionCommit() ==NO_ERROR) |
OutputDebugString( "send() detouredsuccessfully" ); |
break ; |
. |
} |
} |
int WINAPI MySend(SOCKETs, const char * buf, int len, int flags) |
{ |
fopen_s(&pSendLogFile, "C:\\SendLog.txt" , "a+" ); |
fprintf (pSendLogFile, "%s\n" , buf); |
fclose (pSendLogFile); |
return pSend(s, |
} |
int WINAPI char * buf, int len, int flags) |
{ |
fopen_s(&pRecvLogFile, "C:\\RecvLog.txt" , "a+" ); |
fprintf (pRecvLogFile, "%s\n" , buf); |
fclose (pRecvLogFile); |
return pRecv(s, |
} |
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中:
#undef UNICODE |
#include <cstdio> |
#include <windows.h> |
#include <detours\detours.h> |
int main() |
{ |
STARTUPINFO |
PROCESS_INFORMATION pi; |
ZeroMemory(&si, sizeof (STARTUPINFO)); |
ZeroMemory(&pi, sizeof (PROCESS_INFORMATION)); |
si.cb sizeof (STARTUPINFO); |
char * new char [MAX_PATH]; |
char * new char [MAX_PATH]; //testdll.dll |
char * new char [MAX_PATH]; //detoured.dll |
GetCurrentDirectory(MAX_PATH, |
sprintf_s(DLLPath, "%s\\testdll.dll" , |
sprintf_s(DetourPath, "%s\\detoured.dll" , |
DetourCreateProcessWithDll(NULL, "C:\\windows\\notepad.exe" , |
NULL,NULL, |
delete [] |
delete [] |
delete [] |
return 0; |
} |
2.5DetouringbyAddress
假如出现这种情况怎么办?我们需要hook的函数既不是一个标准的WIN32API,也不是导出函数。这时我们需要吧我们的程序和被所要注入的程序同事编译,或者,把函数的地址硬编码:
view
source
print?
#undef
UNICODE
#include
<cstdio>
#include
<windows.h>
#include
<detours\detours.h>
typedef
void
(WINAPI
*pFunc)(
DWORD
);
void
WINAPI
MyFunc(
DWORD
);
pFunc
FuncToDetour=(pFunc)(0x0100347C);
//Set
itataddresstodetourin
//the
process
INT
APIENTRY
DllMain(
HMODULE
hDLL,
DWORD
Reason,
LPVOID
Reserved)
{
switch
(Reason)
{
case
DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hDLL);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(
PVOID
&)FuncToDetour,
MyFunc);
DetourTransactionCommit();
}
break
;
case
DLL_PROCESS_DETACH:
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(
PVOID
&)FuncToDetour,
MyFunc);
DetourTransactionCommit();
break
;
case
DLL_THREAD_ATTACH:
case
DLL_THREAD_DETACH:
break
;
}
return
TRUE;
}
void
WINAPI
MyFunc(
DWORD
someParameter)
{
//Some
magiccanhappenhere
}
view
source
#undef UNICODE |
#include <cstdio> |
#include <windows.h> |
#include <detours\detours.h> |
typedef void (WINAPI *pFunc)( DWORD ); |
void WINAPI MyFunc( DWORD ); |
pFunc //Set |
//the process |
INT APIENTRY DllMain( HMODULE hDLL, DWORD Reason, LPVOID Reserved) |
{ |
switch (Reason) |
{ |
case DLL_PROCESS_ATTACH: |
{ |
DisableThreadLibraryCalls(hDLL); |
DetourTransactionBegin(); |
DetourUpdateThread(GetCurrentThread()); |
DetourAttach(&( PVOID &)FuncToDetour, |
DetourTransactionCommit(); |
} |
break ; |
case DLL_PROCESS_DETACH: |
DetourTransactionBegin(); |
DetourUpdateThread(GetCurrentThread()); |
DetourDetach(&( PVOID &)FuncToDetour, |
DetourTransactionCommit(); |
break ; |
case DLL_THREAD_ATTACH: |
case DLL_THREAD_DETACH: |
break ; |
} |
return TRUE; |
} |
void WINAPI MyFunc( DWORD someParameter) |
{ |
//Some |
} |
相关文章推荐