首页 > 系统相关 >搜索驱动程序分配的内存和查看KEVENT状态

搜索驱动程序分配的内存和查看KEVENT状态

时间:2022-11-07 21:36:04浏览次数:37  
标签:驱动程序 kd 内存 EVET event pool KEVENT


问题的提出:

(类似windbg ~*kb命令)的调用栈不就行了。没错,对于应用程序而言,这样做十有八九已经定位了。但是,对于驱动程序而言,它运行的上下文可能并不固定在某一进程,回溯内核中所有线程的方式不大可取,因此只能换一种思路定位去问题。我的选择是搜索KEVENT所在的内存,然后查看KEVENT!_DISPATCHER_HEADER!SignalState的值:

kd> dt nt!_KEVENT
+0x000 Header : _DISPATCHER_HEADER
kd> dt nt!_DISPATCHER_HEADER
+0x000 Type : UChar
...
+0x004 SignalState : Int4B
+0x008 WaitListHead : _LIST_ENTRY

思路:

    一般而言,由于KEVENT多用于多线程同步(不可能在栈上分配),驱动程序主要通过2种方式分配并初始化KEVENT:1.在调用IoCreateDevice后,KEVENT作为设备扩展(devObj->DeviceExtension)中的某一个域,被初始化;2.调用ExAllocatePoolWithTag分配堆内存,并初始化。看到这,你可能会怀疑我是不是用windbg的s命令(search搜索内存命令)来定位信号量?这工作量无异于大海捞针!当然不是,你的问题,我需要按上面提到的2种情况分类讨论:对于情况1,通过!devobj命令获得设备拓展来定位KEVENT即可;对于情况2,通过!poolused&!poolfind命令的组合来定位。下面让我们一起来看具体步骤。

情况1,如果KEVENT作为设备拓展的一部分存在:


    虽然event设备扩展中不存在KEVENT对象,但仍然可以用以演示说明。首先查找设备对象的地址:通过!drvobj和!devobj命令完成:


kd> !drvobj event
Driver object (fffffa801b391e70) is for:
\Driver\event
Driver Extension List: (id , addr)

Device Object list:
fffffa80191f7e20
kd> !devobj fffffa80191f7e20
Device object (fffffa80191f7e20) is for:
Event_Sample \Driver\event DriverObject fffffa801b391e70
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00000044
SecurityDescriptor fffff8a0000840e0 DevExt fffffa80191f7f70 <-这才是设备拓展,右边的DevObjExt并不是。具体请查看情景分析相关章节 DevObjExt fffffa80191f7f90
ExtensionFlags (0x00000800) DOE_DEFAULT_SD_PRESENT
Characteristics (0x00000100) FILE_DEVICE_SECURE_OPEN
Device queue is not busy.

在这个例子中,event驱动创建的设备对象地址为0xfffffa80191f7e20;其设备扩展为0xfffffa80191f7f70。把这个地址作为参数,传递给dt命令,即可获得设备扩展各个域的当前状态:


kd> dt event!_DEVICE_EXTENSION 0xfffffa80191f7f70
+0x000 Self : 0xfffffa80`191f7e20 _DEVICE_OBJECT ;Self指向0xfffffa80191f7f70,这符合!drvobj的输出
+0x008 EventQueueHead : _LIST_ENTRY [ 0xfffffa80`191f7f78 - 0xfffffa80`191f7f78 ]
+0x018 QueueLock : 0

情况2,KEVENT是通过ExAllocatePoolWithTag系列函数动态分配的:


    对于这种情况,定位需要用到ExAllocatePoolWithTag在分配内存时,制定的Tag参数。event定义的Tag值如下:


event.c:
case IRP_MJ_CREATE:
DebugPrint(("IRP_MJ_CREATE\n"));

fileContext = ExAllocatePoolWithQuotaTag(NonPagedPool,
sizeof(FILE_CONTEXT),
TAG);
event.h:
#define TAG (ULONG)'TEVE' //因为CPU以小端序存储数据,所以,代码中定义的'TEVE',在内存中看起来就是EVET。


kd> bl
0 e Disable Clear fffff880`02f3d1b0 0001 (0001) event!EventCreateClose+0xd0




搜索驱动程序分配的内存和查看KEVENT状态_sed


此时,可以查看fileContext的值,并定位其中各个域的状态:


kd> ?? fileContext
struct _FILE_CONTEXT * 0xfffffa80`191d16e0
+0x000 FileRundownLock : _IO_REMOVE_LOCK
kd> dt event!_FILE_CONTEXT 0xfffffa80`191d16e0
+0x000 FileRundownLock : _IO_REMOVE_LOCK

    回到本文的主题,程序死锁时,我们可能并不知道是哪出的问题,这时,只能用Tag,打一套组合拳去定位:


首先,查看驱动分配的pool:


kd> !poolused 2 EVET ;2代表查找非分页内存
.
Sorting by NonPaged Pool Consumed

NonPaged Paged
Tag Allocs Used Allocs Used

EVET 1 144 0 0 UNKNOWN pooltag 'EVET', please update pooltag.txt

TOTAL 1 144 0 0ram
kd> !poolfind EVET -nonpaged

Scanning large pool allocation table for tag 0x54455645 (EVET) (fffffa801adbc000 : fffffa801ae7c000)


Searching nonpaged pool (fffffa8018c04000 : fffffa8075400000) for tag 0x54455645 (EVET)

fffffa80191d16e0 : tag EVET, size 0x80, Nonpaged pool, quota process fffffa80191d2b30

!poolused显示标为EVET的pool的总体情况,而!poolfind则显示各个pool的情况。!poolfind的输出0xfffffa80191d16e0和?? fileContext的输出有点出路,这是因为每个pool对象有POOL_HEADER头结构,就如同应用程序分配堆时,为每个请求的内存添加一个HEAP_ENTRY一样。!poolfind输出的是从POOL_HEADER开始的内存,而??fileContext则显示pool正文的起始。所以,我们在真实的应用中还需要加上这段偏移,才能获得真正的内容。



标签:驱动程序,kd,内存,EVET,event,pool,KEVENT
From: https://blog.51cto.com/u_13927568/5831394

相关文章

  • Redis优化神技:如何用更少内存,保存更多数据
      今天跟大家分享一些优化神技,当你面试或者工作中你遇到如下问题,那就使出今天学到的绝招,一招定乾坤! 如何用更少的内存保存更多的数据? 我们应该从Redis是如何......
  • C指针之二:c的动态内存管理
    参考书籍《深入理解c指针》原书作者:RichardReese华盛顿州塔尔顿州立大学副教授篇首语指针为什么强大?因为能够追踪动态分配的内存,通过指针来管理这部分内存是很多操作的基......
  • C指针之一:指针和内存
    参考书籍《深入理解c指针》原书作者:RichardReese华盛顿州塔尔顿州立大学副教授如果想在C/C++道路上走的更远,那么必须非常熟悉指针1、关于指针大小的谣言,指针到底多大?指......
  • 记录一次上个月27号晚上元空间内存溢出
    这次是测试环境,处理问题的时间比较充裕。同样和之前堆内存溢出一样,arthasattachfailure。不同的是这次attach过程报错显示OutOfMemoryError:Metaspace。随即想......
  • pkl中list,tensor, numpy占内存的大小
    pickle中可以存储list,tensor,array类型的数据但是tensor占的内存要比list和array大的多经测试,存储nuscenemini数据集的参数信息,tensor:39Marray:23Mlist:......
  • 第9章 内存模型和名称空间
    看《C++PrimerPlus》时整理的学习笔记,部分内容完全摘抄自《C++PrimerPlus》(第6版)中文版,StephenPrata著,张海龙袁国忠译,人民邮电出版社。只做学习记录用途。目录9.1......
  • 面试必考 - 结构体内存对齐,还有人不会?
    很多人在编写代码实现功能的时候,或多或少都会接触到结构体的使用,在很多的编语言中,结构体都是很多数据结构的重要的组成部分。 在嵌入式的项目开发中,很多时候芯片的内存资源......
  • 详细了解JVM运行时内存
    1.程序计数器概念程序计数器也叫作PC寄存器,是一块很小的内存区域,可以看做是当前线程执行的字节码的行号指示器。字节码的解释工作就是通过改变程序计数器里面的值来获得下一......
  • 深入理解Java内存区域(最新版面试题)
    1、什么是JVM?JVM(JavaVirtualMachine)是用于运行Java字节码的虚拟机,包括一套字节码指令集、一组程序寄存器、一个虚拟机栈、一个虚拟机堆、一个方法区和一个垃圾回收器。JVM......
  • C++-内存四区
    内存四区:1.代码区:代码区:用来存放你写的代码的,只读和共享。只读:意思是编译运行后不能操作,其目的是防止程序意外的修改了他的命令。共享:共享的目的是对于频繁执行的程序,......