欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2025/6/17 编程问答 11 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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\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.CallbackListb=TRUE;break;}case 9600:{ObjectCallbackListOffset=0xC8; //OBJECT_TYPE.CallbackListb=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 + retif(!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

 

 

 

 

总结

以上是生活随笔为你收集整理的Win64 驱动内核编程-33.枚举与删除对象回调的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。