fix up pool reporting system

This commit is contained in:
lhodges1 2023-09-18 13:15:26 +10:00
parent 86316e9bbf
commit 6958b7090b
9 changed files with 69 additions and 64 deletions

View file

@ -2,6 +2,15 @@
#include <iostream>
/*
* Massive WIP from which I have essentially just copied from these 2 repos:
*
* https://github.com/yardenshafir/MitigationFlagsCliTool
* https://github.com/lilhoser/livedump
*
* just to help with leraning the windows debugger api
*/
static NtSystemDebugControl g_NtSystemDebugControl = NULL;
BOOL

View file

@ -54,6 +54,7 @@
#define OBJECT_HEADER_TYPE_INDEX_OFFSET 0x018
#define POOL_HEADER_BLOCK_SIZE_OFFSET 0x02
#define POOL_HEADER_TAG_OFFSET 0x04
#define KPROCESS_OFFSET_FROM_POOL_HEADER_SIZE_1 0x70
#define KPROCESS_OFFSET_FROM_POOL_HEADER_SIZE_2 0x80

View file

@ -10,6 +10,8 @@
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
#define MAX_REPORTS_PER_IRP 20
#define POOL_TAG_STRINGS 'strs'
#define IOCTL_STORAGE_QUERY_PROPERTY 0x002D1400

View file

@ -249,14 +249,6 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
}
object_attributes.ObjectName = NULL;
if ( !NT_SUCCESS( status ) )
{
DEBUG_ERROR( "NTSetInformationProcess failed with status %x", status );
ZwClose( file_handle );
//TerminateProtectedProcessOnViolation();
return status;
}
/*
* Its important that we set the SEC_IMAGE flag with the PAGE_READONLY

View file

@ -3,6 +3,7 @@
#include "common.h"
#include "callbacks.h"
#include "queue.h"
#include <intrin.h>
@ -79,7 +80,6 @@ VOID GetPsActiveProcessHead(
_In_ PUINT64 Address
)
{
/* TODO: have a global debugger pool here since shit aint really change */
PKDDEBUGGER_DATA64 debugger_data = GetGlobalDebuggerData();
*Address = *( UINT64* )( debugger_data->PsActiveProcessHead );
@ -166,14 +166,6 @@ BOOLEAN ValidateIfAddressIsProcessStructure(
}
/*
* For ~90% of EPROCESS structures the header layout is as follows:
*
* Pool base + 0x00 = ?? (not sure what structure lies here)
* Pool base + 0x10 = OBJECT_HEADER_QUOTA_INFO
* Pool base + 0x30 = OBJECT_HEADER_HANDLE_INFO
* Pool base + 0x40 = OBJECT_HEADER
* Pool base + 0x70 = EPROCESS
*
* OBJECT_HEADER->InfoMask is a bit mask that tells us which optional
* headers the object has. The bits are as follows:
*
@ -232,12 +224,19 @@ VOID ScanPageForKernelObjectAllocation(
if ( sig_index == POOL_TAG_LENGTH )
{
pool_header = ( UINT64 )PageBase + offset - 0x04;
pool_header = ( UINT64 )PageBase + offset - POOL_HEADER_TAG_OFFSET;
if ( !MmIsAddressValid( ( PVOID )pool_header ) )
break;
for ( ULONG header_size = 0x30; header_size < 0xb0; header_size += 0x10 )
/*
* Since every executive allocation is required to have an _OBJECT_HEADER, we start
* iterating from the size of this object header, then jump up in blocks of 0x10 since
* every object header is divisible by 0x10. We iterate up to 0xb0 which is equal to the following:
*
* 0xb0 = sizeof(ALL_HEADER_OBJECTS) + 0x10 where the 0x10 is 16 bytes of padding.
*/
for ( ULONG header_size = OBJECT_HEADER_SIZE; header_size < 0xb0; header_size += 0x10 )
{
test_process = ( PEPROCESS )( ( UINT64 )pool_header + sizeof( POOL_HEADER ) + header_size );
@ -309,10 +308,13 @@ VOID EnumerateKernelLargePages(
_In_ ULONG ObjectIndex
)
{
/*
* Split the large pages up into blocks of 0x1000 and scan each block
*/
for ( INT page_index = 0; page_index < PageSize; page_index++ )
{
ScanPageForKernelObjectAllocation(
PageBase + ( page_index * PageSize ),
PageBase + ( page_index * PAGE_SIZE ),
PAGE_SIZE,
ObjectIndex,
AddressBuffer
@ -545,17 +547,6 @@ VOID CheckIfProcessAllocationIsInProcessList(
}
}
/*
* Plan:
* 1. Find number of running procs and allocate a pool equal to size 1.5 * num_procs.
* 2. Walk the pages tables and store all found process allocation base addresses in this pool
* 3. Enumerate the process allocation list and make sure that each allocation is within
* 0x50 bytes of the EPROCESS base of one of the running processes.
* 4. If there exists a process allocation that doesn't have a matching running process,
* make sure it hasnt been deallocated
* 5. If it hasn't been deallocated, search for the .exe via the long string file name
* and report. Maybe do some further analysis can figure this out once we get there.
*/
NTSTATUS FindUnlinkedProcesses(
_In_ PIRP Irp
)
@ -581,8 +572,6 @@ NTSTATUS FindUnlinkedProcesses(
WalkKernelPageTables( process_buffer );
__debugbreak();
EnumerateProcessListWithCallbackFunction(
CheckIfProcessAllocationIsInProcessList,
NULL
@ -595,41 +584,31 @@ NTSTATUS FindUnlinkedProcesses(
if ( allocation_address[ i ] == NULL )
continue;
/* process has been deallocated yet the pool header hasnt been updated? */
if ( *( UINT8* )( allocation_address[ i ] + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET ) == 0x00 )
continue;
/* report / do some further analysis */
/* report / do some further analysis etc. */
DEBUG_ERROR( "INVALID POOL proc OMGGG" );
report_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( INVALID_PROCESS_ALLOCATION_REPORT ), INVALID_PROCESS_REPORT_TAG );
report_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( INVALID_PROCESS_ALLOCATION_REPORT ), REPORT_POOL_TAG );
if ( !report_buffer )
goto end;
//report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
//RtlCopyMemory(
// report_buffer->process,
// allocation_address[ i ],
// REPORT_INVALID_PROCESS_BUFFER_SIZE );
RtlCopyMemory(
report_buffer->process,
(UINT64)allocation_address[ i ] - OBJECT_HEADER_SIZE,
REPORT_INVALID_PROCESS_BUFFER_SIZE
);
//Irp->IoStatus.Information = sizeof( INVALID_PROCESS_ALLOCATION_REPORT );
//RtlCopyMemory(
// Irp->AssociatedIrp.SystemBuffer,
// report_buffer,
// sizeof( INVALID_PROCESS_ALLOCATION_REPORT ) );
InsertReportToQueue( report_buffer );
}
end:
if ( report_buffer )
ExFreePoolWithTag( report_buffer, INVALID_PROCESS_REPORT_TAG );
if ( process_buffer )
ExFreePoolWithTag( process_buffer, PROCESS_ADDRESS_LIST_TAG );
/* todo: make use of the new context variable in the enum proc func */
process_count = NULL;
process_buffer = NULL;

View file

@ -4,7 +4,7 @@
#include <ntifs.h>
#include "common.h"
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 4096
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 4000 // we want to make sure this allocation fits on a page
#define PAGE_BASE_SIZE 0x1000
#define POOL_TAG_SIZE 0x004

View file

@ -204,6 +204,17 @@ NTSTATUS HandlePeriodicGlobalReportQueueQuery(
total_size += sizeof( ATTACH_PROCESS_REPORT );
break;
case REPORT_INVALID_PROCESS_ALLOCATION:
RtlCopyMemory(
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
report,
sizeof( INVALID_PROCESS_ALLOCATION_REPORT )
);
total_size += sizeof( INVALID_PROCESS_ALLOCATION_REPORT );
break;
}
/* QueuePop frees the node, but we still need to free the returned data */

View file

@ -143,7 +143,7 @@ namespace global
CHAR driver_name[ 128 ];
};
struct OPEN_HANDLE_FAILURE_REPORT_HEADER
struct REPORT_QUEUE_HEADER
{
INT count;
};

View file

@ -174,8 +174,9 @@ VOID kernelmode::Driver::QueryReportQueue()
SIZE_T total_size = NULL;
global::report_structures::OPEN_HANDLE_FAILURE_REPORT* handle_report;
global::report_structures::ATTACH_PROCESS_REPORT* attach_report;
global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT* allocation_report;
buffer_size = 1024 * 2;
buffer_size = sizeof( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT ) * MAX_REPORTS_PER_IRP;
buffer = malloc( buffer_size );
status = DeviceIoControl(
@ -196,8 +197,8 @@ VOID kernelmode::Driver::QueryReportQueue()
return;
}
global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER* header =
( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER* )buffer;
global::report_structures::REPORT_QUEUE_HEADER* header =
( global::report_structures::REPORT_QUEUE_HEADER* )buffer;
if ( !header )
goto end;
@ -209,15 +210,15 @@ VOID kernelmode::Driver::QueryReportQueue()
for ( INT i = 0; i < header->count; i++ )
{
report_header = (REPORT_ID*)( ( UINT64 )buffer +
sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
report_header = ( REPORT_ID* )( ( UINT64 )buffer +
sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
LOG_INFO( "Report id: %d", report_header->report_id );
if ( report_header->report_id == REPORT_ILLEGAL_ATTACH_PROCESS )
{
attach_report = ( global::report_structures::ATTACH_PROCESS_REPORT* )(
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
this->report_interface->ReportViolation( attach_report );
@ -225,16 +226,26 @@ VOID kernelmode::Driver::QueryReportQueue()
continue;
}
if ( report_header->report_id == REPORT_ILLEGAL_HANDLE_OPERATION )
else if ( report_header->report_id == REPORT_ILLEGAL_HANDLE_OPERATION )
{
handle_report = ( global::report_structures::OPEN_HANDLE_FAILURE_REPORT* )(
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
this->report_interface->ReportViolation( handle_report );
total_size += sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT );
continue;
}
else if ( report_header->report_id == REPORT_INVALID_PROCESS_ALLOCATION )
{
allocation_report = ( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT* )(
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
this->report_interface->ReportViolation( allocation_report );
total_size += sizeof( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT );
continue;
}
}