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
用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到原函数未改变的部分