吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 891|回复: 2
上一主题 下一主题
收起左侧

[系统底层] 内核注册即插即用 (PnP) 通知回调函数IoRegisterPlugPlayNotification 浅析

[复制链接]
跳转到指定楼层
楼主
称霸梦 发表于 2025-11-7 16:17 回帖奖励
本帖最后由 称霸梦 于 2025-11-7 16:52 编辑

先看函数原型
[C++] 纯文本查看 复制代码
NTSTATUS IoRegisterPlugPlayNotification(
  [in]           IO_NOTIFICATION_EVENT_CATEGORY        EventCategory,
  [in]           ULONG                                 EventCategoryFlags,
  [in, optional] PVOID                                 EventCategoryData,
  [in]           PDRIVER_OBJECT                        DriverObject,
  [in]           PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
  [in, optional] __drv_aliasesMem PVOID                Context,
  [out]          PVOID                                 *NotificationEntry
);

官网对于参数解释
EventCategory 是一个枚举类型表示要注册什么类型的通知回调,不同的类型插入到不同的链表里
EventCategoryFlags 只有 EventCategory为 EventCategoryDeviceInterfaceChange 该值才有效
EventCategoryData  这里是一个指针根据注册类型来解释这个指针的结构 EventCategory 为 EventCategoryHardwareProfileChange 该值必须为NULL;
DriverObject 驱动对象
CallbackRoutine 回调
回调原型 按照注册的类型来解释 NotificationStructure  这里就不帖了- -有兴趣可以看官网介绍
[C++] 纯文本查看 复制代码
typedef NTSTATUS
  DRIVER_NOTIFICATION_CALLBACK_ROUTINE(
    _In_ PVOID NotificationStructure,
    _Inout_opt_ PVOID Context
    );

Context 由你在注册时传入,只回传给你使用。可以做任何事情
NotificationEntry 传出的指针,用来注销回调。知道了怎么用之后,开始分析
IDA拖入内核文件,找到IoRegisterPlugPlayNotification
直接F5 开始分析,哦对了 忘记说了,EventCategory  枚举是有5个值但实际上 0 跟 4 都是系统保留使用的,所以给我们用就能注册三种回调 也就是 1 2 3 这三个值

[C++] 纯文本查看 复制代码
v11 = EventCategory - 1;  
    if ( v11 ) EventCategory 如果减一之后 == 0 表示该值为  1走 另外一个分支
    {
      v12 = v11 - 1; 
      if ( v12 ) 如果再 - 1  == 0 表示 该值为2 
      {
        v13 = v12 - 1;
        if ( v13 ) 这里再 - 1 还有值。说明该值>= 4  
        { 
          if ( v13 != 1 )  这里就是判断不是 1 就直接返回报错了
          {
            restarted = 0xC00000EF;
            goto LABEL_33;
          }          那么 - 3 之后等于 1 说明改枚举值为 4  就调用这个函数注册回调
restarted = PiRegisterKernelSoftRestartNotification(   双击进去看下是干了啥好事吧
                        (__int64)DriverObject,
                        (__int64)CallbackRoutine,
                        (__int64)Context,
                        NotificationEntry);
          goto LABEL_13;


这里这贴了主要代码。
[C++] 纯文本查看 复制代码
 PoolWithTag = ExAllocatePoolWithTag(PagedPool, 0x58u, 0x61706E50u); 
      inPoolWithTag = PoolWithTag;
      if ( PoolWithTag )
      {
        memset(PoolWithTag, 0, 0x58u);
        v8 = PnpInitializeNotifyEntry(
               (__int64)inPoolWithTag,
               4,
               CallbackRoutine,
               Context,
               DriverObject,
               (__int64)&PnpKsrNotifyLock);
        if ( v8 < 0 || (v8 = PnpDeferNotification((__int64)inPoolWithTag), v8 < 0) )
        {
          ExFreePoolWithTag(inPoolWithTag, 0x61706E50u);
        }
        else
        {
          ExAcquireFastMutex(&PnpKsrNotifyLock);
          v11 = (_QWORD *)qword_140C430B8;
          if ( *(PVOID **)qword_140C430B8 != &PnpKsrNotifyList )
            __fastfail(3u);
          *inPoolWithTag = &PnpKsrNotifyList;
          inPoolWithTag[1] = v11;
          *v11 = inPoolWithTag;
          qword_140C430B8 = (__int64)inPoolWithTag;
          KeReleaseGuardedMutex(&PnpKsrNotifyLock);
          *NotificationEntry = inPoolWithTag;
        }


首先在这里申请0x58个字节用来存放 存放我们的注册信息。PnpInitializeNotifyEntry 在这里函数里进行初始化,
[C++] 纯文本查看 复制代码
_int64 __fastcall PnpInitializeNotifyEntry(
        __int64 inPoolWithTag,
        int a2,
        __int64 CallbackRoutine,
        __int64 Context,
        __int64 DriverObject,
        __int64 lock)
{
  __int64 v7; // rsi
  unsigned int v11; // r14d
  int v12; // ebx
  struct _ERESOURCE *PoolWithTag; // rax
  unsigned int SessionId; // eax
  __int64 v16; // [rsp+20h] [rbp-E0h] BYREF
  UNICODE_STRING DestinationString; // [rsp+28h] [rbp-D8h] BYREF
  __int128 v18; // [rsp+38h] [rbp-C8h] BYREF
  __int128 v19; // [rsp+48h] [rbp-B8h]
  __int128 v20; // [rsp+58h] [rbp-A8h]
  wchar_t Dst[256]; // [rsp+70h] [rbp-90h] BYREF

  v7 = 0;
  v18 = 0;
  v16 = 0;
  v19 = 0;
  v20 = 0;
  v11 = 0;
  v12 = 0;
  DestinationString = 0;
  if ( !(unsigned int)MmIsSessionAddress(CallbackRoutine) )
    goto LABEL_2;
  SessionId = MmGetSessionIdEx(KeGetCurrentThread()->ApcState.Process);
  v11 = SessionId;
  if ( SessionId == -1 )
    return (unsigned int)-1073741811;
  swprintf_s(Dst, 0x100u, L"\\KernelObjects\\Session%d", SessionId);
  RtlInitUnicodeString(&DestinationString, Dst);
  *((_QWORD *)&v18 + 1) = 0;
  *(_QWORD *)&v19 = &DestinationString;
  LODWORD(v18) = 48;
  DWORD2(v19) = 512;
  v20 = 0;
  v12 = ZwOpenSession(&v16, 0, &v18);
  if ( v12 < 0 || (v7 = v16) == 0 )
  {
    return (unsigned int)-1073741811;
  }
  else
  {
LABEL_2:
    *(_QWORD *)(inPoolWithTag + 0x30) = DriverObject;
    *(_QWORD *)(inPoolWithTag + 8) = inPoolWithTag;
    *(_WORD *)(inPoolWithTag + 0x38) = 1;
    *(_QWORD *)(inPoolWithTag + 0x40) = lock;
    *(_QWORD *)inPoolWithTag = inPoolWithTag;
    *(_DWORD *)(inPoolWithTag + 0x10) = a2;   //上一层传进来的固定数字4 也就是我们的[size=4]EventCategory[/size][size=4] [/size]
    *(_DWORD *)(inPoolWithTag + 0x14) = v11; //  == SessionId
    *(_QWORD *)(inPoolWithTag + 0x18) = v7;   
    *(_QWORD *)(inPoolWithTag + 0x20) = CallbackRoutine;
    *(_QWORD *)(inPoolWithTag + 0x28) = Context;
    *(_BYTE *)(inPoolWithTag + 0x3A) = 0;
    PoolWithTag = (struct _ERESOURCE *)ExAllocatePoolWithTag(NonPagedPoolNx, 0x68u, 0x56706E50u);
    *(_QWORD *)(inPoolWithTag + 0x48) = PoolWithTag;    if ( PoolWithTag )
      ExInitializeResourceLite(PoolWithTag);
    else
      return (unsigned int)-1073741670;
  }
  return (unsigned int)v12;
}

OK 看到关键赋值的地方了,推测大概结构体信息如下
typedef struct _PNP_NOTIFY_ENTRY
{
    LIST_ENTRY ListEntry;               // 0x00 链入全局通知链表
    ULONG EventCategory;           // 0x10 通知类别 (1=HwProfile, 2=DeviceClass, 3=TargetDevice)
    ULONG SessionId;                   // +0x14
    ULONG64 SessionHandle;       // +0x18
    PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine; // 0x20 回调函数地址
    PVOID Context;                 // 0x28 驱动注册时传入的上下文
    PDRIVER_OBJECT DriverObject;   // 0x30 所属驱动对象
    USHORT UNO;         // 0x38
    USHORT UNO1;         // 0x3A
    ULONG UNO2;         //0x3c
    PFAST_MUTEX* Lock;             // 0x40 保护此结构的互斥锁
    PERESOURCE ERESOURCE;           // 0x48
    ULONG64 UNO4                        //0x50 未知
} PNP_NOTIFY_ENTRY, * PPNP_NOTIFY_ENTRY;

大致结构体就是这样。
ExInitializeResourceLite(PoolWithTag); 这里就是在给PERESOURCE ERESOURCE;           // 0x48  这里进行赋值了,对这个结构体有兴趣可以看一下


这里大概就分析完了,那我们在返回到上一层的代码看他是怎么插入到链表里,
这里正常返回之后v8 < 0 就释放咱们结构体的内存了- - 然后就返回 0xC000009A;
[C++] 纯文本查看 复制代码
 
        if ( v8 < 0 || (v8 = PnpDeferNotification((__int64)inPoolWithTag), v8 < 0) )
        {
          ExFreePoolWithTag(inPoolWithTag, 0x61706E50u);
        }
        else
        {
          ExAcquireFastMutex(&PnpKsrNotifyLock); //这里获取互斥锁
          v11 = (_QWORD *)qword_140C430B8;       
          if ( *(PVOID **)qword_140C430B8 != &PnpKsrNotifyList )
            __fastfail(3u);
          *inPoolWithTag = &PnpKsrNotifyList;
          inPoolWithTag[1] = v11;
          *v11 = inPoolWithTag;
          qword_140C430B8 = (__int64)inPoolWithTag;
          KeReleaseGuardedMutex(&PnpKsrNotifyLock);//这里释放互斥锁
          *NotificationEntry = inPoolWithTag;
        }
      }
      else
      {
        return 0xC000009A;
      }


v11 = (_QWORD *)qword_140C430B8;        首先拿到当前尾节点的全局变量
          if ( *(PVOID **)qword_140C430B8 != &PnpKsrNotifyList ) 如果这个尾节点不指向&PnpKsrNotifyList 说明异常了直接蓝屏
            __fastfail(3u);
          *inPoolWithTag = &PnpKsrNotifyList;  这里相当于就是把我们结构体的Flink = 链表头的地址
          inPoolWithTag[1] = v11;                        如果这里只有插入我们一个节点的话我们的Blink 也是 =  链表头的地址
          *v11 = inPoolWithTag;                          把尾节点链表的Flink  指向我们
          qword_140C430B8 = (__int64)inPoolWithTag; 把当前尾节点替换成换成我们的结构体指针,等下一个节点进来还是走这个流程

除了在这个链表里,同时还插入了另外一个链表在
   if ( v8 < 0 || (v8 = PnpDeferNotification((__int64)inPoolWithTag), v8 < 0) ) 这个函数里


而且发现一个问题就是在插入链表的时候呢给我们的结构体 + 0x38的地方++ 了- -
这里有可能就是我们引用计数的地方,具体还是得看卸载函数的流程是什么样的
[C++] 纯文本查看 复制代码
__int64 __fastcall PnpDeferNotification(__int64 a1)
{
  char v2; // bp
  unsigned int v3; // ebx
  _QWORD *PoolWithTag; // rax
  _QWORD *v5; // rdi
  _QWORD *v6; // rax

  v2 = 0;
  v3 = 0;
  ExAcquireFastMutex(&PnpNotificationInProgressLock);
  if ( BYTE2(NlsMbCodePageTag) || *(_DWORD *)(a1 + 0x10) == 3 )
  {
    PoolWithTag = ExAllocatePoolWithTag(PagedPool, 0x18u, 0x37706E50u);
    v5 = PoolWithTag;
    if ( PoolWithTag )
    {
      PoolWithTag[2] = a1;
      ++*(_WORD *)(a1 + 0x38);
      *(_BYTE *)(a1 + 0x3A) = 1;
      ExAcquireFastMutex(&PnpDeferredRegistrationLock);
      v6 = (_QWORD *)qword_140D2EB28;
      if ( *(PVOID **)qword_140D2EB28 != &PnpDeferredRegistrationList )
        __fastfail(3u);
      *v5 = &PnpDeferredRegistrationList;
      v5[1] = v6;
      *v6 = v5;
      qword_140D2EB28 = (__int64)v5;
      KeReleaseGuardedMutex(&PnpDeferredRegistrationLock);
      if ( !BYTE2(NlsMbCodePageTag) )
        v2 = 1;
    }
    else
    {
      v3 = -1073741670;
    }
  }
  KeReleaseGuardedMutex(&PnpNotificationInProgressLock);
  if ( v2 )
  {
    PnpInsertNoopEvent(0, 0);
    return 0;
  }
  return v3;
}

本来想整个函数分析都贴出来 -  - 感觉自己有点啰嗦很多点不说又觉得说不下去,存放的结构大概是这样 ,后面也大差不差有兴趣可以自己尝试分析一下 也就是3
如果枚举值是 EventCategory= EventCategoryTargetDeviceChange 也就是3 走下面这个分支申请0x70个字节
[C++] 纯文本查看 复制代码
PoolWithTag = ExAllocatePoolWithTag(PagedPool, 0x70u, 0x43706E50u);
        if ( PoolWithTag )
        {
          restarted = PnpInitializeNotifyEntry(
                        (unsigned int)PoolWithTag,
                        3,
                        (unsigned int)CallbackRoutine,
                        (unsigned int)Context,
                        (__int64)DriverObject,
                        (__int64)&PnpTargetDeviceNotifyLock);
          if ( restarted < 0 )  如果失败就是释放内存了
          {
            ExFreePoolWithTag(PoolWithTag, 0x43706E50u);
            v28 = (struct _DMA_ADAPTER *)*((_QWORD *)SourceString + 4);
          }
          else
          {
            v16 = SourceString;   // 来源在这里 LODWORD(SourceString) = EventCategoryFlags;  是我们的Flags
            PoolWithTag[10] = EventCategoryData;
            PoolWithTag[11] = *((_QWORD *)v16 + 4);
            restarted = PnpDeferNotification((__int64)PoolWithTag);
            if ( restarted >= 0 )
            {
              KeAcquireGuardedMutex(&PnpTargetDeviceNotifyLock);
              v17 = (PCWSTR *)*((_QWORD *)v16 + 60);
              if ( *v17 == v16 + 236 )
              {
                *PoolWithTag = v16 + 236;
                v18 = &PnpTargetDeviceNotifyLock;
                PoolWithTag[1] = v17;
                *v17 = (PCWSTR)PoolWithTag;
                *((_QWORD *)v16 + 60) = PoolWithTag;
LABEL_11:
                KeReleaseGuardedMutex(v18);
LABEL_12:
                *NotificationEntry = PoolWithTag;


相差不多的给申请的结构体赋值过程
[C++] 纯文本查看 复制代码
__int64 __fastcall PnpInitializeNotifyEntry(
        __int64 inPoolWithTag,
        int a2,
        __int64 CallbackRoutine,
        __int64 Context,
        __int64 DriverObject,
        __int64 lock)
{
  __int64 v7; // rsi
  unsigned int v11; // r14d
  int v12; // ebx
  struct _ERESOURCE *PoolWithTag; // rax
  unsigned int SessionId; // eax
  __int64 v16; // [rsp+20h] [rbp-E0h] BYREF
  UNICODE_STRING DestinationString; // [rsp+28h] [rbp-D8h] BYREF
  __int128 v18; // [rsp+38h] [rbp-C8h] BYREF
  __int128 v19; // [rsp+48h] [rbp-B8h]
  __int128 v20; // [rsp+58h] [rbp-A8h]
  wchar_t Dst[256]; // [rsp+70h] [rbp-90h] BYREF

  v7 = 0;
  v18 = 0;
  v16 = 0;
  v19 = 0;
  v20 = 0;
  v11 = 0;
  v12 = 0;
  DestinationString = 0;
  if ( !(unsigned int)MmIsSessionAddress(CallbackRoutine) )
    goto LABEL_2;
  SessionId = MmGetSessionIdEx((__int64)KeGetCurrentThread()->ApcState.Process);
  v11 = SessionId;
  if ( SessionId == -1 )
    return (unsigned int)-1073741811;
  swprintf_s(Dst, 0x100u, L"\\KernelObjects\\Session%d", SessionId);
  RtlInitUnicodeString(&DestinationString, Dst);
  *((_QWORD *)&v18 + 1) = 0;
  *(_QWORD *)&v19 = &DestinationString;
  LODWORD(v18) = 48;
  DWORD2(v19) = 512;
  v20 = 0;
  v12 = ZwOpenSession(&v16, 0, &v18);
  if ( v12 < 0 || (v7 = v16) == 0 )
  {
    return (unsigned int)-1073741811;
  }
  else
  {
LABEL_2:
    *(_QWORD *)(inPoolWithTag + 0x30) = DriverObject;
    *(_QWORD *)(inPoolWithTag + 8) = inPoolWithTag;
    *(_WORD *)(inPoolWithTag + 0x38) = 1;
    *(_QWORD *)(inPoolWithTag + 0x40) = lock;
    *(_QWORD *)inPoolWithTag = inPoolWithTag;
    *(_DWORD *)(inPoolWithTag + 0x10) = a2;
    *(_DWORD *)(inPoolWithTag + 0x14) = v11;
    *(_QWORD *)(inPoolWithTag + 0x18) = v7;
    *(_QWORD *)(inPoolWithTag + 0x20) = CallbackRoutine;
    *(_QWORD *)(inPoolWithTag + 0x28) = Context;
    *(_BYTE *)(inPoolWithTag + 0x3A) = 0;
    PoolWithTag = (struct _ERESOURCE *)ExAllocatePoolWithTag(NonPagedPoolNx, 0x68u, 0x56706E50u);
    *(_QWORD *)(inPoolWithTag + 0x48) = PoolWithTag;
    if ( PoolWithTag )
      ExInitializeResourceLite(PoolWithTag);
    else
      return (unsigned int)-1073741670;
  }
  return (unsigned int)v12;

如果  EventCategory = EventCategoryDeviceInterfaceChange 那么走下面这个分支
[C++] 纯文本查看 复制代码
restarted = PnpInitializeNotifyEntry(
                    (unsigned int)PoolWithTag,
                    2,
                    (unsigned int)CallbackRoutine,
                    (unsigned int)Context,
                    (__int64)DriverObject,
                    (__int64)&PnpDeviceClassNotifyLock);
      if ( restarted < 0 )
        goto LABEL_33;
      v19 = PoolWithTag + 10;
      *((_OWORD *)PoolWithTag + 5) = *(_OWORD *)EventCategoryData;
      restarted = PnpDeferNotification((__int64)PoolWithTag);
      if ( restarted >= 0 )
      {
        KeAcquireGuardedMutex(&PnpDeviceClassNotifyLock);
        v20 = (char *)&PnpDeviceClassNotifyList
            + 16
            * ((*v19 + *((_DWORD *)PoolWithTag + 21) + *((_DWORD *)PoolWithTag + 22) + *((_DWORD *)PoolWithTag + 23))
             % 0xDu);
        v21 = (char **)*((_QWORD *)v20 + 1);
        if ( *v21 == v20 )
        {
          *PoolWithTag = v20;
          PoolWithTag[1] = v21;
          *v21 = (char *)PoolWithTag;
          *((_QWORD *)v20 + 1) = PoolWithTag;
          KeReleaseGuardedMutex(&PnpDeviceClassNotifyLock);
          if ( ((unsigned __int8)SourceString & 1) != 0 )
          {
            v22 = *(_OWORD *)v19;
            SourceString = 0;
            DestinationString = 0;
            v35 = 0;
            v32 = 3145729;
            v33 = GUID_DEVICE_INTERFACE_ARRIVAL;
            v34 = v22;
            restarted = IopGetDeviceInterfaces((int)PoolWithTag + 80, 0, 0, 0, &SourceString, 0);
            if ( restarted < 0 )
              goto LABEL_33;
            v23 = (WCHAR *)SourceString;
            for ( i = SourceString; *i; i += ((unsigned __int64)DestinationString.Length >> 1) + 1 )
            {
              LODWORD(SourceString) = 0;
              RtlInitUnicodeString(&DestinationString, i);
              p_DestinationString = &DestinationString;
              CurrentServerSilo = ((__int64 (*)(void))PsGetCurrentServerSilo)();
              if ( *((_DWORD *)PoolWithTag + 5) != (unsigned int)PsGetServerSiloServiceSessionId(CurrentServerSilo) )
              {
                SessionIdFromSymbolicName = IopGetSessionIdFromSymbolicName(p_DestinationString);
                if ( SessionIdFromSymbolicName != -1 && *((_DWORD *)PoolWithTag + 5) != SessionIdFromSymbolicName )
                  continue;
              }
              PnpNotifyDriverCallback((__int64)PoolWithTag, (__int64)&v32, &SourceString);
            }
            ExFreePoolWithTag(v23, 0);
          }
          goto LABEL_12;
        }
        goto LABEL_47;
      }
      v29 = 1148218960;
    }

结构体大致是这样
typedef struct _PNP_NOTIFY_ENTRY
{
    LIST_ENTRY ListEntry;          // 0x00 链入全局通知链表
    ULONG EventCategory;           // 0x10 通知类别 (1=HwProfile, 2=DeviceClass, 3=TargetDevice)
    ULONG SessionId;
    ULONG64 SessionHandle;                 // +0x18
    PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine; // 0x20 回调函数地址
    PVOID Context;                 // 0x28 驱动注册时传入的上下文
    PDRIVER_OBJECT DriverObject;   // 0x30 所属驱动对象
    USHORT UNO;         // 0x38
    USHORT UNO1;         // 0x3A
    ULONG UNO2;         //0x3c
    PFAST_MUTEX* Lock;             // 0x40 保护此结构的互斥锁
    PERESOURCE ERESOURCE;           // 0x48
    union {                                // 0x50
        struct {   
            ULONG64 EventCategoryData; // 0x58
            ULONG64 EventCategoryFlags; // 0x68
        };
        struct {
             GUID ClassGuid;
            UNICODE_STRING SymbolicLinkName;        };
    };
        struct {
            PFILE_OBJECT TargetDevice;
            PDEVICE_OBJECT PhysicalDevice;
        };
} PNP_NOTIFY_ENTRY, * PPNP_NOTIFY_ENTRY;

免费评分

参与人数 1威望 +2 吾爱币 +100 热心值 +1 收起 理由
willJ + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| 称霸梦 发表于 2025-11-8 18:56 |楼主
如果类型为4 插入到 PnpKsrNotifyList 链表上
如果类型为3 插入到 PnpTargetDeviceNotifyLock链表上
如果类型为2 插入到 PnpDeviceClassNotifyList 这个链表是一个数组一共十三组每个成员都是一个双向链表
如果类型为1 插入到 PnpProfileNotifyList链表上

1: kd> dq PnpDeviceClassNotifyList l20
fffff806`3412f2c0  fffff806`3412f2c0 fffff806`3412f2c0
fffff806`3412f2d0  fffff806`3412f2d0 fffff806`3412f2d0
fffff806`3412f2e0  ffffad85`e6d3a1b0 ffffad85`eabc28d0
fffff806`3412f2f0  ffffad85`e834a6f0 ffffad85`e834a6f0
fffff806`3412f300  ffffad85`e6d3aa00 ffffad85`e8492f00
fffff806`3412f310  ffffad85`e81caca0 ffffad85`ea533300
fffff806`3412f320  ffffad85`ea533450 ffffad85`ea533450
fffff806`3412f330  fffff806`3412f330 fffff806`3412f330
fffff806`3412f340  fffff806`3412f340 fffff806`3412f340
fffff806`3412f350  fffff806`3412f350 fffff806`3412f350
fffff806`3412f360  ffffad85`e834af40 ffffad85`e834af40
fffff806`3412f370  ffffad85`e81ca7d0 ffffad85`ea532ce0
fffff806`3412f380  ffffad85`e6d3ad80 ffffad85`e81cab50

结构体也是大概是这样
typedef struct _PNP_NOTIFY_ENTRY
{
    LIST_ENTRY ListEntry;          // 0x00 链入全局通知链表
    ULONG EventCategory;           // 0x10 通知类别 (1=HwProfile, 2=DeviceClass, 3=TargetDevice)
    ULONG SessionId;
    ULONG64 SessionHandle;                 // +0x18
    PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine; // 0x20 回调函数地址
    PVOID Context;                 // 0x28 驱动注册时传入的上下文
    PDRIVER_OBJECT DriverObject;   // 0x30 所属驱动对象
    USHORT UNO;         // 0x38
    USHORT UNO1;         // 0x3A
    ULONG UNO2;         //0x3c
    PFAST_MUTEX Lock;             // 0x40 保护此结构的互斥锁
    PERESOURCE ERESOURCE;           // 0x48
    union {// 0x50
        struct {
            GUID ClassGuid;
        };
        struct {
            PFILE_OBJECT TargetDevice;
            PDEVICE_OBJECT PhysicalDevice;
            ULONG64 UNO3;
            ULONG64 UNO4;
        };
        union {
            struct {
                UCHAR Zero;
                UCHAR UNO5;
                USHORT UNO6;
            }UNO7;

        };
        
    };
} PNP_NOTIFY_ENTRY, * PPNP_NOTIFY_ENTRY;
沙发
 楼主| 称霸梦 发表于 2025-11-7 16:44 |楼主
本帖最后由 称霸梦 于 2025-11-7 17:01 编辑

文笔不好怎么弄
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-24 05:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表