📄 regmon.c
字号:
#include <ntddk.h>
#include <ntstrsafe.h>
#include <ntifs.h>
//NTSTATUS
//RtlUnicodeStringCopy(
// OUT PUNICODE_STRING DestinationString,
// IN PCUNICODE_STRING SourceString );
//
//NTSTATUS
//RtlUnicodeStringCatString(
// IN OUT PUNICODE_STRING DestinationString,
// IN LPCTSTR pszSrc );
//
//NTSTATUS
//RtlUnicodeStringCat(
// IN OUT PUNICODE_STRING DestinationString,
// IN PCUNICODE_STRING SourceString );
#define USERSPACE_CONNECTION_TIMEOUT 10
#define NTSTRSAFE_UNICODE_STRING_MAX_CCH 2147483647
#define REGISTRY_POOL_TAG 'pRE'
#define FILE_DEVICE_UNKNOWN 0x00000022
#define IOCTL_CAPTURE_GET_REGEVENTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER,FILE_READ_DATA | FILE_WRITE_DATA)
typedef unsigned int UINT;
PDEVICE_OBJECT gl_DeviceObject;
typedef struct _DEVICE_EXTENSION
{
BOOLEAN ready;
KSPIN_LOCK guard;
LIST_ENTRY queuedRegistryEvents;
LARGE_INTEGER registryCallbackCookie;
KTIMER connectionCheckerTimer;
KDPC connectionCheckerFunction;
ULONG lastContactTime;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
typedef struct _REGISTRY_EVENT
{
REG_NOTIFY_CLASS eventType;
TIME_FIELDS time;
HANDLE processId;
ULONG dataType;
ULONG dataLengthB;
ULONG registryPathLengthB;
UCHAR registryData[];
} REGISTRY_EVENT, * PREGISTRY_EVENT;
typedef struct _REGISTRY_EVENT_PACKET
{
LIST_ENTRY Link;
PREGISTRY_EVENT pRegistryEvent;
} REGISTRY_EVENT_PACKET, * PREGISTRY_EVENT_PACKET;
ULONG GetCurrentTime()
{
LARGE_INTEGER currentSystemTime;
LARGE_INTEGER currentLocalTime;
ULONG time;
KeQuerySystemTime(¤tSystemTime);
ExSystemTimeToLocalTime(¤tSystemTime,¤tLocalTime);
RtlTimeToSecondsSince1970(¤tLocalTime, &time);
return time;
}
VOID UpdateLastContactTime()
{
PDEVICE_EXTENSION pde;
pde = gl_DeviceObject->DeviceExtension;
pde->lastContactTime = GetCurrentTime();
}
VOID ConnectionChecker(PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
{
PDEVICE_EXTENSION pde = (PDEVICE_EXTENSION)DeferredContext;
if((GetCurrentTime() - pde->lastContactTime) > (USERSPACE_CONNECTION_TIMEOUT+(USERSPACE_CONNECTION_TIMEOUT/2)))
{
DbgPrint("RegistryMonitor: WARNING Userspace IOCTL timeout, clearing old queued registry events\n");
while(!IsListEmpty(&pde->queuedRegistryEvents))
{
PLIST_ENTRY head = ExInterlockedRemoveHeadList(&pde->queuedRegistryEvents, &pde->guard);
PREGISTRY_EVENT_PACKET packet = CONTAINING_RECORD(head, REGISTRY_EVENT_PACKET, Link);
ExFreePoolWithTag(packet->pRegistryEvent, REGISTRY_POOL_TAG);
ExFreePoolWithTag(packet, REGISTRY_POOL_TAG);
}
}
}
BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING RegPath, PUNICODE_STRING PartialRegPath, PVOID RegObject)
{
PDEVICE_EXTENSION pde = gl_DeviceObject->DeviceExtension;
BOOLEAN foundCompleteName = FALSE;
BOOLEAN partial = FALSE;
if((!MmIsAddressValid(RegObject)) || (RegObject == NULL))
{
return FALSE;
}
if(PartialRegPath != NULL)
{
if( (((PartialRegPath->Buffer[0] == '\\') || (PartialRegPath->Buffer[0] == '%')) ||
((PartialRegPath->Buffer[0] == 'T') && (PartialRegPath->Buffer[1] == 'R') && (PartialRegPath->Buffer[2] == 'Y') && (PartialRegPath->Buffer[3] == '\\'))) )
{
RtlUnicodeStringCopy(RegPath, PartialRegPath);
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(RegObject, (POBJECT_NAME_INFORMATION)pObjectName, 0, &returnedLength );
if(status == STATUS_INFO_LENGTH_MISMATCH)
{
pObjectName = ExAllocatePoolWithTag(NonPagedPool, returnedLength, REGISTRY_POOL_TAG);
status = ObQueryNameString(RegObject, (POBJECT_NAME_INFORMATION)pObjectName, returnedLength, &returnedLength );
if(NT_SUCCESS(status))
{
RtlUnicodeStringCopy(RegPath, pObjectName);
foundCompleteName = TRUE;
}
ExFreePoolWithTag(pObjectName, REGISTRY_POOL_TAG);
}
}
//ASSERT(foundCompleteName == TRUE);
return foundCompleteName;
}
BOOLEAN QueueRegistryEvent(PREGISTRY_EVENT pRegistryEvent)
{
PDEVICE_EXTENSION pde = gl_DeviceObject->DeviceExtension;
/* Check the last contact time of the user space program before queuing */
if( (GetCurrentTime() - pde->lastContactTime) <= USERSPACE_CONNECTION_TIMEOUT)
{
PREGISTRY_EVENT_PACKET pRegistryEventPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(REGISTRY_EVENT_PACKET), REGISTRY_POOL_TAG);
pRegistryEventPacket->pRegistryEvent = pRegistryEvent;
/* Queue registry event */
ExInterlockedInsertTailList(&pde->queuedRegistryEvents, &pRegistryEventPacket->Link, &pde->guard);
return TRUE;
}
return FALSE;
}
NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2)
{
BOOLEAN regEventIsValid = FALSE;
BOOLEAN exception = FALSE;
LARGE_INTEGER CurrentSystemTime;
LARGE_INTEGER CurrentLocalTime;
PREG_POST_CREATE_KEY_INFORMATION createKey = NULL;
PREG_POST_OPEN_KEY_INFORMATION openKey = NULL;
PREG_DELETE_VALUE_KEY_INFORMATION deleteValueKey = NULL;
PREG_DELETE_KEY_INFORMATION deleteKey = NULL;
PREG_SET_VALUE_KEY_INFORMATION setValueKey = NULL;
PREG_ENUMERATE_KEY_INFORMATION enumerateKey = NULL;
PREG_ENUMERATE_VALUE_KEY_INFORMATION enumerateValueKey = NULL;
PREG_QUERY_KEY_INFORMATION queryKey = NULL;
PREG_QUERY_VALUE_KEY_INFORMATION queryValueKey = NULL;
PREG_KEY_HANDLE_CLOSE_INFORMATION closeKey = NULL;
TIME_FIELDS TimeFields;
int type;
UNICODE_STRING RegPath;
PUCHAR regData = NULL;
ULONG regDataLength = 0;
ULONG regDataType = 0;
RegPath.Length = 0;
RegPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR);
RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, RegPath.MaximumLength, REGISTRY_POOL_TAG);
KeQuerySystemTime(&CurrentSystemTime);
ExSystemTimeToLocalTime(&CurrentSystemTime,&CurrentLocalTime);
type = (REG_NOTIFY_CLASS)Argument1;
__try
{
switch(type)
{
case RegNtPostCreateKey:
createKey = (PREG_POST_CREATE_KEY_INFORMATION)Argument2;
if(NT_SUCCESS(createKey->Status))
{
PVOID* registryObject = createKey->Object;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, createKey->CompleteName, *registryObject);
}
break;
case RegNtPostOpenKey:
openKey = (PREG_POST_OPEN_KEY_INFORMATION)Argument2;
if(NT_SUCCESS(openKey->Status))
{
PVOID* registryObject = openKey->Object;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, openKey->CompleteName, *registryObject);
}
break;
case RegNtPreDeleteKey:
deleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, NULL, deleteKey->Object);
break;
case RegNtDeleteValueKey:
deleteValueKey = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, NULL, deleteValueKey->Object);
if((regEventIsValid) && (deleteValueKey->ValueName->Length > 0))
{
RtlUnicodeStringCatString(&RegPath, L"\\");
RtlUnicodeStringCat(&RegPath, deleteValueKey->ValueName);
}
break;
case RegNtPreSetValueKey:
setValueKey = (PREG_SET_VALUE_KEY_INFORMATION)Argument2;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, NULL, setValueKey->Object);
if((regEventIsValid) && (setValueKey->ValueName->Length > 0))
{
regDataType = setValueKey->Type;
regDataLength = setValueKey->DataSize;
regData = ExAllocatePoolWithTag(NonPagedPool, regDataLength, REGISTRY_POOL_TAG);
if(regData != NULL)
{
RtlCopyBytes(regData,setValueKey->Data,setValueKey->DataSize);
}
else
{
DbgPrint("RegistryMonitor: ERROR can't allocate memory for setvalue data\n");
}
RtlUnicodeStringCatString(&RegPath, L"\\");
RtlUnicodeStringCat(&RegPath, setValueKey->ValueName);
}
break;
case RegNtEnumerateKey:
enumerateKey = (PREG_ENUMERATE_KEY_INFORMATION)Argument2;
regDataType = enumerateKey->KeyInformationClass;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, NULL, enumerateKey->Object);
break;
case RegNtEnumerateValueKey:
enumerateValueKey = (PREG_ENUMERATE_VALUE_KEY_INFORMATION)Argument2;
regDataType = enumerateValueKey->KeyValueInformationClass;
regEventIsValid = GetRegistryObjectCompleteName(&RegPath, NULL, enumerateValueKey->Object);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -