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

    xiaoxiao2021-03-25  160

    枚举与删除对象回调

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

    宋孖健,13

     

     

     

     

    转载请注明原文地址: https://ju.6miu.com/read-1583.html

    最新回复(0)