Win64 驱动内核编程-33.枚举与删除对象回调

转载:http://www.voidcn.com/article/p-wulgeluy-bao.html

枚举与删除对象回调

    对象回调存储在对应对象结构体里,简单来说,就是存储在 ObjectType. CallbackList 

个双向链表里。但对象结构体在每个系统上都不一定相同。比如 WIN7X64 的结构体如下:

ntdll!_OBJECT_TYPE

+0x000 TypeList : _LIST_ENTRY

+0x010 Name : _UNICODE_STRING

+0x020 DefaultObject : Ptr64 Void

+0x028 Index : UChar

+0x02c TotalNumberOfObjects : Uint4B

+0x030 TotalNumberOfHandles : Uint4B

+0x034 HighWaterNumberOfObjects : Uint4B

+0x038 HighWaterNumberOfHandles : Uint4B

+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER

+0x0b0 TypeLock : _EX_PUSH_LOCK

+0x0b8 Key : Uint4B

+0x0c0 CallbackList : _LIST_ENTRY

 

Object.CallbackList->FLink 指向的地址,是一个结构体链表,它的定义如下:

 

typedef struct _OB_CALLBACK

{

LIST_ENTRY  ListEntry;

ULONG64 Unknown;

ULONG64 ObHandle;

ULONG64 ObjTypeAddr;

ULONG64 PreCall;

ULONG64 PostCall;

} OB_CALLBACK, *POB_CALLBACK

 

微软没有公开这个结构体的定义,这个结构体是资料作者逆向出来的。但是至少在 WIN7WIN8和 WIN8.1 上通用。知道了结构体的定义,枚举就方便了(WINDOWS 目前仅有进程对象回调和线程对象回调,但就算以后有了其它回调,也是通用的):

 

ULONG EnumObCallbacks()
{
ULONG c=0;
PLIST_ENTRY CurrEntry=NULL;
POB_CALLBACK pObCallback;
BOOLEAN IsTxCallback;
ULONG64 ObProcessCallbackListHead = *(ULONG64*)PsProcessType + ObjectCallbackListOffset;
ULONG64 ObThreadCallbackListHead = *(ULONG64*)PsThreadType + ObjectCallbackListOffset;
//
dprintf("ObProcessCallbackListHead: %p\n",ObProcessCallbackListHead);
CurrEntry=((PLIST_ENTRY)ObProcessCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
do
{
pObCallback=(POB_CALLBACK)CurrEntry;
if(pObCallback->ObHandle!=0)
{
dprintf("ObHandle: %p\n",pObCallback->ObHandle);
dprintf("PreCall: %p\n",pObCallback->PreCall);
dprintf("PostCall: %p\n",pObCallback->PostCall);
c++;
}
CurrEntry = CurrEntry->Flink;
}
while(CurrEntry != (PLIST_ENTRY)ObProcessCallbackListHead);
//
dprintf("ObThreadCallbackListHead: %p\n",ObThreadCallbackListHead);
CurrEntry=((PLIST_ENTRY)ObThreadCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
do
{
pObCallback=(POB_CALLBACK)CurrEntry;
if(pObCallback->ObHandle!=0)
{
dprintf("ObHandle: %p\n",pObCallback->ObHandle);
dprintf("PreCall: %p\n",pObCallback->PreCall);
dprintf("PostCall: %p\n",pObCallback->PostCall);
c++;
}
CurrEntry = CurrEntry->Flink;
}
while(CurrEntry != (PLIST_ENTRY)ObThreadCallbackListHead);
dprintf("ObCallback count: %ld\n",c);
return c;
}


执行结果:

 

Win64 驱动内核编程-33.枚举与删除对象回调


对付对象回调,方法还是老三套

1.用 ObUnRegisterCallbacks 传入 ObHandle 注销回调;

2.把记录的回调函数地址改为自己的设置的空回调;

3.给对方设置的回调函数地址写入 RET

    不过这次使用第三种方法要注意,必须先禁掉 PostCall,再禁用 PreCall,否则容易蓝屏。


完整代码:

 

#define dprintf				DbgPrint

#define	DEVICE_NAME			L"\\Device\\MyDriver"
#define LINK_NAME			L"\\DosDevices\\MyDriver"
#define LINK_GLOBAL_NAME	L"\\DosDevices\\Global\\MyDriver"

ULONG NtBuildNumber=0;
ULONG ObjectCallbackListOffset=0;

typedef struct _OB_CALLBACK
{
	LIST_ENTRY	ListEntry;
	ULONG64		Unknown;
	ULONG64		ObHandle;
	ULONG64		ObjTypeAddr;
	ULONG64		PreCall;
	ULONG64		PostCall;
} OB_CALLBACK, *POB_CALLBACK;

BOOLEAN GetVersionAndHardCode()
{
	BOOLEAN b=FALSE;
	RTL_OSVERSIONINFOW	osi;
	osi.dwOSVersionInfoSize=sizeof(RTL_OSVERSIONINFOW);
	RtlFillMemory(&osi,sizeof(RTL_OSVERSIONINFOW),0);
	RtlGetVersion(&osi);
	NtBuildNumber=osi.dwBuildNumber;
	DbgPrint("NtBuildNumber: %ld\n",NtBuildNumber);
	switch (NtBuildNumber)
	{
	case 7600:
	case 7601:
	{
		ObjectCallbackListOffset=0xC0;
		b=TRUE;
		break;
	}
	case 9200:
	{
		ObjectCallbackListOffset=0xC8;	//OBJECT_TYPE.CallbackList
		b=TRUE;
		break;
	}
	case 9600:
	{
		ObjectCallbackListOffset=0xC8;	//OBJECT_TYPE.CallbackList
		b=TRUE;
		break;
	}
	default:
		break;
	}
	return b;
}

KIRQL WPOFFx64()
{
	KIRQL irql=KeRaiseIrqlToDpcLevel();
	UINT64 cr0=__readcr0();
	cr0 &= 0xfffffffffffeffff;
	__writecr0(cr0);
	_disable();
	return irql;
}

void WPONx64(KIRQL irql)
{
	UINT64 cr0=__readcr0();
	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);
	KeLowerIrql(irql);
}

VOID DisableObcallbacks(PVOID Address)
{
	KIRQL irql;
	CHAR patchCode[] = "\x33\xC0\xC3";	//xor eax,eax + ret
	if(!Address)
		return;
	if(MmIsAddressValid(Address))
	{
		irql=WPOFFx64();
		memcpy(Address,patchCode,3);
		WPONx64(irql);
	}
}

ULONG EnumObCallbacks()
{
	ULONG c=0;
	PLIST_ENTRY CurrEntry=NULL;
	POB_CALLBACK pObCallback;
	BOOLEAN IsTxCallback;
	ULONG64 ObProcessCallbackListHead = *(ULONG64*)PsProcessType + ObjectCallbackListOffset;
	ULONG64 ObThreadCallbackListHead = *(ULONG64*)PsThreadType + ObjectCallbackListOffset;
	//
	dprintf("ObProcessCallbackListHead: %p\n",ObProcessCallbackListHead);
	CurrEntry=((PLIST_ENTRY)ObProcessCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
	do
	{
		pObCallback=(POB_CALLBACK)CurrEntry;
		if(pObCallback->ObHandle!=0)
		{
			dprintf("ObHandle: %p\n",pObCallback->ObHandle);
			dprintf("PreCall: %p\n",pObCallback->PreCall);
			dprintf("PostCall: %p\n",pObCallback->PostCall);
			c++;
		}
		CurrEntry = CurrEntry->Flink;
	}
	while(CurrEntry != (PLIST_ENTRY)ObProcessCallbackListHead);
	//
	dprintf("ObThreadCallbackListHead: %p\n",ObThreadCallbackListHead);
	CurrEntry=((PLIST_ENTRY)ObThreadCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
	do
	{
		pObCallback=(POB_CALLBACK)CurrEntry;
		if(pObCallback->ObHandle!=0)
		{
			dprintf("ObHandle: %p\n",pObCallback->ObHandle);
			dprintf("PreCall: %p\n",pObCallback->PreCall);
			dprintf("PostCall: %p\n",pObCallback->PostCall);
			c++;
		}
		CurrEntry = CurrEntry->Flink;
	}
	while(CurrEntry != (PLIST_ENTRY)ObThreadCallbackListHead);
	dprintf("ObCallback count: %ld\n",c);
	return c;
}

Win64 驱动内核编程-33.枚举与删除对象回调

上一篇:win10下部署.Net Web项目到IIS10


下一篇:docker remote api