Detour Hook COM成员函数present和Hook 类成员函数


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即可。

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