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.枚举与删除对象回调相关推荐
- Win64 驱动内核编程-30.枚举与删除线程回调
枚举与删除线程回调 进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了.某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出.而线程回调则通常用 ...
- Win64 驱动内核编程-32.枚举与删除注册表回调
枚举与删除注册表回调 注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果.部分游戏保护还会在注册表回调上做功夫,监控 service ...
- Win64 驱动内核编程-31.枚举与删除映像回调
枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...
- Win64 驱动内核编程-28.枚举消息钩子
枚举消息钩子 简单粘贴点百度的解释,科普下消息钩子: 钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之 ...
- Win64 驱动内核编程-3.内核里使用内存
内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...
- Win64 驱动内核编程-8.内核里的其他常用
内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...
- Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)
驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...
- Win64 驱动内核编程-18.SSDT
SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...
- Win64 驱动内核编程-13.回调监控模块加载
回调监控模块加载 模块加载包括用户层模块(.DLL)和内核模块(.SYS)的加载.传统方法要监控这两者加在必须 HOOK 好几个函数,比如 NtCreateSection 和 NtLoadDriver ...
最新文章
- Linux Kernel TCP/IP Stack — L1 Layer
- springboot session默认失效时间_Spring Boot 整合 Redis,用起来真简单
- 2.static关键字.rs
- mysql中用完即删用什么_MySQL使用和操作总结(《MySQL必知必会》读书笔记)
- flex 学习笔记 皮肤(一)
- chattr lsattr
- 职称评审英语计算机不作要求,安徽:基层专业技术人员评职称外语计算机不作要求...
- Java中的内部类与匿名内部类
- 网上订餐系统需求分析报告
- winRar禁止弹窗广告方法
- ES6中的模块化编程
- deepfacelab安卓版_deepfacelab
- 离职原因之3B分类问题
- 程序猿生存指南-11 入职朗云
- [mybatis] sql语句无错误,但是执行多条sql语句时,抛出java.sql.SQLSyntaxErrorException...
- 狸猫的面试——项目描述——视频通信
- 万字回顾FTX 兴衰史:众人的一座山,时代的一粒尘
- 线性代数(三十九) :格拉姆-施密特正交化与标准正交基
- 【转】Linux服务器性能评估与优化(一)
- C语言文件操作实例代码