Files
jsecurity101-JonMon/JonMon/registry.cpp
T
2023-09-26 09:03:04 -05:00

484 lines
13 KiB
C++

#include "registry.h"
#include "shared.h"
#include "token.h"
#include "process.h"
#include "thread.h"
#include <winerror.h>
PAGED_FILE();
NTSTATUS
GetRegistryKeyPath(
_In_ PVOID object,
_In_ ULONG tag,
_In_ PCWSTR* keyPath
) {
PCUNICODE_STRING registryPath = NULL;
NTSTATUS status;
PWCHAR buffer = NULL;
ULONG bufferSize;
PAGED_CODE();
status = CmCallbackGetKeyObjectIDEx(&Cookie, object, NULL, &registryPath, 0);
if (!NT_SUCCESS(status) || registryPath == NULL) {
DbgPrint("CmCallbackGetKeyObjectIDEx failed. Status 0x%x", status);
goto Exit;
}
// Allocate a buffer for the registry path
bufferSize = (registryPath->Length / sizeof(WCHAR)) + 1;
buffer = (PWCHAR)ExAllocatePool2(POOL_FLAG_PAGED, bufferSize * sizeof(WCHAR), tag);
if (buffer == NULL) {
DbgPrint("ExAllocatePool2 failed. Status 0x%x", status);
goto Exit;
}
// Zero the buffer before copying the registry path and adding a null terminator
RtlZeroMemory(buffer, bufferSize + sizeof(UNICODE_NULL));
RtlCopyMemory(buffer, registryPath->Buffer, registryPath->Length);
buffer[bufferSize - 1] = UNICODE_NULL;
*keyPath = buffer;
status = STATUS_SUCCESS;
Exit:
if (registryPath != NULL) {
CmCallbackReleaseKeyObjectIDEx(registryPath);
}
return status;
}
NTSTATUS
GetRegistryEventInfo(
_In_ HANDLE pid,
_In_ PUNICODE_STRING pRequestorImagePath,
_In_ PUNICODE_STRING pFullUserName,
_In_ PULONG pLogonId
) {
// Get process image name
pRequestorImagePath->Length = 0;
pRequestorImagePath->MaximumLength = MAX_ALLOC;
pRequestorImagePath->Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
NTSTATUS status = GetProcessImageName(pid, pRequestorImagePath);
if (!NT_SUCCESS(status)) {
DbgPrint("GetProcessImageName failed. Status 0x%x", status);
pRequestorImagePath->Buffer = L"Unknown";
}
// Get process username and logon ID
pFullUserName->Length = 0;
pFullUserName->MaximumLength = MAX_ALLOC;
pFullUserName->Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
*pLogonId = 0;
status = GetProcessUserName(pFullUserName, pid, pLogonId);
if (!NT_SUCCESS(status)) {
DbgPrint("GetProcessUserName failed. Status 0x%x", status);
pFullUserName->Buffer = L"Unknown";
}
return status;
}
VOID
DeleteKey(
_In_ PVOID context,
_In_ PREG_DELETE_KEY_INFORMATION info
) {
UNREFERENCED_PARAMETER(context);
HANDLE Requestorpid = PsGetCurrentProcessId();
UNICODE_STRING RequestorImagePath{};
UNICODE_STRING FullUserName{};
ULONG LogonId;
ULONGLONG sourceProcStartKey = PsGetProcessStartKey(PsGetCurrentProcess());
ULONGLONG USourceProcessId = HandleToULong(Requestorpid);
ULONGLONG sourceThreadId = HandleToULong(PsGetCurrentThreadId());
FILETIME fileTime;
PCWSTR keyPath = NULL;
NTSTATUS status;
PAGED_CODE();
status = GetRegistryKeyPath(info->Object, REGISTRY_TAG, &keyPath);
if (keyPath == NULL) {
goto Exit;
}
RequestorImagePath.Length = 0;
RequestorImagePath.MaximumLength = MAX_ALLOC;
RequestorImagePath.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
status = GetProcessImageName(Requestorpid, &RequestorImagePath);
if (RequestorImagePath.Length == 0 || RequestorImagePath.Buffer == NULL)
{
//
// fatal
//
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
return;
}
//
// get the username and logon id of the process that is deleting the key
//
FullUserName.Length = 0;
FullUserName.MaximumLength = MAX_ALLOC;
FullUserName.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
LogonId = 0;
status = GetProcessUserName(&FullUserName, Requestorpid, &LogonId);
if (FullUserName.Length == 0 || FullUserName.Buffer == NULL)
{
//
// fatal
//
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
if (RequestorImagePath.Buffer != NULL) {
ExFreePoolWithTag(RequestorImagePath.Buffer, REGISTRY_TAG);
}
return;
}
KeQuerySystemTime(&fileTime);
EventWriteRegistryDeleteKey(0, &fileTime, RequestorImagePath.Buffer, USourceProcessId, sourceThreadId, sourceProcStartKey, keyPath, FullUserName.Buffer, LogonId);
Exit:
if (RequestorImagePath.Buffer != NULL) {
ExFreePoolWithTag(RequestorImagePath.Buffer, REGISTRY_TAG);
}
if (FullUserName.Buffer != NULL) {
ExFreePoolWithTag(FullUserName.Buffer, REGISTRY_TAG);
}
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
return;
}
VOID
SendSetValueRegistryInfo(
_In_ PVOID StartContext
) {
NTSTATUS status = STATUS_SUCCESS;
PCWSTR keyPath = NULL;
UNICODE_STRING RequestorImagePath = { 0 };
UNICODE_STRING FullUserName = { 0 };
ULONG LogonId;
HANDLE hToken = NULL;
FILETIME fileTime;
KeQuerySystemTime(&fileTime);
PAGED_CODE();
PREG_SET_VALUE_CALLBACK_INFO callbackInfo = (PREG_SET_VALUE_CALLBACK_INFO)StartContext;
ULONGLONG sourceProcessId = HandleToULong(callbackInfo->SourceProcessId);
ULONGLONG sourceThreadId = HandleToULong(callbackInfo->SourceThreadId);
ULONGLONG sourceProcStartKey = PsGetProcessStartKey(callbackInfo->SourceProcess);
keyPath = callbackInfo->KeyPath;
PVOID data = callbackInfo->Data;
if (data == NULL)
{
status = STATUS_UNSUCCESSFUL;
goto Exit;
}
//
//reducing loud noise
//
if (wcsstr(keyPath, L"DeliveryOptimization\\Usage") != NULL) {
goto Exit;
}
if (wcsstr(keyPath, L"\\DeliveryOptimization\\Config") != NULL) {
goto Exit;
}
//
//source image path
//
RequestorImagePath.Length = 0;
RequestorImagePath.MaximumLength = MAX_ALLOC;
RequestorImagePath.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
status = GetProcessImageName(callbackInfo->SourceProcessId, &RequestorImagePath);
if (RequestorImagePath.Buffer == NULL)
{
goto Exit;
}
//
// get the username and logon id of the process that is deleting the key
//
FullUserName.Length = 0;
FullUserName.MaximumLength = MAX_ALLOC;
FullUserName.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
LogonId = 0;
status = GetProcessUserName(&FullUserName, callbackInfo->SourceProcessId, &LogonId);
if (FullUserName.Buffer == NULL)
{
goto Exit;
}
//
// Grabbing impersonation data
//
status = GetProcessToken((HANDLE)sourceProcessId, &hToken);
if (!NT_SUCCESS(status)) {
goto Exit;
}
DWORD SessionId = GetSessionIdFromToken(hToken);
if (SessionId != 0) {
status = ThreadImpersonationEvent(hToken, callbackInfo->SourceThread, L"RegSetValue", RequestorImagePath.Buffer, sourceProcessId, sourceProcStartKey, NULL, NULL);
}
//
// End of querying for impersonation
//
switch (callbackInfo->Type) {
case REG_DWORD:
{
////
//// DWORD is 32-bits / 4 bytes
////
WCHAR buffer[11]; // Allocate space for up to 10 digits plus the null-terminator
swprintf(buffer, L"%u", *(PULONG)data);
EventWriteRegistrySetValue(0, &fileTime, RequestorImagePath.Buffer, sourceProcessId, sourceThreadId, sourceProcStartKey, keyPath, callbackInfo->ValueName.Buffer, buffer, L"REG_DWORD", FullUserName.Buffer, LogonId);
goto Exit;
}
case REG_QWORD:
{
////
//// QWORD is 64-bits / 8 bytes
////
WCHAR buffer[21]; // Allocate space for up to 20 digits plus the null-terminator
swprintf(buffer, L"%llu", *(PULONGLONG)data);
EventWriteRegistrySetValue(0, &fileTime, RequestorImagePath.Buffer, sourceProcessId, sourceThreadId, sourceProcStartKey, keyPath, callbackInfo->ValueName.Buffer, buffer, L"REG_QWORD", FullUserName.Buffer, LogonId);
goto Exit;
}
case REG_SZ:
{
//
// Create a buffer to hold the string from data and null-terminate it
//
PWSTR buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, callbackInfo->DataSize + sizeof(WCHAR), REGISTRY_TAG);
if (buffer == NULL)
{
status = STATUS_UNSUCCESSFUL;
goto Exit;
}
RtlCopyMemory(buffer, data, callbackInfo->DataSize);
buffer[callbackInfo->DataSize / sizeof(WCHAR)] = L'\0';
EventWriteRegistrySetValue(0, &fileTime, RequestorImagePath.Buffer, sourceProcessId, sourceThreadId, sourceProcStartKey, keyPath, callbackInfo->ValueName.Buffer, buffer, L"REG_SZ", FullUserName.Buffer, LogonId);
//
// Free the buffer
//
ExFreePoolWithTag(buffer, REGISTRY_TAG);
goto Exit;
}
default:
{
goto Exit;
}
}
Exit:
if (RequestorImagePath.Buffer != NULL)
{
ExFreePoolWithTag(RequestorImagePath.Buffer, REGISTRY_TAG);
}
if (FullUserName.Buffer != NULL)
{
ExFreePoolWithTag(FullUserName.Buffer, REGISTRY_TAG);
}
if (keyPath != NULL)
{
ExFreePoolWithTag((PVOID)keyPath, SYSTEM_THREAD_TAG);
}
if (callbackInfo->ValueName.Buffer != NULL)
{
ExFreePoolWithTag(callbackInfo->ValueName.Buffer, SYSTEM_THREAD_TAG);
}
if (callbackInfo->Data != NULL) {
ExFreePoolWithTag((PVOID)callbackInfo->Data, SYSTEM_THREAD_TAG);
}
if (callbackInfo != NULL)
{
ExFreePoolWithTag(StartContext, SYSTEM_THREAD_TAG);
}
PsTerminateSystemThread(STATUS_SUCCESS);
return;
}
VOID
CreateKey(
_In_ PVOID StartContext
)
{
NTSTATUS status;
UNICODE_STRING fullUserName{};
UNICODE_STRING sourceImagePath{};
ULONG LogonId;
FILETIME fileTime;
KeQuerySystemTime(&fileTime);
PAGED_CODE();
PREG_CREATE_KEY_CALLBACK_INFO callbackInfo = (PREG_CREATE_KEY_CALLBACK_INFO)StartContext;
if (callbackInfo == NULL)
{
goto Exit;
}
ULONGLONG sourceProcessId = HandleToULong(callbackInfo->SourceProcessId);
ULONGLONG sourceThreadId = HandleToULong(callbackInfo->SourceThreadId);
sourceImagePath.Length = 0;
sourceImagePath.MaximumLength = MAX_ALLOC;
sourceImagePath.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
status = GetProcessImageName(callbackInfo->SourceProcessId, &sourceImagePath);
if (!NT_SUCCESS(status) || sourceImagePath.Buffer == NULL || sourceImagePath.Length == 0) {
DbgPrint("GetProcessImageName failed. Status 0x%x", status);
goto Exit;
}
fullUserName.Length = 0;
fullUserName.MaximumLength = 520;
fullUserName.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, 520, REGISTRY_TAG);
status = GetProcessUserName(&fullUserName, callbackInfo->SourceProcessId, &LogonId);
if (!NT_SUCCESS(status) || fullUserName.Buffer == NULL || fullUserName.Length == 0) {
DbgPrint("GetProcessUserName failed. Status 0x%x", status);
goto Exit;
}
EventWriteRegistryCreateKey(0, &fileTime, sourceImagePath.Buffer, sourceProcessId, sourceThreadId, callbackInfo->ProcStartKey, callbackInfo->KeyPath.Buffer, callbackInfo->DesiredAccess, fullUserName.Buffer, LogonId);
//
// Grabbing impersonation data
//
HANDLE hToken = NULL;
status = GetProcessToken((HANDLE)sourceProcessId, &hToken);
if (NT_SUCCESS(status)) {
DWORD SessionId = GetSessionIdFromToken(hToken);
if (SessionId != 0) {
status = ThreadImpersonationEvent(hToken, callbackInfo->SourceThread, L"RegCreateValue", sourceImagePath.Buffer, sourceProcessId, callbackInfo->ProcStartKey, NULL, NULL);
}
ZwClose(hToken);
}
//
// End of querying for impersonation
//
Exit:
if (sourceImagePath.Buffer != NULL)
{
ExFreePoolWithTag(sourceImagePath.Buffer, REGISTRY_TAG);
}
if (fullUserName.Buffer != NULL)
{
ExFreePoolWithTag(fullUserName.Buffer, REGISTRY_TAG);
}
if (callbackInfo->KeyPath.Buffer != NULL) {
ExFreePoolWithTag(callbackInfo->KeyPath.Buffer, REGISTRY_TAG);
}
if (callbackInfo != NULL)
{
ExFreePoolWithTag(callbackInfo, SYSTEM_THREAD_TAG);
}
return;
}
VOID
SaveKey(
_In_ PVOID context,
_In_ PREG_SAVE_KEY_INFORMATION info
) {
HANDLE Requestorpid = PsGetCurrentProcessId();
ULONGLONG sourceProcStartKey = PsGetProcessStartKey(PsGetCurrentProcess());
UNICODE_STRING RequestorImagePath{};
UNICODE_STRING FullUserName{};
ULONG LogonId;
ULONGLONG sourceProcessId = HandleToULong(Requestorpid);
ULONGLONG sourceThreadId = HandleToULong(PsGetCurrentThreadId());
FILETIME fileTime;
PCWSTR keyPath = NULL;
KeQuerySystemTime(&fileTime);
NTSTATUS status;
PAGED_CODE();
UNREFERENCED_PARAMETER(context);
if (info->Object != NULL && info->FileHandle != NULL) {
status = GetRegistryKeyPath(info->Object, REGISTRY_TAG, &keyPath);
if (keyPath == NULL) {
goto Exit;
}
RequestorImagePath.Length = 0;
RequestorImagePath.MaximumLength = MAX_ALLOC;
RequestorImagePath.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
status = GetProcessImageName(Requestorpid, &RequestorImagePath);
if (RequestorImagePath.Length == 0 || RequestorImagePath.Buffer == NULL)
{
//
// fatal
//
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
return;
}
//
// get the username and logon id of the process that is deleting the key
//
FullUserName.Length = 0;
FullUserName.MaximumLength = MAX_ALLOC;
FullUserName.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, REGISTRY_TAG);
LogonId = 0;
status = GetProcessUserName(&FullUserName, Requestorpid, &LogonId);
if (FullUserName.Length == 0 || FullUserName.Buffer == NULL)
{
//
// fatal
//
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
if (RequestorImagePath.Buffer != NULL) {
ExFreePoolWithTag(RequestorImagePath.Buffer, REGISTRY_TAG);
}
return;
}
EventWriteRegistrySaveKey(NULL, &fileTime, RequestorImagePath.Buffer, sourceProcessId, sourceThreadId, sourceProcStartKey, keyPath, FullUserName.Buffer, LogonId);
}
Exit:
if (RequestorImagePath.Buffer != NULL)
{
ExFreePoolWithTag(RequestorImagePath.Buffer, REGISTRY_TAG);
}
if (FullUserName.Buffer != NULL)
{
ExFreePoolWithTag(FullUserName.Buffer, REGISTRY_TAG);
}
if (keyPath != NULL) {
ExFreePoolWithTag((PVOID)keyPath, REGISTRY_TAG);
}
return;
}