看流星社区

 找回密码
 注册账号
查看: 2016|回复: 0

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

[复制链接]

该用户从未签到

发表于 2015-3-27 10:53:13 | 显示全部楼层 |阅读模式
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即可。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-20 09:54

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表