在笔者上一篇文章《内核枚举进程与线程ObCall回调》简单介绍了如何枚举系统中已经存在的进程与线程回调,本章LyShark将通过对象回调实现对进程线程的句柄监控,在内核中提供了ObRegisterCallbacks回调,使用这个内核回调函数,可注册一个对象回调,不过目前该函数只能监控进程与线程句柄操作,通过监控进程或线程句柄,可实现保护指定进程线程不被终止的目的。

ObRegisterCallbacks是Windows操作系统提供的一个内核API函数,它允许开发者注册一个回调函数,用于监控对象的创建、打开、关闭和删除等事件。对象可以是文件、目录、进程、线程、注册表键等等。

当操作系统创建、打开、关闭或删除一个对象时,它会触发注册的回调函数,然后在回调函数中调用开发者定义的代码。开发者可以在回调函数中执行自定义的逻辑,例如记录日志、过滤敏感数据、或者阻止某些操作。

ObRegisterCallbacks函数提供了多个回调函数的注册,这些回调函数包括:

  • PreOperation: 在操作执行之前被调用,可以阻止或修改操作。
  • PostOperation: 在操作执行之后被调用,可以记录操作结果或者清理资源。

需要注意的是,注册回调函数需要开发者有一定的内核开发经验,并且需要遵守一些约束条件,例如不能阻塞或挂起对象的操作,不能调用一些内核API函数等。

内核注册并监控对象回调ObRegisterCallbacks在安全软件、系统监控和调试工具等领域有着广泛的应用。开发者可以利用这个机制来监控系统对象的使用情况,以保护系统安全。

由于目前对象回调只能监控进程与线程,而这个监控是通过ObjectType这么一个成员控制的,如果成员是PsProcessType则代表监控进程,反之PsThreadType则是监控线程,无论监控进程还是线程都调用ObRegisterCallbacks这个函数来完成注册。

函数ObRegisterCallbacks其微软对他的定义是这样的,用户传入OB_OPERATION_REGISTRATION结构,以及OB_CALLBACK_REGISTRATION回调结构,其中PreOperation则是传入的回调函数,也是最重要的,其次是ObjectType指定成进程回调。

NTSTATUS ObRegisterCallbacks(
[in] POB_CALLBACK_REGISTRATION CallbackRegistration,
[out] PVOID *RegistrationHandle
);

首先来实现一个检测的案例,注册一个进程回调对象MyLySharkComObjectCallBack,通过ObRegisterCallbacks注册的回调只需要传入一个填充好的OB_CALLBACK_REGISTRATION回调结构体,以及一个全局句柄即可,这个全局句柄的作用仅仅只是在程序结束时,调用ObUnRegisterCallbacks卸载监控而已,实现代码如下所示。

#include <ntddk.h>
#include <ntstrsafe.h> PVOID Globle_Object_Handle; // 绕过签名检测
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA; PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
} // 自定义回调
OB_PREOP_CALLBACK_STATUS MyLySharkComObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
DbgPrint("[lyshark] 执行回调函数... \n");
return STATUS_SUCCESS;
} VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回调卸载完成... \n");
} NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n"); BypassCheckSign(Driver); OB_OPERATION_REGISTRATION Base; // 回调函数结构体
OB_CALLBACK_REGISTRATION CallbackReg; // 回调函数 CallbackReg.RegistrationContext = NULL; // 注册上下文(你回调函数返回参数)
CallbackReg.Version = OB_FLT_REGISTRATION_VERSION; // 注册回调版本
CallbackReg.OperationRegistration = &Base; // 回调结构体
CallbackReg.OperationRegistrationCount = 1; // 操作计数(下钩数量) RtlUnicodeStringInit(&CallbackReg.Altitude, L"600000"); // 长度
Base.ObjectType = PsProcessType; // 进程操作类型.此处为进程操作
Base.Operations = OB_OPERATION_HANDLE_CREATE; // 操作句柄创建
Base.PreOperation = MyLySharkComObjectCallBack; // 你自己的回调函数
Base.PostOperation = NULL; // 注册回调
if (ObRegisterCallbacks(&CallbackReg, &Globle_Object_Handle))
{
DbgPrint("[lyshark message] 回调注册成功...");
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

当驱动程序被加载以后,一旦有进程运行则会执行我们自己的MyLySharkComObjectCallBack回调,而在回调函数内则可以执行任意功能,运行如下所示。

如上所示只是演示基本的回调申请流程,回调函数通常需要包含两个值,其一RegistrationContext用于标注上下文,其二POB_PRE_OPERATION_INFORMATION则用于标注进程或者线程创建的信息结构体。

OB_PREOP_CALLBACK_STATUS MyLySharkComObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)

那么如何实现拦截进程启动这个功能呢,我们可以在回调函数中写入以下代码进行拦截。

  • CreateHandleInformation.DesiredAccess 将打开句柄的权限清零
  • CreateHandleInformation.OriginalDesiredAccess 判断是否终止
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
DbgPrint("lyshark.exe 进程打开 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}

拦截进程创建核心代码如下所示。

#include <ntddk.h>
#include <ntstrsafe.h> #define PROCESS_TERMINATE 0x1 // 导出两个API
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process); // 全局句柄
PVOID Globle_Object_Handle = NULL; // 绕过签名检测
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA; PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
} // 判断是否是需要保护的进程
BOOLEAN CheckProcess(PEPROCESS eprocess)
{
char *Name = PsGetProcessImageFileName(eprocess);
if (!_stricmp("lyshark.exe", Name))
return TRUE;
else
return FALSE;
} // 进程回调
OB_PREOP_CALLBACK_STATUS MyLySharkProcessObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
HANDLE pid; // 只取出进程回调
if (pOperationInformation->ObjectType != *PsProcessType)
{
return OB_PREOP_SUCCESS;
} // 得到所有进程的ID
pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
// DbgPrint("进程PID= %ld \n", pid); UNREFERENCED_PARAMETER(RegistrationContext); // 验证是否是需要的进程
if (CheckProcess((PEPROCESS)pOperationInformation->Object))
{
// 创建句柄
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
DbgPrint("lyshark.exe 进程打开事件 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
DbgPrint("[LyShark Message] 拦截进程打开 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
// 复制句柄
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
DbgPrint("lyshark.exe 进程被关闭 \n");
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
}
return OB_PREOP_SUCCESS;
} VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回调卸载完成... \n");
} NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n"); BypassCheckSign(Driver); OB_OPERATION_REGISTRATION ob_process_callback;
OB_CALLBACK_REGISTRATION op_process_operation; memset(&ob_process_callback, 0, sizeof(ob_process_callback));
ob_process_callback.ObjectType = PsProcessType;
ob_process_callback.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ob_process_callback.PreOperation = MyLySharkProcessObjectCallBack;
ob_process_callback.PostOperation = NULL; RtlUnicodeStringInit(&op_process_operation.Altitude, L"600000");
op_process_operation.RegistrationContext = NULL;
op_process_operation.Version = OB_FLT_REGISTRATION_VERSION;
op_process_operation.OperationRegistration = &ob_process_callback;
op_process_operation.OperationRegistrationCount = 1; // 注册进程回调
if (ObRegisterCallbacks(&op_process_operation, &Globle_Object_Handle))
{
DbgPrint("进程回调注册成功...");
} Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

加载这个驱动,当有进程被创建时,则首先判断是否是lyshark.exe如果是则直接禁止打开,也就是终止掉。

同理进程可以被拦截,那么如果增加更多的过滤条件,则线程同样可以被拦截,拦截线程代码如下所示。

#include <ntddk.h>
#include <ntstrsafe.h> #define THREAD_TERMINATE2 0x1 // 导出两个API
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process); // 全局句柄
PVOID Globle_Object_Handle = NULL; // 绕过签名检测
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA; PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
} // 判断是否是需要保护的进程
BOOLEAN CheckProcess(PEPROCESS eprocess)
{
char *Name = PsGetProcessImageFileName(eprocess);
if (!_stricmp("lyshark.exe", Name))
return TRUE;
else
return FALSE;
} // 线程回调
OB_PREOP_CALLBACK_STATUS MyThreadObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
PEPROCESS ep;
PETHREAD et;
HANDLE pid; // 线程过滤
if (pOperationInformation->ObjectType != *PsThreadType)
{
return OB_PREOP_SUCCESS;
} et = (PETHREAD)pOperationInformation->Object;
ep = IoThreadToProcess(et);
pid = PsGetProcessId(ep); // DbgPrint("线程PID= %ld | TID= %ld \n", pid, PsGetThreadId(et));
UNREFERENCED_PARAMETER(RegistrationContext); if (CheckProcess(ep))
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
DbgPrint("[LyShark] 拦截lyshark.exe进程内 %d 线程创建 \n", PsGetThreadId(et));
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
}
return OB_PREOP_SUCCESS;
} VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回调卸载完成... \n");
} NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n"); BypassCheckSign(Driver); OB_OPERATION_REGISTRATION ob_thread_callback;
OB_CALLBACK_REGISTRATION op_thread_operation; memset(&ob_thread_callback, 0, sizeof(ob_thread_callback));
ob_thread_callback.ObjectType = PsThreadType;
ob_thread_callback.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ob_thread_callback.PreOperation = MyThreadObjectCallBack;
ob_thread_callback.PostOperation = NULL; RtlUnicodeStringInit(&op_thread_operation.Altitude, L"600001");
op_thread_operation.RegistrationContext = NULL;
op_thread_operation.Version = OB_FLT_REGISTRATION_VERSION;
op_thread_operation.OperationRegistration = &ob_thread_callback;
op_thread_operation.OperationRegistrationCount = 1; // 注册进程回调
if (ObRegisterCallbacks(&op_thread_operation, &Globle_Object_Handle))
{
DbgPrint("进程回调注册成功...");
} Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

这段驱动加载后,如果有新线程被创建,则会被拦截并打印输出,效果图如下。

7.2 Windows驱动开发:内核注册并监控对象回调的更多相关文章

  1. Windows驱动开发-内核常用内存函数

    搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool

  2. Windows驱动开发(中间层)

    Windows驱动开发 一.前言 依据<Windows内核安全与驱动开发>及MSDN等网络质料进行学习开发. 二.初步环境 1.下载安装WDK7.1.0(WinDDK\7600.16385 ...

  3. [Windows驱动开发](一)序言

    笔者学习驱动编程是从两本书入门的.它们分别是<寒江独钓——内核安全编程>和<Windows驱动开发技术详解>.两本书分别从不同的角度介绍了驱动程序的制作方法. 在我理解,驱动程 ...

  4. windows 驱动开发入门——驱动中的数据结构

    最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...

  5. Windows驱动开发-IRP的完成例程

    <Windows驱动开发技术详解 >331页, 在将IRP发送给底层驱动或其他驱动之前,可以对IRP设置一个完成例程,一旦底层驱动将IRP完成后,IRP完成例程立刻被处罚,通过设置完成例程 ...

  6. C++第三十八篇 -- 研究一下Windows驱动开发(二)--WDM式驱动的加载

    基于Windows驱动开发技术详解这本书 一.简单的INF文件剖析 INF文件是一个文本文件,由若干个节(Section)组成.每个节的名称用一个方括号指示,紧接着方括号后面的就是节内容.每一行就是一 ...

  7. C++第三十三篇 -- 研究一下Windows驱动开发(一)内部构造介绍

    因为工作原因,需要做一些与网卡有关的测试,其中涉及到了驱动这一块的知识,虽然程序可以运行,但是不搞清楚,心里总是不安,觉得没理解清楚.因此想看一下驱动开发.查了很多资料,看到有人推荐Windows驱动 ...

  8. windows驱动开发推荐书籍

    [作者] 猪头三 个人网站 :http://www.x86asm.com/ [序言] 很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资料少有关系.大多学的驱动开发资料都 ...

  9. Windows驱动——读书笔记《Windows驱动开发技术详解》

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  请通过右侧公告中的“联系邮 ...

  10. Windows 驱动开发 - 5

    上篇<Windows 驱动开发 - 4>我们已经完毕了硬件准备. 可是我们还没有详细的数据操作,比如接收读写操作. 在WDF中进行此类操作前须要进行设备的IO控制,已保持数据的完整性. 我 ...

随机推荐

  1. IDEA中无法import自己工程中类的问题解决方法

    今天开个很久没搞的工程,刚开的时候一片红,很自然的想到,要去配置一下项目的JDK,但是配置好之后,又出了个诡异问题:项目可以运行,但是import项目内部自己写的类的时候,都出现了红色错误.虽然imp ...

  2. Windows 10 修改环境变量不重启生效的解决方案

    # 表示 Win 键 #R 进入 cmd(不要使用 Listary 的 cmd 方式进入,设置不会生效) 键入 set PATH=C: 关闭窗口 同样方式打开 cmd 键入 echo %PATH%,会 ...

  3. 深入浅出 ZooKeeper

    ZooKeeper 是一个分布式协调服务 ,由 Apache 进行维护. ZooKeeper 可以视为一个高可用的文件系统. ZooKeeper 可以用于发布/订阅.负载均衡.命令服务.分布式协调/通 ...

  4. vue学习笔记 五、创建子组件实例

    系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...

  5. mock.js使用

    前后端联调必备技术之Mock讲解 什么是Mock数据? 处于开发环境模拟接口返回的数据(用于开发状态后端还没给接口) 不会影响生产环境,只是方便我们还没与后端交互时,不阻塞我们开发流程 mock数据好 ...

  6. qiankun 微前端实例化使用

    一.qiankun使用场景 1. 简介:qiankun是在single-spa的基础上实现的,可以保证各个项目独立使用,也可以集成使用.各系统之间不受技术栈的限制,集成使用也能保证各样式和全局变量的隔 ...

  7. Android Gradle 导入 Kotlin gRPC

    project build.gradle plugins { id "com.google.protobuf" version "0.9.1" apply fa ...

  8. 安卓系统如何使用谷歌框架下的app?

    1.问题 安卓系统从理论上无法使用谷歌框架下的应用(比如像GMail,YouTube,Google play等等),会导致一些麻烦(闪退,卡在登陆界面等等) 注意:使用前提是会魔法,否则请绕道 2.解 ...

  9. 【TouchGFX 】使用 CubeMX 创建 TouchGFX 工程时 LCD 显示为雪花屏

    经几个晚上折腾,修改大量的LTDC时钟.时序,FMC时序等,结果还是一样,耐心与好使的工程仔细对比,发现是时钟源配置问题,真是冤,聊以此以示纪念 实质上是没有分清有源和无源晶振 无源晶振又被叫做 谐振 ...

  10. phpcms : 解决phpcms后台验证码不显示的问题