• 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

  • 相关阅读:
    深度学习原理与框架-Tensorflow卷积神经网络-神经网络mnist分类
    深度学习原理与框架-Tensorflow基本操作-mnist数据集的逻辑回归 1.tf.matmul(点乘操作) 2.tf.equal(对应位置是否相等) 3.tf.cast(将布尔类型转换为数值类型) 4.tf.argmax(返回最大值的索引) 5.tf.nn.softmax(计算softmax概率值) 6.tf.train.GradientDescentOptimizer(损失值梯度下降器)
    深度学习原理与框架-Tensorflow基本操作-实现线性拟合
    深度学习原理与框架-Tensorflow基本操作-变量常用操作 1.tf.random_normal(生成正态分布随机数) 2.tf.random_shuffle(进行洗牌操作) 3. tf.assign(赋值操作) 4.tf.convert_to_tensor(转换为tensor类型) 5.tf.add(相加操作) tf.divide(相乘操作) 6.tf.placeholder(输入数据占位
    深度学习原理与框架-Tensorflow基本操作-Tensorflow中的变量
    深度学习原理与框架-RNN网络框架-LSTM框架 1.控制门单元 2.遗忘门单元 3.记忆门单元 4.控制门单元更新 5.输出门单元 6.LSTM网络结构
    深度学习原理与框架-RNN网络架构-RNN网络 1.RNN的前向传播 2.RNN的反向传播
    深度学习原理与框架-卷积网络细节-三代物体检测算法 1.R-CNN 2.Fast R-CNN 3.Faster R-CNN
    线上服务内存OOM问题定位
    linux下追查线上问题常用命令
  • 原文地址:https://www.cnblogs.com/csnd/p/12061979.html
Copyright © 2020-2023  润新知