zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    [POJ1195] Mobile phones(二维树状数组)
    [SWUST1740] 圆桌问题(最大流)
    [SWUST1759] 骑士共存问题(最大流,最大独立集)
    欧拉函数O(sqrt(n))与欧拉线性筛素数O(n)总结
    BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊
    POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘
    计蒜客 30999.Sum-筛无平方因数的数 (ACM-ICPC 2018 南京赛区网络预赛 J)
    洛谷 P3383 【模板】线性筛素数-线性筛素数(欧拉筛素数)O(n)基础题贴个板子备忘
    计蒜客 30996.Lpl and Energy-saving Lamps-线段树(区间满足条件最靠左的值) (ACM-ICPC 2018 南京赛区网络预赛 G)
    计蒜客 30990.An Olympian Math Problem-数学公式题 (ACM-ICPC 2018 南京赛区网络预赛 A)
  • 原文地址:https://www.cnblogs.com/csnd/p/12061978.html
Copyright © 2011-2022 走看看