• 欢迎光临~

windows异常处理学习总结

开发技术 开发技术 2022-01-28 172次浏览

目录
  • 异常学习
    • 一丶CPU异常
      • 1.1 异常处理简介
      • 1.2 异常的分类之CPU异常
      • 1.3 CPU异常的 记录
      • 1.4 CPU异常的分发
      • 1.5 CPU 异常记录小总结

异常学习

一丶CPU异常

1.1 异常处理简介

此为Windows异常处理。学习异常可以帮助我们更好的调试程序。或者更好的寻找异常点。

先说一下异常产生之后要进行的操作

  • 异常记录

  • 异常分发

  • 异常处理

异常产生后第一步就是要进行异常记录 原因是首先要记录哪里产生了异常。 异常的类型是什么。 第二步就是要分发异常 分发异常指的就是去寻找异常处理函数 找到函数之后就会进行调用,调用的函数我们就称为异常处理

1.2 异常的分类之CPU异常

异常分类有两种,第一种就是CPU产生的异常。 第二种就是软件模拟的产生的异常。

CPU异常如下:

C++代码示例

  1. CPU异常示例
int main(int argc, char **argv)
{
    int x = 10;
    int y = 0;
    int c = x / y;

    return 0;
}

windows异常处理学习总结

提示我们除零异常 这个是CPU可以检测出来的。

  1. 软件模拟的异常
void fun()
{
    throw 1;
}
int main(int argc, char **argv)
{
    fun();
    return 0;
}

当我们使用高级语言编写代码的时候。多多少少高级语言都会提供异常处理机制。

比如C++ 我们可以使用 throw 关键字来抛出一个异常。

这个就是软件模拟的异常。

1.3 CPU异常的 记录

CPU 检测到异常之后会进行如下操作。

XP下

windows异常处理学习总结

WIN10 64位下

windows异常处理学习总结

这里说下64位下的把。

其实最重要的就是 KiExceptionDisPatch 此函数会先 进行异常记录

此函数结构大概为:

__int64 __fastcall KiExceptionDispatch(
        int arg_ExceptionCode,   
        unsigned int arg_ExceptionNumberParameters,
        void *arg_ExceptionAddress,
        unsigned __int64 arg_ExceptionInformation, 
        char a5)  
参数 说明
arg_ExceptionCode 异常记录的代码
arg_ExceptionNumberParameters 异常记录的附加参数大小
arg_ExceptionAddress 异常记录出错的地址
arg_ExceptionInformation 异常记录附加参数数组信息
a5 暂时未知

在调用函数之前代码汇编代码如下:

.text:00000001401C72F3 B9 03 00 00 10                 mov     ecx, 10000003h
.text:00000001401C72F8 33 D2                          xor     edx, edx
.text:00000001401C72FA 4C 8B 85 E8 00+                mov     r8, [rbp+0E8h]
.text:00000001401C72FA 00 00
.text:00000001401C7301 E8 7A 71 00 00                 call    KiExceptionDispatch

传递了一个 10000003 值。此值就是我们的除零异常的的SWITCH值 注意 除零异常的值 应该是 0xC0000094 这个后面说。

下图为 KiExceptionDisPatch 异常记录区域。可以看到会把我们的 switch 值 进行记录 并且会记录我们出现异常的地址

windows异常处理学习总结

异常记录结构体为如下:

#defien EXCEPTION_MAXIMUM_PARAMETERS 15
typedef struct _EXCEPTION_RECORD32 {
    DWORD    ExceptionCode;
    DWORD ExceptionFlags;
    DWORD ExceptionRecord;
    DWORD ExceptionAddress;
    DWORD NumberParameters;
    DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD32, *PEXCEPTION_RECORD32;

typedef struct _EXCEPTION_RECORD64 {
    DWORD    ExceptionCode;
    DWORD ExceptionFlags;
    DWORD64 ExceptionRecord;
    DWORD64 ExceptionAddress;
    DWORD NumberParameters;
    DWORD __unusedAlignment;
    DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD64, *PEXCEPTION_RECORD64;

含义如下:

参数 说明
ExceptionCode 记录异常的代码
ExceptionFlags 记录异常的状态 确定我们是CPU异常还是 软件模拟的异常 还是嵌套异常。根据不同场合值也不一样。
ExceptionRecord 指向下一个异常记录。当出现嵌套异常的时候会记录下一个异常。
ExceptionAddress 记录异常发生的地址
NumberParameters 附加参数
ExceptionInformation 附加参数指针

观看结构体,其中最重要的其实就是前4个成员。 此结构体 我称为异常记录结构体,此结构体也是我所说的异常产生的时候进行的第一步。记录异常信息。此结构体中我们重点还需要知道 ExceptionCode ExceptionAddress 这两个成员分别记录的异常代码和异常地址。这在我们调试的时候很有帮助。

假设我们是 DIV 0 的异常 那么CPU 回去 IDT表中寻找 KiDivideErrorFaultShadow 此函数会最终调用到 KiDivideErrorFault

如果在WINDBG中调试的时候 输入 !IDT 并且有符号的情况下则可以看到 IDT表中的符号名称。

windows异常处理学习总结

反汇编查看 KiDivideErrorFault 则可以看到异常流程。

1.4 CPU异常的分发

异常的分发就是去寻找异常处理函数。 我们继续反汇编

KiExceptionDisPatch 可以看到异常分发函数

反汇编

windows异常处理学习总结

再上图上我们可以看到会继续调用 KiDispatchException

此函数如下:

void KiDispatchException (
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN PKEXCEPTION_FRAME ExceptionFrame,
    IN PKTRAP_FRAME TrapFrame,
    IN KPROCESSOR_MODE PreviousMode,
    IN BOOLEAN FirstChance
    )
参数 说明
ExceptionRecord 异常记录结构体
ExceptionFrame 异常信息框架
TrapFrame 陷阱框架
PreviousMode 先前模式
FirstChance 机会。第几次异常

继续反汇编

windows异常处理学习总结

在反汇编过程中 可以看到。 他会对比异常记录结构体中记录的switch值 然后进行修复 如果我们是除零异常 则会修复异常错误代码为 0xC0000094;

在后面会着重说一下 异常分发和处理。 这里先抛出问题。知道我们 CPU产生异常了 如何进行 异常记录 异常分发掉哟个你的函数是哪个

1.5 CPU 异常记录小总结

CPU产生除零异常后会调用 IDT表中 KiDivideErrorFaultShadow 然后此函数继续调用 KiDivideErrorFault 这两个函数都不会进行异常处理只是继续往内核层面下发发。

KiDivideErrorFault 继续调用 KiExceptionDispatch 然后继续调用 KiDispatchException

其中异常记录 是在 KiExceptionDispatch 中产生的。 KiExceptionDispatch 会生成一个 结构体 我们称为异常记录结构体(EXCEPTION_RECORD) 此结构体来保存上层传递过来的 异常代码 异常地址 等信息。

最中会交给 KiDispatchException 去分发。

还了解两个函数。 这两个函数可以在调试中帮助我们来快速定位问题。

void KiDispatchException (
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN PKEXCEPTION_FRAME ExceptionFrame,
    IN PKTRAP_FRAME TrapFrame,
    IN KPROCESSOR_MODE PreviousMode,
    IN BOOLEAN FirstChance
    )
__int64 __fastcall KiExceptionDispatch(
        int arg_ExceptionCode,   
        unsigned int arg_ExceptionNumberParameters,
        void *arg_ExceptionAddress,
        unsigned __int64 arg_ExceptionInformation, 
        char a5)  
程序员灯塔
转载请注明原文链接:windows异常处理学习总结
喜欢 (0)
违法和不良信息举报电话:022-22558618 举报邮箱:dljd@tidljd.com