mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
add irp buffer validation
This commit is contained in:
parent
e0c44632cb
commit
8ea66dbfc9
11 changed files with 190 additions and 26 deletions
|
@ -775,6 +775,14 @@ ProcLoadInitialiseProcessConfig(
|
|||
PEPROCESS eprocess;
|
||||
PDRIVER_INITIATION_INFORMATION information;
|
||||
|
||||
status = ValidateIrpInputBuffer(Irp, sizeof(DRIVER_INITIATION_INFORMATION));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate input buffer");
|
||||
return status;
|
||||
}
|
||||
|
||||
information = (PDRIVER_INITIATION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
status = PsLookupProcessByProcessId(information->protected_process_id, &eprocess);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <intrin.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "ioctl.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, PerformVirtualizationDetection)
|
||||
|
@ -90,6 +91,14 @@ PerformVirtualizationDetection(
|
|||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(HYPERVISOR_DETECTION_REPORT));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
return status;
|
||||
}
|
||||
|
||||
HYPERVISOR_DETECTION_REPORT report;
|
||||
report.aperf_msr_timing_check = APERFMsrTimingCheck();
|
||||
report.invd_emulation_check = TestINVDEmulation();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "driver.h"
|
||||
#include "modules.h"
|
||||
#include "callbacks.h"
|
||||
#include "ioctl.h"
|
||||
|
||||
#include <bcrypt.h>
|
||||
#include <initguid.h>
|
||||
|
@ -155,9 +156,19 @@ GetDriverImageSize(
|
|||
&modules
|
||||
);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(ULONG));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof(ULONG);
|
||||
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &driver_info->ImageSize, sizeof(ULONG));
|
||||
|
||||
end:
|
||||
|
||||
if (modules.address)
|
||||
ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
|
||||
|
||||
|
@ -834,6 +845,14 @@ RetrieveInMemoryModuleExecutableSections(
|
|||
return status;
|
||||
}
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, bytes_written);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = bytes_written;
|
||||
|
||||
RtlCopyMemory(
|
||||
|
@ -842,6 +861,8 @@ RetrieveInMemoryModuleExecutableSections(
|
|||
bytes_written
|
||||
);
|
||||
|
||||
end:
|
||||
|
||||
if (buffer)
|
||||
ExFreePoolWithTag(buffer, POOL_TAG_INTEGRITY);
|
||||
|
||||
|
@ -1071,6 +1092,14 @@ ValidateProcessLoadedModule(
|
|||
PVOID section = NULL;
|
||||
ULONG section_size = NULL;
|
||||
|
||||
status = ValidateIrpInputBuffer(Irp, sizeof(PROCESS_MODULE_INFORMATION));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP input buffer");
|
||||
return status;
|
||||
}
|
||||
|
||||
module_info = (PPROCESS_MODULE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
GetProtectedProcessEProcess(&process);
|
||||
|
@ -1154,6 +1183,14 @@ ValidateProcessLoadedModule(
|
|||
|
||||
bstatus = RtlEqualMemory(in_memory_hash, disk_hash, in_memory_hash_size);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(PROCESS_MODULE_VALIDATION_RESULT));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because each module is passed per IRP we don't need to send any reports
|
||||
* to the queue we can simply pass it back to usermode via the same IRP.
|
||||
|
|
|
@ -74,6 +74,64 @@ DispatchApcOperation(
|
|||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obviously, its important we check that the output buffer size for each IRP is big enough
|
||||
* to hold whatever we are passing back to usermode.
|
||||
*
|
||||
* Another important thing to note is that the windows IO manager will only zero out the size
|
||||
* of the input buffer. Given that we use METHOD_BUFFERED for all communication, the input
|
||||
* and output buffer are the same, with the size used being that of the greatest buffer passed
|
||||
* to DeviceIoControl. The IO manager will then zero our the buffer to the size of the input
|
||||
* buffer, so if the output buffer is larger then the input buffer there will be uninitialised
|
||||
* memory in the buffer so we must zero out the buffer to the length of the output buffer.
|
||||
*/
|
||||
NTSTATUS
|
||||
ValidateIrpOutputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
)
|
||||
{
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
if (io->Parameters.DeviceIoControl.OutputBufferLength < RequiredSize)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
RtlSecureZeroMemory(Irp->AssociatedIrp.SystemBuffer, RequiredSize);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we just check that the input buffers size matches the expected size..
|
||||
* It isnt a very secure check but we can work on that later...
|
||||
*/
|
||||
NTSTATUS
|
||||
ValidateIrpInputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
)
|
||||
{
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
if (io->Parameters.DeviceIoControl.InputBufferLength != RequiredSize)
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
||||
NTSTATUS
|
||||
DeviceControl(
|
||||
|
@ -280,7 +338,7 @@ DeviceControl(
|
|||
|
||||
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
|
||||
|
||||
status = FindUnlinkedProcesses(Irp);
|
||||
status = FindUnlinkedProcesses();
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("FindUNlinekdProcesses failed with status %x", status);
|
||||
|
@ -289,7 +347,7 @@ DeviceControl(
|
|||
|
||||
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD:
|
||||
|
||||
ValidateKPCRBThreads(Irp);
|
||||
ValidateKPCRBThreads();
|
||||
|
||||
break;
|
||||
|
||||
|
@ -328,6 +386,14 @@ DeviceControl(
|
|||
goto end;
|
||||
}
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(SYSTEM_INFORMATION));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof(SYSTEM_INFORMATION);
|
||||
|
||||
RtlCopyMemory(
|
||||
|
|
|
@ -33,4 +33,16 @@ DeviceCreate(
|
|||
_Inout_ PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ValidateIrpOutputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ValidateIrpInputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
);
|
||||
|
||||
#endif
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "callbacks.h"
|
||||
#include "driver.h"
|
||||
#include "ioctl.h"
|
||||
|
||||
#define WHITELISTED_MODULE_TAG 'whte'
|
||||
|
||||
|
@ -698,6 +699,8 @@ HandleValidateDriversIOCTL(
|
|||
PAGED_CODE();
|
||||
|
||||
NTSTATUS status;
|
||||
PVOID buffer = NULL;
|
||||
ULONG buffer_size = 0;
|
||||
SYSTEM_MODULES system_modules = { 0 };
|
||||
|
||||
/* Fix annoying visual studio linting error */
|
||||
|
@ -745,8 +748,18 @@ HandleValidateDriversIOCTL(
|
|||
{
|
||||
DEBUG_LOG("found INVALID drivers with count: %i", head->count);
|
||||
|
||||
PVOID buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
|
||||
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT * sizeof(MODULE_VALIDATION_FAILURE), MODULES_REPORT_POOL_TAG);
|
||||
buffer_size = sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
|
||||
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT * sizeof(MODULE_VALIDATION_FAILURE);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, buffer_size);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate output buffer.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, buffer_size, MODULES_REPORT_POOL_TAG);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
|
@ -815,6 +828,7 @@ HandleValidateDriversIOCTL(
|
|||
DEBUG_LOG("No INVALID drivers found :)");
|
||||
}
|
||||
|
||||
end:
|
||||
ExFreePoolWithTag(head, INVALID_DRIVER_LIST_HEAD_POOL);
|
||||
ExFreePoolWithTag(system_modules.address, SYSTEM_MODULES_POOL);
|
||||
|
||||
|
@ -873,6 +887,14 @@ AnalyseNmiData(
|
|||
/* Make sure our NMIs were run */
|
||||
if (!context->nmi_callbacks_run)
|
||||
{
|
||||
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(NMI_CALLBACK_FAILURE));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate output buffer.");
|
||||
return status;
|
||||
}
|
||||
|
||||
NMI_CALLBACK_FAILURE report;
|
||||
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
|
||||
report.kthread_address = NULL;
|
||||
|
@ -910,6 +932,14 @@ AnalyseNmiData(
|
|||
|
||||
if (flag == FALSE)
|
||||
{
|
||||
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(NMI_CALLBACK_FAILURE));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate output buffer.");
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: for now, we only handle 1 report at a time so we stop the
|
||||
* analysis once we receive a report since we only send a buffer
|
||||
|
|
|
@ -661,9 +661,7 @@ CheckIfProcessAllocationIsInProcessList(
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
FindUnlinkedProcesses(
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
FindUnlinkedProcesses()
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@ typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
|
|||
}INVALID_PROCESS_ALLOCATION_REPORT, * PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
|
||||
NTSTATUS
|
||||
FindUnlinkedProcesses(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
FindUnlinkedProcesses();
|
||||
|
||||
VOID
|
||||
GetPsActiveProcessHead(
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "queue.h"
|
||||
#include "pool.h"
|
||||
#include "thread.h"
|
||||
#include "ioctl.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
|
@ -176,22 +177,29 @@ HandlePeriodicGlobalReportQueueQuery(
|
|||
_Inout_ PIRP Irp
|
||||
)
|
||||
{
|
||||
PVOID report = NULL;
|
||||
INT count = 0;
|
||||
GLOBAL_REPORT_QUEUE_HEADER header;
|
||||
PVOID report_buffer = NULL;
|
||||
PREPORT_HEADER report_header;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PVOID report = NULL;
|
||||
SIZE_T total_size = NULL;
|
||||
PVOID report_buffer = NULL;
|
||||
ULONG report_buffer_size = 0;
|
||||
PREPORT_HEADER report_header;
|
||||
GLOBAL_REPORT_QUEUE_HEADER header;
|
||||
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
report_buffer_size = sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP + sizeof(GLOBAL_REPORT_QUEUE_HEADER);
|
||||
|
||||
report_buffer = ExAllocatePool2(
|
||||
POOL_FLAG_NON_PAGED,
|
||||
sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP + sizeof(GLOBAL_REPORT_QUEUE_HEADER),
|
||||
REPORT_QUEUE_TEMP_BUFFER_TAG
|
||||
);
|
||||
status = ValidateIrpOutputBuffer(Irp, report_buffer_size);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate Irp output buffer");
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
report_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, report_buffer_size, REPORT_QUEUE_TEMP_BUFFER_TAG);
|
||||
|
||||
if (!report_buffer)
|
||||
{
|
||||
|
@ -199,6 +207,8 @@ HandlePeriodicGlobalReportQueueQuery(
|
|||
return STATUS_MEMORY_NOT_ALLOCATED;
|
||||
}
|
||||
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
|
||||
if (report == NULL)
|
||||
{
|
||||
DEBUG_LOG("callback report queue is empty, returning");
|
||||
|
|
|
@ -71,9 +71,7 @@ KPRCBThreadValidationProcessCallback(
|
|||
*
|
||||
*/
|
||||
VOID
|
||||
ValidateKPCRBThreads(
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
ValidateKPCRBThreads()
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
|
|
|
@ -25,9 +25,7 @@ typedef struct _ATTACH_PROCESS_REPORT
|
|||
}ATTACH_PROCESS_REPORT, * PATTACH_PROCESS_REPORT;
|
||||
|
||||
VOID
|
||||
ValidateKPCRBThreads(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
ValidateKPCRBThreads();
|
||||
|
||||
VOID
|
||||
DetectThreadsAttachedToProtectedProcess();
|
||||
|
|
Loading…
Reference in a new issue