C++ 如何拦截对AfxThrowMemoryException的所有调用

C++ 如何拦截对AfxThrowMemoryException的所有调用,c++,exception,api-hook,C++,Exception,Api Hook,我有一个大的MFC程序。我们很少遇到客户获得CMemoryException的情况 问题是,我们得到的是异常,但不是引发异常的位置 我可以截取IAT(导入地址表),但在这种情况下,我只能检测从应用程序到MFC DLL或从其他DLL到MFC DLL的调用 如何截获所有调用AfxThrowMemoryException?因此,MFC DLL中的所有调用也可以被我捕获 事实上,我不知道我想要捕获的函数的内部地址。好的,我可以使用IAT计算内部地址 我知道要走弯路,但我不想把它和我的软件一起交付 在C+

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

问题是,我们得到的是异常,但不是引发异常的位置

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

如何截获所有调用
AfxThrowMemoryException
?因此,MFC DLL中的所有调用也可以被我捕获

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

我知道要走弯路,但我不想把它和我的软件一起交付

在C++代码中有没有更简单的方法来抛出投掷操作?< /P>
最好的办法是,我可以在抛出异常之前捕获任何异常。因此我可以看到调用方代码。

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

只需实现您自己的MyAfxThrow…异常函数。应该有和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);
typedef void(WINAPI*PFN_void)();
自动重定向异常处理程序=[](PFN\u VOID pOld,PFN\u VOID pNew)->bool
{
//获取的实际地址可能有1或2个间接地址
字节*p=重新解释强制转换(pOld);
//调试版本从这里开始。我们首先有一个相对的跳转
//00CDF86F E9 39 AD 06 01 jmp AfxThrowMemoryException(01D4A5ADh)
如果(*p==0xE9)
{
//获取相对跳转地址
int offset=*重新解释铸型(p+1);
//计算新的物理地址
p=p+offset+5;
}
//发布从这里开始。我们有一个JP
//01D4A5AD FF 25 2C 15 17 02 jmp dword ptr[(0217152Ch)]
如果(*p!=0xFF&&*(p+1)!=25)
//意外操作码
返回false;
//获取存储指针的偏移量
p=*重新解释铸型(p+2);
//获取指向执行地址的指针。
字节*pCode=*重新解释强制转换(p);
//补丁前的代码
//790319D0 55推动ebp
//790319D1 8B EC mov ebp,esp
//790319D3 51推动ecx
//790319D4 C7 45 FC CC mov dword ptr[ebp-4],0CCCCH
存储器基本信息mbi;
if(虚拟查询(pCode,&mbi,sizeof(内存基本信息)))
{
//如果页面尚未写入,请尝试将其更改为可写
if(VirtualProtect(mbi.BaseAddress、mbi.RegionSize、PAGE\u EXECUTE\u READWRITE和mbi.Protect))
{
//补丁后的代码
//790319D0 68 70 1A 7B 01推压17B1A70h
//790319D5 C3 ret
//设置新的目标地址
pCode[0]=0x68;//推送
*重新解释强制转换(pCode+1)=重新解释强制转换(pNew);
pCode[5]=0xC3;//返回
//恢复页面上的旧标志
VirtualProtect(mbi.BaseAddress、mbi.RegionSize、mbi.Protect和mbi.Protect);
返回true;
}
其他的
{
//无法更改保护。
断言(假);
返回false;
}
}
其他的
返回false;
};
//用MyAfxThrow…异常替换AfxThrow…异常
bool bSuccess=true;
b成功&=RedirectExceptionHandler(AfxThrowMemoryException,MyAfxThrowMemoryException);
b成功&=RedirectExceptionHandler(AfxThrowResourceException,MyAfxThrowResourceException);
b成功&=RedirectExceptionHandler(afxthrowInvalidargeException,myafxthrowInvalidargeException);
b成功&=RedirectExceptionHandler(AfxThrowNotSupportedException,MyAfxThrowNotSupportedException);