Windows Notification Facility (WNF)组件的详细介绍
前言
关于Windows Notification Facility (WNF)组件,或许我和你一样,从来不知道这个组件,并且互联网上关于该组件的信息也很少。能查到的也只是如下信息:
14. Reverse engineer the following Windows kernel functions.
The result of this exercise will be used in the next exercise.
• ExSubscribeWnfStateChange
• ExQueryWnfStateData
15. Write a driver that gets notified when an application is using the microphone.
Print its pid.
Hints:
• check contentDeliveryManager_Utilities.dll for the WNF StateName.
• some interesting info is available here:
http://redplait.blogspot.com/2017/08/wnf-ids-from-perfntcdll.html
Windows Notification Facility(WNF)是一个不是很知名的内核组件,在整个系统中的主要任务就是用于通知,相当于通知中心。它既可以在内核模式中使用,也可以在用户空间 (USER-LAND)中使用,其中包含一组导出的但显然没有文档化的API函数和相关的数据结构。应用程序可以订阅特定类型的事件(由StateName标识),以便在每次发生状态更改时进行通知(可以与StateData关联)。另一方面,发布通知的组件负责提供与通知一起发送的数据并触发事件。
应该注意的是,WNF状态名称可以实例化(Scope)到单个进程,silo(Windows容器)或整个设备中。例如,如果应用程序在silo内运行,则只会通知其自身容器内发生的SiloScope内的事件。
数据结构
WNF中涉及很多数据结构,以下就是它们在内存中关系的简化图。
WNF_NAME_INSTANCE结构在内存中表示事件或WNF状态名称的实例,这些结构在二叉树中排序,并链接到事件发生的scope,scope属性(使用 scope 属性,可以将数据单元格与表头单元格联系起来。)确定组件能够查看或访问的信息,它们还支持为相同的状态名实例化不同的数据。
有五种可能的scope类型,定义如下。
typedef enum _WNF_DATA_SCOPE{
WnfDataScopeSystem = 0x0,
WnfDataScopeSession = 0x1,
WnfDataScopeUser = 0x2,
WnfDataScopeProcess = 0x3,
WnfDataScopeMachine = 0x4,} WNF_DATA_SCOPE;
使用WNF_SCOPE_INSTANCE结构标识的作用域按类型存储在双向链接列表中,并且它们的表头保存在特定于silo的WNF_SCOPE_MAP中。
当组件订阅WNF状态名称时,将创建新的WNF_SUBSCRIPTION结构并将其添加到属于关联的WNF_NAME_INSTANCE的链接列表中。如果通知订阅者使用的是低级API(例如下面描述的API),则会在WNF_SUBSCRIPTION中添加回调,并在需要通知组件时调用。
WNF_PROCESS_CONTEXT对象会跟踪特定通知订阅者进程涉及的所有不同结构。它还存储用于通知进程的KEVENT。可以通过EPROCESS对象访问此上下文,也可以通过抓取nt!ExpWnfProcessesListHead指向的双向链表来访问此上下文,你可以在下面找到这些连接的示意图。
0x906指的是什么呢?它与WNF使用的所有结构都有一个描述结构类型和大小的小头(Windows文件系统相关数据结构中常见的情况)有关。
typedef struct _WNF_CONTEXT_HEADER{
CSHORT NodeTypeCode;
CSHORT NodeByteSize;} WNF_CONTEXT_HEADER, *PWNF_CONTEXT_HEADER;
这个头文件在调试时非常方便,因为很容易发现内存中的对象,下面是一些WNF结构的节点类型代码。
#define WNF_SCOPE_MAP_CODE ((CSHORT)0x901)
#define WNF_SCOPE_INSTANCE_CODE ((CSHORT)0x902)
#define WNF_NAME_INSTANCE_CODE ((CSHORT)0x903)
#define WNF_STATE_DATA_CODE ((CSHORT)0x904)
#define WNF_SUBSCRIPTION_CODE ((CSHORT)0x905)
#define WNF_PROCESS_CONTEXT_CODE ((CSHORT)0x906)
反转函数
掌握了这些背景知识后,让我们开始学习如何使用该组件,第一部分实际上是反转下列函数,以便了解其目的:
· ExSubscribeWnfStateChange
· ExQueryWnfStateData
ExSubscribeWnfStateChange
NTSTATUSExSubscribeWnfStateChange (
_Out_ptr_ PWNF_SUBSCRIPTION* Subscription,
_In_ PWNF_STATE_NAME StateName,
_In_ ULONG DeliveryOption,
_In_ WNF_CHANGE_STAMP CurrentChangeStamp,
_In_ PWNF_CALLBACK Callback,
_In_opt_ PVOID CallbackContext
);
ExSubscribeWnfStateChange允许在WNF引擎中注册新的订阅,它将StateName作为参数之一,指定我们感兴趣的事件类型,并在触发通知时调用回调函数。它还会返回一个新的订阅指针,该指针可用于查询与通知关联的数据。
在内部,此函数仅将执行流转移到private counterpart(ExpWnfSubscribeWnfStateChange),由它处理所有进程。
由于WNF状态名称以不透明格式存储,因此ExpWnfSubscribeWnfStateChange首先使用ExpCaptureWnfStateName解码ID的“清洁”版本。
这个“清洁”的WNF状态名称可以解码如下:
#define WNF_XOR_KEY 0x41C64E6DA3BC0074
ClearStateName = StateName ^ WNF_XOR_KEY;
前言
关于Windows Notification Facility (WNF)组件,或许我和你一样,从来不知道这个组件,并且互联网上关于该组件的信息也很少。能查到的也只是如下信息:
14. Reverse engineer the following Windows kernel functions.
The result of this exercise will be used in the next exercise.
• ExSubscribeWnfStateChange
• ExQueryWnfStateData
15. Write a driver that gets notified when an application is using the microphone.
Print its pid.
Hints:
• check contentDeliveryManager_Utilities.dll for the WNF StateName.
• some interesting info is available here:
http://redplait.blogspot.com/2017/08/wnf-ids-from-perfntcdll.html
Windows Notification Facility(WNF)是一个不是很知名的内核组件,在整个系统中的主要任务就是用于通知,相当于通知中心。它既可以在内核模式中使用,也可以在用户空间 (USER-LAND)中使用,其中包含一组导出的但显然没有文档化的API函数和相关的数据结构。应用程序可以订阅特定类型的事件(由StateName标识),以便在每次发生状态更改时进行通知(可以与StateData关联)。另一方面,发布通知的组件负责提供与通知一起发送的数据并触发事件。
应该注意的是,WNF状态名称可以实例化(Scope)到单个进程,silo(Windows容器)或整个设备中。例如,如果应用程序在silo内运行,则只会通知其自身容器内发生的SiloScope内的事件。
数据结构
WNF中涉及很多数据结构,以下就是它们在内存中关系的简化图。
WNF_NAME_INSTANCE结构在内存中表示事件或WNF状态名称的实例,这些结构在二叉树中排序,并链接到事件发生的scope,scope属性(使用 scope 属性,可以将数据单元格与表头单元格联系起来。)确定组件能够查看或访问的信息,它们还支持为相同的状态名实例化不同的数据。
有五种可能的scope类型,定义如下。
typedef enum _WNF_DATA_SCOPE{
WnfDataScopeSystem = 0x0,
WnfDataScopeSession = 0x1,
WnfDataScopeUser = 0x2,
WnfDataScopeProcess = 0x3,
WnfDataScopeMachine = 0x4,} WNF_DATA_SCOPE;
使用WNF_SCOPE_INSTANCE结构标识的作用域按类型存储在双向链接列表中,并且它们的表头保存在特定于silo的WNF_SCOPE_MAP中。 内容来自无奈安全网
当组件订阅WNF状态名称时,将创建新的WNF_SUBSCRIPTION结构并将其添加到属于关联的WNF_NAME_INSTANCE的链接列表中。如果通知订阅者使用的是低级API(例如下面描述的API),则会在WNF_SUBSCRIPTION中添加回调,并在需要通知组件时调用。
WNF_PROCESS_CONTEXT对象会跟踪特定通知订阅者进程涉及的所有不同结构。它还存储用于通知进程的KEVENT。可以通过EPROCESS对象访问此上下文,也可以通过抓取nt!ExpWnfProcessesListHead指向的双向链表来访问此上下文,你可以在下面找到这些连接的示意图。
0x906指的是什么呢?它与WNF使用的所有结构都有一个描述结构类型和大小的小头(Windows文件系统相关数据结构中常见的情况)有关。
typedef struct _WNF_CONTEXT_HEADER{
CSHORT NodeTypeCode;
CSHORT NodeByteSize;} WNF_CONTEXT_HEADER, *PWNF_CONTEXT_HEADER;
这个头文件在调试时非常方便,因为很容易发现内存中的对象,下面是一些WNF结构的节点类型代码。 本文来自无奈人生安全网
#define WNF_SCOPE_MAP_CODE ((CSHORT)0x901)
#define WNF_SCOPE_INSTANCE_CODE ((CSHORT)0x902)
#define WNF_NAME_INSTANCE_CODE ((CSHORT)0x903)
#define WNF_STATE_DATA_CODE ((CSHORT)0x904)
#define WNF_SUBSCRIPTION_CODE ((CSHORT)0x905)
#define WNF_PROCESS_CONTEXT_CODE ((CSHORT)0x906)
反转函数
掌握了这些背景知识后,让我们开始学习如何使用该组件,第一部分实际上是反转下列函数,以便了解其目的:
· ExSubscribeWnfStateChange
· ExQueryWnfStateData
ExSubscribeWnfStateChange
NTSTATUSExSubscribeWnfStateChange (
_Out_ptr_ PWNF_SUBSCRIPTION* Subscription,
_In_ PWNF_STATE_NAME StateName,
_In_ ULONG DeliveryOption,
_In_ WNF_CHANGE_STAMP CurrentChangeStamp,
_In_ PWNF_CALLBACK Callback, 内容来自无奈安全网
_In_opt_ PVOID CallbackContext
);
ExSubscribeWnfStateChange允许在WNF引擎中注册新的订阅,它将StateName作为参数之一,指定我们感兴趣的事件类型,并在触发通知时调用回调函数。它还会返回一个新的订阅指针,该指针可用于查询与通知关联的数据。
在内部,此函数仅将执行流转移到private counterpart(ExpWnfSubscribeWnfStateChange),由它处理所有进程。
由于WNF状态名称以不透明格式存储,因此ExpWnfSubscribeWnfStateChange首先使用ExpCaptureWnfStateName解码ID的“清洁”版本。
这个“清洁”的WNF状态名称可以解码如下:
#define WNF_XOR_KEY 0x41C64E6DA3BC0074
ClearStateName = StateName ^ WNF_XOR_KEY;