UnhandledExceptionFilter 未被调用分析一例
来源:互联网 发布:以色列 知乎 编辑:程序博客网 时间:2024/05/18 02:05
有时候会遇到 crash 的时候没有生成 dump file. 因为 unhandledexceptionfilter 没有被调用. 而没有被调用的原因, 文档上说有时候的确不会调用. 比如在处理异常的时候再次发生异常.
最近发现在 space 打开的情况下, unhandledexceptionfilter 不被调用, 此时, 会出现系统默认的 crash 对话框. 这个对话框的出现意味着 kernel32!UnhandledExceptionFilter 被调用了, 虽然在 2000, xp, vista 里, 出现对话框的具体实现都不一样, 但都是从 kernel32!UnhandledExceptionFilter 开始的.
这个函数并不长. 它会调用 IsDebugPortPresent(), 如果存在调试器, 则直接返回, 让调试器处理异常. 否则调用用户通过 SetUnhandledExceptionFilter() 注册的处理函数. 如果要调试自己的处理函数,可以在 IsDebugPortPresent() 函数返回之后, 将 eax 置 0.
bp 772b5a38 "r eax=0;g";bp connect!_UnhandledExceptionFilter
地址 772b5a38 是在 vista enterprise build 6000 中反汇编 kernel32!UnhandledExceptionFilter 得到的. 当然, 随着 windows 版本的不同地址是不一样的.
在 space 打开时, 触发异常, 的确没有进到 connect!_UnhandledExceptionFilter 中. 怀疑是不是我们的处理函数被替换了. SetUnhandledExceptionFilter() 将用户注册的函数地址存到全局变量 kernel32!BasepCurrentTopLevelFilter 中, 查看该变量的值, 却发现不是一个函数地址. 查看 SetUnhandledExceptionFilter() 的代码, 才知道它会将函数地址用 RtlEncodePointer() 加密. 而在调用这个函数时会使用 RtlDecodePointer() 解密. 既然每次调用 SetUnhandledExceptionFilter() 都会返回之前的处理函数的地址. 于是在手动触发异常之前先来一个 ASSERT:
ATLASSERT(_UnhandledExceptionFilter == SetUnhandledExceptionFilter(_UnhandledExceptionFilter));
运行程序, 居然真的 ASSERT 了. 有其他的代码在调用 SetUnhandledExceptionFilter(), 遂在其上加断点, 不看不知道, 一看吓一跳. 原来很多的 dll 都会设置自己的异常处理函数.
为了确保我们的处理函数能够调用, 过河拆桥, 在我们调用 SetUnhandledExceptionFilter() 之后, 给 SetUnhandledExceptionFilter() 打一个补丁, 以后再有调用, 则直接返回. 打补丁的代码很简单:
void PatchSetUnhandledExceptionFilter(){static BYTE RETURN_CODE[] = { 0xc2, 0x04, 0x00}; // __asm ret 4MEMORY_BASIC_INFORMATION mbi;DWORD dwOldProtect = 0;DWORD pfnSetFilter =(DWORD)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetUnhandledExceptionFilter");VirtualQuery((void *)pfnSetFilter, &mbi, sizeof(mbi) );VirtualProtect( (void *)pfnSetFilter, sizeof(RETURN_CODE), PAGE_READWRITE, &dwOldProtect);WriteProcessMemory(GetCurrentProcess(),(void *)pfnSetFilter,RETURN_CODE,sizeof(RETURN_CODE), NULL);VirtualProtect((void *)pfnSetFilter, sizeof(RETURN_CODE), mbi.Protect, 0);FlushInstructionCache(GetCurrentProcess(), (void *)pfnSetFilter, sizeof(RETURN_CODE));}
在 kernel32!UnhandledExceptionFilter() 的起始处直接写上 __asm ret 4.
测试通过.
- UnhandledExceptionFilter 未被调用分析一例
- 理解UnhandledExceptionFilter
- Yamon startup分析 (未整理一)
- ios8 didRegisterForRemoteNotificationsWithDeviceToken 未被调用
- touches began未被调用
- startPreview()调用细节分析一
- ORA-00600:17285 dbms_debug调用异常分析一例
- onConfigurationChanged未被调用的原因
- onConfigurationChanged未被调用的原因
- onConfigurationChanged未被调用的原因
- onConfigurationChanged未被调用的原因
- onConfigurationChanged未被调用的原因
- 有关onPreviewFrame未被调用的问题
- WordPress主题未汉化一例
- 实现 UnhandledExceptionFilter() 需要的几个问题
- 实现 UnhandledExceptionFilter() 需要的几个问题
- 当Form中对象未被声明时的调用:
- onConfigurationChanged 未被 调用 onConfigurationChanged not getting called
- 《领域驱动设计——精简版》随笔
- Android屏幕密度(Density)和分辨率的解释
- 五、Struts例子
- linux内核gpiolib文档
- 动态改变Quartz的调度时间
- UnhandledExceptionFilter 未被调用分析一例
- 正则表达式大小写匹配以及解决思路的探索
- struts2 使用 servlet api
- HDU 3277 Marriage Match III
- 实现 UnhandledExceptionFilter() 需要的几个问题
- 网站商铺格式问题 : style="word-wrap:break-word;table-layout: fixed;"
- C++重复定义
- grub的3种安装方式
- Flex App的Size和Link报告