- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
void * pPresent=NULL;//IDirect3DDevice9::Present函数地址指针
pPresent=(void*)*(DWORD*)(*(DWORD*)Device+0x44);//IDirect3DDevice9* Device
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID *)&pPresent, New_Present);
DWORD nErr = DetourTransactionCommit();
HRESULT __stdcall New_Present(
LPDIRECT3DDEVICE9 pDxdevice, //类的this指针
CONST RECT * pSourceRect, //此参数请参考dx sdk
CONST RECT * pDestRect, //同上
HWND hDestWindowOverride, //同上
CONST RGNDATA * pDirtyRegion //同上
)
{
__asm pushad
static float lastTime = (float)timeGetTime();
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime)*0.001f;
Device->BeginScene();
Device->Clear(0, NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
fps.CalcFPS(timeDelta);
fps.Show();
Device->EndScene();
__asm popad
__asm
{
push pDirtyRegion
push hDestWindowOverride
push pDestRect
push pSourceRect
push pDxdevice
call pPresent
}
lastTime = currTime;
}
另一种方式,采用__declspec(naked)方式,注意的是这种方式不需要编译器添加任何汇编代码,在标明naked的函数中是不可以使用任何赋值,所以把它单独提出来:还要注意子函数New_Present_Sub最好用__stdcall,这样不用考虑堆栈平衡
void __stdcall New_Present_Sub( LPDIRECT3DDEVICE9 pDxdevice)
{
if (pDxdevice)
{
static BOOL bInitFps = FALSE;
if (!bInitFps)
{
bInitFps = g_fps.Create(pDxdevice);
MyOutputDebugString("tpfps-[New_Present] g_fps.Create");
}
if (bInitFps)
{
static DWORD lastTime = timeGetTime();
DWORD currTime = timeGetTime();
DWORD timeDelta = (currTime - lastTime);
pDxdevice->BeginScene();
g_fps.CalcFPS(timeDelta);//传入的是毫秒
switch (g_nOpe)
{
case SHOW_FPS:
{
g_fps.Show();
}
break;
case RECODE_FPS:
{
g_fps.RecordShow(pDxdevice, g_bAutoRecord, g_nAutoRecordTime);
if (g_fps.bAutoRecordExit())
{
MyOutputDebugString("[New_Present]bAutoRecordExit");
g_nOpe = UNRECODE_FPS;
}
}
break;
case UNRECODE_FPS:
{
g_fps.EndRecord(pDxdevice);
g_nOpe = SHOW_FPS;
}
break;
default:
break;
}
pDxdevice->EndScene();
lastTime = currTime;
}
}
}
__declspec(naked) HRESULT __stdcall New_Present(
LPDIRECT3DDEVICE9 pDxdevice, //类的this指针
CONST RECT * pSourceRect, //此参数请参考dx sdk
CONST RECT * pDestRect, //同上
HWND hDestWindowOverride, //同上
CONST RGNDATA * pDirtyRegion //同上
)
{
__asm// 必不可少的,把ebp代码去掉或pushad去掉,都会程序OVER
{
push ebp
mov ebp, esp
pushad
pushfd
}
__asm
{
mov esi, pDxdevice
push esi
mov eax, New_Present_Sub
call eax
}
__asm
{
popfd
popad
mov esp, ebp
pop ebp
jmp g_pPresent
}
}
Hook类成员函数:
术语说明:
原函数:被hook的target
hook函数:指自己写的函数,也即让原函数jmp到该函数
原因分析:
用detours hook类成员函数,因为成员函数会有一个this指针,如果在hook函数中调用原函数,没有传入this指针,那么原函数的调用将会出错。
解决方法是:
1. 首先在ollydbg中找到这个this指针。其实也就是那个类的对象地址,一般来说,在ollydbg中调用原函数时,也即在call原函数之前,总会有一条指令mov ecx,xxx或者lea ecx,xxx,那个ecx就是我们要找的this指针!
2. 在hook函数调用原函数时使用内联汇编代码调用,push所有的参数之后,然后初始化ecx为this指针的值!然后在call原函数,这样call原函数就不会出现崩溃。
需要注意的地方:
1. 注意原函数是否能自动平衡堆栈,如不行,则需要在hook函数中自己手动平衡堆栈
2. hook函数返回时,必须是手动编写汇编返回(ret),不要让系统帮忙返回!在带有参数的hook例子中,系统帮忙放回必定出错!
3. ret后面的值与传入hook函数的参数有关,一般来说,该值=4*参数个数
或者如上面:代替的函数原型第一个参数加this即可。 |
|