Windows ObjectType Hook 之 ParseProcedure
1、背景
Object Type Hook 是基于 Object Type的一种深入的 Hook,比起常用的 SSDT Hook 更为深入。
有关 Object Type 的分析见文章 《Windows驱动开发学习记录-ObjectType Hook之ObjectType结构相关分析》。
这里进行的 Hook 为 其中之一的 ParseProcedure。文章实现注册表 Key 对象的过滤。
2、ParseProcedure 函数声明
见文章 《Windows驱动开发学习记录-ObjectType Hook之ObjectType结构相关分析》。
这里取 x64 环境下结构:
typedef NTSTATUS (*OB_PARSE_METHOD)(
IN PVOID ParseObject,
IN PVOID ObjectType,
IN OUT PACCESS_STATE AccessState,
IN KPROCESSOR_MODE AccessMode,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
OUT PVOID *Object
);
在Win11 x64 环境下结构如下:
typedef NTSTATUS (*OB_PARSE_METHOD)(
IN PVOID ParseObject,
IN PVOID ObjectType,
IN OUT PACCESS_STATE AccessState,
IN KPROCESSOR_MODE AccessMode,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
IN POB_EXTENDED_PARSE_PARAMETERS Paramters, //Win 11上有这个参数
OUT PVOID *Object
);
3、Key 对象过滤
3.1 实验目标
这里实现对注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 键值过滤,达到不能打开该键的逻辑。
3.2 实现逻辑
经过实验分析以及在小节 2 中的结构声明,对于路径的判断可以先用 ObQueryNameString 查询参数 ParseObject,得到一个路径。
但该路径并不一定是完整的全路径,需要再附加上参数 RemainingName 所对应的路径,加上该路径后的就是完整的全路径。
Key对象的指针是导出的,可以直接使用,名称为 CmKeyObjectType, 也可以参考 《遍历Windows内核ObjectType》来获取。
3.3 实现代码
#if DBG
#define KDPRINT(projectName, format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,\
projectName "::【" __FUNCTION__ "】" ##format, \
##__VA_ARGS__ )
#else
#define KDPRINT(format, ...)
#endif
typedef struct _OBJECT_TYPE_FLAGS {
UCHAR CaseInsensitive : 1;
UCHAR UnnamedObjectsOnly : 1;
UCHAR UseDefaultObject : 1;
UCHAR SecurityRequired : 1;
UCHAR MaintainHandleCount : 1;
UCHAR MaintainTypeList : 1;
UCHAR SupportsObjectCallbacks : 1;
UCHAR CacheAligned : 1;
}OBJECT_TYPE_FLAGS, * P_OBJECT_TYPE_FLAGS;
typedef struct _OB_EXTENDED_PARSE_PARAMETERS
{
USHORT Length;
ULONG RestrictedAccessMask;
PVOID Silo;
}OB_EXTENDED_PARSE_PARAMETERS, *POB_EXTENDED_PARSE_PARAMETERS;
typedef struct _OBJECT_TYPE_INITIALIZER {
USHORT wLength;
OBJECT_TYPE_FLAGS ObjectTypeFlags;
ULONG ObjcetTypeCode;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
ULONG RetainAccess;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
PVOID DumpProcedure;
PVOID OpenProcedure;
PVOID CloseProcedure;
PVOID DeleteProcedure;
union
{
PVOID ParseProcedure;
PVOID ParseProcedureEx;
};
PVOID SecurityProcedure;
PVOID QueryNameProcedure;
PVOID OkayToCloseProcedure;
}OBJECT_TYPE_INITIALIZER, * POBJECT_TYPE_INITIALIZER;
typedef struct _OBJECT_TYPE_EX {
LIST_ENTRY TypeList;
UNICODE_STRING Name;
ULONGLONG DefaultObject;
ULONG Index;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
OBJECT_TYPE_INITIALIZER TypeInfo;
ULONGLONG TypeLock;
ULONG Key;
LIST_ENTRY CallbackList;
}OBJECT_TYPE_EX, * POBJECT_TYPE_EX;
typedef enum _OB_OPEN_REASON {
ObCreateHandle,
ObOpenHandle,
ObDuplicateHandle,
ObInheritHandle,
ObMaxOpenReason
} OB_OPEN_REASON;
typedef
NTSTATUS
(NTAPI* PPARSE_PROCEDURE_EX)(
IN PVOID ParseObject,
IN POBJECT_TYPE ObjectType,
IN OUT PACCESS_STATE AccessState,
IN CHAR Flag,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
IN POB_EXTENDED_PARSE_PARAMETERS Paramters, //Win 11上有这个参数
OUT PVOID* Object
);
typedef struct _OBJECT_TYPE_HOOK_INFORMATION
{
POBJECT_TYPE_EX pHookedObject;
PPARSE_PROCEDURE_EX pOringinalParseProcedureAddress;
}OBJECT_TYPE_HOOK_INFORMATION, * POBJECT_TYPE_HOOK_INFORMATION;
OBJECT_TYPE_HOOK_INFORMATION g_HookInfomation = { 0 };
UNICODE_STRING g_usRunKeyName =
RTL_CONSTANT_STRING(L"*\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN*");
UNICODE_STRING g_usSeperator = RTL_CONSTANT_STRING(L"\\");
NTSTATUS
NTAPI
CustomKeyParseProcedure(
IN PVOID ParseObject,
IN POBJECT_TYPE ObjectType,
IN OUT PACCESS_STATE AccessState,
IN CHAR Flag,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
IN POB_EXTENDED_PARSE_PARAMETERS Paramters,
OUT PVOID* Object)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ulRet = 0;
BOOLEAN bFilterKey = false;
if (ParseObject && (ObjectType == *CmKeyObjectType))
{
POBJECT_NAME_INFORMATION pName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(
NonPagedPool, 1024, 'Mut');
if (pName)
{
ntStatus = ObQueryNameString(ParseObject, pName, 1024, &ulRet);
if (NT_SUCCESS(ntStatus))
{
//KDPRINT("【ObjectTypeHook】", "ParseObject is %wZ\r\n", &pName->Name);
if (RemainingName)
{
//KDPRINT("【ObjectTypeHook】", "CompleteName is %wZ\r\n", CompleteName);
//KDPRINT("【ObjectTypeHook】", "RemainingName is %wZ\r\n", RemainingName);
pName->Name.MaximumLength = 1024 - sizeof(UNICODE_STRING);
RtlAppendUnicodeStringToString(&pName->Name, &g_usSeperator);
ntStatus = RtlAppendUnicodeStringToString(&pName->Name, RemainingName);
if (NT_SUCCESS(ntStatus))
{
if (FsRtlIsNameInExpression(&g_usRunKeyName, &pName->Name, true, NULL))
{
KDPRINT("【ObjectTypeHook】", "Need Filter Key Path Is %wZ\r\n", &pName->Name);
KDPRINT("【ObjectTypeHook】", "Denied Process Id is 0x%08d\r\n", PsGetCurrentProcessId());
bFilterKey = true;
}
}
}
}
ExFreePoolWithTag(pName, 'name');
}
}
if (bFilterKey)
{
return STATUS_ACCESS_DENIED;
}
else
{
ntStatus = STATUS_SUCCESS;
if (g_HookInfomation.pOringinalParseProcedureAddress)
{
ntStatus = g_HookInfomation.pOringinalParseProcedureAddress(
ParseObject, ObjectType, AccessState, Flag, Attributes, CompleteName, RemainingName, Context,
SecurityQos, Paramters, Object);
}
return ntStatus;
}
}
void UnHookObjectType()
{
KDPRINT("【ObjectTypeHook】", "UnHook...\r\n");
if (g_HookInfomation.pHookedObject)
{
InterlockedExchangePointer(
(PVOID*)(&g_HookInfomation.pHookedObject->TypeInfo.ParseProcedure),
g_HookInfomation.pOringinalParseProcedureAddress);
}
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UNREFERENCED_PARAMETER(pDriverObject);
KDPRINT("【ObjectTypeHook】", "CurrentProcessId : 0x%p CurrentIRQL : 0x%u \r\n",
PsGetCurrentProcessId(),
KeGetCurrentIrql());
UnHookObjectType();
}
EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath)
{
UNREFERENCED_PARAMETER(pDriverObject);
UNREFERENCED_PARAMETER(pRegistryPath);
NTSTATUS ntStatus = STATUS_SUCCESS;
KDPRINT("【ObjectTypeHook】", " Hello Kernel World! CurrentProcessId:0x%p CurrentIRQL:0x%u\r\n",
PsGetCurrentProcessId(),
KeGetCurrentIrql());
pDriverObject->DriverUnload = DriverUnload;
g_HookInfomation.pHookedObject = (POBJECT_TYPE_EX)(*CmKeyObjectType);
g_HookInfomation.pOringinalParseProcedureAddress =
(PPARSE_PROCEDURE_EX)(((POBJECT_TYPE_EX)(*CmKeyObjectType))->TypeInfo.ParseProcedure);
InterlockedExchangePointer(
(PVOID*)(&g_HookInfomation.pHookedObject->TypeInfo.ParseProcedure),
CustomKeyParseProcedure);
return ntStatus;
}
3.4 实现效果
安装驱动后去打开注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 键,效果如下: