Detour注意点及原理

	DetourTransactionBegin();
			DetourUpdateThread(GetCurrentThread());
			DetourAttach((PVOID *)&g_pPresent, New_Present);
			DWORD nErr = DetourTransactionCommit();


 

DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourDetach((PVOID *)&g_pPresent, New_Present);
		DWORD nErr = DetourTransactionCommit();
		if (!nErr)
		{
			::FreeLibrary(g_hDll);
			g_bSubclassed = false;	
		}
		else
		{


注意的是卸载时,必须加上这个DetourTransactionCommit,这函数退出时才是Hook真正被还原,我刚开始没加这个,接着后面直接FreeLibrary,结果杯具了!直接崩掉在Hook函数部分

好东西,

用DETOURS库获取NT管理员权限 
陈志敏 
---- 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
 
这样可能更清楚点:
DetourAttach((PVOID *)&pPresent, New_Present);
DWORD nErr = DetourTransactionCommit();
pPresent传入前的值为5d0a10c3,传入后的值为5ce50060(DetourTransactionCommit后)
0:000> u 5d0a10c3    //Hook前函数汇编
d3d9!CBaseDevice::Present:
5d0a10c3 8bff            mov     edi,edi
5d0a10c5 55              push    ebp
5d0a10c6 8bec            mov     ebp,esp
5d0a10c8 56              push    esi
5d0a10c9 57              push    edi
5d0a10ca 8b7d08          mov     edi,dword ptr [ebp+8]
5d0a10cd 85ff            test    edi,edi
5d0a10cf 7444            je      d3d9!CBaseDevice::Present+0x13 (5d0a1115)

d3d9!CBaseDevice::Present://Hook后函数汇编
5d0a10c3 e9dc002fa3      jmp     FpsTool1!ILT+415(?New_PresentYGJPAUIDirect3DDevice9PBUtagRECT (003911a4)  //5个字节
5d0a10c8 56              push    esi
5d0a10c9 57              push    edi
5d0a10ca 8b7d08          mov     edi,dword ptr [ebp+8]
5d0a10cd 85ff            test    edi,edi
5d0a10cf 7444            je      d3d9!CBaseDevice::Present+0x13 (5d0a1115)
5d0a10d1 8d7704          lea     esi,[edi+4]
5d0a10d4 837e1800        cmp     dword ptr [esi+18h],0


0:000> u 5ce50060//Hook后pPresent的值,我们可以看到是保存了Hook前函数汇编的前五个字节,再跳转回前面函数
5ce50060 8bff            mov     edi,edi
5ce50062 55              push    ebp
5ce50063 8bec            mov     ebp,esp
5ce50065 e95e102500      jmp     d3d9!CBaseDevice::Present+0x5 (5d0a10c8)
所以注意的是pPresent在HOOK前和HOOK后都是指向原函数的地址,只不过函数地址值不再相同了,HOOK后是把原函数被截掉的字节先保存到新地址,再JMP到原函数未改变的部分

原文地址:https://www.cnblogs.com/hgy413/p/3693461.html