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


    无论在用户层还是内核层,操作文件的流程基本一致,除了在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 发送相关的硬件中断请求,而硬件中断则负责完成实际的磁盘寻址,此时数据就真的从硬盘里读取了出来,然后再按照相反的方向把数据返回到调用者。

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

    #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;
    }
    
  • 相关阅读:
    WPF入门教程系列六——布局介绍与Canvas(一)
    WPF入门教程系列五——Window 介绍
    WPF入门教程系列四——Dispatcher介绍
    WPF入门教程系列三——Application介绍(续)
    html5 标签
    html5
    sublime汉化教程
    html5 文本格式化
    主键和索引的区别
    响应式布局的开发基础知识
  • 原文地址:https://www.cnblogs.com/LyShark/p/11720764.html
Copyright © 2020-2023  润新知