天天看點

驅動開發:對象回調監控檔案通路

  • 假設我們要讀取檔案,他們最終都會被轉換為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;
}