ObjectType_Callback探索

使用PCHunter工具查看object钩子时发现有一种Hook是ObjectType_Callback,Object类型为Process
在这里插入图片描述
WRK中的全局类型对象变量中没有这一类型
查看ObTypeIndexTable表,对比有HOOK和无HOOk的情况下,看元素是否有增加,如果是自创类型,在这个表里,应该有增加一项
ObTypeIndexTable在XP系统中不存在,前两项是无效的
当有HOOK的情况下WINDBG中显示如下:
在这里插入图片描述
没有HOOK的情况下显示如图:
在这里插入图片描述
可以看出数量是没有变化的,从而可以推断出这个HOOK不是新增加对象类型完成的,只是一种描述

重新运行游戏以后,HOOK又出现了:
在这里插入图片描述

断点此类HOOK的函数,看函数什么时候被调用,看看栈回溯,分析下经历的函数
第一个如下:
第一个函数是空的
在这里插入图片描述
第二个函数如下:
在这里插入图片描述
断点第二个函数,很快会断下来,查看栈回溯
在这里插入图片描述
可以看到调用NtOpenProcess的时候会调用到他,这正起到了保护作用,其中最接近他的ObpCallPreOperationCallbacks函数和ObpPreInterceptHandleCreate函数在WRK中都没有。只有ObpCreateHandle在WRK中可以查到,这个函数解释为:This function creates a new handle to an existing object。相当于为了引用一个对象,新建一个句柄,这个句柄就是这个对象的引用方式。至此我们知道了,是引用一个对象的时候才会触发到这个保护函数,看来PCHunter大牛还是很强大的,把它分到了object钩子这类里边很精确。

由于WRK中没有ObpCallPreOperationCallbacks函数和ObpPreInterceptHandleCreate这两个函数,所以为了弄清楚什么时候调用的它必须要反汇编以上两个函数,使用IDA反汇编看,IDA打开内核文件ntkrnlpa,exe在左侧列表中搜索obpPreInterceptHandleCreate函数反汇编如图:
在这里插入图片描述
可以看到对象类型表ObTypeIndexTable,看来还是和对象类型有关,在往下看记录找到调用ObpCallPreOperationCallbacks函数的地方
在这里插入图片描述
可以看到在开头不远处,发现这个函数代码量也很小,继续跟进这个函数,定位CALL相关的代码,寻找保护函数调用点,一直往下都是系统调用直到这里:
在这里插入图片描述
在WINDBG中栈回溯显示的是
9d158758 840df832 xxxx!SampleDouble+0xcdf8
9d1587a0 840dfa1f nt!ObpCallPreOperationCallbacks+0x163
9d1587e8 8402dbfb nt!ObpPreInterceptHandleCreate+0x6f
对比下代码看看是不是这个地方,也可以计算下位置看看是不是这个地方,直接对比下吧,如图:
在这里插入图片描述
看来应该这就是调用点,再从CALL EAX中的EAX反推回去,看看怎么来的。通过IDA的鼠标点击变量寄存器变色可以轻松定位出以下过程EAX-》
006D581F mov eax, [edi+18h]-》
006D572C mov edi, [eax]-》
006D5729 mov eax, [ebp+var_C]-》
006D56E7 mov [ebp+var_C], eax-》
006D56DF lea eax, [edi+80h]-》
006D56DD mov edi, eax
说明在这个函数调用时 EAX就是关键所在了,分析上一个函数入调用点
通过前边的截图可以看到 EAX-》
006D5A12 mov eax, edx-》
006D59C0 mov edx, _ObTypeIndexTable[eax*4]
看来一切原因都来自于对象类型。
006D5A12位置的EAX是一个_OBJECT_TYPE WINDBG中看看WIN7中的结构成员
在这里插入图片描述
可以推测006D56DF中的EAX就是一个CallbackList了,看看这个名字再看看PCHunter中的ObjectType_Callback真是完全一样啊,回想先前也看了下_OBJECT_TYPE结构但是没注意到这个成员,想必一定是他保存了回调,这是一个双链表。现在就来看看这个对象类型里边的具体内容,想必就应该可以找到保护函数的地址了。
通过前边的分析可以知道再调用ObpCallPreOperationCallbacks函数时的EAX就是当前对象类型的地址,所以在这里设置断点,当然也有可能是其它的函数调用它,虽然知道不正确但是也只有赌一把了,具体操作如下:
在这里插入图片描述
可以看到名称是Process这和工具里边显示的是一样,感觉应该就是它了,在具体查看一下CallbackList 看看链表的内容
在这里插入图片描述
第一项链表头节点指向首节点a83175f8,首节点也指向首节点86ad3f30,看来只有双向链表中只有一项,查看内容发现红框处就是保护函数的地址,双链表结构也说明还可以增加其他的callback函数。
整体回顾一下 当NtOpenProcess被调用时就会调用到保护函数,这个函数是放在进程对象类型中的CallbackList中的,系统会调用它,且这个结构是双链表,还可以增加其他函数,至此疑问1基本就解决了。
接着来看疑问3,既然知道系统有这么一个机制,肯定应该有相应的系统函数吧,总不可能手工来添加删除吧,既然知道了这个新成员名称就应该搜索下,看看有什么信息 GOOGLE搜索下发现有以下内容
在这里插入图片描述
再翻译了下大致就是说ObRegisterCallbacks函数来注册的回调,MSDN搜索发现有这样的解释:The ObRegisterCallbacks routine registers a list of callback routines for thread and process handle operations.
这和我们遇到的情况一样,看来保护函数就是用这个函数来添加的了,怎么卸载呢?看看MSDN的左侧栏
在这里插入图片描述
发现一个对应的UN函数 点击查看解释:The ObUnRegisterCallbacks routine unregisters a set of callback routines that were registered with the ObRegisterCallbacks routine.

看来就是它了,两个函数的参数和进程创建卸载的系统回调差不多,具体可以参考《教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护》http://bbs.pediy.com/showthread.php?t=168023

我们一起来看一看WDK文档里面对ObRegisterCallbacks()的主要描述:

The ObRegisterCallbacks routine registers a list of callback routines for thread and process handle operations.

NTSTATUS
ObRegisterCallbacks(
IN POB_CALLBACK_REGISTRATION CallBackRegistration,
OUT PVOID *RegistrationHandle
);

CallBackRegistration
A pointer to an OB_CALLBACK_REGISTRATION structure that specifies the list of callback routines and other registration information.

RegistrationHandle
A pointer to a variable that receives a value that identifies the set of registered callback routines. The caller passes this value to the ObUnRegisterCallbacks routine to unregister the set of callbacks.

我们可以看见,有一个对应的ObUnRegisterCallbacks函数,以及其他的说明。
其实保护进程,也就是修改结构体POB_PRE_OPERATION_INFORMATION里面对应的成员值了。
PVOID obHandle;//定义一个void*类型的变量,它将会作为ObRegisterCallbacks函数的第2个参数。

NTSTATUS ProtectProcess(BOOLEAN Enable)
{

OB_CALLBACK_REGISTRATION obReg;
OB_OPERATION_REGISTRATION opReg;

memset(&obReg, 0, sizeof(obReg));
obReg.Version = ObGetFilterVersion();
obReg.OperationRegistrationCount = 1;
obReg.RegistrationContext = NULL;
RtlInitUnicodeString(&obReg.Altitude, L"321000");

memset(&opReg, 0, sizeof(opReg)); //初始化结构体变量

//下面 请注意这个结构体的成员字段的设置
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE|OB_OPERATION_HANDLE_DUPLICATE;

opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall; //在这里注册一个回调函数指针

obReg.OperationRegistration = &opReg; //注意这一条语句

return ObRegisterCallbacks(&obReg, &obHandle); //在这里注册回调函数
}
现在好了,到这里为止,我们已经用上了ObRegisterCallbacks函数了。事情有了一个好的开始,接着马上就要讲实现了。 在这里,我希望你再次打开WDK帮助文档,当然还是有关ObRegisterCallbacks函数的帮助。
我们首先注意上面代码的一条语句:
opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall; //在这里注册一个回调函数指针

我们在WDK帮助文档里面找到有关结构体OB_OPERATION_REGISTRATION的说明。我们在这个结构体里面找到 PreOperation结构体成员变量的帮助说明:
PreOperation
A pointer to an ObjectPreCallback routine. The system calls this routine before the requested operation occurs.

我们不需要使用另外一个 成员变量–PostOperation
PostOperation
A pointer to an ObjectPostCallback routine. The system calls this routine after the requested operation occurs.

PostOperation成员不是我们关心的,我们不去讨论它。

好了,这下,你找到了 PreOperation的用法说明了。我们知道了PreOperation是一个函数指针,我们的进程保护程序就在这个函数指针里面进行。
我们再回过头来看上面的程序代码,ProtectProcess函数的实现。 我们刚才就注意到了opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall;
现在,我们来实现 preCall函数,代码如下:
OB_PREOP_CALLBACK_STATUS
preCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
HANDLE pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
char szProcName[16]={0};
UNREFERENCED_PARAMETER(RegistrationContext);
strcpy(szProcName,GetProcessNameByProcessId(pid));
if( !_stricmp(szProcName,“calc.exe”) )
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_READ) == PROCESS_VM_READ)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
}
}
}
return OB_PREOP_SUCCESS;
}
还有,在驱动卸载的时候,要调用ObUnRegisterCallbacks函数。像这样:
VOID
Unload(IN PDRIVER_OBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint(“driver unloading…\n”);

ObUnRegisterCallbacks(obHandle); //obHandle是上面定义的 PVOID obHandle;
}
代码就这样吗? 是的,这样就可以实现进程保护了。

另外,还需要注意绕过MmVerifyCallbackFunction函数
你只要在百度或Google上,搜索关键字-----绕过MmVerifyCallbackFunction。这会出来很多的文章供你参考。

NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA ldr;

// 绕过MmVerifyCallbackFunction。
ldr = (PLDR_DATA)DriverObject->DriverSection;
ldr->Flags |= 0x20;
绕过MmVerifyCallbackFunction函数其实很容易的。

其实只要定义一个LDR_DATA的结构体。

typedef struct _LDR_DATA // 24 elements, 0xE0 bytes (sizeof)
{
struct _LIST_ENTRY InLoadOrderLinks; // 2 elements, 0x10 bytes (sizeof)
struct _LIST_ENTRY InMemoryOrderLinks; // 2 elements, 0x10 bytes (sizeof)
struct _LIST_ENTRY InInitializationOrderLinks; // 2 elements, 0x10 bytes (sizeof)
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 PADDING0[0x4];
struct _UNICODE_STRING FullDllName; // 3 elements, 0x10 bytes (sizeof)
struct _UNICODE_STRING BaseDllName; // 3 elements, 0x10 bytes (sizeof)
ULONG32 Flags;
UINT16 LoadCount;
UINT16 TlsIndex;
union
{
struct _LIST_ENTRY HashLinks;
struct
{
VOID* SectionPointer;
ULONG32 CheckSum;
UINT8 PADDING1[0x4];
};
};

     union                                                   
      {
         ULONG32      TimeDateStamp;
         VOID*        LoadedImports;
      };
 struct _ACTIVATION_CONTEXT* EntryPointActivationContext;
VOID*        PatchInformation;
struct _LIST_ENTRY ForwarderLinks;                   
struct _LIST_ENTRY ServiceTagLinks;                   
struct _LIST_ENTRY StaticLinks;                         
VOID*        ContextInformation;
UINT64       OriginalBase;
union _LARGE_INTEGER LoadTime;                      

}LDR_DATA, *PLDR_DATA;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码包含了一系列函数调用和任务创建,用于初始化设备并启动相关功能。下面是每个函数调用的简要解释: 1. `xQueueCreate(10, sizeof(D_MsgData))`:创建一个队列 `g_usif_queue`,队列大小为 10,每个元素大小为 `D_MsgData` 的字节大小。 2. `d_ble_register_callback(ble_user_callback)`:注册 BLE 回调函数 `ble_user_callback`。 3. `d_sensor_data_register_callback(sensor_data_user_callback)`:注册传感器数据回调函数 `sensor_data_user_callback`。 4. `d_timer_register_callback(timer_user_callback)`:注册定时器回调函数 `timer_user_callback`。 5. `d_uart_register_callback(uart_user_callback, LOOKUP_STR_OK, LOOKUP_STR_ERR, LOOKUP_STR_NEW_MSG, CAN_SEND_DATA_2_IOT)`:注册 UART 回调函数 `uart_user_callback`,并传递一些字符串参数。 6. `d_iot_timeout_timer_register_callback(iot_timeout_timer_user_callback)`:注册物联网超时定时器回调函数 `iot_timeout_timer_user_callback`。 7. `d_acc_gpiote_interrupt_disable()`:禁用加速度计 GPIO 中断。 8. `d_lcd_display_str(D_LCD_DISPLAY_STR_BOOT, 0)`:在 LCD 上显示启动信息。 9. `d_led_light_on(D_LED_LIGHT_RED)`:点亮红色 LED 灯。 10. `nrf_delay_us(5000000)`:延迟 5000000 微秒(5秒)。 11. `d_led_light_off(D_LED_LIGHT_RED)`:关闭红色 LED 灯。 12. `d_led_uninit()`:关闭 LED 灯。 13. `d_alarm_off()`:关闭报警功能。 14. `d_acc_gpiote_interrupt_enable()`:启用加速度计 GPIO 中断。 15. `d_power_register_callback(power_off_user_callback)`:注册电源关闭回调函数 `power_off_user_callback`。 16. `d_acc_register_callback(acc_user_callback)`:注册加速度计回调函数 `acc_user_callback`。 17. `d_lcd_clean()`:清空 LCD 屏幕。 18. `xTaskCreate(d_usif_task, "d_usif_task", 256*3, g_usif_queue, 2, &xHandle_usif_task)`:创建一个任务 `d_usif_task`,任务名为 "d_usif_task",任务栈大小为 256*3 字节,传递 `g_usif_queue` 给任务作为参数,优先级为 2,并将任务句柄保存在 `xHandle_usif_task` 中。 19. `configASSERT(xHandle_usif_task)`:确保任务创建成功。 20. `d_sensor_data_send_start()`:启动传感器数据发送。 21. `d_uart_clear_data_buf()`:清空 UART 数据缓冲区。 综上所述,这段代码的作用是初始化设备和相关功能,并创建一个名为 "d_usif_task" 的任务。具体的实现细节可能需要参考相关函数的定义和文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值