首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何拦截对AfxThrowMemoryException的所有调用

如何拦截对AfxThrowMemoryException的所有调用
EN

Stack Overflow用户
提问于 2019-10-17 20:20:44
回答 1查看 196关注 0票数 0

我有一个很大的MFC程序。我们很少有客户获得CMemoryException的情况。

问题是,我们得到了异常,而不是异常被抛出的位置。

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

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

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

我知道Detour,但我不想把它和我的软件一起交付。

或者有没有更简单的方法来在C++代码中对抛出操作进行说唱?

最好的情况是,我可以在抛出任何异常之前抓取它们。这样我就可以看到调用者代码了。

EN

回答 1

Stack Overflow用户

发布于 2019-10-21 20:26:11

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

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

代码语言:javascript
运行
复制
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);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58432535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档