Windows调试1.WinDbg基本使用-异常基础知识
WinDbg 的基本使用
终结处理器// 终结处理器: 保证程序在执行的过程中,一定会执行 _finally 块的代码 // - 保证无论 __try 是以何种方式退出的,最终都会执行 __finally // - 不能够处理异常,通常只能用于执行清理工作 ? // __try: 保存的通常是需要进行检测的代码 // __finally: 保存的是一定会执行的一段代码 // __leave: 用于正常退出 __try 块 //goto :非正常退出 int main() { __try { printf("__try { ... }n"); ? // 推荐使用 __leave 退出代码块,使用跳转语句会产生多余的函数调用 // __leave 对应实际是一条 jmp 语句,执行更加的迅速,用于正常退出__try块 __leave; ? // 使用跳转指令退出 __try 块,例如 continue break goto return,属于非正常退出 goto label_exit; } __finally { // 通常用于执行某一些特定的清理工作,比如关闭句柄或释放内存 printf("__finally { ... }n"); ? // 使用 AbnormalTermination 判断是否是异常退出的 if (AbnormalTermination()) printf("异常退出代码块"); else printf("正常退出代码块"); } ? label_exit: ? return 0; } ? ? 异常处理SEH // SEH 的两种实现方式是不能同时存在的,但是可以嵌套 // 两种功能指__try__finanly跟__try__except // SEH 的处理函数被保存在了栈中,所以不同的线程拥有各自的处理函数 ? // 异常处理程序(SEH): 可以用于捕获产生的异常,并且对它执行相应的处理 ? // __try: 是需要被保护(可能产生异常)的代码 // __except: 存放过滤表达式和异常处理块 ? ? // 保存异常信息和线程环境的异常结构体 // typedef struct _EXCEPTION_POINTERS { // PEXCEPTION_RECORD ExceptionRecord; // 保存了[异常类型]和[产生异常的指令所在的位置] // PCONTEXT ContextRecord; // 保存的是异常发生时的寄存器环境,通过修改可以修复异常 // } EXCEPTION_POINTERS,* PEXCEPTION_POINTERS; ? ? // 过滤函数: 用于根据不同的情况,返回不同类型的值 // GetExceptionCode()返回值是 unsigned long // typedef unsigned long DWORD; DWORD FilterHandler(DWORD ExceptionCode,PEXCEPTION_POINTERS ExceptionInfo) { // 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 if (ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) { ExceptionInfo->ContextRecord->Ecx = 1; return EXCEPTION_CONTINUE_EXECUTION; //这个是-1 } ? // 否则其它的异常不做处理,向上传递,这个是0 return EXCEPTION_CONTINUE_SEARCH; } ? ? int main() { __try { printf("__try { ... }n"); ? // 可能会产生异常的指令,只有产生了异常,才会执行 ___except __asm mov eax,100 __asm xor edx,edx __asm xor ecx,ecx __asm idiv ecx ? // 处理异常有意义么? 没有意义的,具体需要分析目标的处理函数 printf("异常已经被处理类!n"); ? // 一个触发内存访问异常的代码 // *(DWORD*)0 = 0; } ? // __except() 过滤表达式的内容可以是任意形式的,但是它的值必须是下面的三个之一,通常是函数调用 // - EXCEPTION_EXECUTE_HANDLER(1): 表示捕获到了异常,需要执行异常处理块的代码,并继续往下执行 // - EXCEPTION_CONTINUE_SEARCH(0): 表示无能为力,交给其它异常处理函数,通常没有处理的返回这一个 // - EXCEPTION_CONTINUE_EXECUTION(-1): 表示不相信不能执行,需要重新执行一遍,只有处理了的异常才会使用 // 异常过滤函数通常要用到的两个函数调用 // - GetExceptionCode: 获取产生的异常的类型,只能在过滤表达式和异常处理块中调用 // - GetExceptionInformation: 获取异常的信息和异常产生时的线程环境,只能在过滤表达式中使用 __except(FilterHandler(GetExceptionCode(),GetExceptionInformation())) { // 只会在异常过滤表达式的值为 EXCEPTION_EXECUTE_HANDLER 才会调用 printf("__except(EXCEPTION_EXECUTE_HANDLER) { ... }n"); } ? return 0; } ? 顶层异常处理// 顶层异常处理(UEH): 是应用程序的最后一道防线,如果所有的 SEH 都没有能够处理异常,就会执行它 // - UEH 通常被用于执行内存转储操作,将收集的错误信息(异常类型,线程上下文和内存)提交到服务器 // - UEH 在 64位系统 下的调试器内是永远不会执行的,需要单独的进行运行 ? ? // 自定义的顶层异常处理函数,即使没有自定义,也会有一个默认的处理函数,且只有一个 // 它的返回值类型和 SEH 是相同的,但是缺少了 EXCEPTION_EXECUTE_HANDLER LONG WINAPI TopLevelExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("TopLevelExceptionHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); ? // 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) { ExceptionInfo->ContextRecord->Ecx = 1; return EXCEPTION_CONTINUE_EXECUTION; // 0 } ? // 否则其它的异常不做处理,向上传递 return EXCEPTION_CONTINUE_SEARCH; // 1 } ? ? int main() { // 顶层异常处理的设置依赖于一个函数 SetUnhandledExceptionFilter(TopLevelExceptionHandler); ? __try { // 产生除零异常 __asm mov eax,ecx __asm idiv ecx } __except (EXCEPTION_CONTINUE_SEARCH) { // 这里永远不会执行,因为不是 EXCEPTION_EXECUTE_HANDLER(1) printf("__except (EXCEPTION_CONTINUE_SEARCH)n"); ? } ? printf("异常处理成功!"); system("pause"); ? return 0; } ? 向量化异常处理程序(VEH) // 向量化异常处理程序(VEH): 用户层支持的一种机制,在 SEH 之前被执行 // - 保存在一个全局的链表中,整个进行都可以访问到 ? ? // 自定义的 VEH 异常处理函数,它的执行位于 SEH 之前,如果 VEH 没有处理成功,才会调用 SEH LONG WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("VectoredExceptionHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); ? // 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) { ExceptionInfo->ContextRecord->Ecx = 1; return EXCEPTION_CONTINUE_EXECUTION; // 0 } ? // 否则其它的异常不做处理,向上传递 return EXCEPTION_CONTINUE_SEARCH; // 1 } ? ? int main() { // 设置一个向量化异常处理函数(VEH),参数一表示添加到异常处理函数链表的位置 AddVectoredExceptionHandler(TRUE,VectoredExceptionHandler); ? __try { // 产生除零异常 __asm mov eax,ecx __asm idiv ecx } __except (EXCEPTION_EXECUTE_HANDLER) { // 这里永远不会执行,因为不是 EXCEPTION_EXECUTE_HANDLER(1) printf("__except (EXCEPTION_EXECUTE_HANDLER)n"); ? } ? printf("异常处理成功!"); system("pause"); ? return 0; } ? // 向量化异常处理程序(VCH): 用户层支持的一种机制,在 最后 被执行 // - 保存在一个全局的链表中,整个进程都可以访问到,和 VEH 在同一个表中,只是标志位不同 // - VCH 只会在异常被处理的情况下,最后被执行。 ? // VEH -> SEH -> UEH -> [VCH] ? ? // 自定义 UEH 函数,在 SEH 之后执行 LONG WINAPI TopLevelExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("TopLevelExceptionHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); ? // 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) { ExceptionInfo->ContextRecord->Ecx = 1; return EXCEPTION_CONTINUE_EXECUTION; } ? // 否则其它的异常不做处理,向上传递 return EXCEPTION_CONTINUE_SEARCH; } ? // 自定义的 VEH 异常处理函数,它的执行位于 SEH 之前,如果 VEH 没有处理成功,才会调用 SEH LONG WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("VectoredExceptionHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); ? // 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 //if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) //{ // ExceptionInfo->ContextRecord->Ecx = 1; // return EXCEPTION_CONTINUE_EXECUTION; //} ? // 否则其它的异常不做处理,向上传递 return EXCEPTION_CONTINUE_SEARCH; } ? // 自定义的 VCH 异常处理函数,只有在异常处理成功的情况下,最后才会被调用 LONG WINAPI VectoredContinueHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("VectoredContinueHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); return EXCEPTION_CONTINUE_SEARCH; } ? ? // 过滤函数: 用于根据不同的情况,返回不同类型的值 DWORD FilterHandler(DWORD ExceptionCode,PEXCEPTION_POINTERS ExceptionInfo) { printf("FilterHandler(): %08Xn",ExceptionInfo->ExceptionRecord->ExceptionCode); ? //// 假设产生的是一个整数除零异常,尝试对异常进行处理,并返回继续执行 //if (ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) //{ // ExceptionInfo->ContextRecord->Ecx = 1; // return EXCEPTION_CONTINUE_EXECUTION; //} ? // 否则其它的异常不做处理,向上传递 return EXCEPTION_CONTINUE_SEARCH; } ? int main() { // 设置一个向量化异常处理函数(VEH) AddVectoredExceptionHandler(TRUE,VectoredExceptionHandler); // 设置一个向量化异常处理函数(VCH) AddVectoredContinueHandler(TRUE,VectoredContinueHandler); // UEH 处理函数 SetUnhandledExceptionFilter(TopLevelExceptionHandler); ? __try { // 产生除零异常 __asm mov eax,ecx __asm idiv ecx } __except (FilterHandler(GetExceptionCode(),GetExceptionInformation())) { // 这里永远不会执行,因为不是 EXCEPTION_EXECUTE_HANDLER(1) printf("__except (EXCEPTION_EXECUTE_HANDLER)n"); } ? printf("异常处理成功!"); system("pause"); ? return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- windows – 编译qtHaskell时发生错误
- windows – 我无法将网络驱动器映射到sharepoint
- 推送通知 – 企业Windows Phone 8.1的推送通知
- CVE 2019-0708漏洞复现防御修复
- 如何克服`文件名或扩展名太长`错误与Windows中的Gradle
- windows-phone-8 – Longlistselector中的ItemsPanel属性控
- Microsoft Azure CDN是真正的CDN还是其他什么?
- <EDEM 基础案例03>Block factory
- 将新修改键添加到Windows需要什么?
- microsoft-graph – 不使用登录页面访问Microsoft Graph AP
- windows – Delphi:如何知道TEdit何时改变大小?
- windows-server-2008-r2 – 如何在共享驱动器上自
- windows – 如何将子域重定向到另一个本地ip:端
- winapi – 以编程方式启用/禁用多点触控手指输入
- windows-server-2008-r2 – 如何在域控制器上禁用
- 命令行 – 导致xcopy告诉我访问被拒绝的原因是什
- .net – 为什么System.Windows.MessageBoxImage具
- .net core autofac automapper
- 使用memory_profiler异常
- 通过Windows GPO管理Acrobat Reader和Flash播放器