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


    枚举与删除对象回调

        对象回调存储在对应对象结构体里,简单来说,就是存储在 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

    微软没有公开这个结构体的定义,这个结构体是资料作者逆向出来的。但是至少在 WIN7、WIN8和 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;
    }

    宋孖健,13

  • 相关阅读:
    ADB命令大全
    Backup your Android without root or custom recovery -- adb backup
    Content portal for Pocketables Tasker articles
    Is there a way to detect if call is in progress? Phone Event
    Tasker to proximity screen off
    Tasker to detect application running in background
    Tasker to create toggle widget for ES ftp service -- Send Intent
    Tasker to proximity screen on
    Tasker to answer incoming call by pressing power button
    Tasker to stop Poweramp control for the headset while there is an incoming SMS
  • 原文地址:https://www.cnblogs.com/csnd/p/12061978.html
Copyright © 2020-2023  润新知