我是靠谱客的博主 聪慧白昼,最近开发中收集的这篇文章主要介绍遍历Windows内核ObjectType一、背景二、几个主要的内核变量三、代码实现四、调试结果五、结束语,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、背景

        Windows内核中有很多类型,例如PROCESS、THREAD、FILE、MUTANT,这些类型都由对象管理器集中管理,见下图:

        其中有些对象类型是导出的,例如有IoDriverObjectType, PsProcessType等,有些是文档化的,有些是导出的,还有的是未导出的。在使用未导出的对象指针时就得想办法获得,在此遍历对象类型及其相关信息,使用未导出的对象类型时可以直接使用,对象类型结构之类不作详细分析,直接上相关实现的分析。

 

二、几个主要的内核变量

ObpTypeObjectType、ObpObjectTypes、ObTypeIndexTable。

  • ObpTypeObjectType

这个表保存的是原始对象名称为"Type"的对象类型。Windbg调试Win7格式化如下:

5: kd>  dq nt!ObpTypeObjectType
fffff800`0666e5a8  fffffa80`30e4c530 00000000`00000000
fffff800`0666e5b8  00000000`00000000 fffffa80`30e4c530
fffff800`0666e5c8  fffffa80`30e4c3e0 fffffa80`30e4c290
fffff800`0666e5d8  fffffa80`30e525a0 fffffa80`30e52380
fffff800`0666e5e8  fffffa80`30e52230 fffffa80`30ee0080
fffff800`0666e5f8  fffffa80`30ee0f30 fffffa80`30ee0de0
fffff800`0666e608  fffffa80`30ee1080 fffffa80`30f5a940
fffff800`0666e618  fffffa80`30f4ca10 fffffa80`30f4c8c0

然后取第一个数据查看如下:

5: kd> dt _object_type fffffa80`30e4c530
ntdll!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xfffffa80`30e4c4e0 - 0xfffffa80`3205db20 ]
   +0x010 Name             : _UNICODE_STRING "Type"
   +0x020 DefaultObject    : 0xfffff800`0666e7a0 Void
   +0x028 Index            : 0x2 ''
   +0x02c TotalNumberOfObjects : 0x2a
   +0x030 TotalNumberOfHandles : 0
   +0x034 HighWaterNumberOfObjects : 0x2a
   +0x038 HighWaterNumberOfHandles : 0
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
   +0x0b8 Key              : 0x546a624f
   +0x0c0 CallbackList     : _LIST_ENTRY [ 0xfffffa80`30e4c5f0 - 0xfffffa80`30e4c5f0 ]

这个就是第一个名为Type的ObjectType。再取后边第五个非fffffa80`30e4c530的看:

5: kd> dt _object_type fffffa80`30e4c3e0
ntdll!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xfffffa80`30e4c3e0 - 0xfffffa80`30e4c3e0 ]
   +0x010 Name             : _UNICODE_STRING "Directory"
   +0x020 DefaultObject    : 0xfffff800`0666e7a0 Void
   +0x028 Index            : 0x3 ''
   +0x02c TotalNumberOfObjects : 0x25
   +0x030 TotalNumberOfHandles : 0x70
   +0x034 HighWaterNumberOfObjects : 0x29
   +0x038 HighWaterNumberOfHandles : 0x83
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
   +0x0b8 Key              : 0x65726944
   +0x0c0 CallbackList     : _LIST_ENTRY [ 0xfffffa80`30e4c4a0 - 0xfffffa80`30e4c4a0 ]

其为目录对象。

那似乎通过ObpTypeObjectType这个就可以遍历所有的对象类型,之前查看其它的文章也有这个指出的。

那如何获取到ObpTypeObjectType,根据Windbg调试Win7发现ObCreateObjectTypeEx中有对其的引用 :

nt!ObCreateObjectTypeEx+0x2e3:
fffff800`068a1373 0fb74602        movzx   eax,word ptr [rsi+2]
fffff800`068a1377 488d4c2460      lea     rcx,[rsp+60h]
fffff800`068a137c 488bd6          mov     rdx,rsi
fffff800`068a137f 6689442462      mov     word ptr [rsp+62h],ax
fffff800`068a1384 e827fec0ff      call    nt!RtlCopyUnicodeString (fffff800`064b11b0)
fffff800`068a1389 4c8b2518d2dcff  mov     r12,qword ptr [nt!ObpTypeObjectType (fffff800`0666e5a8)]
fffff800`068a1390 4d3be6          cmp     r12,r14
fffff800`068a1393 7555            jne     nt!ObCreateObjectTypeEx+0x35a (fffff800`068a13ea)  Branch

而ObCreateObjectTypeEx又被ObCreateObjectType调用:

5: kd> uf nt!ObCreateObjectType
nt!ObCreateObjectType:
fffff800`068a1a90 4883ec38        sub     rsp,38h
fffff800`068a1a94 4c894c2420      mov     qword ptr [rsp+20h],r9
fffff800`068a1a99 4533c9          xor     r9d,r9d
fffff800`068a1a9c e8eff5ffff      call    nt!ObCreateObjectTypeEx (fffff800`068a1090)
fffff800`068a1aa1 4883c438        add     rsp,38h
fffff800`068a1aa5 c3              ret

而ObCreateObjectType是导出的。

似乎得出结论可以用此来定位。

但在Win10系统上格式化结构却得出来的数据不正确,见下:

0: kd> dq nt!ObpTypeObjectType
fffff806`11c25b30  ffffb386`f147fea0 ffffe001`81a2fce0
fffff806`11c25b40  00000000`00000000 00000000`00000000
fffff806`11c25b50  00000000`00000000 00000000`00000000
fffff806`11c25b60  00000000`00000000 00000000`00000000
fffff806`11c25b70  00000000`00000000 00000000`00000000
fffff806`11c25b80  00000000`00000000 00000000`00000000
fffff806`11c25b90  00000000`00000000 00000000`00000000
fffff806`11c25ba0  00000000`00000000 00000000`00000000

发现除了第一个头外后边都是空的。

其原因就是在Win7上后边连续填充的数据对应的是另一个ObpObjectTypes的数据。

5: kd>  dq nt!ObpTypeObjectType
fffff800`0666e5a8  fffffa80`30e4c530 00000000`00000000
fffff800`0666e5b8  00000000`00000000 fffffa80`30e4c530
fffff800`0666e5c8  fffffa80`30e4c3e0 fffffa80`30e4c290
fffff800`0666e5d8  fffffa80`30e525a0 fffffa80`30e52380
fffff800`0666e5e8  fffffa80`30e52230 fffffa80`30ee0080
fffff800`0666e5f8  fffffa80`30ee0f30 fffffa80`30ee0de0
fffff800`0666e608  fffffa80`30ee1080 fffffa80`30f5a940
fffff800`0666e618  fffffa80`30f4ca10 fffffa80`30f4c8c0
5: kd> dq nt!ObpObjectTypes
fffff800`0666e5c0  fffffa80`30e4c530 fffffa80`30e4c3e0
fffff800`0666e5d0  fffffa80`30e4c290 fffffa80`30e525a0
fffff800`0666e5e0  fffffa80`30e52380 fffffa80`30e52230
fffff800`0666e5f0  fffffa80`30ee0080 fffffa80`30ee0f30
fffff800`0666e600  fffffa80`30ee0de0 fffffa80`30ee1080
fffff800`0666e610  fffffa80`30f5a940 fffffa80`30f4ca10
fffff800`0666e620  fffffa80`30f4c8c0 fffffa80`30f30c30
fffff800`0666e630  fffffa80`30f30ae0 fffffa80`30f538c0

可以看到 ObpTypeObjectType之后第三个数据的地址及为ObpObjectTypes的开始地址。

而在Win10上是不连续的,没办法用ObpTypeObjectType来遍历了。

0: kd> dq nt!ObpTypeObjectType
fffff806`11c25b30  ffffb386`f147fea0 ffffe001`81a2fce0
fffff806`11c25b40  00000000`00000000 00000000`00000000
fffff806`11c25b50  00000000`00000000 00000000`00000000
fffff806`11c25b60  00000000`00000000 00000000`00000000
fffff806`11c25b70  00000000`00000000 00000000`00000000
fffff806`11c25b80  00000000`00000000 00000000`00000000
fffff806`11c25b90  00000000`00000000 00000000`00000000
fffff806`11c25ba0  00000000`00000000 00000000`00000000
0: kd> dq nt!ObpObjectTypes
fffff806`11c25280  ffffb386`f147fea0 ffffb386`f1460a10
fffff806`11c25290  ffffb386`f145fe70 ffffb386`f14c7e80
fffff806`11c252a0  ffffb386`f14c77a0 ffffb386`f14c7220
fffff806`11c252b0  ffffb386`f14c7640 ffffb386`f14c70c0
fffff806`11c252c0  ffffb386`f14c7900 ffffb386`f14c7a60
fffff806`11c252d0  ffffb386`f14c7380 ffffb386`f14c74e0
fffff806`11c252e0  ffffb386`f14c7d20 ffffb386`f14c7bc0
fffff806`11c252f0  ffffb386`f14f1f00 ffffb386`f14f1c40

 

  •  ObpObjectTypes

这个变量来说确实是保存了所有的对象类型,但有个问题是不太容易从导出的函数来定位这个数据。IDA查看其代码引用处如下:

 第2、3、4个函数不是直接使用的ObpObjectTypes,而其它的都不能方便的从导出函数进行定位。

所以此方法不通。

  • ObTypeIndexTable、

此变量是以索顺序来存放对象类型的指针的,结构数据如下:

5: kd> dq ObTypeIndexTable
fffff800`06670100  00000000`00000000 00000000`bad0b0b0
fffff800`06670110  fffffa80`30e4c530 fffffa80`30e4c3e0
fffff800`06670120  fffffa80`30e4c290 fffffa80`30e525a0
fffff800`06670130  fffffa80`30e52380 fffffa80`30e52230
fffff800`06670140  fffffa80`30ee0080 fffffa80`30ee0f30
fffff800`06670150  fffffa80`30ee0de0 fffffa80`30ee1080
fffff800`06670160  fffffa80`30f5a940 fffffa80`30f4ca10
fffff800`06670170  fffffa80`30f4c8c0 fffffa80`30f30c30
5: kd> dt _object_type fffffa80`30e4c530
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xfffffa80`30e4c4e0 - 0xfffffa80`3205db20 ]
   +0x010 Name             : _UNICODE_STRING "Type"
   +0x020 DefaultObject    : 0xfffff800`0666e7a0 Void
   +0x028 Index            : 0x2 ''
   +0x02c TotalNumberOfObjects : 0x2a
   +0x030 TotalNumberOfHandles : 0
   +0x034 HighWaterNumberOfObjects : 0x2a
   +0x038 HighWaterNumberOfHandles : 0
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
   +0x0b8 Key              : 0x546a624f
   +0x0c0 CallbackList     : _LIST_ENTRY [ 0xfffffa80`30e4c5f0 - 0xfffffa80`30e4c5f0 ]
5: kd> dt _object_type fffffa80`30e4c3e0
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xfffffa80`30e4c3e0 - 0xfffffa80`30e4c3e0 ]
   +0x010 Name             : _UNICODE_STRING "Directory"
   +0x020 DefaultObject    : 0xfffff800`0666e7a0 Void
   +0x028 Index            : 0x3 ''
   +0x02c TotalNumberOfObjects : 0x29
   +0x030 TotalNumberOfHandles : 0x76
   +0x034 HighWaterNumberOfObjects : 0x29
   +0x038 HighWaterNumberOfHandles : 0x83
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
   +0x0b8 Key              : 0x65726944
   +0x0c0 CallbackList     : _LIST_ENTRY [ 0xfffffa80`30e4c4a0 - 0xfffffa80`30e4c4a0 ]

 从第2个 fffffa80`30e4c530的地址结构格式化可以看出其Index为2,对应表中的地址索引为2。其这个表就是从第2号索引开始, 第1号索引00000000`bad0b0b0    指向的实际是无效对象类型。

 IDA查看其引用如下,有很多函数中都用到:

 取其中较实现查找的ObGetObjectType,通过查找特征码就可以获得:

5: kd> u nt!ObGetObjectType
nt!ObGetObjectType:
fffff800`06796e60 0fb641e8        movzx   eax,byte ptr [rcx-18h]
fffff800`06796e64 488d0d9592edff  lea     rcx,[nt!ObTypeIndexTable (fffff800`06670100)]
fffff800`06796e6b 488b04c1        mov     rax,qword ptr [rcx+rax*8]
fffff800`06796e6f c3              ret
fffff800`06796e70 cc              int     3
fffff800`06796e71 cc              int     3
fffff800`06796e72 cc              int     3
fffff800`06796e73 cc              int     3

三、代码实现

 PrintOjbectTypeList.h

#pragma once
#include <ntddk.h>

#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;

PrintOjbectList.cpp

#include "PrintObjectTypeList.h"

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	UNREFERENCED_PARAMETER(pDriverObject);
	KDPRINT("【PrintObjectTypeList】", "CurrentProcessId : 0x%p CurrentIRQL : 0x%u rn",
		PsGetCurrentProcessId(),
		KeGetCurrentIrql());
}

void PrintObTypeIndexList(PVOID pObTypeIndexTable)
{
	if (pObTypeIndexTable)
	{
		PUCHAR pStartAddress = ((PUCHAR)pObTypeIndexTable + 8 * 2); //从第2个开始
		POBJECT_TYPE_EX *pTempObjectType = (POBJECT_TYPE_EX*)(pStartAddress);
		ULONG ulIndex = 0;
		while(*pTempObjectType != NULL)
		{
			KDPRINT("【PrintObjectTypeList】", "Index:%02ld  Address:0x%p Name:%wZrn", 
				ulIndex,
				*pTempObjectType,
				&(*pTempObjectType)->Name);
			pTempObjectType++;
			ulIndex++;
		}

	}
}

PVOID GetObTypeIndexTable()
{
	UNICODE_STRING usObGetObjectType = RTL_CONSTANT_STRING(L"ObGetObjectType");
	PVOID pGetObTypeIndexTable = NULL;
	PVOID pObGetObjectType = (PVOID)MmGetSystemRoutineAddress(&usObGetObjectType);
	do
	{
		if (!pObGetObjectType)
		{
			KDPRINT("【PrintObjectTypeList】", "MmGetSystemRoutineAddress Failed! rn");
			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 rn", pGetObTypeIndexTable);
	}
	else
	{
		KDPRINT("【PrintObjectTypeList】", "ObTypeIndexTable Not Found!rn");
	}
	return pGetObTypeIndexTable;
}

EXTERN_C NTSTATUS  DriverEntry(PDRIVER_OBJECT pDriverObject,
	PUNICODE_STRING pRegistryPath)
{
	UNREFERENCED_PARAMETER(pDriverObject);
	UNREFERENCED_PARAMETER(pRegistryPath);
	KDPRINT("【PrintObjectTypeList】", " Hello Kernel World! CurrentProcessId:0x%p CurrentIRQL:0x%urn",
		PsGetCurrentProcessId(),
		KeGetCurrentIrql());
	pDriverObject->DriverUnload = DriverUnload;

	NTSTATUS ntStatus = STATUS_SUCCESS;
	PVOID pGetObTypeIndexTable = GetObTypeIndexTable();
	if (pGetObTypeIndexTable)
	{
		PrintObTypeIndexList(pGetObTypeIndexTable);
	}

	return ntStatus;
}

四、调试结果

  • Win7 x64

  •  Win10 x64

 

 

五、结束语

  本次代码只考虑了x64环境下的Win7 和 Win10,32位环境下以及XP未考虑,但思路大同小异。

  通过对对象类型的遍历,可以用在使用未导出的对象类型的时候取得对象指针。

最后

以上就是聪慧白昼为你收集整理的遍历Windows内核ObjectType一、背景二、几个主要的内核变量三、代码实现四、调试结果五、结束语的全部内容,希望文章能够帮你解决遍历Windows内核ObjectType一、背景二、几个主要的内核变量三、代码实现四、调试结果五、结束语所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部