|
|
|
|
|
|
|
Windows内核调试
帖子发起人: 明眸的心 发起时间: 2010-03-01 22:27 下午 回复: 4
|
帖子排序:
|
|
|
|
2010-03-01, 22:27 下午
|
明眸的心
注册: 2009-01-05
发 贴: 7
|
|
|
张老师,您好,我有问题想请教您,如下,当异常发生时,比如用户层执行int 3指令,还是内核下(驱动)执行DbgPrint(),还是程序发生Page Fault错误。CPU都会发生异常,由KiTrap3或是KiTrapE处理,它们最后都会调用CommonDispatchException->KiDispachException。我想问的在KiDispchException时的IRQL应该是多少?我自认为应该是很高, 我做过如下测试,我把CommonDispatchException里Call KiDispachException里改成了Call 我自己的函数。在我自己的函数里,我仿照WRK里代码的,在这函数内,如果是在内核下发生的异常,我调用DbgPrint(),一调用就说内核堆栈错误。但是如果是在用户下发生的异常,DbgPrint()能输出成功。这同一函数,内核异常和用户异常也有差别?
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2010-03-01, 23:09 下午
|
格蠹老雷
注册: 2005-12-19
发 贴: 1,303
|
|
|
首先,这个函数的代码是不可以被交换到磁盘上的。你自己的dispatch函数是放在驱动模块里的吧?如果那样,可能是当发生异常时,你的函数不在物理内存中......
对于调用DbgPrint,不知道你是在哪里做的调用,如果是在异常分发函数中,那么注定有问题的,会导致死循环。因为DbgPrint会调用调试服务,触发异常(《软件调试》18.6.6).......
楼主对hook这个函数很执着:-),想达到什么目的呢?
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2010-03-02, 10:54 上午
|
明眸的心
注册: 2009-01-05
发 贴: 7
|
|
|
谢谢了,我好像在哪里看到自己写的驱动模块代码是加载在NonPagePool里,难道自己理解错了。调用DbgPrint,我确定一定是在异常分发函数中调用的。我先开始时也有疑惑怎么行呢。我代码发到你邮箱。我是想HOOK 这函数,让自己分发进程的调试异常。不发送到Process->DebugPort,而是移到别的结构里面。
然后是指定函数位置的预编译指令。比如下面的例子:
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, NdisProtUnload)
#pragma alloc_text(PAGE, NdisProtOpen)
#pragma alloc_text(PAGE, NdisProtClose)
#pragma alloc_text
这个宏仅仅用来指定某个函数的可执行代码在编译出来后在sys文件中的位置。内核模块编译出来之后是一个PE格式的sys文件,这个文件的代码段(text段)中有不同的节(Section),不同的节被加载到内存中之后处理情况不同。读者需要关心的主要是3种节:INIT节的特点是在初始化完毕之后就被释放。也就是说,就不再占用内存空间了。PAGE节的特点是位于可以进行分页交换的内存空间,这些空间在内存紧张时可以被交换到硬盘上以节省内存。如果未用上述的预编译指令处理,则代码默认位于PAGELK节,加载后位于不可分页交换的内存空间中。
函数DriverEntry显然只需要在初始化阶段执行一次,因此这个函数一般都用#pragma alloc_text(INIT, DriverEntry)使之位于初始化后立刻释放的空间内。为了节约内存,可以把很多函数放在PAGE节中。但是要注意:放在PAGE节中的函数不可以在Dispatch级调用,因为这种函数的调用可能诱发缺页中断。但是缺页中断处理不能在Dispatch级完成。为此,一般都用一个宏PAGED_CODE()进行测试。如果发现当前中断级为Dispatch级,则程序直接报异常,让程序员及早发现。示例如下:
#pragma alloc_text(PAGE, SfAttachToMountedDevice)
……
NTSTATUS
SfAttachToMountedDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT SFilterDeviceObject
)
{
PSFILTER_DEVICE_EXTENSION newDevExt =
SFilterDeviceObject->DeviceExtension;
NTSTATUS status;
ULONG i;
PAGED_CODE();
…
本文摘自《寒江独钓:Windows内核安全编程》
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2010-03-02, 20:17 下午
|
格蠹老雷
注册: 2005-12-19
发 贴: 1,303
|
|
|
看了下你的代码,当发生用户态异常时,能成功工作的DbgPrint不是在函数的关键路径上,而是在一个分支中,对应的是用户态异常的分支,即下面的else分支中:
if(异常来自内核态) { //分发源于内核态的异常 // DbgPrint("lan \n"); //如果是内核下发生的异常,调用这句也错 } else { DbgPrint("lan \n"); //如果是在用户模式下发生的异常,这句会输出没有问题 //分发源于用户态的异常 }
对于else分支中的DbgPrint,它调用调试服务而触发的异常是内核态异常,因此第二次进入这个函数时,会走分发内核态异常的分支,所以这个DbgPrint调用不会导致递归,可以工作。
对于其它失败的DbgPrint调用,因为它们位于分发内核异常的路径上,因此当分发DbgPrint触发的异常时,第二次进入Dispatch函数时会再次经过这个DbgPrint函数,导致递归......
总的来说,这个函数内部最好不要用DbgPrint,也不建议修改这个函数...
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2010-03-04, 10:56 上午
|
明眸的心
注册: 2009-01-05
发 贴: 7
|
|
|
恩,谢谢张老师,搞懂原因了。感觉系统内核很难啊。尤其是多CPU的系统同步,有没有资料还是网站推荐一下。
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
高端调试 » 软件调试 » Windows内核调试 » Re: 请教张老师,关于异常IRQL的问题
|
|
|
|
|
|