Object Type Hook 是基于 Object Type的一种深入的 Hook,比起常用的 SSDT Hook 更为深入。
有关 Object Type 的分析见文章 《Windows驱动开发学习记录-ObjectType Hook之ObjectType结构相关分析》。
这里进行的 Hook 为 其中之一的 OpenProcedure。文章分两部分,分别实现 Event 对象和 Process 对象的过滤。
见文章 《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,正常情况下只能单开,如下图所示:
这里多开即会提示已经运行的消息,使用的是大多数程序单例运行的处理逻辑,启动时创建一个命名事件,然后进行相关判断。
用 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,而是直接返回拒绝访问,按以上的逻辑就可以实现魔兽的多开。
#pragma once
#include
#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 _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》。
安装驱动效果如下:
再打开魔兽争霸,效果如下:
实现原理同 Event 对象过滤,只不过对象换成了 Process。
在任务管理器结束进程时要先打开目标进程,然后再结束,我这里在打开进程时直接返回失败来实现相关过滤。
#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 _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;
}
在安装驱动后用任务管理器结束 explorer.exe,在测试机上 PID 为 5284,效果如下: