好友
阅读权限10
听众
最后登录1970-1-1
|
楼主
称霸梦
发表于 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 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
查看全部评分
|