• 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
    ",ObProcessCallbackListHead);
    CurrEntry=((PLIST_ENTRY)ObProcessCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
    do
    {
    pObCallback=(POB_CALLBACK)CurrEntry;
    if(pObCallback->ObHandle!=0)
    {
    dprintf("ObHandle: %p
    ",pObCallback->ObHandle);
    dprintf("PreCall: %p
    ",pObCallback->PreCall);
    dprintf("PostCall: %p
    ",pObCallback->PostCall);
    c++;
    }
    CurrEntry = CurrEntry->Flink;
    }
    while(CurrEntry != (PLIST_ENTRY)ObProcessCallbackListHead);
    //
    dprintf("ObThreadCallbackListHead: %p
    ",ObThreadCallbackListHead);
    CurrEntry=((PLIST_ENTRY)ObThreadCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
    do
    {
    pObCallback=(POB_CALLBACK)CurrEntry;
    if(pObCallback->ObHandle!=0)
    {
    dprintf("ObHandle: %p
    ",pObCallback->ObHandle);
    dprintf("PreCall: %p
    ",pObCallback->PreCall);
    dprintf("PostCall: %p
    ",pObCallback->PostCall);
    c++;
    }
    CurrEntry = CurrEntry->Flink;
    }
    while(CurrEntry != (PLIST_ENTRY)ObThreadCallbackListHead);
    dprintf("ObCallback count: %ld
    ",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
    ",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[] = "x33xC0xC3";	//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
    ",ObProcessCallbackListHead);
    	CurrEntry=((PLIST_ENTRY)ObProcessCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
    	do
    	{
    		pObCallback=(POB_CALLBACK)CurrEntry;
    		if(pObCallback->ObHandle!=0)
    		{
    			dprintf("ObHandle: %p
    ",pObCallback->ObHandle);
    			dprintf("PreCall: %p
    ",pObCallback->PreCall);
    			dprintf("PostCall: %p
    ",pObCallback->PostCall);
    			c++;
    		}
    		CurrEntry = CurrEntry->Flink;
    	}
    	while(CurrEntry != (PLIST_ENTRY)ObProcessCallbackListHead);
    	//
    	dprintf("ObThreadCallbackListHead: %p
    ",ObThreadCallbackListHead);
    	CurrEntry=((PLIST_ENTRY)ObThreadCallbackListHead)->Flink;	//list_head的数据是垃圾数据,忽略
    	do
    	{
    		pObCallback=(POB_CALLBACK)CurrEntry;
    		if(pObCallback->ObHandle!=0)
    		{
    			dprintf("ObHandle: %p
    ",pObCallback->ObHandle);
    			dprintf("PreCall: %p
    ",pObCallback->PreCall);
    			dprintf("PostCall: %p
    ",pObCallback->PostCall);
    			c++;
    		}
    		CurrEntry = CurrEntry->Flink;
    	}
    	while(CurrEntry != (PLIST_ENTRY)ObThreadCallbackListHead);
    	dprintf("ObCallback count: %ld
    ",c);
    	return c;
    }
  • 相关阅读:
    The first appliaction for "Hello World!"
    zone
    learn to study
    深入理解 Angular 2 变化监测和 ngZone
    看看吧
    生命周期钩子
    一个简单的todo
    依赖注入
    @Output()
    @Input
  • 原文地址:https://www.cnblogs.com/kuangke/p/11133920.html
Copyright © 2020-2023  润新知