您的位置:首页 > 其它

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函数起作用并检查函数的返回值判断是正确还是错误。


2.1hook
DLL中的函数

在这个例子中,将要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:

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
;
.
}
基本上是用上面介绍的步骤开始和结束——初始化,更新detours线程,用DetourAttach(…)开始hook函数,最后调用DetourTransactionCommit()函数,当调用成功时返回NO_ERROR,失败是返回一些错误码.下面是我们的函数的实现,我发送和接收的信息写入到一个日志文件中:

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,
buf,len,flags);
}
int
WINAPI
MyRecv(SOCKETs,
char
*
buf,
int
len,
int
flags)
{
fopen_s(&pRecvLogFile,
"C:\\RecvLog.txt"
,
"a+"
);
fprintf
(pRecvLogFile,
"%s\n"
,
buf);
fclose
(pRecvLogFile);
return
pRecv(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中:

#undef
UNICODE
#include
<cstdio>
#include
<windows.h>
#include
<detours\detours.h>
int
main()
{
STARTUPINFO
si;
PROCESS_INFORMATION
pi;
ZeroMemory(&si,
sizeof
(STARTUPINFO));
ZeroMemory(&pi,
sizeof
(PROCESS_INFORMATION));
si.cb
=
sizeof
(STARTUPINFO);
char
*
DirPath=
new
char
[MAX_PATH];
char
*
DLLPath=
new
char
[MAX_PATH];
//testdll.dll
char
*
DetourPath=
new
char
[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;
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
}

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