• VS2005中SetUnhandledExceptionFilter函数应用


    很多软件通过设置自己的异常捕获函数,捕获未处理的异常,生成报告或者日志(例如生成mini-dump文件),达到Release版本下追踪Bug的目的。但是,到了VS2005(即VC8),MicrosoftCRTC运行时库)的一些与安全相关的代码做了些改动,典型的,例如增加了对缓冲溢出的检查。新CRT版本在出现错误时强制把异常抛给默认的调试器(如果没有配置的话,默认是Dr.Watson),而不再通知应用程序设置的异常捕获函数,这种行为主要在以下三种情况出现。

    (1)       调用abort函数,并且设置了_CALL_REPORTFAULT选项(这个选项在Release版本是默认设置的)。

    (2)       启用了运行时安全检查选项,并且在软件运行时检查出安全性错误,例如出现缓存溢出。(安全检查选项/GS 默认也是打开的)

    (3)       遇到_invalid_parameter错误,而应用程序又没有主动调用

    _set_invalid_parameter_handler设置错误捕获函数。

    所以结论是,使用VS2005VC8)编译的程序,许多错误都不能在SetUnhandledExceptionFilter捕获到。这是CRT相对于前面版本的一个比较大的改变,但是很遗憾,Microsoft却没有在相应的文档明确指出。

    解决方法

           之所以应用程序捕获不到那些异常,原因是因为新版本的CRT实现在异常处理中强制删除所有应用程序先前设置的捕获函数,如下所示:

     /* Make sure any filter already in place is deleted. */

     SetUnhandledExceptionFilter(NULL);

     UnhandledExceptionFilter(&ExceptionPointers);

    解决方法是拦截CRT调用SetUnhandledExceptionFilter函数,使之无效。在X86平台下,可以使用以下代码。

    #ifndef _M_IX86

           #error "The following code only works for x86!"

    #endif

     

    void DisableSetUnhandledExceptionFilter()

    {

        void *addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")),

                                                             "SetUnhandledExceptionFilter");

        if (addr)

        {

                  unsigned char code[16];

                  int size = 0;

                  code[size++] = 0x33;

                  code[size++] = 0xC0;

                  code[size++] = 0xC2;

                  code[size++] = 0x04;

                  code[size++] = 0x00;

     

                   DWORD dwOldFlag, dwTempFlag;

                  VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);

                  WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);

                  VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);

           }

    }

    在设置自己的异常处理函数后,调用DisableSetUnhandledExceptionFilter禁止CRT设置即可。

    其它讨论

           上面通过设置api hook,解决了在VS2005上的异常捕获问题,这种虽然不是那么“干净”的解决方案,确是目前唯一简单有效的方式。

           虽然也可以通过_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT), signal(SIGABRT, ...),_set_invalid_parameter_handler(...) 解决(1)(3),但是对于(2),设置api hook是唯一的方式。

  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/lidabo/p/3486130.html
Copyright © 2020-2023  润新知