驱动开发:内核注册并监控对象回调

驱动,开发,内核,注册,监控,对象,回调 · 浏览次数 : 579

小编点评

**代码分析** ```C# // 署名权 right to sign one's name on a piece of work // PowerBy: LyShark Email: me@lyshark.com#include <ntddk.h>#include <ntstrsafe.h>#define THREAD_TERMINATE2 0x1// 导出两个APINTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread) NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process) // 全局句柄PVOID Globle_Object_Handle = NULL;// 绕过签名检测void BypassCheckSign(PDRIVER_OBJECT pDriverObj){\ttypedef struct _LDR_DATA\t{\t\tstruct _LIST_ENTRY InLoadOrderLinks;\t\tstruct _LIST_ENTRY InMemoryOrderLinks;\t\tstruct _LIST_ENTRY InInitializationOrderLinks;\t\tVOID* DllBase;\t\tVOID* EntryPoint;\t\tULONG32 SizeOfImage;\t\tUINT8 _PADDING0_[0x4]; ... ``` **代码注释** * `right to sign one's name on a piece of work`:该句描述了线程回调的签名权,即线程只能签名其自身的名称。 * `PowerBy: LyShark`:该句指定了线程的运行环境,即LyShark。 * `Email: me@lyshark.com#include <ntddk.h>`:该句指定了线程的运行环境,即LyShark。 * `#define THREAD_TERMINATE2 0x1`:该句定义了一个线程终止的标志值,即0x1。 * `NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process)`:该函数获取了进程图像文件名。 * `// 全局句柄PVOID Globle_Object_Handle = NULL;// 绕过签名检测void BypassCheckSign(PDRIVER_OBJECT pDriverObj)`:该函数获取了进程的句柄,并绕过签名检测。 * `// PowerBy: LyShark Email: me@lyshark.com#include <ntddk.h>`:该句设置了线程的运行环境,即LyShark。 * `#define THREAD_TERMINATE2 0x1`:该句定义了一个线程终止的标志值,即0x1。 * `// 署名权 right to sign one's name on a piece of work`:该句描述了线程回调的签名权,即线程只能签名其自身的名称。

正文

在笔者上一篇文章《驱动开发:内核枚举进程与线程ObCall回调》简单介绍了如何枚举系统中已经存在的进程与线程回调,本章LyShark将通过对象回调实现对进程线程的句柄监控,在内核中提供了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卸载监控而已,实现代码如下所示。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \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;
	}
}

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

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \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如果是则直接禁止打开,也就是终止掉。

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

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \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;
}

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

参考文献

https://www.cnblogs.com/ciyze0101/p/5468175.html

与驱动开发:内核注册并监控对象回调相似的内容:

驱动开发:内核注册并监控对象回调

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

驱动开发:内核监控FileObject文件回调

本篇文章与上一篇文章`《驱动开发:内核注册并监控对象回调》`所使用的方式是一样的都是使用`ObRegisterCallbacks`注册回调事件,只不过上一篇博文中`LyShark`将回调结构体`OB_OPERATION_REGISTRATION`中的`ObjectType`填充为了`PsProcessType`和`PsThreadType`格式从而实现监控进程与线程,本章我们需要将该结构填充为`I

驱动开发:内核监视LoadImage映像回调

在笔者上一篇文章`《驱动开发:内核注册并监控对象回调》`介绍了如何运用`ObRegisterCallbacks`注册`进程与线程`回调,并通过该回调实现了`拦截`指定进行运行的效果,本章`LyShark`将带大家继续探索一个新的回调注册函数,`PsSetLoadImageNotifyRoutine`常用于注册`LoadImage`映像监视,当有模块被系统加载时则可以第一时间获取到加载模块信息,需要

驱动开发:内核监控Register注册表回调

在笔者前一篇文章`《驱动开发:内核枚举Registry注册表回调》`中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过`CmRegisterCallback`创建监控事件并传入自己的回调函数,与该创建对应的是

驱动开发:内核运用LoadImage屏蔽驱动

在笔者上一篇文章`《驱动开发:内核监视LoadImage映像回调》`中`LyShark`简单介绍了如何通过`PsSetLoadImageNotifyRoutine`函数注册回调来`监视驱动`模块的加载,注意我这里用的是`监视`而不是`监控`之所以是监视而不是监控那是因为`PsSetLoadImageNotifyRoutine`无法实现参数控制,而如果我们想要控制特定驱动的加载则需要自己做一些事情来

驱动开发:内核注册表增删改查

注册表是Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息,注册表是一个巨大的树形结构,无论在应用层还是内核层操作注册表都有独立的API函数可以使用,而在内核中读写注册表则需要使用内核装用API函数,如下将依次介绍并封装一些案例,实现对注册表的创建,删除,更新,查询等操作。

驱动开发:内核枚举Registry注册表回调

在笔者上一篇文章`《驱动开发:内核枚举LoadImage映像回调》`中`LyShark`教大家实现了枚举系统回调中的`LoadImage`通知消息,本章将实现对`Registry`注册表通知消息的枚举,与`LoadImage`消息不同`Registry`消息不需要解密只要找到`CallbackListHead`消息回调链表头并解析为`_CM_NOTIFY_ENTRY`结构即可实现枚举。

驱动开发:内核ShellCode线程注入

还记得`《驱动开发:内核LoadLibrary实现DLL注入》`中所使用的注入技术吗,我们通过`RtlCreateUserThread`函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简单的问题,如何注入`ShellCode`代码实现反弹Shell,这里需要注意一般情况下`RtlCreateUserThread`需要传入两个最重要的参数,一个是`StartAddress`开始执行的内存块

驱动开发:内核LoadLibrary实现DLL注入

远程线程注入是最常用的一种注入技术,在应用层注入是通过`CreateRemoteThread`这个函数实现的,通过该函数通过创建线程并调用 `LoadLibrary` 动态载入指定的DLL来实现注入,而在内核层同样存在一个类似的内核函数`RtlCreateUserThread`,但需要注意的是此函数未被公开,`RtlCreateUserThread`其实是对`NtCreateThreadEx`的包

驱动开发:内核RIP劫持实现DLL注入

本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用`CreateRemoteThread`直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的