1、背景
Object Type Hook 是基于 Object Type的一种深入的 Hook,比起常用的 SSDT Hook 更为深入。
有关 Object Type 的分析见文章 《Windows驱动开发学习记录-ObjectType Hook之ObjectType结构相关分析》。
这里进行的 Hook 为 其中之一的 OpenProcedure。文章分两部分,分别实现 Event 对象和 Process 对象的过滤。
2、OpenProcedure 函数声明
见文章 《Windows驱动开发学习记录-ObjectType Hook之ObjectType结构相关分析》。
这里取 x64 环境下结构:
typedef NTSTATUS (*OB_OPEN_METHOD)(IN OB_OPEN_REASON OpenReason,IN CHAR Flag,IN PEPROCESS Process OPTIONAL,IN PVOID Object,IN OUT PACCESS_MASK GrantedAccess,IN ULONG HandleCount);
3、Event 对象过滤
3.1 实验目标
这里实验的目标魔兽争霸3,正常情况下只能单开,如下图所示:
这里多开即会提示已经运行的消息,使用的是大多数程序单例运行的处理逻辑,启动时创建一个命名事件,然后进行相关判断。
3.2 魔兽的IDA分析
用 IDA 分析魔兽的 Frozen Throne.exe,如下:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{......v4 = 0;ExitCode = 0;v5 = GetTickCount() + 25000;v19 = v5;hObject = CreateEventA(0, 0, 0, LauncherName);if (GetLastError() == 183){CloseHandle(hObject);result = 0;}else{v17 = CreateEventA(0, 0, 0, aWarcraftIiiGam);if (GetLastError() == 183){LoadStringA(hInstance, 0xCu, Buffer, 260);LoadStringA(hInstance, 0xDu, Caption, 260);MessageBoxA(0, Buffer, Caption, 0);CloseHandle(v17);result = 0;}else{......
其中 LanucherName 和 aWarcraftIiiGam 定义如下:
.data:00408048 ; CHAR aWarcraftIiiGam[]
.data:00408048 aWarcraftIiiGam db 'Warcraft III Game Application',0
.data:00408048 ; DATA XREF: WinMain(x,x,x,x):loc_40105F↑o
.data:00408066 align 4
.data:00408068 ; CHAR LauncherName[]
.data:00408068 LauncherName db 'WARCRAFT_III_LAUNCHER',0
可以看出逻辑是创建这两个命名事件,如果返回 183,即 当文件已存在时,无法创建该文件的情况,表示已经在运行了,然后弹出上边的对话框。
我们这里要实现的功能就是让它在创建命名事件时不返回 183,而是直接返回拒绝访问,按以上的逻辑就可以实现魔兽的多开。
3.3 实现代码
#pragma once
#include <ntifs.h>#if DBG
#define KDPRINT(projectName, format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,\projectName "::【" __FUNCTION__ "】" ##format, \##__VA_ARGS__ )
#else
#define KDPRINT(format, ...)
#endiftypedef 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 _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;PVOID ParseProcedure;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* POPEN_PROCEDURE)(IN OB_OPEN_REASON Reason,IN CHAR cUnnamed,IN PEPROCESS Process OPTIONAL,IN PVOID ObjectBody,IN PACCESS_MASK GrantedAccess,IN ULONG HandleCount);typedef struct _OBJECT_TYPE_HOOK_INFORMATION
{POBJECT_TYPE_EX pHookedObject;POPEN_PROCEDURE pOringinalOpenProcedureAddress;
}OBJECT_TYPE_HOOK_INFORMATION, * POBJECT_TYPE_HOOK_INFORMATION;OBJECT_TYPE_HOOK_INFORMATION g_HookInfomation = { 0 };UNICODE_STRING g_usEventWarIIIOK = RTL_CONSTANT_STRING(L"*WARCRAFT_III_OK*");
UNICODE_STRING g_usEventWarIIIGameApplication = RTL_CONSTANT_STRING(L"*WARCRAFT III GAME APPLICATION*");
UNICODE_STRING g_usEventWarIIILauncher = RTL_CONSTANT_STRING(L"*WARCRAFT_III_LAUNCHER*");
PVOID GetObTypeIndexTable()
{UNICODE_STRING usObGetObjectType = RTL_CONSTANT_STRING(L"ObGetObjectType");PVOID pGetObTypeIndexTable = NULL;PVOID pObGetObjectType = (PVOID)MmGetSystemRoutineAddress(&usObGetObjectType);do{if (!pObGetObjectType){KDPRINT("【ObjectTypeHook】", "MmGetSystemRoutineAddress Failed! \r\n");break;}PUCHAR pStartAddress = (PUCHAR)pObGetObjectType;PUCHAR pTempAddress = pStartAddress;for (; pTempAddress < pStartAddress + PAGE_SIZE; pTempAddress++){if ((*(pTempAddress - 3) == 0x48) &&(*(pTempAddress - 2) == 0x8d) &&(*(pTempAddress - 1) == 0x0d) &&(*(pTempAddress + 4) == 0x48) &&(*(pTempAddress + 5) == 0x8b) &&(*(pTempAddress + 6) == 0x04) &&(*(pTempAddress + 7) == 0xc1)){LONG lOffset = *(PLONG)(pTempAddress);pGetObTypeIndexTable = pTempAddress + 4 + lOffset;break;}}} while (false);if (pGetObTypeIndexTable){KDPRINT("【ObRegisterCallback】", "Found ObTypeIndexTable Address:0x%p \r\n", pGetObTypeIndexTable);}else{KDPRINT("【ObjectTypeHook】", "ObTypeIndexTable Not Found!\r\n");}return pGetObTypeIndexTable;
}void HookObjectType(PVOID pObTypeIndexTable, PUNICODE_STRING pUsObjectTypeName, PVOID pHookFunction)
{if (pObTypeIndexTable){PUCHAR pStartAddress = ((PUCHAR)pObTypeIndexTable + 8 * 2); //从第2个开始POBJECT_TYPE_EX* pTempObjectType = (POBJECT_TYPE_EX*)(pStartAddress);ULONG ulIndex = 0;PVOID pOpenProcedureAddress = NULL;while (*pTempObjectType != NULL){KDPRINT("【ObjectTypeHook】", "Index:%02ld Address:0x%p Name:%wZ\r\n",ulIndex,*pTempObjectType,&(*pTempObjectType)->Name);if (RtlCompareUnicodeString(&(*pTempObjectType)->Name, pUsObjectTypeName, true) == 0){KDPRINT("【ObjectTypeHook】", "Found Target, Hooking...\r\n");g_HookInfomation.pHookedObject = *pTempObjectType;g_HookInfomation.pOringinalOpenProcedureAddress =(POPEN_PROCEDURE)(*pTempObjectType)->TypeInfo.OpenProcedure;pOpenProcedureAddress = &((*pTempObjectType)->TypeInfo.OpenProcedure);InterlockedExchangePointer((PVOID*)pOpenProcedureAddress, pHookFunction);}pTempObjectType++;ulIndex++;}}
}NTSTATUS
NTAPI
CustomEventOpen(IN OB_OPEN_REASON Reason,IN CHAR Flag,IN PEPROCESS Process OPTIONAL,IN PVOID ObjectBody,IN PACCESS_MASK GrantedAccess,IN ULONG HandleCount)
{NTSTATUS ntStatus = STATUS_SUCCESS;ULONG ulRet = 0;BOOLEAN bFilterEvent = false;if (Reason == OB_OPEN_REASON::ObCreateHandle){if (ObjectBody){POBJECT_NAME_INFORMATION pName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, 1024, 'Mut');if (pName){ntStatus = ObQueryNameString(ObjectBody, pName, 1024, &ulRet);if (NT_SUCCESS(ntStatus)){if (//FsRtlIsNameInExpression(&g_usWarIIIOK, &pName->Name, true, NULL) ||FsRtlIsNameInExpression(&g_usEventWarIIIGameApplication, &pName->Name, true, NULL) ||FsRtlIsNameInExpression(&g_usEventWarIIILauncher, &pName->Name, true, NULL)){KDPRINT("【ObjectTypeHook】", "Need Filter Event Name Is %wZ\r\n", &pName->Name);bFilterEvent = true;}}ExFreePoolWithTag(pName, 'name');}}}if (bFilterEvent){return STATUS_ACCESS_DENIED;}else{ntStatus = STATUS_SUCCESS;if (g_HookInfomation.pOringinalOpenProcedureAddress){ntStatus = g_HookInfomation.pOringinalOpenProcedureAddress(Reason, Flag, Process, ObjectBody, GrantedAccess, HandleCount);}return ntStatus;}}void UnHookObjectType()
{KDPRINT("【ObjectTypeHook】", "UnHook...\r\n");if (g_HookInfomation.pHookedObject){InterlockedExchangePointer((PVOID*)(&g_HookInfomation.pHookedObject->TypeInfo.OpenProcedure), g_HookInfomation.pOringinalOpenProcedureAddress);}
}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;UNICODE_STRING usEventName = RTL_CONSTANT_STRING(L"Event");PVOID pGetObTypeIndexTable = GetObTypeIndexTable();if (pGetObTypeIndexTable){HookObjectType(pGetObTypeIndexTable, &usEventName, CustomEventOpen);}return ntStatus;
}
其中 GetObTypeIndexTable 是利用特征码搜索 Object Type, 详细参见《遍历Windows内核ObjectType》。
3.4 实现效果
安装驱动效果如下:
再打开魔兽争霸,效果如下:
4、Process 对象过滤
实现原理同 Event 对象过滤,只不过对象换成了 Process。
在任务管理器结束进程时要先打开目标进程,然后再结束,我这里在打开进程时直接返回失败来实现相关过滤。
4.1 实现代码
#if DBG
#define KDPRINT(projectName, format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,\projectName "::【" __FUNCTION__ "】" ##format, \##__VA_ARGS__ )
#else
#define KDPRINT(format, ...)
#endiftypedef 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 _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;PVOID ParseProcedure;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* POPEN_PROCEDURE)(IN OB_OPEN_REASON Reason,IN CHAR cUnnamed,IN PEPROCESS Process OPTIONAL,IN PVOID ObjectBody,IN PACCESS_MASK GrantedAccess,IN ULONG HandleCount);typedef struct _OBJECT_TYPE_HOOK_INFORMATION
{POBJECT_TYPE_EX pHookedObject;POPEN_PROCEDURE pOringinalOpenProcedureAddress;
}OBJECT_TYPE_HOOK_INFORMATION, * POBJECT_TYPE_HOOK_INFORMATION;OBJECT_TYPE_HOOK_INFORMATION g_HookInfomation = { 0 };PVOID GetObTypeIndexTable()
{UNICODE_STRING usObGetObjectType = RTL_CONSTANT_STRING(L"ObGetObjectType");PVOID pGetObTypeIndexTable = NULL;PVOID pObGetObjectType = (PVOID)MmGetSystemRoutineAddress(&usObGetObjectType);do{if (!pObGetObjectType){KDPRINT("【ObjectTypeHook】", "MmGetSystemRoutineAddress Failed! \r\n");break;}PUCHAR pStartAddress = (PUCHAR)pObGetObjectType;PUCHAR pTempAddress = pStartAddress;for (; pTempAddress < pStartAddress + PAGE_SIZE; pTempAddress++){if ((*(pTempAddress - 3) == 0x48) &&(*(pTempAddress - 2) == 0x8d) &&(*(pTempAddress - 1) == 0x0d) &&(*(pTempAddress + 4) == 0x48) &&(*(pTempAddress + 5) == 0x8b) &&(*(pTempAddress + 6) == 0x04) &&(*(pTempAddress + 7) == 0xc1)){LONG lOffset = *(PLONG)(pTempAddress);pGetObTypeIndexTable = pTempAddress + 4 + lOffset;break;}}} while (false);if (pGetObTypeIndexTable){KDPRINT("【ObRegisterCallback】", "Found ObTypeIndexTable Address:0x%p \r\n", pGetObTypeIndexTable);}else{KDPRINT("【ObjectTypeHook】", "ObTypeIndexTable Not Found!\r\n");}return pGetObTypeIndexTable;
}void HookObjectType(PVOID pObTypeIndexTable, PUNICODE_STRING pUsObjectTypeName, PVOID pHookFunction)
{if (pObTypeIndexTable){PUCHAR pStartAddress = ((PUCHAR)pObTypeIndexTable + 8 * 2); //从第2个开始POBJECT_TYPE_EX* pTempObjectType = (POBJECT_TYPE_EX*)(pStartAddress);ULONG ulIndex = 0;PVOID pOpenProcedureAddress = NULL;while (*pTempObjectType != NULL){KDPRINT("【ObjectTypeHook】", "Index:%02ld Address:0x%p Name:%wZ\r\n",ulIndex,*pTempObjectType,&(*pTempObjectType)->Name);if (RtlCompareUnicodeString(&(*pTempObjectType)->Name, pUsObjectTypeName, true) == 0){KDPRINT("【ObjectTypeHook】", "Found Target, Hooking...\r\n");g_HookInfomation.pHookedObject = *pTempObjectType;g_HookInfomation.pOringinalOpenProcedureAddress =(POPEN_PROCEDURE)(*pTempObjectType)->TypeInfo.OpenProcedure;pOpenProcedureAddress = &((*pTempObjectType)->TypeInfo.OpenProcedure);InterlockedExchangePointer((PVOID*)pOpenProcedureAddress, pHookFunction);}pTempObjectType++;ulIndex++;}}
}NTSTATUS
NTAPI
CustomProcessOpen(IN OB_OPEN_REASON Reason,IN CHAR Flag,IN PEPROCESS Process OPTIONAL,IN PVOID ObjectBody,IN PACCESS_MASK GrantedAccess,IN ULONG HandleCount)
{NTSTATUS ntStatus = STATUS_SUCCESS;BOOLEAN bFilterProcess = false;if (Reason == OB_OPEN_REASON::ObOpenHandle){if (ObjectBody){POBJECT_NAME_INFORMATION pName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, 1024, 'Proc');if (pName){HANDLE hProcessId = PsGetProcessId((PEPROCESS)ObjectBody);if (hProcessId == (HANDLE)5284) // exporer.exe{KDPRINT("【ObjectTypeHook】", "Need Filter Mutex Name Is %wZ\r\n", &pName->Name);bFilterProcess = true;}ExFreePoolWithTag(pName, 'Proc');}}}if (bFilterProcess){return STATUS_ACCESS_DENIED;}else{ntStatus = STATUS_SUCCESS;if (g_HookInfomation.pOringinalOpenProcedureAddress){ntStatus = g_HookInfomation.pOringinalOpenProcedureAddress(Reason, Flag, Process, ObjectBody, GrantedAccess, HandleCount);}return ntStatus;}}void UnHookObjectType()
{KDPRINT("【ObjectTypeHook】", "UnHook...\r\n");if (g_HookInfomation.pHookedObject){InterlockedExchangePointer((PVOID*)(&g_HookInfomation.pHookedObject->TypeInfo.OpenProcedure), g_HookInfomation.pOringinalOpenProcedureAddress);}
}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;UNICODE_STRING usEventName = RTL_CONSTANT_STRING(L"Process");PVOID pGetObTypeIndexTable = GetObTypeIndexTable();if (pGetObTypeIndexTable){HookObjectType(pGetObTypeIndexTable, &usEventName, CustomProcessOpen);}return ntStatus;
}
4.2 实现效果
在安装驱动后用任务管理器结束 explorer.exe,在测试机上 PID 为 5284,效果如下: