Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

Windows内核调试

帖子发起人: 明眸的心   发起时间: 2010-03-01 22:27 下午   回复: 4

Print Search
帖子排序:    
   2010-03-01, 22:27 下午
ylb001 离线,最后访问时间: 2010/11/2 8:39:20 明眸的心

发帖数前150位
注册: 2009-01-05
发 贴: 7
请教张老师,关于异常IRQL的问题
Reply Quote
张老师,您好,我有问题想请教您,如下,当异常发生时,比如用户层执行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 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 请教张老师,关于异常IRQL的问题
Reply Quote

首先,这个函数的代码是不可以被交换到磁盘上的。你自己的dispatch函数是放在驱动模块里的吧?如果那样,可能是当发生异常时,你的函数不在物理内存中......

对于调用DbgPrint,不知道你是在哪里做的调用,如果是在异常分发函数中,那么注定有问题的,会导致死循环。因为DbgPrint会调用调试服务,触发异常(《软件调试》18.6.6).......

楼主对hook这个函数很执着:-),想达到什么目的呢?


IP 地址: 已记录   报告
   2010-03-02, 10:54 上午
ylb001 离线,最后访问时间: 2010/11/2 8:39:20 明眸的心

发帖数前150位
注册: 2009-01-05
发 贴: 7
Re: 请教张老师,关于异常IRQL的问题
Reply Quote

谢谢了,我好像在哪里看到自己写的驱动模块代码是加载在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 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 请教张老师,关于异常IRQL的问题
Reply Quote

看了下你的代码,当发生用户态异常时,能成功工作的DbgPrint不是在函数的关键路径上,而是在一个分支中,对应的是用户态异常的分支,即下面的else分支中:


if(异常来自内核态)
{
   //分发源于内核态的异常
   // DbgPrint("lan \n");  //如果是内核下发生的异常,调用这句也错
}
else
{
   DbgPrint("lan \n"); //如果是在用户模式下发生的异常,这句会输出没有问题
   //分发源于用户态的异常
}

对于else分支中的DbgPrint,它调用调试服务而触发的异常是内核态异常,因此第二次进入这个函数时,会走分发内核态异常的分支,所以这个DbgPrint调用不会导致递归,可以工作。

对于其它失败的DbgPrint调用,因为它们位于分发内核异常的路径上,因此当分发DbgPrint触发的异常时,第二次进入Dispatch函数时会再次经过这个DbgPrint函数,导致递归......

总的来说,这个函数内部最好不要用DbgPrint,也不建议修改这个函数...


IP 地址: 已记录   报告
   2010-03-04, 10:56 上午
ylb001 离线,最后访问时间: 2010/11/2 8:39:20 明眸的心

发帖数前150位
注册: 2009-01-05
发 贴: 7
Re: 请教张老师,关于异常IRQL的问题
Reply Quote
恩,谢谢张老师,搞懂原因了。感觉系统内核很难啊。尤其是多CPU的系统同步,有没有资料还是网站推荐一下。
IP 地址: 已记录   报告
高端调试 » 软件调试 » Windows内核调试 » Re: 请教张老师,关于异常IRQL的问题

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.