Win64 驅動內核編程-33.枚舉與刪除對象回調

轉載:http://www.voidcn.com/article/p-wulgeluy-bao.html

枚舉與刪除對象回調

    對象回調存儲在對應對象結構體裏,簡單來講,就是存儲在 ObjectType. CallbackList html

個雙向鏈表裏。但對象結構體在每一個系統上都不必定相同。好比 WIN7X64 的結構體以下:c++

ntdll!_OBJECT_TYPE函數

+0x000 TypeList : _LIST_ENTRYui

+0x010 Name : _UNICODE_STRINGspa

+0x020 DefaultObject : Ptr64 Void.net

+0x028 Index : UChar線程

+0x02c TotalNumberOfObjects : Uint4Bcode

+0x030 TotalNumberOfHandles : Uint4Bhtm

+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;
}


執行結果:

 



對付對象回調,方法仍是老三套

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;
}
相關文章
相關標籤/搜索