前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >驱动开发:对象回调监控文件访问

驱动开发:对象回调监控文件访问

作者头像
微软技术分享
发布2022-12-28 16:22:03
2570
发布2022-12-28 16:22:03
举报
文章被收录于专栏:Windows 内核安全编程技术实践

无论在用户层还是内核层,操作文件的流程基本一致,除了在API函数上的区别(用户层调用用户层API,内核层调用内核API)以外其他基本一致,先讲解一下文件系统执行的流程。实现文件的监控呢,比如当文件被访问时自动触发回调,看如下代码实现方式。

以NTFS文件系统为例:

  • 假设我们要读取文件,他们最终都会被转换为IRP(I/O Request Package)请求,该请求会被分发到 NTFS.sys 驱动中的 IRP_MJ_READ 分发函数里。
  • NTFS.sys 驱动经过处理后,继续将IRP请求传递给CLASSPNP.sys磁盘类驱动的 IRP_MJ_READ 分发函数。
  • 磁盘类驱动处理完毕后,又把 IRP 传给磁盘ATAPI.SYS小端口驱动的 IRP_MJ_SCSI 分发函数中。
  • 依靠 HAL.DLL 发送相关的硬件中断请求,而硬件中断则负责完成实际的磁盘寻址,此时数据就真的从硬盘里读取了出来,然后再按照相反的方向把数据返回到调用者。

那么如何实现文件的监控呢,比如当文件被访问时自动触发回调,看如下代码实现方式。

代码语言:javascript
复制
#include <ntddk.h>
#include <string.h>

PVOID obHandle;

typedef struct _OBJECT_TYPE_INITIALIZER
{
	/*0x000*/     UINT16       Length;
	union
	{
		/*0x002*/         UINT8        ObjectTypeFlags;
		struct
		{
			/*0x002*/             UINT8        CaseInsensitive : 1;
			/*0x002*/             UINT8        UnnamedObjectsOnly : 1;
			/*0x002*/             UINT8        UseDefaultObject : 1;
			/*0x002*/             UINT8        SecurityRequired : 1;
			/*0x002*/             UINT8        MaintainHandleCount : 1;
			/*0x002*/             UINT8        MaintainTypeList : 1;
			/*0x002*/             UINT8        SupportsObjectCallbacks : 1;
		};
	};
	/*0x004*/     ULONG32      ObjectTypeCode;
	/*0x008*/     ULONG32      InvalidAttributes;
	/*0x00C*/     struct _GENERIC_MAPPING GenericMapping;
	/*0x01C*/     ULONG32      ValidAccessMask;
	/*0x020*/     ULONG32      RetainAccess;
	/*0x024*/     enum _POOL_TYPE PoolType;
	/*0x028*/     ULONG32      DefaultPagedPoolCharge;
	/*0x02C*/     ULONG32      DefaultNonPagedPoolCharge;
	/*0x030*/     PVOID DumpProcedure;
	/*0x038*/     PVOID OpenProcedure;
	/*0x040*/     PVOID CloseProcedure;
	/*0x048*/     PVOID DeleteProcedure;
	/*0x050*/     PVOID ParseProcedure;
	/*0x058*/     PVOID SecurityProcedure;
	/*0x060*/     PVOID QueryNameProcedure;
	/*0x068*/     PVOID OkayToCloseProcedure;
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _EX_PUSH_LOCK                 // 7 elements, 0x8 bytes (sizeof)
{
	union                                    // 3 elements, 0x8 bytes (sizeof)
	{
		struct                               // 5 elements, 0x8 bytes (sizeof)
		{
			/*0x000*/             UINT64       Locked : 1;         // 0 BitPosition
			/*0x000*/             UINT64       Waiting : 1;        // 1 BitPosition
			/*0x000*/             UINT64       Waking : 1;         // 2 BitPosition
			/*0x000*/             UINT64       MultipleShared : 1; // 3 BitPosition
			/*0x000*/             UINT64       Shared : 60;        // 4 BitPosition
		};
		/*0x000*/         UINT64       Value;
		/*0x000*/         VOID*        Ptr;
	};
}EX_PUSH_LOCK, *PEX_PUSH_LOCK;

typedef struct _MY_OBJECT_TYPE
{
	/*0x000*/     struct  _LIST_ENTRY TypeList;
	/*0x010*/     struct  _UNICODE_STRING Name;
	/*0x020*/     VOID*   DefaultObject;
	/*0x028*/     UINT8   Index;
	/*0x029*/     UINT8   _PADDING0_[0x3];
	/*0x02C*/     ULONG32 TotalNumberOfObjects;
	/*0x030*/     ULONG32 TotalNumberOfHandles;
	/*0x034*/     ULONG32 HighWaterNumberOfObjects;
	/*0x038*/     ULONG32 HighWaterNumberOfHandles;
	/*0x03C*/     UINT8   _PADDING1_[0x4];
	/*0x040*/     struct _OBJECT_TYPE_INITIALIZER TypeInfo;
	/*0x0B0*/     struct _EX_PUSH_LOCK TypeLock;
	/*0x0B8*/     ULONG32      Key;
	/*0x0BC*/     UINT8        _PADDING2_[0x4];
	/*0x0C0*/     struct _LIST_ENTRY CallbackList;
}MY_OBJECT_TYPE, *PMY_OBJECT_TYPE;


// 要监控文件,首先要文件对象支持对象回调
VOID EnableObType(POBJECT_TYPE ObjectType)
{
	PMY_OBJECT_TYPE myobtype = (PMY_OBJECT_TYPE)ObjectType;
	myobtype->TypeInfo.SupportsObjectCallbacks = 1;
}

OB_PREOP_CALLBACK_STATUS preFileCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
	UNICODE_STRING DosName;
	PFILE_OBJECT fileo = OperationInformation->Object;
	HANDLE CurrentProcessId = PsGetCurrentProcessId();
	UNREFERENCED_PARAMETER(RegistrationContext);

	if (OperationInformation->ObjectType != *IoFileObjectType) { return OB_PREOP_SUCCESS; }
	//过滤无效指针
	if (fileo->FileName.Buffer == NULL ||
		!MmIsAddressValid(fileo->FileName.Buffer) ||
		fileo->DeviceObject == NULL ||
		!MmIsAddressValid(fileo->DeviceObject))
		return OB_PREOP_SUCCESS;

	// 此处可添加过滤规则,过滤掉无效文件名
	if (!_wcsicmp(fileo->FileName.Buffer, L"\\Endpoint") ||
		!_wcsicmp(fileo->FileName.Buffer, L"?") ||
		!_wcsicmp(fileo->FileName.Buffer, L"\\.\\.") ||
		!_wcsicmp(fileo->FileName.Buffer, L"\\"))
		return OB_PREOP_SUCCESS;

	if (wcsstr(_wcslwr(fileo->FileName.Buffer), L".exe")) // 如果包含有exe文件,则触发
	{
		DbgPrint("当前ID= %ld ---> 路径= %wZ", (ULONG64)CurrentProcessId, &fileo->FileName);
	}
	return OB_PREOP_SUCCESS;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
	UNREFERENCED_PARAMETER(driver);
	ObUnRegisterCallbacks(obHandle);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	OB_CALLBACK_REGISTRATION obReg;
	OB_OPERATION_REGISTRATION opReg;

	EnableObType(*IoFileObjectType);
	memset(&obReg, 0, sizeof(obReg));
	obReg.Version = ObGetFilterVersion();
	obReg.OperationRegistrationCount = 1;
	obReg.RegistrationContext = NULL;
	RtlInitUnicodeString(&obReg.Altitude, L"321000");
	obReg.OperationRegistration = &opReg;
	memset(&opReg, 0, sizeof(opReg));
	opReg.ObjectType = IoFileObjectType;
	opReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
	opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preFileCallBack;
	status = ObRegisterCallbacks(&obReg, &obHandle);
	
	if (!NT_SUCCESS(status))
		status = STATUS_UNSUCCESSFUL;
	Driver->DriverUnload = UnDriver;
	return status;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档