其实我感觉这个东西挺鸡肋的,只是雕虫小技,大佬们笑笑就好。
如有错误,请大佬们指出。
测试环境:win7 x64
这里以ObjectType类型为PsProcessType的PreCallback为例子。
先自己注册一个回调,下个断点看看是什么在调用我们注册的回调。
查看栈回溯得到关键函数ObpCallPreOperationCallbacks,ida上看有三个参数,网上搜了一圈只确定了前两个参数。
1 | signed __int64 __fastcall ObpCallPreOperationCallbacks(POBJECT_TYPE pObjectType, POB_PRE_OPERATION_INFORMATION OperationInformation, _QWORD *a3); |
ida f5如下(做了一点重命名)
1 | signed __int64 __fastcall ObpCallPreOperationCallbacks(POBJECT_TYPE pObjectType, POB_PRE_OPERATION_INFORMATION pOperationInformation, _QWORD *a3) |
虽然这个f5问题很大,但是大致可以看出来ObpCallPreOperationCallbacks是通过循环遍历_OBJECT_TYPE里的CallbackList来调用注册的回调的。
TA教程里提供的有关CallbackList的结构如下,里面的ListEntry就是CallbackList。
1 | typedef struct _OB_CALLBACK |
但是通过阅读f5的函数之后,我发现TA提供的结构并不完整,现补充一下。
1 | typedef struct _OB_CALLBACK |
有关RundownProtect可以看https://bbs.pediy.com/thread-173763.htm
这个补充的成员在后面绕过的时候会用到。
现在看看有关循环的部分
1 | for ( _RBX = pCallbackList->ListEntry.Flink; ; _RBX = _RBX->ListEntry.Flink ) |
可以发现ObpCallPreOperationCallbacks通过RBX来存储当前的CallbackList节点,我寻思着能不能通过在自己注册的回调里面改变这个RBX来跳过其他的回调,于是我做了一个实验。
先写两个回调
回调1
1 | OB_PREOP_CALLBACK_STATUS PreCallbackProcess( |
回调2(因为要操作RBX 想了想就用汇编来写了,代码有点渣,请见谅)
1 | DbgPrint proto |
这里需要用到ExAcquireRundownProtection和ExReleaseRundownProtection是因为ObpCallPreOperationCallbacks里有维护每个回调的RundownProtect成员,如果我们通过修改RBX来跳过其他回调的话,就需要自己动手维护这个成员,否则在卸载回调的时候会出大问题。
然后通过ObRegisterCallbacks来注册这两个回调,因为回调的顺序是根据Altitude来确定的,所以PreCallbackProcess2的高度要比PreCallbackProcess高,否则将起不到绕过其他回调的效果。
载入驱动后用DebugView看看
可以看到PreCallbackProcess并没有执行,证明可以成功绕过。
后来我在win10 x64也测试过了,暂时没发现啥大问题。
然而一通操作下来我发现用处似乎不大,大家看着乐一乐就好。