Windows调试1.WinDbg基本使用-异常基础知识

WinDbg 的基本使用

  • WinDbg 支持的调试方式

    • 直接调试(打开一个 exe 程序) 附加调试
    • (附加到一个已经在运行的进程上)
      • 入侵式:可以改变代码的执行流程和寄存器的内容。
      • 非入侵式:不可以改变代码的执行流程,实际上就是挂起了目标进程,对目标进程的线 程环境和内存进行远程访问操作。
    • 基础指令:
      • dd dw dt da du 等:
      • 查看内存信息 ed ew ea 等:
      • 编辑内存信息 t p g 等: 流程控制
  • 中断与异常
    • 中断: 通常由外部硬件产生,属于异步事件,处理器可以不进行处理 异常:
    • 通常是由内部主动触发,属于同步事件,必须要进行处理
    • 中断和异常被统一管理,可以在 WinDbg 使用 !idt 查看中断描述符表。
  • 异常的种类
    • 错误:已经执行了,但是没有执行成功,eip 指向了当前的错误指令

      • 内存访问错误,除零错误,分页错误,硬件执行断点
  • 陷阱:已经执行了,并且执行成功,eip 指向了当前指令的下一条
    • 软件断点(int 3) 单步异常(TF) 硬件读写断点
    • 终止:一旦产生,无法修复,会直接崩溃
  • SEH(结构化异常处理)
    • 关键字: 需要和 C++(try throw catch) 异常处理的关键字区分开来
    • 终止处理程序:
      • 使用的关键字有 __ try __ ?nally __ leave ,保证__ ?nally块绝对被执行,通常被用作清理工 作
    • 异常处理程序: 使用关键字 __ try 和 __ except,当 __ try 有异常产生时,进行相应的处理。
    • 过滤表达式中存放的可以是任何表达式,但是返回值必须是 0 1 -1
      • EXCEPTION_CONTINUE_EXECUTION: 表示重新执行,修复了才会用
      • EXCEPTION_CONTINUE_SEARCH: 表示无法修复,继续向下以 VEH SEH UEH 的顺序寻 找
      • EXCEPTION_EXECUTE_HANDLER:表示执行 __ except 中的代码,影响执行流程
    • GetExceptionCode:过滤表达式和 except 块,获取异常类型
    • GetExceptionInfomation:只能个用于过滤表达式,获取寄存器和异常信息
  • 终止异常处理程序和普通异常处理程序都是线程相关的,可以有多个

    UEH(顶层异常处理程序)

  • 是异常处理的最后一道关卡,通常用于执行错误信息的收集工作,也被用于反调试
  • 设置异常处理的函数是 SetUnhandledExceptionFilter()
  • 进程相关,被存放在一个全局变量中,只能有一个
  • UEH的调用位于SEH之后,如果所有SEH都无法处理才会被调用
  • 如果程序处于被调试状态,那么UEH函数不会被调用

    VEH\VCH(向量化异常处理程序)

  • VEH 和 VCH 都被存放在一个全局的链表中,可以设置多个
  • VEH的调用是最先的,如果所有VEH都无法处理异常,则会调用UEH
  • VCH只会在异常被处理的时候被调用,如果异常没有被处理程序会崩溃

终结处理器

// 终结处理器: 保证程序在执行的过程中,一定会执行 _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(): %08X\n", 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, 100
        __asm xor edx, edx
        __asm xor ecx, 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(): %08X\n", 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, 100
        __asm xor edx, edx
        __asm xor ecx, ecx
        __asm idiv ecx
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        // 这里永远不会执行,因为不是 EXCEPTION_EXECUTE_HANDLER(1)
        printf("__except (EXCEPTION_EXECUTE_HANDLER)\n");
?
    }
?
    printf("异常处理成功!");
    system("pause");
?
    return 0;
}
 

向量化异常处理程序(VCH)

// 向量化异常处理程序(VCH): 用户层支持的一种机制,在 最后 被执行
//  - 保存在一个全局的链表中,整个进程都可以访问到,和 VEH 在同一个表中,只是标志位不同
//  - VCH 只会在异常被处理的情况下,最后被执行。
?
// VEH -> SEH -> UEH -> [VCH]
?
?
// 自定义 UEH 函数,在 SEH 之后执行
LONG WINAPI TopLevelExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
    printf("TopLevelExceptionHandler(): %08X\n", 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(): %08X\n", 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(): %08X\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
    return EXCEPTION_CONTINUE_SEARCH;
}
?
?
// 过滤函数: 用于根据不同的情况,返回不同类型的值
DWORD FilterHandler(DWORD ExceptionCode, PEXCEPTION_POINTERS ExceptionInfo)
{
    printf("FilterHandler(): %08X\n", 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, 100
        __asm xor edx, edx
        __asm xor ecx, ecx
        __asm idiv ecx
    }
    __except (FilterHandler(GetExceptionCode(), GetExceptionInformation()))
    {
        // 这里永远不会执行,因为不是 EXCEPTION_EXECUTE_HANDLER(1)
        printf("__except (EXCEPTION_EXECUTE_HANDLER)\n");
    }
?
    printf("异常处理成功!");
    system("pause");
?
    return 0;
}

原文地址:https://www.cnblogs.com/ltyandy/p/11153773.html

时间: 2024-10-29 03:43:31

Windows调试1.WinDbg基本使用-异常基础知识的相关文章

windows上Python开发--3.Django的基础知识

最近两天下了班,没事学习了django的开发,今天做个总结.其实大家可以从百度,google搜到一些django的入门视频,初步了解一下django的框架.学习一些基础的概念和知识.本篇主要是对自己这两天做的做个总结. 1.创建第一个views.py 上一篇文章我们在windows上搭建好了django的开发环境并建立一个测试demo. 在settings.py的同级目录下新建views.py目录.并输入以下代码 from django.http import HttpResponse def

java 异常基础知识以及一些面试题讲解

java是面向对象设计语言,所以异常在java中也封装了成类,而我们只要知道如何处理异常就可以, 异常概述 异常:异常就是Java程序在运行过程中出现的错误. 异常由来:问题也是现实生活中一个具体事务,也可以通过java 的类的形式进行描述,并封装成对象.其实就是Java对不正常情况进行描述后的对象体现 异常分类 程序的异常:Throwable 严重问题:Error 我们不处理.这种问题一般都是很严重的,比如说内存溢出. 问题:Exception 编译期问题:不是RuntimeException

Java 异常基础知识总结

RuntimeException类是Exception类的子类,它叫做运行时异常,Java中的所有运行时异常都会直接或者间接地继承自RuntimeException类. RuntimeException Java中凡是继承自Exception,而不继承自RuntimeException类的异常都是非运行时异常. Exception在程序中必须使用try--catch进行处理:而RuntimeException可以不使用try--catch进行处理,但是如果有异常产生,则异常交给JVM(java虚

Windows调试2.异常产生详细流程

程序设置了int3断点函数 CPU获取后,根据IDT表中的int3的处理函数 主要工作大概是 填充 _KTRAP_FRAME 结构体, 保存的是异常发生时的寄存器环境, 因为在异常处理完毕之后,需要返回产生异常的地方继续执行 然后把异常给CommonDispatchException //总结如下几个顺序 __asm int 3; ? -> IDT[3]: _KiTrap03 (填充一个陷阱帧,用于继续执行代码) ? -> CommonDisapathException(异常地址, 异常的类型

WinDbg配置和使用基础

WinDbg配置和使用基础 WinDbg是微软发布的一款相当优秀的源码级(source-level)调试工具,可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件. 1. WinDbg介绍:    Debugging Tools and Symbols: Getting Startedhttp://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx    A word for WinDbghttp://mtaulty.

关于内核调试(Windbg)的虚拟机配置问题

注:本文配置 环境为VMware® Workstation11.1.2 build-2780323+Windows xp SP2+Windbg 6.12.0002.63 x86 *在win7以后的操作系统中配置会略有不同,会在最后进行补充 一.虚拟机端配置: 1.打开虚拟机系统,在c盘根目录下找到boot.ini文件( 该文件是系统隐藏文件,修改时需要设置相关属性),打开,在最后加入以下内容(不加引号) “multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="

Ant学习-001-ant 基础知识及windows环境配置

一.Ant 概要基础知识 Apache Ant 是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发,用以构建应用,或结合其他开源测试工具例如 git.TestNG等搭建持续集成测试开发环境,从而高效.高质量的构建产品. Ant 有以下一些优点: 跨平台,可移植.Ant 是 Java 语言编写的,所以有很好的跨平台性和可移植性,无论是在 windows.Linux,还是 mac. 操作简单. Ant 是由一个内置任务和可选任务组成的,运行时需要一个构

学习笔记之二(断点调试的基础知识)

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>调试</title> <script type="text/javascript"> function writeTimesTable(timesTable){ var counter1; var writeString; for (counter1=1;count

OllyICE 调试的程序无法处理异常 解决方法

问题描述 在用OllyICE打开可执行文件时出现如下图所示错误 解决方法 1. 选项 -> 调试设置 , 打开调试选项 2. 切换到 异常 页签 3. 取消勾选 忽略(传递给程序)以下异常: 单步中断 4. 确定保存设置 OK, 重新加载可执行文件, 会出现单步中断, 按F9继续执行即可, 问题解决! 我也不清楚为何这样可以解决, 如果有高手知道原因, 请不吝赐教, 谢谢:)