mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
bed time c:
This commit is contained in:
parent
a5822fb5cf
commit
013f5a9906
15 changed files with 455 additions and 390 deletions
|
@ -132,7 +132,6 @@
|
|||
<ClCompile Include="integrity.c" />
|
||||
<ClCompile Include="ioctl.c" />
|
||||
<ClCompile Include="modules.c" />
|
||||
<ClCompile Include="nmi.c" />
|
||||
<ClCompile Include="pool.c" />
|
||||
<ClCompile Include="queue.c" />
|
||||
</ItemGroup>
|
||||
|
@ -144,7 +143,6 @@
|
|||
<ClInclude Include="integrity.h" />
|
||||
<ClInclude Include="ioctl.h" />
|
||||
<ClInclude Include="modules.h" />
|
||||
<ClInclude Include="nmi.h" />
|
||||
<ClInclude Include="pool.h" />
|
||||
<ClInclude Include="queue.h" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
<ClCompile Include="ioctl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nmi.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="modules.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -62,9 +59,6 @@
|
|||
<ClInclude Include="ioctl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nmi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="modules.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -44,7 +44,7 @@ NTSTATUS GetDriverImageSize(
|
|||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS New_CopyDriverExecutableRegions(
|
||||
NTSTATUS CopyDriverExecutableRegions(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
|
@ -181,4 +181,20 @@ end:
|
|||
ExFreePoolWithTag( buffer, POOL_TAG_INTEGRITY );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. map driver to memory
|
||||
* 2. store executable sections in buffer
|
||||
* 3. do the same with the in-memory module
|
||||
* 4. hash both buffers with the current time or something
|
||||
* 5. compare
|
||||
*/
|
||||
NTSTATUS PerformInMemoryIntegrityCheckVsDiskImage(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
|
||||
}
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#define POOL_TAG_INTEGRITY 'intg'
|
||||
|
||||
VOID WalkKernelPageTables();
|
||||
|
||||
NTSTATUS CopyDriverExecutableRegions(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
@ -15,10 +13,6 @@ NTSTATUS GetDriverImageSize(
|
|||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS New_CopyDriverExecutableRegions(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
|
||||
#define IMAGE_SIZEOF_SHORT_NAME 8
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#include "nmi.h"
|
||||
#include "modules.h"
|
||||
#include "driver.h"
|
||||
#include "callbacks.h"
|
||||
|
@ -156,7 +155,7 @@ NTSTATUS DeviceControl(
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
New_CopyDriverExecutableRegions,
|
||||
CopyDriverExecutableRegions,
|
||||
Irp
|
||||
);
|
||||
|
||||
|
@ -210,6 +209,15 @@ NTSTATUS DeviceControl(
|
|||
|
||||
break;
|
||||
|
||||
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
|
||||
|
||||
status = FindUnlinkedProcesses( Irp );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
DEBUG_ERROR( "FindUNlinekdProcesses failed with status %x", status );
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR( "Invalid IOCTL passed to driver" );
|
||||
break;
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include <wdftypes.h>
|
||||
#include <wdf.h>
|
||||
|
||||
#include "nmi.h"
|
||||
|
||||
#define IOCCTL_RUN_NMI_CALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
@ -16,6 +14,7 @@
|
|||
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2008, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
typedef struct _DRIVER_INITIATION_INFORMATION
|
||||
{
|
||||
|
|
296
driver/modules.c
296
driver/modules.c
|
@ -1,9 +1,14 @@
|
|||
#include "modules.h"
|
||||
|
||||
#include "nmi.h"
|
||||
|
||||
#define WHITELISTED_MODULE_TAG 'whte'
|
||||
|
||||
PVOID nmi_callback_handle = NULL;
|
||||
|
||||
/* Global structure to hold pointers to required memory for the NMI's */
|
||||
NMI_POOLS nmi_pools = { 0 };
|
||||
|
||||
#define NMI_DELAY 100 * 10000
|
||||
|
||||
#define WHITELISTED_MODULE_COUNT 3
|
||||
#define MODULE_MAX_STRING_SIZE 256
|
||||
|
||||
|
@ -18,13 +23,6 @@ CHAR WHITELISTED_MODULES[ WHITELISTED_MODULE_COUNT ][ MODULE_MAX_STRING_SIZE ] =
|
|||
"Wdf01000.sys",
|
||||
};
|
||||
|
||||
typedef struct _WHITELISTED_REGIONS
|
||||
{
|
||||
UINT64 base;
|
||||
UINT64 end;
|
||||
|
||||
}WHITELISTED_REGIONS, *PWHITELISTED_REGIONS;
|
||||
|
||||
PRTL_MODULE_EXTENDED_INFO FindSystemModuleByName(
|
||||
_In_ LPCSTR ModuleName,
|
||||
_In_ PSYSTEM_MODULES SystemModules
|
||||
|
@ -546,5 +544,285 @@ NTSTATUS HandleValidateDriversIOCTL(
|
|||
ExFreePoolWithTag( head, INVALID_DRIVER_LIST_HEAD_POOL );
|
||||
ExFreePoolWithTag( system_modules.address, SYSTEM_MODULES_POOL );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS IsInstructionPointerInInvalidRegion(
|
||||
_In_ UINT64 RIP,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_Out_ PBOOLEAN Result
|
||||
)
|
||||
{
|
||||
if ( !RIP || !SystemModules || !Result )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* Note that this does not check for HAL or PatchGuard Execution */
|
||||
for ( INT i = 0; i < SystemModules->module_count; i++ )
|
||||
{
|
||||
PRTL_MODULE_EXTENDED_INFO system_module = ( PRTL_MODULE_EXTENDED_INFO )(
|
||||
( uintptr_t )SystemModules->address + i * sizeof( RTL_MODULE_EXTENDED_INFO ) );
|
||||
|
||||
UINT64 base = ( UINT64 )system_module->ImageBase;
|
||||
UINT64 end = base + system_module->ImageSize;
|
||||
|
||||
if ( RIP >= base && RIP <= end )
|
||||
{
|
||||
*Result = TRUE;
|
||||
return STATUS_SUCCESS;;
|
||||
}
|
||||
}
|
||||
|
||||
*Result = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS AnalyseNmiData(
|
||||
_In_ INT NumCores,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
if ( !NumCores || !SystemModules )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for ( INT core = 0; core < NumCores; core++ )
|
||||
{
|
||||
PNMI_CONTEXT context = ( PNMI_CONTEXT )( ( uintptr_t )nmi_pools.nmi_context + core * sizeof( NMI_CONTEXT ) );
|
||||
|
||||
/* Make sure our NMIs were run */
|
||||
if ( !context->nmi_callbacks_run )
|
||||
{
|
||||
NMI_CALLBACK_FAILURE report;
|
||||
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
|
||||
report.kthread_address = NULL;
|
||||
report.invalid_rip = NULL;
|
||||
report.were_nmis_disabled = TRUE;
|
||||
|
||||
Irp->IoStatus.Information = sizeof( NMI_CALLBACK_FAILURE );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( NMI_CALLBACK_FAILURE )
|
||||
);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
PNMI_CALLBACK_DATA thread_data = ( PNMI_CALLBACK_DATA )(
|
||||
( uintptr_t )nmi_pools.thread_data_pool + core * sizeof( NMI_CALLBACK_DATA ) );
|
||||
|
||||
DEBUG_LOG( "cpu number: %i callback count: %i", core, context->nmi_callbacks_run );
|
||||
|
||||
/* Walk the stack */
|
||||
for ( INT frame = 0; frame < thread_data->num_frames_captured; frame++ )
|
||||
{
|
||||
BOOLEAN flag;
|
||||
DWORD64 stack_frame = *( DWORD64* )(
|
||||
( ( uintptr_t )nmi_pools.stack_frames + thread_data->stack_frames_offset + frame * sizeof( PVOID ) ) );
|
||||
|
||||
if ( !NT_SUCCESS( IsInstructionPointerInInvalidRegion( stack_frame, SystemModules, &flag ) ) )
|
||||
{
|
||||
DEBUG_ERROR( "errro checking RIP for current stack address" );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( flag == FALSE )
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* large enough for 1 report. In the future this should be changed
|
||||
* to a buffer that can hold atleast 4 reports (since the chance we
|
||||
* get 4 reports with a single NMI would be impossible) so we can
|
||||
* continue parsing the rest of the stack frames after receiving a
|
||||
* single report.
|
||||
*/
|
||||
|
||||
NMI_CALLBACK_FAILURE report;
|
||||
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
|
||||
report.kthread_address = thread_data->kthread_address;
|
||||
report.invalid_rip = stack_frame;
|
||||
report.were_nmis_disabled = FALSE;
|
||||
|
||||
Irp->IoStatus.Information = sizeof( NMI_CALLBACK_FAILURE );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( NMI_CALLBACK_FAILURE )
|
||||
);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN NmiCallback(
|
||||
_In_ PVOID Context,
|
||||
_In_ BOOLEAN Handled
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER( Handled );
|
||||
|
||||
ULONG proc_num = KeGetCurrentProcessorNumber();
|
||||
PVOID current_thread = KeGetCurrentThread();
|
||||
NMI_CALLBACK_DATA thread_data = { 0 };
|
||||
|
||||
/*
|
||||
* Cannot allocate pool in this function as it runs at IRQL >= dispatch level
|
||||
* so ive just allocated a global pool with size equal to 0x200 * num_procs
|
||||
*/
|
||||
INT num_frames_captured = RtlCaptureStackBackTrace(
|
||||
NULL,
|
||||
STACK_FRAME_POOL_SIZE,
|
||||
( uintptr_t )nmi_pools.stack_frames + proc_num * STACK_FRAME_POOL_SIZE,
|
||||
NULL
|
||||
);
|
||||
|
||||
/*
|
||||
* This function is run in the context of the interrupted thread hence we can
|
||||
* gather any and all information regarding the thread that may be useful for analysis
|
||||
*/
|
||||
thread_data.kthread_address = ( UINT64 )current_thread;
|
||||
thread_data.kprocess_address = ( UINT64 )PsGetCurrentProcess();
|
||||
thread_data.stack_base = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_STACK_BASE_OFFSET ) );
|
||||
thread_data.stack_limit = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_STACK_LIMIT_OFFSET ) );
|
||||
thread_data.start_address = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_START_ADDRESS_OFFSET ) );
|
||||
thread_data.cr3 = __readcr3();
|
||||
thread_data.stack_frames_offset = proc_num * STACK_FRAME_POOL_SIZE;
|
||||
thread_data.num_frames_captured = num_frames_captured;
|
||||
|
||||
RtlCopyMemory(
|
||||
( ( uintptr_t )nmi_pools.thread_data_pool ) + proc_num * sizeof( thread_data ),
|
||||
&thread_data,
|
||||
sizeof( thread_data )
|
||||
);
|
||||
|
||||
PNMI_CONTEXT context = ( PNMI_CONTEXT )( ( uintptr_t )Context + proc_num * sizeof( NMI_CONTEXT ) );
|
||||
context->nmi_callbacks_run += 1;
|
||||
DEBUG_LOG( "num nmis called: %i from addr: %llx", context->nmi_callbacks_run, ( uintptr_t )context );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS LaunchNonMaskableInterrupt(
|
||||
_In_ ULONG NumCores
|
||||
)
|
||||
{
|
||||
if ( !NumCores )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PKAFFINITY_EX ProcAffinityPool = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( KAFFINITY_EX ), PROC_AFFINITY_POOL );
|
||||
|
||||
if ( !ProcAffinityPool )
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
nmi_pools.stack_frames = ExAllocatePool2( POOL_FLAG_NON_PAGED, NumCores * STACK_FRAME_POOL_SIZE, STACK_FRAMES_POOL );
|
||||
|
||||
if ( !nmi_pools.stack_frames )
|
||||
{
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
nmi_pools.thread_data_pool = ExAllocatePool2( POOL_FLAG_NON_PAGED, NumCores * sizeof( NMI_CALLBACK_DATA ), THREAD_DATA_POOL );
|
||||
|
||||
if ( !nmi_pools.thread_data_pool )
|
||||
{
|
||||
ExFreePoolWithTag( nmi_pools.stack_frames, STACK_FRAMES_POOL );
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
LARGE_INTEGER delay = { 0 };
|
||||
delay.QuadPart -= NMI_DELAY;
|
||||
|
||||
for ( ULONG core = 0; core < NumCores; core++ )
|
||||
{
|
||||
KeInitializeAffinityEx( ProcAffinityPool );
|
||||
KeAddProcessorAffinityEx( ProcAffinityPool, core );
|
||||
|
||||
DEBUG_LOG( "Sending NMI" );
|
||||
HalSendNMI( ProcAffinityPool );
|
||||
|
||||
/*
|
||||
* Only a single NMI can be active at any given time, so arbitrarily
|
||||
* delay execution to allow time for the NMI to be processed
|
||||
*/
|
||||
KeDelayExecutionThread( KernelMode, FALSE, &delay );
|
||||
}
|
||||
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS HandleNmiIOCTL(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
SYSTEM_MODULES system_modules = { 0 };
|
||||
ULONG num_cores = KeQueryActiveProcessorCountEx( 0 );
|
||||
|
||||
/* Fix annoying visual studio linting error */
|
||||
RtlZeroMemory( &system_modules, sizeof( SYSTEM_MODULES ) );
|
||||
RtlZeroMemory( &nmi_pools, sizeof( NMI_POOLS ) );
|
||||
|
||||
nmi_pools.nmi_context = ExAllocatePool2( POOL_FLAG_NON_PAGED, num_cores * sizeof( NMI_CONTEXT ), NMI_CONTEXT_POOL );
|
||||
|
||||
if ( !nmi_pools.nmi_context )
|
||||
{
|
||||
DEBUG_ERROR( "nmi_context ExAllocatePool2 failed" );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to register and unregister our callback each time so it becomes harder
|
||||
* for people to hook our callback and get up to some funny business
|
||||
*/
|
||||
nmi_callback_handle = KeRegisterNmiCallback( NmiCallback, nmi_pools.nmi_context );
|
||||
|
||||
if ( !nmi_callback_handle )
|
||||
{
|
||||
DEBUG_ERROR( "KeRegisterNmiCallback failed" );
|
||||
ExFreePoolWithTag( nmi_pools.nmi_context, NMI_CONTEXT_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
/*
|
||||
* We query the system modules each time since they can potentially
|
||||
* change at any time
|
||||
*/
|
||||
status = GetSystemModuleInformation( &system_modules );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "Error retriving system module information" );
|
||||
return status;
|
||||
}
|
||||
status = LaunchNonMaskableInterrupt( num_cores );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "Error running NMI callbacks" );
|
||||
ExFreePoolWithTag( system_modules.address, SYSTEM_MODULES_POOL );
|
||||
return status;
|
||||
}
|
||||
status = AnalyseNmiData( num_cores, &system_modules, Irp );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
DEBUG_ERROR( "Error analysing nmi data" );
|
||||
|
||||
ExFreePoolWithTag( system_modules.address, SYSTEM_MODULES_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.stack_frames, STACK_FRAMES_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.thread_data_pool, THREAD_DATA_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.nmi_context, NMI_CONTEXT_POOL );
|
||||
KeDeregisterNmiCallback( nmi_callback_handle );
|
||||
|
||||
return status;
|
||||
}
|
|
@ -13,6 +13,55 @@
|
|||
#define REASON_NO_BACKING_MODULE 1
|
||||
#define REASON_INVALID_IOCTL_DISPATCH 2
|
||||
|
||||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
|
||||
NTSTATUS HandleNmiIOCTL(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
typedef struct _WHITELISTED_REGIONS
|
||||
{
|
||||
UINT64 base;
|
||||
UINT64 end;
|
||||
|
||||
}WHITELISTED_REGIONS, * PWHITELISTED_REGIONS;
|
||||
|
||||
typedef struct _NMI_POOLS
|
||||
{
|
||||
PVOID thread_data_pool;
|
||||
PVOID stack_frames;
|
||||
PVOID nmi_context;
|
||||
|
||||
}NMI_POOLS, * PNMI_POOLS;
|
||||
|
||||
typedef struct NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
|
||||
}NMI_CALLBACK_FAILURE, * PNMI_CALLBACK_FAILURE;
|
||||
|
||||
typedef struct _NMI_CONTEXT
|
||||
{
|
||||
INT nmi_callbacks_run;
|
||||
|
||||
}NMI_CONTEXT, * PNMI_CONTEXT;
|
||||
|
||||
typedef struct _NMI_CALLBACK_DATA
|
||||
{
|
||||
UINT64 kthread_address;
|
||||
UINT64 kprocess_address;
|
||||
UINT64 start_address;
|
||||
UINT64 stack_limit;
|
||||
UINT64 stack_base;
|
||||
uintptr_t stack_frames_offset;
|
||||
INT num_frames_captured;
|
||||
UINT64 cr3;
|
||||
|
||||
}NMI_CALLBACK_DATA, * PNMI_CALLBACK_DATA;
|
||||
|
||||
typedef struct _MODULE_VALIDATION_FAILURE_HEADER
|
||||
{
|
||||
INT module_count;
|
||||
|
|
299
driver/nmi.c
299
driver/nmi.c
|
@ -1,299 +0,0 @@
|
|||
#include "nmi.h"
|
||||
|
||||
#include "modules.h"
|
||||
#include "common.h"
|
||||
|
||||
#define NMI_DELAY 100 * 10000
|
||||
|
||||
typedef struct _NMI_POOLS
|
||||
{
|
||||
PVOID thread_data_pool;
|
||||
PVOID stack_frames;
|
||||
PVOID nmi_context;
|
||||
|
||||
}NMI_POOLS, * PNMI_POOLS;
|
||||
|
||||
PVOID nmi_callback_handle = NULL;
|
||||
|
||||
/* Global structure to hold pointers to required memory for the NMI's */
|
||||
NMI_POOLS nmi_pools = { 0 };
|
||||
|
||||
NTSTATUS IsInstructionPointerInInvalidRegion(
|
||||
_In_ UINT64 RIP,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_Out_ PBOOLEAN Result
|
||||
)
|
||||
{
|
||||
if ( !RIP || !SystemModules || !Result )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* Note that this does not check for HAL or PatchGuard Execution */
|
||||
for ( INT i = 0; i < SystemModules->module_count; i++ )
|
||||
{
|
||||
PRTL_MODULE_EXTENDED_INFO system_module = ( PRTL_MODULE_EXTENDED_INFO )(
|
||||
( uintptr_t )SystemModules->address + i * sizeof( RTL_MODULE_EXTENDED_INFO ) );
|
||||
|
||||
UINT64 base = ( UINT64 )system_module->ImageBase;
|
||||
UINT64 end = base + system_module->ImageSize;
|
||||
|
||||
if ( RIP >= base && RIP <= end )
|
||||
{
|
||||
*Result = TRUE;
|
||||
return STATUS_SUCCESS;;
|
||||
}
|
||||
}
|
||||
|
||||
*Result = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS AnalyseNmiData(
|
||||
_In_ INT NumCores,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
if ( !NumCores || !SystemModules )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for ( INT core = 0; core < NumCores; core++ )
|
||||
{
|
||||
PNMI_CONTEXT context = ( PNMI_CONTEXT )( ( uintptr_t )nmi_pools.nmi_context + core * sizeof( NMI_CONTEXT ) );
|
||||
|
||||
/* Make sure our NMIs were run */
|
||||
if ( !context->nmi_callbacks_run )
|
||||
{
|
||||
NMI_CALLBACK_FAILURE report;
|
||||
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
|
||||
report.kthread_address = NULL;
|
||||
report.invalid_rip = NULL;
|
||||
report.were_nmis_disabled = TRUE;
|
||||
|
||||
Irp->IoStatus.Information = sizeof( NMI_CALLBACK_FAILURE );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( NMI_CALLBACK_FAILURE )
|
||||
);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
PNMI_CALLBACK_DATA thread_data = ( PNMI_CALLBACK_DATA )(
|
||||
( uintptr_t )nmi_pools.thread_data_pool + core * sizeof( NMI_CALLBACK_DATA ) );
|
||||
|
||||
DEBUG_LOG( "cpu number: %i callback count: %i", core, context->nmi_callbacks_run );
|
||||
|
||||
/* Walk the stack */
|
||||
for ( INT frame = 0; frame < thread_data->num_frames_captured; frame++ )
|
||||
{
|
||||
BOOLEAN flag;
|
||||
DWORD64 stack_frame = *( DWORD64* )(
|
||||
( ( uintptr_t )nmi_pools.stack_frames + thread_data->stack_frames_offset + frame * sizeof( PVOID ) ) );
|
||||
|
||||
if ( !NT_SUCCESS( IsInstructionPointerInInvalidRegion( stack_frame, SystemModules, &flag ) ) )
|
||||
{
|
||||
DEBUG_ERROR( "errro checking RIP for current stack address" );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( flag == FALSE )
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* large enough for 1 report. In the future this should be changed
|
||||
* to a buffer that can hold atleast 4 reports (since the chance we
|
||||
* get 4 reports with a single NMI would be impossible) so we can
|
||||
* continue parsing the rest of the stack frames after receiving a
|
||||
* single report.
|
||||
*/
|
||||
|
||||
NMI_CALLBACK_FAILURE report;
|
||||
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
|
||||
report.kthread_address = thread_data->kthread_address;
|
||||
report.invalid_rip = stack_frame;
|
||||
report.were_nmis_disabled = FALSE;
|
||||
|
||||
Irp->IoStatus.Information = sizeof( NMI_CALLBACK_FAILURE );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( NMI_CALLBACK_FAILURE )
|
||||
);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN NmiCallback(
|
||||
_In_ PVOID Context,
|
||||
_In_ BOOLEAN Handled
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER( Handled );
|
||||
|
||||
ULONG proc_num = KeGetCurrentProcessorNumber();
|
||||
PVOID current_thread = KeGetCurrentThread();
|
||||
NMI_CALLBACK_DATA thread_data = { 0 };
|
||||
|
||||
/*
|
||||
* Cannot allocate pool in this function as it runs at IRQL >= dispatch level
|
||||
* so ive just allocated a global pool with size equal to 0x200 * num_procs
|
||||
*/
|
||||
INT num_frames_captured = RtlCaptureStackBackTrace(
|
||||
NULL,
|
||||
STACK_FRAME_POOL_SIZE,
|
||||
( uintptr_t )nmi_pools.stack_frames + proc_num * STACK_FRAME_POOL_SIZE,
|
||||
NULL
|
||||
);
|
||||
|
||||
/*
|
||||
* This function is run in the context of the interrupted thread hence we can
|
||||
* gather any and all information regarding the thread that may be useful for analysis
|
||||
*/
|
||||
thread_data.kthread_address = ( UINT64 )current_thread;
|
||||
thread_data.kprocess_address = ( UINT64 )PsGetCurrentProcess();
|
||||
thread_data.stack_base = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_STACK_BASE_OFFSET ) );
|
||||
thread_data.stack_limit = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_STACK_LIMIT_OFFSET ) );
|
||||
thread_data.start_address = *( ( UINT64* )( ( uintptr_t )current_thread + KTHREAD_START_ADDRESS_OFFSET ) );
|
||||
thread_data.cr3 = __readcr3();
|
||||
thread_data.stack_frames_offset = proc_num * STACK_FRAME_POOL_SIZE;
|
||||
thread_data.num_frames_captured = num_frames_captured;
|
||||
|
||||
RtlCopyMemory(
|
||||
( ( uintptr_t )nmi_pools.thread_data_pool ) + proc_num * sizeof( thread_data ),
|
||||
&thread_data,
|
||||
sizeof( thread_data )
|
||||
);
|
||||
|
||||
PNMI_CONTEXT context = ( PNMI_CONTEXT )( ( uintptr_t )Context + proc_num * sizeof( NMI_CONTEXT ) );
|
||||
context->nmi_callbacks_run += 1;
|
||||
DEBUG_LOG( "num nmis called: %i from addr: %llx", context->nmi_callbacks_run, ( uintptr_t )context );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS LaunchNonMaskableInterrupt(
|
||||
_In_ ULONG NumCores
|
||||
)
|
||||
{
|
||||
if ( !NumCores )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PKAFFINITY_EX ProcAffinityPool = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( KAFFINITY_EX ), PROC_AFFINITY_POOL );
|
||||
|
||||
if ( !ProcAffinityPool )
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
nmi_pools.stack_frames = ExAllocatePool2( POOL_FLAG_NON_PAGED, NumCores * STACK_FRAME_POOL_SIZE, STACK_FRAMES_POOL );
|
||||
|
||||
if ( !nmi_pools.stack_frames )
|
||||
{
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
nmi_pools.thread_data_pool = ExAllocatePool2( POOL_FLAG_NON_PAGED, NumCores * sizeof( NMI_CALLBACK_DATA ), THREAD_DATA_POOL );
|
||||
|
||||
if ( !nmi_pools.thread_data_pool )
|
||||
{
|
||||
ExFreePoolWithTag( nmi_pools.stack_frames, STACK_FRAMES_POOL );
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
LARGE_INTEGER delay = { 0 };
|
||||
delay.QuadPart -= NMI_DELAY;
|
||||
|
||||
for ( ULONG core = 0; core < NumCores; core++ )
|
||||
{
|
||||
KeInitializeAffinityEx( ProcAffinityPool );
|
||||
KeAddProcessorAffinityEx( ProcAffinityPool, core );
|
||||
|
||||
DEBUG_LOG( "Sending NMI" );
|
||||
HalSendNMI( ProcAffinityPool );
|
||||
|
||||
/*
|
||||
* Only a single NMI can be active at any given time, so arbitrarily
|
||||
* delay execution to allow time for the NMI to be processed
|
||||
*/
|
||||
KeDelayExecutionThread( KernelMode, FALSE, &delay );
|
||||
}
|
||||
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS HandleNmiIOCTL(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
SYSTEM_MODULES system_modules = { 0 };
|
||||
ULONG num_cores = KeQueryActiveProcessorCountEx( 0 );
|
||||
|
||||
/* Fix annoying visual studio linting error */
|
||||
RtlZeroMemory( &system_modules, sizeof( SYSTEM_MODULES ) );
|
||||
RtlZeroMemory( &nmi_pools, sizeof( NMI_POOLS ) );
|
||||
|
||||
nmi_pools.nmi_context = ExAllocatePool2( POOL_FLAG_NON_PAGED, num_cores * sizeof( NMI_CONTEXT ), NMI_CONTEXT_POOL );
|
||||
|
||||
if ( !nmi_pools.nmi_context )
|
||||
{
|
||||
DEBUG_ERROR( "nmi_context ExAllocatePool2 failed" );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to register and unregister our callback each time so it becomes harder
|
||||
* for people to hook our callback and get up to some funny business
|
||||
*/
|
||||
nmi_callback_handle = KeRegisterNmiCallback( NmiCallback, nmi_pools.nmi_context );
|
||||
|
||||
if ( !nmi_callback_handle )
|
||||
{
|
||||
DEBUG_ERROR( "KeRegisterNmiCallback failed" );
|
||||
ExFreePoolWithTag( nmi_pools.nmi_context, NMI_CONTEXT_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
/*
|
||||
* We query the system modules each time since they can potentially
|
||||
* change at any time
|
||||
*/
|
||||
status = GetSystemModuleInformation( &system_modules );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "Error retriving system module information" );
|
||||
return status;
|
||||
}
|
||||
status = LaunchNonMaskableInterrupt( num_cores );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "Error running NMI callbacks" );
|
||||
ExFreePoolWithTag( system_modules.address, SYSTEM_MODULES_POOL );
|
||||
return status;
|
||||
}
|
||||
status = AnalyseNmiData( num_cores, &system_modules, Irp );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
DEBUG_ERROR( "Error analysing nmi data" );
|
||||
|
||||
ExFreePoolWithTag( system_modules.address, SYSTEM_MODULES_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.stack_frames, STACK_FRAMES_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.thread_data_pool, THREAD_DATA_POOL );
|
||||
ExFreePoolWithTag( nmi_pools.nmi_context, NMI_CONTEXT_POOL );
|
||||
KeDeregisterNmiCallback( nmi_callback_handle );
|
||||
|
||||
return status;
|
||||
}
|
41
driver/nmi.h
41
driver/nmi.h
|
@ -1,41 +0,0 @@
|
|||
#ifndef NMI_H
|
||||
#define NMI_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
|
||||
NTSTATUS HandleNmiIOCTL(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
typedef struct NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
|
||||
}NMI_CALLBACK_FAILURE, *PNMI_CALLBACK_FAILURE;
|
||||
|
||||
typedef struct _NMI_CONTEXT
|
||||
{
|
||||
INT nmi_callbacks_run;
|
||||
|
||||
}NMI_CONTEXT, * PNMI_CONTEXT;
|
||||
|
||||
typedef struct _NMI_CALLBACK_DATA
|
||||
{
|
||||
UINT64 kthread_address;
|
||||
UINT64 kprocess_address;
|
||||
UINT64 start_address;
|
||||
UINT64 stack_limit;
|
||||
UINT64 stack_base;
|
||||
uintptr_t stack_frames_offset;
|
||||
INT num_frames_captured;
|
||||
UINT64 cr3;
|
||||
|
||||
}NMI_CALLBACK_DATA, * PNMI_CALLBACK_DATA;
|
||||
|
||||
#endif
|
|
@ -16,18 +16,18 @@
|
|||
#define INDEX_MUTANTS_POOL_TAG 4
|
||||
#define INDEX_FILE_OBJECTS_POOL_TAG 5
|
||||
#define INDEX_DRIVERS_POOL_TAG 6
|
||||
#define INDEX_SYMBOLIC_LINKS_POOL_TAG7
|
||||
#define INDEX_SYMBOLIC_LINKS_POOL_TAG 7
|
||||
|
||||
CHAR EXECUTIVE_OBJECT_POOL_TAGS[ EXECUTIVE_OBJECT_COUNT ][ POOL_TAG_LENGTH ] =
|
||||
{
|
||||
"\x50\x72\x6f\x63",
|
||||
"\x54\x68\x72\x64",
|
||||
"\x44\x65\x73\x6B",
|
||||
"\x57\x69\x6E\x64",
|
||||
"\x4D\x75\x74\x65",
|
||||
"\x46\x69\x6C\x65",
|
||||
"\x44\x72\x69\x76",
|
||||
"\x4C\x69\x6E\x6B"
|
||||
"\x50\x72\x6f\x63", /* Process */
|
||||
"\x54\x68\x72\x64", /* Thread */
|
||||
"\x44\x65\x73\x6B", /* Desktop */
|
||||
"\x57\x69\x6E\x64", /* Windows Station */
|
||||
"\x4D\x75\x74\x65", /* Mutants i.e mutex etc. */
|
||||
"\x46\x69\x6C\x65", /* File objects */
|
||||
"\x44\x72\x69\x76", /* Drivers */
|
||||
"\x4C\x69\x6E\x6B" /* Symbolic links */
|
||||
};
|
||||
|
||||
PVOID process_buffer = NULL;
|
||||
|
@ -123,7 +123,7 @@ VOID ScanPageForKernelObjectAllocation(
|
|||
PUINT64 address_list;
|
||||
ULONG allocation_size;
|
||||
|
||||
if ( !PageBase || !PageSize)
|
||||
if ( !PageBase || !PageSize )
|
||||
return;
|
||||
|
||||
for ( INT offset = 0; offset <= PageSize - POOL_TAG_LENGTH; offset++ )
|
||||
|
@ -152,7 +152,6 @@ VOID ScanPageForKernelObjectAllocation(
|
|||
*
|
||||
* more: https://www.imf-conference.org/imf2006/23_Schuster-PoolAllocations.pdf
|
||||
*/
|
||||
|
||||
allocation_size = pool_header->BlockSize * CHUNK_SIZE - sizeof( POOL_HEADER );
|
||||
|
||||
if ( ( allocation_size == WIN_PROCESS_ALLOCATION_SIZE ||
|
||||
|
@ -207,9 +206,6 @@ BOOLEAN IsPhysicalAddressInPhysicalMemoryRange(
|
|||
UINT64 start_address = 0;
|
||||
UINT64 end_address = 0;
|
||||
|
||||
if ( !PhysicalAddress || !PhysicalMemoryRanges )
|
||||
return FALSE;
|
||||
|
||||
while ( PhysicalMemoryRanges[ page_index ].NumberOfBytes.QuadPart != NULL )
|
||||
{
|
||||
start_address = PhysicalMemoryRanges[ page_index ].BaseAddress.QuadPart;
|
||||
|
@ -407,10 +403,12 @@ VOID CheckIfProcessAllocationIsInProcessList(
|
|||
* 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()
|
||||
NTSTATUS FindUnlinkedProcesses(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PUINT64 allocation_address;
|
||||
PINVALID_PROCESS_ALLOCATION_REPORT report_buffer = NULL;
|
||||
|
||||
EnumerateProcessListWithCallbackFunction(
|
||||
IncrementProcessCounter
|
||||
|
@ -422,8 +420,6 @@ NTSTATUS FindUnlinkedProcesses()
|
|||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Proc count: %lx", process_count );
|
||||
|
||||
process_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, process_count * 2 * sizeof( UINT64 ), PROCESS_ADDRESS_LIST_TAG );
|
||||
|
||||
if ( !process_buffer )
|
||||
|
@ -448,11 +444,34 @@ NTSTATUS FindUnlinkedProcesses()
|
|||
|
||||
/* report / do some further analysis */
|
||||
DEBUG_ERROR( "INVALID POOL proc OMGGG" );
|
||||
|
||||
report_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( INVALID_PROCESS_ALLOCATION_REPORT ), INVALID_PROCESS_REPORT_TAG );
|
||||
|
||||
if ( !report_buffer )
|
||||
goto end;
|
||||
|
||||
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
|
||||
|
||||
RtlCopyMemory(
|
||||
report_buffer->process,
|
||||
allocation_address[i],
|
||||
REPORT_INVALID_PROCESS_BUFFER_SIZE );
|
||||
|
||||
Irp->IoStatus.Information = sizeof( INVALID_PROCESS_ALLOCATION_REPORT );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
report_buffer,
|
||||
sizeof( INVALID_PROCESS_ALLOCATION_REPORT ) );
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Finished pool memory xd" );
|
||||
end:
|
||||
|
||||
ExFreePoolWithTag( process_buffer, PROCESS_ADDRESS_LIST_TAG );
|
||||
if (report_buffer )
|
||||
ExFreePoolWithTag( report_buffer, INVALID_PROCESS_REPORT_TAG );
|
||||
|
||||
if (process_buffer )
|
||||
ExFreePoolWithTag( process_buffer, PROCESS_ADDRESS_LIST_TAG );
|
||||
|
||||
process_count = NULL;
|
||||
process_buffer = NULL;
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
#include <ntifs.h>
|
||||
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 4096
|
||||
|
||||
#define POOL_DUMP_BLOCK_TAG 'dump'
|
||||
#define POOL_DEBUGGER_DATA_TAG 'data'
|
||||
#define PROCESS_ADDRESS_LIST_TAG 'addr'
|
||||
#define ANALYSE_PROCESS_TAG 'anls'
|
||||
#define INVALID_PROCESS_REPORT_TAG 'invd'
|
||||
|
||||
#define PML4_ENTRY_COUNT 512
|
||||
#define PDPT_ENTRY_COUNT 512
|
||||
|
@ -18,6 +23,7 @@
|
|||
#define PROCESS_OBJECT_ALLOCATION_MARGIN 0x90
|
||||
|
||||
#define EPROCESS_VIRTUAL_SIZE_OFFSET 0x498
|
||||
#define EPROCESS_IMAGE_NAME_OFFSET 0x5a8
|
||||
|
||||
/* SIZE_2 = first alloc + 0x10 */
|
||||
#define WIN_PROCESS_ALLOCATION_SIZE 0xcf0
|
||||
|
@ -25,7 +31,16 @@
|
|||
|
||||
#define CHUNK_SIZE 16
|
||||
|
||||
NTSTATUS FindUnlinkedProcesses();
|
||||
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[ REPORT_INVALID_PROCESS_BUFFER_SIZE ];
|
||||
|
||||
}INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
|
||||
NTSTATUS FindUnlinkedProcesses(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
/* creds: https://www.unknowncheats.me/forum/2602838-post2.html */
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "pipe.h"
|
||||
#include <TlHelp32.h>
|
||||
|
||||
#define REPORT_BUFFER_SIZE 1024
|
||||
#define REPORT_BUFFER_SIZE 8192
|
||||
#define SEND_BUFFER_SIZE 8192
|
||||
|
||||
#define MAX_SIGNATURE_SIZE 256
|
||||
|
@ -21,6 +21,7 @@
|
|||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
|
||||
enum REPORT_CODES
|
||||
{
|
||||
|
@ -146,6 +147,12 @@ namespace global
|
|||
LONG desired_access;
|
||||
CHAR process_name[ 64 ];
|
||||
};
|
||||
|
||||
struct INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[ 4096 ];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -343,6 +343,32 @@ end:
|
|||
free( buffer );
|
||||
}
|
||||
|
||||
VOID kernelmode::Driver::ScanForUnlinkedProcess()
|
||||
{
|
||||
BOOLEAN status;
|
||||
DWORD bytes_returned;
|
||||
global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT report;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle,
|
||||
IOCTL_SCAN_FOR_UNLINKED_PROCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof(report),
|
||||
&bytes_returned,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( status == NULL || bytes_returned == NULL)
|
||||
{
|
||||
LOG_ERROR( "failed to scan for unlinked processes %x", GetLastError() );
|
||||
return;
|
||||
}
|
||||
|
||||
this->report_interface->ServerSend( &report, bytes_returned, SERVER_SEND_MODULE_INTEGRITY_CHECK );
|
||||
}
|
||||
|
||||
ULONG kernelmode::Driver::RequestTotalModuleSize()
|
||||
{
|
||||
BOOLEAN status;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2008, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define MAX_HANDLE_REPORTS_PER_IRP 10
|
||||
|
||||
|
@ -44,6 +45,7 @@ namespace kernelmode
|
|||
VOID ValidateKPRCBThreads();
|
||||
VOID CheckHandleTableEntries();
|
||||
VOID RequestModuleExecutableRegions();
|
||||
VOID ScanForUnlinkedProcess();
|
||||
};
|
||||
|
||||
struct DRIVER_INITIATION_INFORMATION
|
||||
|
|
Loading…
Reference in a new issue