【问题标题】:How to intercept all calls to AfxThrowMemoryException如何拦截对 AfxThrowMemoryException 的所有调用
【发布时间】:2019-10-17 12:20:44
【问题描述】:

我有一个大型 MFC 程序。我们很少有客户收到CMemoryException 的情况。

问题是,我们得到了异常,但没有得到引发异常的位置。

我可以拦截 IAT(导入地址表),但在这种情况下,我只能检测到从我的应用程序到 MFC DLL 或从其他 DLL 到 MFC DLL 的调用。

如何拦截AfxThrowMemoryException 的所有呼叫?所以所有来自 MFC DLL 的调用也可以被我捕获。

其实我不知道我要捕获的函数的内部地址。好的,我可以使用 IAT 并计算内部地址。

我知道 Detours,但我也不想在我的软件中提供它..

或者有没有更简单的方法可以在 C++ 代码中调用 throw 操作?

最好的办法是,我可以在抛出任何异常之前捕获它们。这样我就可以看到调用者代码了。

【问题讨论】:

    标签: c++ exception api-hook


    【解决方案1】:

    我替换了函数头本身。对于调试版本,有一个额外的重定向。以下代码有效。

    只需实现您自己的 MyAfxThrow...Exception 函数。应该具有与 AfxThrow... 函数相同的签名。

    typedef void (WINAPI *PFN_VOID)();
    auto RedirectExceptionHandler = [](PFN_VOID pOld, PFN_VOID pNew) -> bool
    {
        // Get the real address of the there might be 1 or 2 indirections
        BYTE* p = reinterpret_cast<BYTE*>(pOld);
    
        // Debug version starts here. We have a Jump Relative first
        //  00CDF86F E9 39 AD 06 01       jmp         AfxThrowMemoryException(01D4A5ADh)
        if (*p == 0xE9)
        {
            // Get the relative jump address
            int offset = *reinterpret_cast<int*>(p + 1);
            // Calculate the new physical address
            p = p + offset + 5;
        }
    
        // Release starts here. We have a JP 
        //  01D4A5AD FF 25 2C 15 17 02    jmp         dword ptr[__imp_AfxThrowMemoryException(0217152Ch)]
        if (*p != 0xFF && *(p + 1) != 25)
            // Unexpected OP-Code
            return false;
    
        // Get the offset where the pointer is stored
        p = *reinterpret_cast<BYTE**>(p + 2);
    
        // Get the pointer to the execution address.
        BYTE* pCode = *reinterpret_cast<BYTE**>(p);
    
        // Code before the patch
        //  790319D0 55                   push        ebp
        //  790319D1 8B EC                mov         ebp, esp
        //  790319D3 51                   push        ecx
        //  790319D4 C7 45 FC CC CC CC CC mov         dword ptr[ebp - 4], 0CCCCCCCCh
    
        MEMORY_BASIC_INFORMATION mbi;
        if (VirtualQuery(pCode, &mbi, sizeof(MEMORY_BASIC_INFORMATION)))
        {
            // Try to change the page to be writable if it's not already
            if (VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect))
            {
                // Code after the patch
                //  790319D0 68 70 1A 7B 01       push        17B1A70h  
                //  790319D5 C3                   ret  
    
                // Set the new target address
                pCode[0] = 0x68; // PUSH <address>
                *reinterpret_cast<void**>(pCode + 1) = reinterpret_cast<void*>(pNew);
                pCode[5] = 0xC3; // RET
    
                // Restore the old flag on the page
                VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &mbi.Protect);
                return true;
            }
            else
            {
                // Can't change protection.
                ASSERT(FALSE);
                return false;
            }
        }
        else
            return false;
    };
    
    // Replace AfxThrow...Exception with MyAfxThrow...Exception
    bool bSuccess = true;
    bSuccess &= RedirectExceptionHandler(AfxThrowMemoryException      , MyAfxThrowMemoryException);
    bSuccess &= RedirectExceptionHandler(AfxThrowResourceException    , MyAfxThrowResourceException);
    bSuccess &= RedirectExceptionHandler(AfxThrowInvalidArgException  , MyAfxThrowInvalidArgException);
    bSuccess &= RedirectExceptionHandler(AfxThrowNotSupportedException, MyAfxThrowNotSupportedException);
    

    【讨论】:

      猜你喜欢
      • 2011-10-16
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-07
      • 1970-01-01
      相关资源
      最近更新 更多