MFCSpy 的学习

功能

  • 列出MFC程序指定窗口的继承关系,消息响应,虚函数

MFC中用户处理程序功能的一般是消息响应,再有就是虚函数。实现以下的功能,首先需要的是窗口的对象。

继承关系

MFC中每个类都有个RuntimeClass以及GetRuntimeClass,调用这个函数就可以获取到类的继承关系。

消息响应

类中的GetMessageMap,可以获取到类中所有的消息响应映射表。

虚函数

 

如何获取对象

通过CWnd::FromHandlePermanent可以获取到窗口对应的类。于是如何获取CWnd::FromHandlePermanent函数的位置就是一个问题。在每个窗口的过程函数中,首个调用的就是CWnd::FromHandlePermanent这个函数。

步骤

  1. 注入DLL

  2. 获取窗口过程函数

  3. 判断是否是DEBUG版本的程序

  4. 获取CWnd::FromHandlePermanent函数地址

    由于MFC中的数据存储在TLS中,数据只能在UI线程中获取,那么就需要替换一下过程函数了.

        void GetFromHandleAddr()
    {
        //动态库版
        HMODULE hMod = GetModuleHandle("mfc140d.dll");
        if (hMod != NULL)
        {
            g_pfnFromHandle = (PFN_FROMHANDLE)GetProcAddress(hMod, MAKEINTRESOURCE(5830));
            g_bDll = TRUE;
            return;
        }
    
        //获取CWnd::FromHandlePermanent(hWnd)的函数地址
        //循环,查找过程函数中的第一个call
        LPBYTE pCode = (LPBYTE)g_pfnWndProcDst;
        if (*pCode == 0xe9)
        {
            //说明是debug版,有调表
            DWORD dwOff = *(LPDWORD)(pCode + 1);
            pCode = pCode + dwOff + 5;
        }
    
        while (*pCode != 0xe8)
        {
            ++pCode;
        }
        DWORD dwOff = *(LPDWORD)(pCode + 1);
        g_pfnFromHandle = (PFN_FROMHANDLE)(pCode + dwOff + 5);
        g_bDll = FALSE;
    }
    
    
    void ReplaceWndProc()
    {
        //判断是否是目标进程在加载自己
        DWORD dwId;
        GetWindowThreadProcessId(g_hDstWnd, &dwId);
        if (dwId != GetCurrentProcessId())
        {
            return;
        }
    
        //获取Fromhandle的地址
        GetFromHandleAddr();
    
        //获取窗口的过程函数
        if (IsWindowUnicode(g_hDstWnd))
        {
            g_pfnWndProcDst = (WNDPROC)GetWindowLongW(g_hDstWnd, GWL_WNDPROC);
        }
        else
        {
            g_pfnWndProcDst = (WNDPROC)GetWindowLongA(g_hDstWnd, GWL_WNDPROC);
        }
    
        if (IsWindowUnicode(g_hDstWnd))
        {
            SetWindowLongW(g_hDstWnd, GWL_WNDPROC, (LONG)MyAfxWndProc);
        }
        else
        {
            SetWindowLongA(g_hDstWnd, GWL_WNDPROC, (LONG)MyAfxWndProc);
        }
    
    }

     

     

  5. 通过CWnd::FromHandlePermanent获取CWnd*

  6. 调用GetruntimeClass获取类名.

    在调用CWnd*类的GetruntimeClass时,可以简单声明一下GetruntimeClass的函数方法.并且之后用到的GetMessageMap也需要定义一下

     

GetRuntimeClass在虚表的第一项,所以如果CWnd类中只声明一个函数也是可以调用的.

兼容性的问题

  • 由于MFC中的数据存储在TLS中,数据只能在UI线程中获取,那么就需要替换一下过程函数了.

  • DEBUG版跟Release版本的代码不同,各动态库跟静态库产生的代码也不同.

  • 静态库中RuntimeClass的父类指针存储着父类RuntimeClass的地址,动态库中RuntimeClass存储的是GetRuntimeClass的函数指针.

上一篇:OpenHarmony JS项目开发流程


下一篇:WinCE 防止屏幕闪动的画屏方法