该代码利用微软提供的注册表回调函数CmRegisterCallback, 无需任何SSDT hook
不仅能够进行注册表监控,还可以拦截。
驱动完整代码如下:
#define NTDDI_WINXPSP2 0x05010200
#define OSVERSION_MASK 0xFFFF0000
#define SPVERSION_MASK 0x0000FF00
#define SUBVERSION_MASK 0x000000FF
//
// macros to extract various version fields from the NTDDI version
//
#define OSVER(Version) ((Version) & OSVERSION_MASK)
#define SPVER(Version) (((Version) & SPVERSION_MASK) >> 8)
#define SUBVER(Version) (((Version) & SUBVERSION_MASK) )
//#define NTDDI_VERSION NTDDI_WINXPSP2
#include <ntifs.h>
#include <wdm.h>
#include <ntstrsafe.h>
#define FILE_DEVICE_UNKNOWN 0x00000022
#define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN
#define IOCTL_CAPTURE_GET_REGEVENTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER,FILE_READ_DATA | FILE_WRITE_DATA)
#define USERSPACE_CONNECTION_TIMEOUT 10
#define REGISTRY_POOL_TAG 'pRE'
typedef unsigned int UINT;
typedef char* PCHAR;
typedef PVOID POBJECT;
/* Registry event */
typedef struct _REGISTRY_EVENT
{
REG_NOTIFY_CLASS eventType;
TIME_FIELDS time;
HANDLE processId;
ULONG dataType;
ULONG dataLengthB;
ULONG registryPathLengthB;
/* Contains path and optionally data */
UCHAR registryData[];
} REGISTRY_EVENT, *PREGISTRY_EVENT;
/* Storage for registry event to be put into a linked list */
typedef struct _REGISTRY_EVENT_PACKET
{
LIST_ENTRY Link;
PREGISTRY_EVENT pRegistryEvent;
} REGISTRY_EVENT_PACKET, *PREGISTRY_EVENT_PACKET;
/* Context stuff */
typedef struct _CAPTURE_REGISTRY_MANAGER
{
PDEVICE_OBJECT deviceObject;
BOOLEAN bReady;
LARGE_INTEGER registryCallbackCookie;
LIST_ENTRY lQueuedRegistryEvents;
KTIMER connectionCheckerTimer;
KDPC connectionCheckerFunction;
KSPIN_LOCK lQueuedRegistryEventsSpinLock;
ULONG lastContactTime;
} CAPTURE_REGISTRY_MANAGER, *PCAPTURE_REGISTRY_MANAGER;
/* Methods */
NTSTATUS KDispatchIoctl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS KDispatchCreateClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
VOID UnloadDriver ( PDRIVER_OBJECT DriverObject );
NTSTATUS RegistryCallback ( IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2 );
//BOOLEAN GetRegistryObjectCompleteName(PREGISTRY_EVENT pRegistryEvent, PUNICODE_STRING pPartialObjectName, PVOID pRegistryObject);
//VOID QueueRegistryEvent(PREGISTRY_EVENT pRegistryEvent);
VOID UpdateLastContactTime();
ULONG GetCurrentTime();
NTSTATUS HandleIoctlGetRegEvents ( IN PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION pIoStackIrp, UINT* pdwDataWritten );
VOID ConnectionChecker (
IN struct _KDPC* Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
/* Global values */
PDEVICE_OBJECT gpDeviceObject;
/* Main entry point into the driver, is called when the driver is loaded */
NTSTATUS DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
UNICODE_STRING uszDriverString;
UNICODE_STRING uszDeviceString;
LARGE_INTEGER registryEventsTimeout;
PDEVICE_OBJECT pDeviceObject;
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
// Point uszDriverString at the driver name
RtlInitUnicodeString ( &uszDriverString, L"[url=file://\\Device\\RegistryMonitor]\\Device\\RegistryMonitor[/url]" );
// Create and initialize device object
status = IoCreateDevice (
DriverObject,
sizeof ( CAPTURE_REGISTRY_MANAGER ),
&uszDriverString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDeviceObject
);
if ( !NT_SUCCESS ( status ) )
{
DbgPrint ( "RegistryMonitor: ERROR IoCreateDevice -> [url=file://\\Device\\RegistryMonitor]\\Device\\RegistryMonitor[/url] - %08x\n", status );
return status;
}
/* Set global device object to newly created object */
gpDeviceObject = pDeviceObject;
/* Get the registr manager from the extension of the device */
pRegistryManager = gpDeviceObject->DeviceExtension;
pRegistryManager->bReady = FALSE;
/* Point uszDeviceString at the device name */
RtlInitUnicodeString ( &uszDeviceString, L"[url=file://\\DosDevices\\RegistryMonitor]\\DosDevices\\RegistryMonitor[/url]" );
/* Create symbolic link to the user-visible name */
status = IoCreateSymbolicLink ( &uszDeviceString, &uszDriverString );
if ( !NT_SUCCESS ( status ) )
{
DbgPrint ( "RegistryMonitor: ERROR IoCreateSymbolicLink -> [url=file://\\DosDevices\\RegistryMonitor]\\DosDevices\\RegistryMonitor[/url] - %08x\n",
status );
IoDeleteDevice ( pDeviceObject );
return status;
}
KeInitializeSpinLock ( &pRegistryManager->lQueuedRegistryEventsSpinLock );
InitializeListHead ( &pRegistryManager->lQueuedRegistryEvents );
// Load structure to point to IRP handlers
DriverObject->DriverUnload = UnloadDriver;
DriverObject->MajorFunction[IRP_MJ_CREATE] = KDispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KDispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KDispatchIoctl;
status = CmRegisterCallback ( RegistryCallback, pRegistryManager, &pRegistryManager->registryCallbackCookie );
if ( !NT_SUCCESS ( status ) )
{
DbgPrint ( "RegistryMonitor: ERROR CmRegisterCallback - %08x\n", status );
return status;
}
UpdateLastContactTime();
/* Create a DPC routine so that it can be called periodically */
KeInitializeDpc ( &pRegistryManager->connectionCheckerFunction,
( PKDEFERRED_ROUTINE ) ConnectionChecker, pRegistryManager );
KeInitializeTimer ( &pRegistryManager->connectionCheckerTimer );
registryEventsTimeout.QuadPart = 0;
/* Set the ConnectionChecker routine to be called every so often */
KeSetTimerEx ( &pRegistryManager->connectionCheckerTimer,
registryEventsTimeout,
( USERSPACE_CONNECTION_TIMEOUT + ( USERSPACE_CONNECTION_TIMEOUT / 2 ) ) * 1000,
&pRegistryManager->connectionCheckerFunction );
pRegistryManager->bReady = TRUE;
DbgPrint ( "RegistryMonitor: Successfully Loaded\n" );
/* Return success */
return STATUS_SUCCESS;
}
/* Checks to see if the registry monitor has received an IOCTL from a userspace
program in a while. If it hasn't then all old queued registry events are
cleared. This is called periodically when the driver is loaded */
VOID ConnectionChecker (
IN struct _KDPC* Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PCAPTURE_REGISTRY_MANAGER pRegistryManager = ( PCAPTURE_REGISTRY_MANAGER ) DeferredContext;
if ( ( GetCurrentTime() - pRegistryManager->lastContactTime ) > ( USERSPACE_CONNECTION_TIMEOUT + ( USERSPACE_CONNECTION_TIMEOUT / 2 ) ) )
{
DbgPrint ( "RegistryMonitor: WARNING Userspace IOCTL timeout, clearing old queued registry events\n" );
while ( !IsListEmpty ( &pRegistryManager->lQueuedRegistryEvents ) )
{
PLIST_ENTRY head = ExInterlockedRemoveHeadList ( &pRegistryManager->lQueuedRegistryEvents, &pRegistryManager->lQueuedRegistryEventsSpinLock );
PREGISTRY_EVENT_PACKET pRegistryEventPacket = CONTAINING_RECORD ( head, REGISTRY_EVENT_PACKET, Link );
ExFreePoolWithTag ( pRegistryEventPacket->pRegistryEvent, REGISTRY_POOL_TAG );
ExFreePoolWithTag ( pRegistryEventPacket, REGISTRY_POOL_TAG );
}
}
}
NTSTATUS KDispatchCreateClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest ( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
NTSTATUS HandleIoctlGetRegEvents ( IN PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION pIoStackIrp, UINT* pdwDataWritten )
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCHAR pOutputBuffer = Irp->UserBuffer;
UINT dwOutputBufferSize = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
/* Get the registry manager from the device extension */
pRegistryManager = gpDeviceObject->DeviceExtension;
*pdwDataWritten = 0;
/* Check we are allowed to write into the buffer passed from the user space program */
if ( pOutputBuffer )
{
try
{
ProbeForWrite ( pOutputBuffer,
pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength,
__alignof ( REGISTRY_EVENT ) );
if ( pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof ( REGISTRY_EVENT ) )
{
PLIST_ENTRY pRegistryListHead;
PREGISTRY_EVENT_PACKET pRegistryPacket;
UINT bufferSpace = dwOutputBufferSize;
UINT bufferSpaceUsed = 0;
/* Fill the buffer passed from userspace with registry events */
while ( !IsListEmpty ( &pRegistryManager->lQueuedRegistryEvents ) &&
( bufferSpaceUsed < bufferSpace ) &&
( ( bufferSpace - bufferSpaceUsed ) >= sizeof ( REGISTRY_EVENT ) ) )
{
UINT registryEventSize = 0;
pRegistryListHead = ExInterlockedRemoveHeadList ( &pRegistryManager->lQueuedRegistryEvents, &pRegistryManager->lQueuedRegistryEventsSpinLock );
pRegistryPacket = CONTAINING_RECORD ( pRegistryListHead, REGISTRY_EVENT_PACKET, Link );
registryEventSize = sizeof ( REGISTRY_EVENT ) + pRegistryPacket->pRegistryEvent->registryPathLengthB + pRegistryPacket->pRegistryEvent->dataLengthB;
if ( ( bufferSpace - bufferSpaceUsed ) >= registryEventSize )
{
//DbgPrint("Sending-%i: %ls\n",bufferSpaceUsed, pRegistryPacket->pRegistryEvent->registryPath);
RtlCopyMemory ( pOutputBuffer + bufferSpaceUsed, pRegistryPacket->pRegistryEvent, registryEventSize );
bufferSpaceUsed += registryEventSize;
ExFreePoolWithTag ( pRegistryPacket->pRegistryEvent, REGISTRY_POOL_TAG );
ExFreePoolWithTag ( pRegistryPacket, REGISTRY_POOL_TAG );
}
else
{
ExInterlockedInsertHeadList ( &pRegistryManager->lQueuedRegistryEvents, &pRegistryPacket->Link, &pRegistryManager->lQueuedRegistryEventsSpinLock );
break;
}
}
/* Return the amount of space that is occupied with registry events */
*pdwDataWritten = bufferSpaceUsed;
status = STATUS_SUCCESS;
}
else
{
*pdwDataWritten = sizeof ( REGISTRY_EVENT );
status = STATUS_BUFFER_TOO_SMALL;
}
}
except ( EXCEPTION_EXECUTE_HANDLER )
{
status = GetExceptionCode();
DbgPrint ( "RegistryMonitor: EXCEPTION IOCTL_CAPTURE_GET_REGEVENTS - %i\n", status );
}
}
return status;
}
NTSTATUS KDispatchIoctl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation ( Irp );
UINT dwDataWritten = 0;
switch ( irpStack->Parameters.DeviceIoControl.IoControlCode )
{
case IOCTL_CAPTURE_GET_REGEVENTS:
UpdateLastContactTime();
status = HandleIoctlGetRegEvents ( DeviceObject, Irp, irpStack, &dwDataWritten );
break;
default:
break;
}
Irp->IoStatus.Status = status;
// Set # of bytes to copy back to user-mode...
if ( NT_SUCCESS ( status ) )
Irp->IoStatus.Information = dwDataWritten;
else
Irp->IoStatus.Information = 0;
IoCompleteRequest ( Irp, IO_NO_INCREMENT );
return status;
}
VOID UpdateLastContactTime()
{
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
/* Get the process manager from the device extension */
pRegistryManager = gpDeviceObject->DeviceExtension;
pRegistryManager->lastContactTime = GetCurrentTime();
}
ULONG GetCurrentTime()
{
LARGE_INTEGER currentSystemTime;
LARGE_INTEGER currentLocalTime;
ULONG time;
KeQuerySystemTime ( ¤tSystemTime );
ExSystemTimeToLocalTime ( ¤tSystemTime, ¤tLocalTime );
RtlTimeToSecondsSince1970 ( ¤tLocalTime, &time );
return time;
}
BOOLEAN GetRegistryObjectCompleteName ( PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject )
{
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
BOOLEAN foundCompleteName = FALSE;
BOOLEAN partial = FALSE;
/* Get the process manager from the device extension */
pRegistryManager = gpDeviceObject->DeviceExtension;
/* Check to see if everything is valid */
/* We sometimes see a partial registry object name which is actually complete
however if fails one of these checks for some reason. Not sure whether to report
this registry event */
if ( ( !MmIsAddressValid ( pRegistryObject ) ) ||
( pRegistryObject == NULL ) )
{
return FALSE;
}
/* Check to see if the partial name is really the complete name */
if ( pPartialRegistryPath != NULL )
{
if ( ( ( ( pPartialRegistryPath->Buffer[0] == '\\' ) || ( pPartialRegistryPath->Buffer[0] == '%' ) ) ||
( ( pPartialRegistryPath->Buffer[0] == 'T' ) && ( pPartialRegistryPath->Buffer[1] == 'R' ) && ( pPartialRegistryPath->Buffer[2] == 'Y' )
&& ( pPartialRegistryPath->Buffer[3] == '\\' ) ) ) )
{
RtlUnicodeStringCopy ( pRegistryPath, pPartialRegistryPath );
partial = TRUE;
foundCompleteName = TRUE;
}
}
if ( !foundCompleteName )
{
/* Query the object manager in the kernel for the complete name */
NTSTATUS status;
ULONG returnedLength;
PUNICODE_STRING pObjectName = NULL;
status = ObQueryNameString ( pRegistryObject, ( POBJECT_NAME_INFORMATION ) pObjectName, 0, &returnedLength );
if ( status == STATUS_INFO_LENGTH_MISMATCH )
{
pObjectName = ExAllocatePoolWithTag ( NonPagedPool, returnedLength, REGISTRY_POOL_TAG );
status = ObQueryNameString ( pRegistryObject, ( POBJECT_NAME_INFORMATION ) pObjectName, returnedLength, &returnedLength );
if ( NT_SUCCESS ( status ) )
{
RtlUnicodeStringCopy ( pRegistryPath, pObjectName );
foundCompleteName = TRUE;
}
ExFreePoolWithTag ( pObjectName, REGISTRY_POOL_TAG );
}
}
//ASSERT(foundCompleteName == TRUE);
return foundCompleteName;
}
BOOLEAN QueueRegistryEvent ( PREGISTRY_EVENT pRegistryEvent )
{
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
/* Get the registry manager from the device extension */
pRegistryManager = gpDeviceObject->DeviceExtension;
/* Check the last contact time of the user space program before queuing */
if ( ( GetCurrentTime() - pRegistryManager->lastContactTime ) <= USERSPACE_CONNECTION_TIMEOUT )
{
PREGISTRY_EVENT_PACKET pRegistryEventPacket = ExAllocatePoolWithTag ( NonPagedPool, sizeof ( REGISTRY_EVENT_PACKET ), REGISTRY_POOL_TAG );
pRegistryEventPacket->pRegistryEvent = pRegistryEvent;
/* Queue registry event */
ExInterlockedInsertTailList ( &pRegistryManager->lQueuedRegistryEvents, &pRegistryEventPacket->Link,
&pRegistryManager->lQueuedRegistryEventsSpinLock );
return TRUE;
}
return FALSE;
}
NTSTATUS RegistryCallback ( IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2 )
{
//REGISTRY_EVENT registryEvent;
BOOLEAN registryEventIsValid = FALSE;
BOOLEAN exception = FALSE;
LARGE_INTEGER CurrentSystemTime;
LARGE_INTEGER CurrentLocalTime;
TIME_FIELDS TimeFields;
int type;
UNICODE_STRING registryPath;
UCHAR* registryData = NULL;
ULONG registryDataLength = 0;
ULONG registryDataType = 0;
/* Allocate a large 64kb string ... maximum path name allowed in windows */
registryPath.Length = 0;
registryPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof ( WCHAR );
registryPath.Buffer = ExAllocatePoolWithTag ( NonPagedPool, registryPath.MaximumLength, REGISTRY_POOL_TAG );
if ( registryPath.Buffer == NULL )
{
return STATUS_SUCCESS;
}
/* Put the time this event occured into the registry event */
KeQuerySystemTime ( &CurrentSystemTime );
ExSystemTimeToLocalTime ( &CurrentSystemTime, &CurrentLocalTime );
//registryEvent.processId = PsGetCurrentProcessId();
//registryEvent.eventType = (REG_NOTIFY_CLASS)Argument1;
type = ( REG_NOTIFY_CLASS ) Argument1;
try
{
/* Large switch statement for all registry events ... fairly easy to understand */
switch ( type )
{
case RegNtPostCreateKey:
{
PREG_POST_CREATE_KEY_INFORMATION createKey = ( PREG_POST_CREATE_KEY_INFORMATION ) Argument2;
if ( NT_SUCCESS ( createKey->Status ) )
{
PVOID* registryObject = createKey->Object;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, createKey->CompleteName, *registryObject );
}
break;
}
case RegNtPostOpenKey:
{
PREG_POST_OPEN_KEY_INFORMATION openKey = ( PREG_POST_OPEN_KEY_INFORMATION ) Argument2;
if ( NT_SUCCESS ( openKey->Status ) )
{
PVOID* registryObject = openKey->Object;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, openKey->CompleteName, *registryObject );
}
break;
}
case RegNtPreDeleteKey:
{
PREG_DELETE_KEY_INFORMATION deleteKey = ( PREG_DELETE_KEY_INFORMATION ) Argument2;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, deleteKey->Object );
break;
}
case RegNtDeleteValueKey:
{
PREG_DELETE_VALUE_KEY_INFORMATION deleteValueKey = ( PREG_DELETE_VALUE_KEY_INFORMATION ) Argument2;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, deleteValueKey->Object );
if ( ( registryEventIsValid ) && ( deleteValueKey->ValueName->Length > 0 ) )
{
RtlUnicodeStringCatString ( ®istryPath, L"\\" );
RtlUnicodeStringCat ( ®istryPath, deleteValueKey->ValueName );
}
break;
}
case RegNtPreSetValueKey:
{
PREG_SET_VALUE_KEY_INFORMATION setValueKey = ( PREG_SET_VALUE_KEY_INFORMATION ) Argument2;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, setValueKey->Object );
if ( ( registryEventIsValid ) && ( setValueKey->ValueName->Length > 0 ) )
{
registryDataType = setValueKey->Type;
registryDataLength = setValueKey->DataSize;
registryData = ExAllocatePoolWithTag ( NonPagedPool, registryDataLength, REGISTRY_POOL_TAG );
if ( registryData != NULL )
{
RtlCopyBytes ( registryData, setValueKey->Data, setValueKey->DataSize );
}
else
{
DbgPrint ( "RegistryMonitor: ERROR can't allocate memory for setvalue data\n" );
}
RtlUnicodeStringCatString ( ®istryPath, L"\\" );
RtlUnicodeStringCat ( ®istryPath, setValueKey->ValueName );
}
break;
}
case RegNtEnumerateKey:
{
PREG_ENUMERATE_KEY_INFORMATION enumerateKey = ( PREG_ENUMERATE_KEY_INFORMATION ) Argument2;
registryDataType = enumerateKey->KeyInformationClass;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, enumerateKey->Object );
break;
}
case RegNtEnumerateValueKey:
{
PREG_ENUMERATE_VALUE_KEY_INFORMATION enumerateValueKey = ( PREG_ENUMERATE_VALUE_KEY_INFORMATION ) Argument2;
registryDataType = enumerateValueKey->KeyValueInformationClass;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, enumerateValueKey->Object );
break;
}
case RegNtQueryKey:
{
PREG_QUERY_KEY_INFORMATION queryKey = ( PREG_QUERY_KEY_INFORMATION ) Argument2;
registryDataType = queryKey->KeyInformationClass;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, queryKey->Object );
break;
}
case RegNtQueryValueKey:
{
PREG_QUERY_VALUE_KEY_INFORMATION queryValueKey = ( PREG_QUERY_VALUE_KEY_INFORMATION ) Argument2;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, queryValueKey->Object );
if ( ( registryEventIsValid ) && ( queryValueKey->ValueName->Length > 0 ) )
{
registryDataType = queryValueKey->KeyValueInformationClass;
RtlUnicodeStringCatString ( ®istryPath, L"\\" );
RtlUnicodeStringCat ( ®istryPath, queryValueKey->ValueName );
}
break;
}
case RegNtKeyHandleClose:
{
PREG_KEY_HANDLE_CLOSE_INFORMATION closeKey = ( PREG_KEY_HANDLE_CLOSE_INFORMATION ) Argument2;
registryEventIsValid = GetRegistryObjectCompleteName ( ®istryPath, NULL, closeKey->Object );
break;
}
default:
break;
}
}
except ( EXCEPTION_EXECUTE_HANDLER )
{
/* Do nothing if an exception occured ... event won't be queued */
registryEventIsValid = FALSE;
exception = TRUE;
}
if ( registryEventIsValid )
{
PREGISTRY_EVENT pRegistryEvent;
UINT eventSize = sizeof ( REGISTRY_EVENT ) + registryPath.Length + ( sizeof ( WCHAR ) ) + registryDataLength;
pRegistryEvent = ExAllocatePoolWithTag ( NonPagedPool, eventSize, REGISTRY_POOL_TAG );
if ( pRegistryEvent != NULL )
{
pRegistryEvent->registryPathLengthB = registryPath.Length + sizeof ( WCHAR );
pRegistryEvent->dataType = registryDataType;
pRegistryEvent->dataLengthB = registryDataLength;
//RtlStringCbCopyUnicodeString(pRegistryEvent->registryPath, pRegistryEvent->registryPathLength, ®istryPath);
RtlCopyBytes ( pRegistryEvent->registryData, registryPath.Buffer, registryPath.Length );
pRegistryEvent->registryData[registryPath.Length] = '\0';
pRegistryEvent->registryData[registryPath.Length + 1] = '\0';
RtlCopyBytes ( pRegistryEvent->registryData + pRegistryEvent->registryPathLengthB, registryData, registryDataLength );
if ( registryData != NULL )
{
ExFreePoolWithTag ( registryData, REGISTRY_POOL_TAG );
}
pRegistryEvent->processId = PsGetCurrentProcessId();
RtlTimeToTimeFields ( &CurrentLocalTime, &pRegistryEvent->time );
pRegistryEvent->eventType = ( REG_NOTIFY_CLASS ) Argument1;
if ( !QueueRegistryEvent ( pRegistryEvent ) )
{
ExFreePoolWithTag ( pRegistryEvent, REGISTRY_POOL_TAG );
}
}
}
if ( registryPath.Buffer != NULL )
{
ExFreePoolWithTag ( registryPath.Buffer, REGISTRY_POOL_TAG );
}
/* Always return a success ... we aren't doing any filtering, just monitoring */
return STATUS_SUCCESS;
}
void UnloadDriver ( IN PDRIVER_OBJECT DriverObject )
{
UNICODE_STRING uszDeviceString;
NTSTATUS ntStatus;
PCAPTURE_REGISTRY_MANAGER pRegistryManager;
/* Get the registry manager from the device extension */
pRegistryManager = gpDeviceObject->DeviceExtension;
if ( pRegistryManager->bReady == TRUE )
{
KeCancelTimer ( &pRegistryManager->connectionCheckerTimer );
CmUnRegisterCallback ( pRegistryManager->registryCallbackCookie );
pRegistryManager->bReady = FALSE;
}
while ( !IsListEmpty ( &pRegistryManager->lQueuedRegistryEvents ) )
{
PLIST_ENTRY head = ExInterlockedRemoveHeadList ( &pRegistryManager->lQueuedRegistryEvents, &pRegistryManager->lQueuedRegistryEventsSpinLock );
PREGISTRY_EVENT_PACKET pRegistryEventPacket = CONTAINING_RECORD ( head, REGISTRY_EVENT_PACKET, Link );
ExFreePoolWithTag ( pRegistryEventPacket->pRegistryEvent, REGISTRY_POOL_TAG );
ExFreePoolWithTag ( pRegistryEventPacket, REGISTRY_POOL_TAG );
}
RtlInitUnicodeString ( &uszDeviceString, L"[url=file://\\DosDevices\\RegistryMonitor]\\DosDevices\\RegistryMonitor[/url]" );
IoDeleteSymbolicLink ( &uszDeviceString );
if ( DriverObject->DeviceObject != NULL )
{
IoDeleteDevice ( DriverObject->DeviceObject );
}
}