关于Windows驱动的CRASH回调函数的一些用法。
我们知道CRASH,是Windows系统产生了无法恢复的错误,导致整个系统无法进行下去,而没有办法的一种选择。表项形式,
就是我们日常电脑中看到的蓝屏。其中的原因是多方面的,可能是内存访问越界,硬件问题,超时机制,中断机制等。我们有时候需
要捕捉这种信息,然后,给用户一种提示,或者反馈给开发人员,系统出现了严重的错误。这里,我们要用到CRASH的回调机制。这
里,主要有2个函数。KeRegisterBugCheckCallback和KeRegisterBugCheckReasonCallback。
先看第一个:
BOOLEAN KeRegisterBugCheckCallback(
IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
IN PVOID Buffer,
IN ULONG Length,
IN PUCHAR Component
);
这个函数很简单;
第一个是CallbackRecord,这个感觉没什么用,感觉就是个枚举类别。需要使用移动非分页内存来初始化。MSDN上面说是指
向KBUGCHECK_CALLBACK_RECORD或者KBUGCHECK_REASON_CALLBACK_RECORD结构体的指针,由于这个结构体WINDOWS没有公开,所以一般
我没有管它。这个分配好空间的指针,需要使用 KeInitializeCallbackRecord函数来调用。
第二个就是回调函数的地址。我们来看一下这个回调函数。
VOID BugCheckCallback(
IN PVOID Buffer,
IN ULONG Length
);
Buffer 感觉是DUMP的指针,Length 是大小,后续我验证后再确定。因为这个函数是在生成了DUMP以后来调用的。
第三个参数:一个指向非分页空间的指针。
第四个参数:空间的大小。
第无个参树:可有可无,如果要填可以把设备驱动的名字写进去。
再看一下第二个函数:
NTKERNELAPI BOOLEAN KeRegisterBugCheckReasonCallback (
IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PUCHAR Component
);
第一个参数:跟上面一样CallbackRecord,这个感觉没什么用,感觉就是个枚举类别。需要使用移动非分页内存来初始化。
MSDN上面说是指向KBUGCHECK_CALLBACK_RECORD或者KBUGCHECK_REASON_CALLBACK_RECORD结构体的指针,由于这个结构体WINDOWS没有
公开,所以一般我没有管它。这个分配好空间的指针,需要使用 KeInitializeCallbackRecord函数来调用。
第二个参数:这里就不一样了,有两种回调函数的形式。
VOID BugcheckDumpIoCallback (
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
);
VOID BugCheckSecondaryDumpDataCallback (
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
);
这两种形式,是有第三个参数决定的。
第三个参数:可以取值KbCallbackDumpIo 来取回调的BugcheckDumpIoCallback这个形式,或者取
KbCallbackSecondaryDumpData指定回调函数的BugCheckSecondaryDumpDataCallback 这中类型。
第四个参数:跟上面一样,可有可无,如果要填可以把设备驱动的名字写进去。
再看一下回调函数的参数:
第一个参数:可以取值KbCallbackDumpIo 来取回调的BugcheckDumpIoCallback这个形式,或者取
KbCallbackSecondaryDumpData指定回调函数的BugCheckSecondaryDumpDataCallback 这中类型。
第二个参数:PKBUGCHECK_REASON_CALLBACK_RECORD Record这个参数,这个是什么了,一看就知道,就一个指向
KBUGCHECK_REASON_CALLBACK_RECORD的指针,但是很可惜,微软也没有公开这个结构体。感觉是记录回调函数的指针。
第三个参树:指向下面结构体的指针。
typedef struct _KBUGCHECK_DUMP_IO {
IN ULONG64 Offset;
IN PVOID Buffer;
IN ULONG BufferLength;
IN KBUGCHECK_DUMP_IO_TYPE Type;
} KBUGCHECK_DUMP_IO, *PKBUGCHECK_DUMP_IO;
typedef enum _KBUGCHECK_DUMP_IO_TYPE {
KbDumpIoInvalid,
KbDumpIoHeader,
KbDumpIoBody,
KbDumpIoSecondaryData,
KbDumpIoComplete
} KBUGCHECK_DUMP_IO_TYPE;
第四个参数:就是系统传下来的KBUGCHECK_DUMP_IO的buffer的大小。如果是BugCheckSecondaryDumpDataCallback,这个大
小固定为sizeof(KBUGCHECK_DUMP_IO).
这里需要说明的,KbDumpIoSecondaryData这个类型就是专为BugCheckSecondaryDumpDataCallback准备的。
KeRegisterBugCheckReasonCallback 这个回调函数是,系统在生成DUMP文件的过程中调用的,
(KeRegisterBugCheckCallback是在生成后调用的),在生成的时候,会同步调用这个回调函数多次。
也就是会将DUMP的所有内容都传到这个函数中来。我们可以通过Buffer,以及KBUGCHECK_DUMP_IO_TYPE来完成整个DUMP文件的备份,
或保护。
还有一点需要注意的是,这两个回调函数的优先级非常高,我之前试过好像是15。所以很多函数都不能调用。一般可以调用
读写硬件寄存器的函数。比如READ/WRITE_REGISTER_XXX,或者READ/WRITE_IO_PORT_XXX系列函数。
禁止进行做的事情有:
1,分配内存(已经崩溃当然不行)。
2,进入分页内存(当然不行,优先级太高)。
3,使用同步机制(当然不行,优先级太高)。
4, 调用那些必须值IRQL等于或小于DISPATCH_LEVEL优先级的函数