转载:http://www.voidcn.com/article/p-wulgeluy-bao.html

枚举与删除对象回调

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

Win64 驱动内核编程-33.枚举与删除对象回调的更多相关文章

  1. Win64 驱动内核编程-30.枚举与删除线程回调

    枚举与删除线程回调 进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了.某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出.而线程回调则通常用 ...

  2. Win64 驱动内核编程-32.枚举与删除注册表回调

    枚举与删除注册表回调 注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果.部分游戏保护还会在注册表回调上做功夫,监控 service ...

  3. Win64 驱动内核编程-31.枚举与删除映像回调

    枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...

  4. Win64 驱动内核编程-28.枚举消息钩子

    枚举消息钩子 简单粘贴点百度的解释,科普下消息钩子: 钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之 ...

  5. Win64 驱动内核编程-3.内核里使用内存

    内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...

  6. Win64 驱动内核编程-8.内核里的其他常用

    内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...

  7. Win64 驱动内核编程-7.内核里操作进程

    在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...

  8. Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)

    驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...

  9. Win64 驱动内核编程-18.SSDT

    SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...

随机推荐

  1. Codeforces Round #601 (Div. 2) E2. Send Boxes to Alice (Hard Version)

    Codeforces Round #601 (Div. 2) E2. Send Boxes to Alice (Hard Version) N个盒子,每个盒子有a[i]块巧克力,每次操作可以将盒子中的 ...

  2. 类型转换的时候,.valueOf()和.parseX(),.Xvalue()的区别

    .valueOf()返回的是包装类(Wrapper Class)中的一些类型:而.parseX()返回的是基本数据类型,如int,char,double等.其参数应该是String类型. .Xvalu ...

  3. 锤子手机做appium自动化测试时,运行脚本总是弹出警告框的问题

    当运行脚本的时候,总是提示若干个如上提示框,必须点击同意才能进行下一步:解决方案: 在设置,全局高级设置,开发者选项中打开“总是允许USB安装应用”即可解决:

  4. .gitignore 标准模板 -适用于SpringBoot+Vue项目 -Idea+VSCode开发

    .gitignore 标准模板 -适用于SpringBoot+Vue项目 node_modules/ target/ !.mvn/wrapper/maven-wrapper.jar ### STS # ...

  5. python应用-综合应用题解决

    题目: A,B,C,D,E五个人捕鱼,不计其数,然后休息, 早上A第一个醒来,将鱼均分成五份,把多余的一条鱼扔掉,拿走自己的一份, B第二个醒来,也将鱼均分为五份,把多余的一条鱼扔掉,拿走自己的一份. ...

  6. 在 Less 中使用 calc() 的坑:height: calc(~"50% - 21px");

    注意点: 中间的运算符两头都要有空格 写法(加上~符号):height: calc(~"50% - 21px"); 出处:https://mp.weixin.qq.com/s/CY ...

  7. oracle中删除表:drop、delete、truncate

    相同点,使用drop delete truncate 都会删除表中的内容 drop table 表名 delete from 表名(后面不跟where语句,则删除表中所有的数据) truncate t ...

  8. yugabyte与cockroachdb 的几个区别

    下图是来自官方文档  说明 今天打算尝试使用yugabyte做为hasura graphql-engine 的pg 引擎,发现比较完美,仔细看官方文档,原来yugabyte 底层实现直接是基于原生pg ...

  9. 【JZOJ6230】【20190625】梦批糼

    题目 一个$n\times m \times l $的立方体,有一些位置有障碍 一次操作会随机选择一个立方体,共有\(w\)次操作 询问所有操作都不选到障碍点,被选到至少一次的点的期望 $n ,m,l ...

  10. nginx之rewrite相关功能

    Nginx Rewrite相关功能 Nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regu ...