驱动开发:对象回调监控文件访问
2023-06-13 09:16:21 时间
无论在用户层还是内核层,操作文件的流程基本一致,除了在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;
}
相关文章
- 自动监控文件并上传S3对象存储服务器 | Golang
- 监控浏览器tab切换或最小化事件
- 智慧校园监控系统解决方案
- druid监控配置
- 加油站智能视频监控系统(人员离岗、抽烟、打电话、烟火识别)
- 如何监控文件已成功通过EDI系统发给客户(三)-997回写
- Zabbix与乐维监控对比分析(一)——架构、性能篇
- 3.Prometheus监控入门之指标与标签使用说明
- 嵌入式Qt-网络监控摄像头
- 我想监控微信的一个文件夹,能不能自动每天把一些重复文件给删除掉,留几个最新的就可以?
- Grafana监控大屏配置参数介绍(一)
- 驱动开发:对象回调监控文件访问
- 虹科分享 | 网络流量监控 | 构建大型捕获文件(Ⅰ)——Wireshark过滤器和其他Allegro网络万用表工具
- 【实践】开源IDS网络流量分析与监控系统Zeek对接GrayLog
- 贪心算法在电脑监控软件中的利弊
- Linux文件系统监控实践(linux监控文件)
- MySQL监控神器:让您轻松管理数据库(mysql监测工具)
- Linux文件系统的实时监控(linux文件监控)
- Linux监控文件大小:实时掌握文件动态(linux监控文件大小)
- 构建基于ELK的Linux服务器监控系统(elklinux搭建)
- 应用Linux监控下Java应用性能分析(linux监控java)
- Linux文件变化监控:实时审视文件的状态(linux文件变化监控)
- 利用Linux文件监听实现实时数据监控与分析(linux文件监听)
- Zabbix监控(七):手动监控windows端口
- 提高Redis性能,必备的监控工具(redis性能监控工具)
- 监测MySQL语句,保护数据库安全(mysql 语句监控)
- 夹Linux自动监控文件夹内变化(linux 监听文件)
- 监控系统统计Redis每秒处理量(统计redis每秒处理量)
- 数据库nmon监控提升Oracle数据库性能的新方法(nmon采集Oracle)
- 自动化监控Redis编写灵活的脚本(监控redis的脚本)
- Java函数式编程(十二):监控文件修改