This commit is contained in:
lhodges1 2023-10-05 17:27:17 +11:00
parent c4c42c3e56
commit 9da18de49f
18 changed files with 2116 additions and 2042 deletions

View file

@ -9,7 +9,7 @@
CALLBACK_CONFIGURATION configuration = { 0 };
STATIC
VOID
VOID
ObPostOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation
@ -19,13 +19,13 @@ ObPostOpCallbackRoutine(
}
STATIC
OB_PREOP_CALLBACK_STATUS
OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
)
{
UNREFERENCED_PARAMETER( RegistrationContext );
UNREFERENCED_PARAMETER(RegistrationContext);
/* access mask to completely strip permissions */
ACCESS_MASK deny_access = SYNCHRONIZE | PROCESS_TERMINATE;
@ -39,39 +39,39 @@ ObPreOpCallbackRoutine(
*/
PEPROCESS process_creator = PsGetCurrentProcess();
PEPROCESS protected_process;
PEPROCESS target_process = ( PEPROCESS )OperationInformation->Object;
LONG target_process_id = PsGetProcessId( target_process );
LONG process_creator_id = PsGetProcessId( process_creator );
PEPROCESS target_process = (PEPROCESS)OperationInformation->Object;
LONG target_process_id = PsGetProcessId(target_process);
LONG process_creator_id = PsGetProcessId(process_creator);
LONG protected_process_id = NULL;
LPCSTR process_creator_name;
LPCSTR target_process_name;
LPCSTR protected_process_name;
KeAcquireGuardedMutex( &configuration.mutex );
KeAcquireGuardedMutex(&configuration.mutex);
GetProtectedProcessId( &protected_process_id );
GetProtectedProcessEProcess( &protected_process );
GetProtectedProcessId(&protected_process_id);
GetProtectedProcessEProcess(&protected_process);
if ( !protected_process_id || !protected_process )
if (!protected_process_id || !protected_process)
goto end;
process_creator_name = PsGetProcessImageFileName( process_creator );
target_process_name = PsGetProcessImageFileName( target_process );
protected_process_name = PsGetProcessImageFileName( protected_process );
process_creator_name = PsGetProcessImageFileName(process_creator);
target_process_name = PsGetProcessImageFileName(target_process);
protected_process_name = PsGetProcessImageFileName(protected_process);
if ( !protected_process_name || !target_process_name )
if (!protected_process_name || !target_process_name)
goto end;
if ( !strcmp( protected_process_name, target_process_name) )
if (!strcmp(protected_process_name, target_process_name))
{
if ( !strcmp( process_creator_name, "lsass.exe" ) || !strcmp( process_creator_name, "csrss.exe" ) )
if (!strcmp(process_creator_name, "lsass.exe") || !strcmp(process_creator_name, "csrss.exe"))
{
/* We will downgrade these handles later */
DEBUG_LOG( "Handles created by CSRSS and LSASS are allowed for now..." );
DEBUG_LOG("Handles created by CSRSS and LSASS are allowed for now...");
}
else if ( target_process == process_creator )
else if (target_process == process_creator)
{
DEBUG_LOG( "handles made by NOTEPAD r okay :)" );
DEBUG_LOG("handles made by NOTEPAD r okay :)");
/* handles created by the game (notepad) are okay */
}
else
@ -84,17 +84,17 @@ ObPreOpCallbackRoutine(
* so we will still strip them but we won't report them.. for now atleast.
*/
if ( !strcmp( process_creator_name, "Discord.exe" ) ||
!strcmp( process_creator_name, "svchost.exe" ) ||
!strcmp( process_creator_name, "explorer.exe" ) )
if (!strcmp(process_creator_name, "Discord.exe") ||
!strcmp(process_creator_name, "svchost.exe") ||
!strcmp(process_creator_name, "explorer.exe"))
goto end;
DEBUG_LOG( "handle stripped from: %s", process_creator_name );
DEBUG_LOG("handle stripped from: %s", process_creator_name);
POPEN_HANDLE_FAILURE_REPORT report =
ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( OPEN_HANDLE_FAILURE_REPORT ), REPORT_POOL_TAG );
POPEN_HANDLE_FAILURE_REPORT report =
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(OPEN_HANDLE_FAILURE_REPORT), REPORT_POOL_TAG);
if ( !report )
if (!report)
goto end;
report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
@ -102,15 +102,15 @@ ObPreOpCallbackRoutine(
report->is_kernel_handle = OperationInformation->KernelHandle;
report->process_id = process_creator_id;
report->thread_id = PsGetCurrentThreadId();
RtlCopyMemory( report->process_name, process_creator_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH );
RtlCopyMemory(report->process_name, process_creator_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
InsertReportToQueue( report );
InsertReportToQueue(report);
}
}
end:
KeReleaseGuardedMutex( &configuration.mutex );
KeReleaseGuardedMutex(&configuration.mutex);
return OB_PREOP_SUCCESS;
}
@ -161,8 +161,8 @@ end:
//}
/* stolen from ReactOS xD */
VOID
NTAPI
VOID
NTAPI
ExUnlockHandleTableEntry(
IN PHANDLE_TABLE HandleTable,
IN PHANDLE_TABLE_ENTRY HandleTableEntry
@ -172,14 +172,14 @@ ExUnlockHandleTableEntry(
PAGED_CODE();
/* Set the lock bit and make sure it wasn't earlier */
old_value = InterlockedOr( ( PLONG )&HandleTableEntry->VolatileLowValue, 1 );
old_value = InterlockedOr((PLONG)&HandleTableEntry->VolatileLowValue, 1);
/* Unblock any waiters */
ExfUnblockPushLock( &HandleTable->HandleContentionEvent, NULL );
ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
}
STATIC
BOOLEAN
BOOLEAN
EnumHandleCallback(
_In_ PHANDLE_TABLE HandleTable,
_In_ PHANDLE_TABLE_ENTRY Entry,
@ -196,113 +196,113 @@ EnumHandleCallback(
LPCSTR protected_process_name;
ACCESS_MASK handle_access_mask;
object_header = GET_OBJECT_HEADER_FROM_HANDLE( Entry->ObjectPointerBits );
object_header = GET_OBJECT_HEADER_FROM_HANDLE(Entry->ObjectPointerBits);
/* Object header is the first 30 bytes of the object */
object = ( uintptr_t )object_header + OBJECT_HEADER_SIZE;
object = (uintptr_t)object_header + OBJECT_HEADER_SIZE;
object_type = ObGetObjectType( object );
object_type = ObGetObjectType(object);
/* TODO: check for threads aswell */
if ( !RtlCompareUnicodeString( &object_type->Name, &OBJECT_TYPE_PROCESS, TRUE ) )
if (!RtlCompareUnicodeString(&object_type->Name, &OBJECT_TYPE_PROCESS, TRUE))
{
process = ( PEPROCESS )object;
process_name = PsGetProcessImageFileName( process );
process = (PEPROCESS)object;
process_name = PsGetProcessImageFileName(process);
GetProtectedProcessEProcess( &protected_process );
GetProtectedProcessEProcess(&protected_process);
protected_process_name = PsGetProcessImageFileName( protected_process );
protected_process_name = PsGetProcessImageFileName(protected_process);
if ( strcmp( process_name, protected_process_name ) )
if (strcmp(process_name, protected_process_name))
goto end;
DEBUG_LOG( "Handle references our protected process with access mask: %lx", ( ACCESS_MASK )Entry->GrantedAccessBits );
DEBUG_LOG("Handle references our protected process with access mask: %lx", (ACCESS_MASK)Entry->GrantedAccessBits);
handle_access_mask = ( ACCESS_MASK )Entry->GrantedAccessBits;
handle_access_mask = (ACCESS_MASK)Entry->GrantedAccessBits;
/* These permissions can be stripped from every process including CSRSS and LSASS */
if ( handle_access_mask & PROCESS_CREATE_PROCESS )
if (handle_access_mask & PROCESS_CREATE_PROCESS)
{
Entry->GrantedAccessBits &= ~PROCESS_CREATE_PROCESS;
DEBUG_LOG( "Stripped PROCESS_CREATE_PROCESS" );
DEBUG_LOG("Stripped PROCESS_CREATE_PROCESS");
}
if ( handle_access_mask & PROCESS_CREATE_THREAD )
if (handle_access_mask & PROCESS_CREATE_THREAD)
{
Entry->GrantedAccessBits &= ~PROCESS_CREATE_THREAD;
DEBUG_LOG( "Stripped PROCESS_CREATE_THREAD" );
DEBUG_LOG("Stripped PROCESS_CREATE_THREAD");
}
if ( handle_access_mask & PROCESS_DUP_HANDLE )
if (handle_access_mask & PROCESS_DUP_HANDLE)
{
Entry->GrantedAccessBits &= ~PROCESS_DUP_HANDLE;
DEBUG_LOG( "Stripped PROCESS_DUP_HANDLE" );
DEBUG_LOG("Stripped PROCESS_DUP_HANDLE");
}
if ( handle_access_mask & PROCESS_QUERY_INFORMATION )
if (handle_access_mask & PROCESS_QUERY_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_QUERY_INFORMATION;
DEBUG_LOG( "Stripped PROCESS_QUERY_INFORMATION" );
DEBUG_LOG("Stripped PROCESS_QUERY_INFORMATION");
}
if ( handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION )
if (handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_QUERY_LIMITED_INFORMATION;
DEBUG_LOG( "Stripped PROCESS_QUERY_LIMITED_INFORMATION" );
DEBUG_LOG("Stripped PROCESS_QUERY_LIMITED_INFORMATION");
}
if ( handle_access_mask & PROCESS_VM_READ )
if (handle_access_mask & PROCESS_VM_READ)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_READ;
DEBUG_LOG( "Stripped PROCESS_VM_READ" );
DEBUG_LOG("Stripped PROCESS_VM_READ");
}
if ( !strcmp( process_name, "csrss.exe" ) || !strcmp( process_name, "lsass.exe" ) )
if (!strcmp(process_name, "csrss.exe") || !strcmp(process_name, "lsass.exe"))
{
DEBUG_LOG( "Required system process allowed, only stripping some permissions" );
DEBUG_LOG("Required system process allowed, only stripping some permissions");
goto end;
}
/* Permissions beyond here can only be stripped from non critical processes */
if ( handle_access_mask & PROCESS_SET_INFORMATION )
if (handle_access_mask & PROCESS_SET_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_SET_INFORMATION;
DEBUG_LOG( "Stripped PROCESS_SET_INFORMATION" );
DEBUG_LOG("Stripped PROCESS_SET_INFORMATION");
}
if ( handle_access_mask & PROCESS_SET_QUOTA )
if (handle_access_mask & PROCESS_SET_QUOTA)
{
Entry->GrantedAccessBits &= ~PROCESS_SET_QUOTA;
DEBUG_LOG( "Stripped PROCESS_SET_QUOTA" );
DEBUG_LOG("Stripped PROCESS_SET_QUOTA");
}
if ( handle_access_mask & PROCESS_SUSPEND_RESUME )
if (handle_access_mask & PROCESS_SUSPEND_RESUME)
{
Entry->GrantedAccessBits &= ~PROCESS_SUSPEND_RESUME;
DEBUG_LOG( "Stripped PROCESS_SUSPEND_RESUME " );
DEBUG_LOG("Stripped PROCESS_SUSPEND_RESUME ");
}
if ( handle_access_mask & PROCESS_TERMINATE )
if (handle_access_mask & PROCESS_TERMINATE)
{
Entry->GrantedAccessBits &= ~PROCESS_TERMINATE;
DEBUG_LOG( "Stripped PROCESS_TERMINATE" );
DEBUG_LOG("Stripped PROCESS_TERMINATE");
}
if ( handle_access_mask & PROCESS_VM_OPERATION )
if (handle_access_mask & PROCESS_VM_OPERATION)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_OPERATION;
DEBUG_LOG( "Stripped PROCESS_VM_OPERATION" );
DEBUG_LOG("Stripped PROCESS_VM_OPERATION");
}
if ( handle_access_mask & PROCESS_VM_WRITE )
if (handle_access_mask & PROCESS_VM_WRITE)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_WRITE;
DEBUG_LOG( "Stripped PROCESS_VM_WRITE" );
DEBUG_LOG("Stripped PROCESS_VM_WRITE");
}
POPEN_HANDLE_FAILURE_REPORT report = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( OPEN_HANDLE_FAILURE_REPORT ), REPORT_POOL_TAG );
POPEN_HANDLE_FAILURE_REPORT report = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(OPEN_HANDLE_FAILURE_REPORT), REPORT_POOL_TAG);
if ( !report )
if (!report)
goto end;
/*
@ -315,20 +315,20 @@ EnumHandleCallback(
*/
report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
report->is_kernel_handle = NULL;
report->process_id = PsGetProcessId( process );
report->process_id = PsGetProcessId(process);
report->thread_id = NULL;
report->access = handle_access_mask;
RtlCopyMemory( &report->process_name, process_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH );
RtlCopyMemory(&report->process_name, process_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
InsertReportToQueue( report );
InsertReportToQueue(report);
}
end:
ExUnlockHandleTableEntry( HandleTable, Entry );
ExUnlockHandleTableEntry(HandleTable, Entry);
return FALSE;
}
NTSTATUS
NTSTATUS
EnumerateProcessHandles(
_In_ PEPROCESS Process
)
@ -336,18 +336,18 @@ EnumerateProcessHandles(
/* Handles are paged out so we need to be at an IRQL that allows paging */
PAGED_CODE();
if ( !Process )
if (!Process)
return STATUS_INVALID_PARAMETER;
if ( Process == PsInitialSystemProcess )
if (Process == PsInitialSystemProcess)
return STATUS_SUCCESS;
PHANDLE_TABLE handle_table = *( PHANDLE_TABLE* )( ( uintptr_t )Process + EPROCESS_HANDLE_TABLE_OFFSET );
PHANDLE_TABLE handle_table = *(PHANDLE_TABLE*)((uintptr_t)Process + EPROCESS_HANDLE_TABLE_OFFSET);
if ( !handle_table )
if (!handle_table)
return STATUS_INVALID_ADDRESS;
if ( !MmIsAddressValid( handle_table ) )
if (!MmIsAddressValid(handle_table))
return STATUS_INVALID_ADDRESS;
#pragma warning(push)
@ -370,11 +370,11 @@ EnumerateProcessHandles(
* cheat which is mass deployed and needs to ensure that it won't crash the system.
* Since we have no access to the process structure locks it is definitely not
* mass deployment safe lol.
*
*
* The Context argument is simply a pointer to a user designed context structure
* which is passed to the callback function.
*/
VOID
VOID
EnumerateProcessListWithCallbackFunction(
_In_ PVOID Function,
_In_opt_ PVOID Context
@ -385,28 +385,28 @@ EnumerateProcessListWithCallbackFunction(
PLIST_ENTRY process_list_entry = NULL;
PEPROCESS base_process = PsInitialSystemProcess;
if ( !base_process )
if (!base_process)
return;
process_list_head = ( UINT64 )( ( UINT64 )base_process + EPROCESS_PLIST_ENTRY_OFFSET );
process_list_head = (UINT64)((UINT64)base_process + EPROCESS_PLIST_ENTRY_OFFSET);
process_list_entry = process_list_head;
do
{
current_process = ( PEPROCESS )( ( UINT64 )process_list_entry - EPROCESS_PLIST_ENTRY_OFFSET );
current_process = (PEPROCESS)((UINT64)process_list_entry - EPROCESS_PLIST_ENTRY_OFFSET);
if ( !current_process )
if (!current_process)
return;
VOID( *callback_function_ptr )( PEPROCESS, PVOID ) = Function;
( *callback_function_ptr )( current_process, Context );
VOID(*callback_function_ptr)(PEPROCESS, PVOID) = Function;
(*callback_function_ptr)(current_process, Context);
process_list_entry = process_list_entry->Flink;
} while ( process_list_entry != process_list_head->Blink);
} while (process_list_entry != process_list_head->Blink);
}
NTSTATUS
NTSTATUS
InitiateDriverCallbacks()
{
NTSTATUS status;
@ -416,7 +416,7 @@ InitiateDriverCallbacks()
* the callback function is running since this might cause some funny stuff
* to happen. Better to be safe then sorry :)
*/
KeInitializeGuardedMutex( &configuration.mutex );
KeInitializeGuardedMutex(&configuration.mutex);
OB_CALLBACK_REGISTRATION callback_registration = { 0 };
OB_OPERATION_REGISTRATION operation_registration = { 0 };
@ -436,9 +436,9 @@ InitiateDriverCallbacks()
&configuration.registration_handle
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "failed to launch obregisters with status %x", status );
DEBUG_ERROR("failed to launch obregisters with status %x", status);
return status;
}
@ -453,19 +453,19 @@ InitiateDriverCallbacks()
return status;
}
VOID
VOID
UnregisterCallbacksOnProcessTermination()
{
DEBUG_LOG( "Process closed, unregistering callbacks" );
KeAcquireGuardedMutex( &configuration.mutex );
DEBUG_LOG("Process closed, unregistering callbacks");
KeAcquireGuardedMutex(&configuration.mutex);
if ( configuration.registration_handle == NULL )
if (configuration.registration_handle == NULL)
{
KeReleaseGuardedMutex( &configuration.mutex );
KeReleaseGuardedMutex(&configuration.mutex);
return;
}
ObUnRegisterCallbacks( configuration.registration_handle );
ObUnRegisterCallbacks(configuration.registration_handle);
configuration.registration_handle = NULL;
KeReleaseGuardedMutex( &configuration.mutex );
KeReleaseGuardedMutex(&configuration.mutex);
}

View file

@ -15,16 +15,16 @@ typedef struct _OPEN_HANDLE_FAILURE_REPORT
LONG process_id;
LONG thread_id;
LONG access;
CHAR process_name[ HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH ];
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
}OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT;
}OPEN_HANDLE_FAILURE_REPORT, * POPEN_HANDLE_FAILURE_REPORT;
typedef struct _CALLBACKS_CONFIGURATION
{
PVOID registration_handle;
KGUARDED_MUTEX mutex;
}CALLBACK_CONFIGURATION, *PCALLBACK_CONFIGURATION;
}CALLBACK_CONFIGURATION, * PCALLBACK_CONFIGURATION;
//handle access masks
//https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
@ -48,25 +48,25 @@ static const uintptr_t EPROCESS_IMAGE_FILE_NAME_OFFSET = 0x5a8;
static const uintptr_t EPROCESS_HANDLE_TABLE_OFFSET = 0x570;
static const uintptr_t EPROCESS_PLIST_ENTRY_OFFSET = 0x448;
static UNICODE_STRING OBJECT_TYPE_PROCESS = RTL_CONSTANT_STRING( L"Process" );
static UNICODE_STRING OBJECT_TYPE_THREAD = RTL_CONSTANT_STRING( L"Thread" );
static UNICODE_STRING OBJECT_TYPE_PROCESS = RTL_CONSTANT_STRING(L"Process");
static UNICODE_STRING OBJECT_TYPE_THREAD = RTL_CONSTANT_STRING(L"Thread");
VOID
NTAPI
VOID
NTAPI
ExUnlockHandleTableEntry(
IN PHANDLE_TABLE HandleTable,
IN PHANDLE_TABLE_ENTRY HandleTableEntry
);
STATIC
VOID
VOID
ObPostOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation
);
STATIC
OB_PREOP_CALLBACK_STATUS
OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
@ -78,21 +78,21 @@ ObPreOpCallbackRoutine(
// _In_ BOOLEAN Create
//);
VOID
VOID
EnumerateProcessListWithCallbackFunction(
_In_ PVOID Function,
_In_opt_ PVOID Context
);
NTSTATUS
NTSTATUS
EnumerateProcessHandles(
_In_ PEPROCESS Process
);
NTSTATUS
NTSTATUS
InitiateDriverCallbacks();
VOID
VOID
UnregisterCallbacksOnProcessTermination();
#endif

View file

@ -29,7 +29,7 @@ typedef struct _DRIVER_CONFIG
UNICODE_STRING driver_path;
UNICODE_STRING registry_path;
SYSTEM_INFORMATION system_information;
PVOID apc_contexts[ MAXIMUM_APC_CONTEXTS ];
PVOID apc_contexts[MAXIMUM_APC_CONTEXTS];
KGUARDED_MUTEX lock;
}DRIVER_CONFIG, * PDRIVER_CONFIG;
@ -52,57 +52,57 @@ DRIVER_CONFIG driver_config = { 0 };
PROCESS_CONFIG process_config = { 0 };
/*
* The driver config structure holds an array of pointers to APC context structures. These
* APC context structures are unique to each APC operation that this driver will perform. For
* The driver config structure holds an array of pointers to APC context structures. These
* APC context structures are unique to each APC operation that this driver will perform. For
* example, a single context will manage all APCs that are used to stackwalk, whilst another
* context will be used to manage all APCs used to query a threads memory for example.
*
*
* Due to the nature of APCs, its important to keep a total or count of the number of APCs we
* have allocated and queued to threads. This information is stored in the APC_CONTEXT_HEADER which
* all APC context structures will contain as the first entry in their structure. It holds the ContextId
* which is a unique identifier for the type of APC operation it is managing aswell as the number of
* currently queued APCs.
*
* When an APC is allocated a queued, we increment this count. When an APC is completed and freed, we
* decrement this counter and free the APC itself. If all APCs have been freed and the counter is 0,the
* currently queued APCs.
*
* When an APC is allocated a queued, we increment this count. When an APC is completed and freed, we
* decrement this counter and free the APC itself. If all APCs have been freed and the counter is 0,the
* following objects will be freed:
*
*
* 1. Any additional allocations used by the APC stored in the context structure
* 2. The APC context structure for the given APC operation
* 3. The APC context entry in driver_config->apc_contexts will be zero'd.
*
*
* It's important to remember that the driver can unload when pending APC's have not been freed due to the
* limitations windows places on APCs, however I am in the process of finding a solution for this.
* limitations windows places on APCs, however I am in the process of finding a solution for this.
*/
STATIC
BOOLEAN
BOOLEAN
FreeAllApcContextStructures()
{
BOOLEAN flag = TRUE;
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
for ( INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++ )
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
PUINT64 entry = driver_config.apc_contexts;
if ( entry[ index ] != NULL )
if (entry[index] != NULL)
{
PAPC_CONTEXT_HEADER context = entry[ index ];
PAPC_CONTEXT_HEADER context = entry[index];
if ( context->count > 0 )
if (context->count > 0)
{
flag = FALSE;
goto unlock;
}
ExFreePoolWithTag( entry, POOL_TAG_APC );
ExFreePoolWithTag(entry, POOL_TAG_APC);
}
}
unlock:
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
return flag;
}
@ -120,19 +120,19 @@ FreeApcContextStructure(
{
BOOLEAN result = FALSE;
DEBUG_LOG( "All APCs executed, freeing context structure" );
DEBUG_LOG("All APCs executed, freeing context structure");
for ( INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++ )
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
PUINT64 entry = driver_config.apc_contexts;
if ( entry[ index ] == Context )
if (entry[index] == Context)
{
if ( Context->count != 0 )
if (Context->count != 0)
goto unlock;
ExFreePoolWithTag( Context, POOL_TAG_APC );
entry[ index ] = NULL;
ExFreePoolWithTag(Context, POOL_TAG_APC);
entry[index] = NULL;
result = TRUE;
goto unlock;
}
@ -148,14 +148,14 @@ IncrementApcCount(
)
{
PAPC_CONTEXT_HEADER header = NULL;
GetApcContext( &header, ContextId );
GetApcContext(&header, ContextId);
if ( !header )
if (!header)
return;
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
header->count += 1;
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
@ -166,38 +166,38 @@ FreeApcAndDecrementApcCount(
{
PAPC_CONTEXT_HEADER context = NULL;
ExFreePoolWithTag( Apc, POOL_TAG_APC );
ExFreePoolWithTag(Apc, POOL_TAG_APC);
GetApcContext( &context, ContextId );
GetApcContext(&context, ContextId);
if ( !context )
if (!context)
goto end;
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
context->count -= 1;
end:
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
/*
* The reason we use a query model rather then checking the count of queued APCs
* after each APC free and decrement is that the lock will be recursively acquired by
* The reason we use a query model rather then checking the count of queued APCs
* after each APC free and decrement is that the lock will be recursively acquired by
* freeing threads (i.e executing APCs) rather then APC allocation threads. The reason for this
* being that freeing threads are executing at a higher IRQL then the APC allocation
* being that freeing threads are executing at a higher IRQL then the APC allocation
* thread, hence they are granted higher priority by the scheduler when determining
* which thread will accquire the lock next:
*
*
* [+] Freeing thread -> ApcKernelRoutine IRQL: 1 (APC_LEVEL)
* [+] Allocation thread -> ValidateThreadViaKernelApcCallback IRQL: 0 (PASSIVE_LEVEL)
*
* As a result, once an APC is executed and reaches the freeing stage, it will acquire the
* As a result, once an APC is executed and reaches the freeing stage, it will acquire the
* lock and decrement it. Then, if atleast 1 APC execution thread is waiting on the lock,
* it will be prioritised due to its higher IRQL and the cycle will continue. Eventually,
* it will be prioritised due to its higher IRQL and the cycle will continue. Eventually,
* the count will reach 0 due to recursive acquisition by the executing APC threads and then
* the function will free the APC context structure. This will then cause a bug check the next
* time a thread accesses the context structure and hence not good :c.
*
*
* So to combat this, we add in a flag specifying whether or not an allocation of APCs is
* in progress, and even if the count is 0 we will not free the context structure until
* the count is 0 and allocation_in_progress is 0. We can then call this function alongside
@ -206,83 +206,83 @@ end:
NTSTATUS
QueryActiveApcContextsForCompletion()
{
for ( INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++ )
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
PAPC_CONTEXT_HEADER entry = NULL;
GetApcContextByIndex( &entry, index );
GetApcContextByIndex(&entry, index);
/* acquire mutex after we get the context to prevent thread deadlock */
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
if ( entry == NULL )
if (entry == NULL)
{
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
continue;
}
DEBUG_LOG( "APC Context Id: %lx", entry->context_id );
DEBUG_LOG( "Active APC Count: %i", entry->count );
DEBUG_LOG("APC Context Id: %lx", entry->context_id);
DEBUG_LOG("Active APC Count: %i", entry->count);
if ( entry->count > 0 || entry->allocation_in_progress == TRUE )
if (entry->count > 0 || entry->allocation_in_progress == TRUE)
{
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
continue;
}
switch ( entry->context_id )
switch (entry->context_id)
{
case APC_CONTEXT_ID_STACKWALK:
FreeApcStackwalkApcContextInformation( entry );
FreeApcContextStructure( entry );
FreeApcStackwalkApcContextInformation(entry);
FreeApcContextStructure(entry);
break;
}
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
return STATUS_SUCCESS;
}
VOID
VOID
InsertApcContext(
_In_ PVOID Context
)
{
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
PAPC_CONTEXT_HEADER header = Context;
for ( INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++ )
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
PUINT64 entry = driver_config.apc_contexts;
if ( entry[ index ] == NULL )
if (entry[index] == NULL)
{
entry[ index ] = Context;
entry[index] = Context;
goto end;
}
}
end:
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetApcContext(
_Inout_ PVOID* Context,
_In_ LONG ContextIdentifier
)
{
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
for ( INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++ )
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
PAPC_CONTEXT_HEADER header = driver_config.apc_contexts[ index ];
PAPC_CONTEXT_HEADER header = driver_config.apc_contexts[index];
if ( header == NULL )
if (header == NULL)
continue;
if ( header->context_id == ContextIdentifier )
if (header->context_id == ContextIdentifier)
{
*Context = header;
goto unlock;
@ -290,7 +290,7 @@ GetApcContext(
}
unlock:
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
@ -299,132 +299,132 @@ GetApcContextByIndex(
_In_ INT Index
)
{
KeAcquireGuardedMutex( &driver_config.lock );
*Context = driver_config.apc_contexts[ Index ];
KeReleaseGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
*Context = driver_config.apc_contexts[Index];
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
ReadProcessInitialisedConfigFlag(
_Out_ PBOOLEAN Flag
)
{
if ( Flag == NULL )
if (Flag == NULL)
return;
KeAcquireGuardedMutex( &process_config.lock );
KeAcquireGuardedMutex(&process_config.lock);
*Flag = process_config.initialised;
KeReleaseGuardedMutex( &process_config.lock );
KeReleaseGuardedMutex(&process_config.lock);
}
VOID
GetProtectedProcessEProcess(
_Out_ PEPROCESS* Process
VOID
GetProtectedProcessEProcess(
_Out_ PEPROCESS* Process
)
{
if ( Process == NULL )
if (Process == NULL)
return;
KeAcquireGuardedMutex( &process_config.lock );
KeAcquireGuardedMutex(&process_config.lock);
*Process = process_config.protected_process_eprocess;
KeReleaseGuardedMutex( &process_config.lock );
KeReleaseGuardedMutex(&process_config.lock);
}
VOID
VOID
GetProtectedProcessId(
_Out_ PLONG ProcessId
)
{
KeAcquireGuardedMutex( &process_config.lock );
RtlZeroMemory( ProcessId, sizeof( LONG ) );
KeAcquireGuardedMutex(&process_config.lock);
RtlZeroMemory(ProcessId, sizeof(LONG));
*ProcessId = process_config.km_handle;
KeReleaseGuardedMutex( &process_config.lock );
KeReleaseGuardedMutex(&process_config.lock);
}
VOID
VOID
ClearProcessConfigOnProcessTermination()
{
DEBUG_LOG( "Process closed, clearing driver process_configuration" );
KeAcquireGuardedMutex( &process_config.lock );
DEBUG_LOG("Process closed, clearing driver process_configuration");
KeAcquireGuardedMutex(&process_config.lock);
process_config.km_handle = NULL;
process_config.um_handle = NULL;
process_config.protected_process_eprocess = NULL;
process_config.initialised = FALSE;
KeReleaseGuardedMutex( &process_config.lock );
KeReleaseGuardedMutex(&process_config.lock);
}
VOID
VOID
GetDriverName(
_Out_ LPCSTR* DriverName
)
{
if ( DriverName == NULL )
if (DriverName == NULL)
return;
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
*DriverName = driver_config.ansi_driver_name.Buffer;
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetDriverPath(
_Out_ PUNICODE_STRING DriverPath
)
{
KeAcquireGuardedMutex( &driver_config.lock );
RtlZeroMemory( DriverPath, sizeof( UNICODE_STRING ) );
RtlInitUnicodeString( DriverPath, driver_config.driver_path.Buffer );
KeReleaseGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
RtlZeroMemory(DriverPath, sizeof(UNICODE_STRING));
RtlInitUnicodeString(DriverPath, driver_config.driver_path.Buffer);
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetDriverRegistryPath(
_Out_ PUNICODE_STRING RegistryPath
)
{
KeAcquireGuardedMutex( &driver_config.lock );
RtlZeroMemory( RegistryPath, sizeof( UNICODE_STRING ) );
RtlCopyUnicodeString( RegistryPath, &driver_config.registry_path );
KeReleaseGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
RtlZeroMemory(RegistryPath, sizeof(UNICODE_STRING));
RtlCopyUnicodeString(RegistryPath, &driver_config.registry_path);
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetDriverDeviceName(
_Out_ PUNICODE_STRING DeviceName
)
{
KeAcquireGuardedMutex( &driver_config.lock );
RtlZeroMemory( DeviceName, sizeof( UNICODE_STRING ) );
RtlCopyUnicodeString( DeviceName, &driver_config.device_name );
KeReleaseGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
RtlZeroMemory(DeviceName, sizeof(UNICODE_STRING));
RtlCopyUnicodeString(DeviceName, &driver_config.device_name);
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetDriverSymbolicLink(
_Out_ PUNICODE_STRING DeviceSymbolicLink
)
{
KeAcquireGuardedMutex( &driver_config.lock );
RtlZeroMemory( DeviceSymbolicLink, sizeof( UNICODE_STRING ) );
RtlCopyUnicodeString( DeviceSymbolicLink, &driver_config.device_symbolic_link );
KeReleaseGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
RtlZeroMemory(DeviceSymbolicLink, sizeof(UNICODE_STRING));
RtlCopyUnicodeString(DeviceSymbolicLink, &driver_config.device_symbolic_link);
KeReleaseGuardedMutex(&driver_config.lock);
}
VOID
VOID
GetDriverConfigSystemInformation(
_Out_ PSYSTEM_INFORMATION* SystemInformation
)
{
if ( SystemInformation == NULL )
if (SystemInformation == NULL)
return;
KeAcquireGuardedMutex( &driver_config.lock );
KeAcquireGuardedMutex(&driver_config.lock);
*SystemInformation = &driver_config.system_information;
KeReleaseGuardedMutex( &driver_config.lock );
KeReleaseGuardedMutex(&driver_config.lock);
}
STATIC
NTSTATUS
NTSTATUS
RegistryPathQueryCallbackRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
@ -435,18 +435,18 @@ RegistryPathQueryCallbackRoutine(
)
{
UNICODE_STRING value_name;
UNICODE_STRING image_path = RTL_CONSTANT_STRING( L"ImagePath" );
UNICODE_STRING display_name = RTL_CONSTANT_STRING( L"DisplayName" );
UNICODE_STRING image_path = RTL_CONSTANT_STRING(L"ImagePath");
UNICODE_STRING display_name = RTL_CONSTANT_STRING(L"DisplayName");
UNICODE_STRING value;
PVOID temp_buffer;
RtlInitUnicodeString( &value_name, ValueName );
RtlInitUnicodeString(&value_name, ValueName);
if ( RtlCompareUnicodeString(&value_name, &image_path, FALSE) == FALSE )
if (RtlCompareUnicodeString(&value_name, &image_path, FALSE) == FALSE)
{
temp_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, ValueLength, POOL_TAG_STRINGS );
temp_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, ValueLength, POOL_TAG_STRINGS);
if ( !temp_buffer )
if (!temp_buffer)
return STATUS_MEMORY_NOT_ALLOCATED;
RtlCopyMemory(
@ -460,11 +460,11 @@ RegistryPathQueryCallbackRoutine(
driver_config.driver_path.MaximumLength = ValueLength + 1;
}
if ( RtlCompareUnicodeString( &value_name, &display_name, FALSE ) == FALSE )
if (RtlCompareUnicodeString(&value_name, &display_name, FALSE) == FALSE)
{
temp_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, ValueLength, POOL_TAG_STRINGS );
temp_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, ValueLength, POOL_TAG_STRINGS);
if ( !temp_buffer )
if (!temp_buffer)
return STATUS_MEMORY_NOT_ALLOCATED;
RtlCopyMemory(
@ -473,7 +473,7 @@ RegistryPathQueryCallbackRoutine(
ValueLength
);
driver_config.unicode_driver_name.Buffer = ( PWCH )temp_buffer;
driver_config.unicode_driver_name.Buffer = (PWCH)temp_buffer;
driver_config.unicode_driver_name.Length = ValueLength;
driver_config.unicode_driver_name.MaximumLength = ValueLength + 1;
}
@ -482,21 +482,21 @@ RegistryPathQueryCallbackRoutine(
}
STATIC
VOID
VOID
FreeDriverConfigurationStringBuffers()
{
if ( driver_config.unicode_driver_name.Buffer )
ExFreePoolWithTag( driver_config.unicode_driver_name.Buffer, POOL_TAG_STRINGS );
if (driver_config.unicode_driver_name.Buffer)
ExFreePoolWithTag(driver_config.unicode_driver_name.Buffer, POOL_TAG_STRINGS);
if ( driver_config.driver_path.Buffer )
ExFreePoolWithTag( driver_config.driver_path.Buffer, POOL_TAG_STRINGS );
if (driver_config.driver_path.Buffer)
ExFreePoolWithTag(driver_config.driver_path.Buffer, POOL_TAG_STRINGS);
if (driver_config.ansi_driver_name.Buffer )
RtlFreeAnsiString( &driver_config.ansi_driver_name );
if (driver_config.ansi_driver_name.Buffer)
RtlFreeAnsiString(&driver_config.ansi_driver_name);
}
STATIC
NTSTATUS
NTSTATUS
InitialiseDriverConfigOnDriverEntry(
_In_ PUNICODE_STRING RegistryPath
)
@ -504,29 +504,29 @@ InitialiseDriverConfigOnDriverEntry(
NTSTATUS status;
/* 3rd page acts as a null terminator for the callback routine */
RTL_QUERY_REGISTRY_TABLE query_table[ 3 ] = { 0 };
RTL_QUERY_REGISTRY_TABLE query_table[3] = { 0 };
KeInitializeGuardedMutex( &driver_config.lock );
RtlInitUnicodeString( &driver_config.device_name, L"\\Device\\DonnaAC" );
RtlInitUnicodeString( &driver_config.device_symbolic_link, L"\\??\\DonnaAC" );
RtlCopyUnicodeString( &driver_config.registry_path, RegistryPath );
KeInitializeGuardedMutex(&driver_config.lock);
query_table[ 0 ].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
query_table[ 0 ].Name = L"ImagePath";
query_table[ 0 ].DefaultType = REG_MULTI_SZ;
query_table[ 0 ].DefaultLength = 0;
query_table[ 0 ].DefaultData = NULL;
query_table[ 0 ].EntryContext = NULL;
query_table[ 0 ].QueryRoutine = RegistryPathQueryCallbackRoutine;
RtlInitUnicodeString(&driver_config.device_name, L"\\Device\\DonnaAC");
RtlInitUnicodeString(&driver_config.device_symbolic_link, L"\\??\\DonnaAC");
RtlCopyUnicodeString(&driver_config.registry_path, RegistryPath);
query_table[ 1 ].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
query_table[ 1 ].Name = L"DisplayName";
query_table[ 1 ].DefaultType = REG_SZ;
query_table[ 1 ].DefaultLength = 0;
query_table[ 1 ].DefaultData = NULL;
query_table[ 1 ].EntryContext = NULL;
query_table[ 1 ].QueryRoutine = RegistryPathQueryCallbackRoutine;
query_table[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
query_table[0].Name = L"ImagePath";
query_table[0].DefaultType = REG_MULTI_SZ;
query_table[0].DefaultLength = 0;
query_table[0].DefaultData = NULL;
query_table[0].EntryContext = NULL;
query_table[0].QueryRoutine = RegistryPathQueryCallbackRoutine;
query_table[1].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
query_table[1].Name = L"DisplayName";
query_table[1].DefaultType = REG_SZ;
query_table[1].DefaultLength = 0;
query_table[1].DefaultData = NULL;
query_table[1].EntryContext = NULL;
query_table[1].QueryRoutine = RegistryPathQueryCallbackRoutine;
status = RtlxQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
@ -536,9 +536,9 @@ InitialiseDriverConfigOnDriverEntry(
NULL
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "RtlxQueryRegistryValues failed with status %x", status );
DEBUG_ERROR("RtlxQueryRegistryValues failed with status %x", status);
FreeDriverConfigurationStringBuffers();
return status;
}
@ -549,44 +549,44 @@ InitialiseDriverConfigOnDriverEntry(
TRUE
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "Failed to convert unicode string to ansi string" );
DEBUG_ERROR("Failed to convert unicode string to ansi string");
FreeDriverConfigurationStringBuffers();
return status;
}
status = ParseSMBIOSTable(
status = ParseSMBIOSTable(
&driver_config.system_information.motherboard_serial,
sizeof(driver_config.system_information.motherboard_serial)
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "ParseSMBIOSTable failed with status %x", status );
DEBUG_ERROR("ParseSMBIOSTable failed with status %x", status);
FreeDriverConfigurationStringBuffers();
return status;
}
status = GetHardDiskDriveSerialNumber(
&driver_config.system_information.drive_0_serial,
sizeof( driver_config.system_information.drive_0_serial )
sizeof(driver_config.system_information.drive_0_serial)
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "GetHardDiskDriverSerialNumber failed with status %x", status );
DEBUG_ERROR("GetHardDiskDriverSerialNumber failed with status %x", status);
FreeDriverConfigurationStringBuffers();
return status;
}
DEBUG_LOG( "Motherboard serial: %s", driver_config.system_information.motherboard_serial );
DEBUG_LOG( "Drive 0 serial: %s", driver_config.system_information.drive_0_serial );
DEBUG_LOG("Motherboard serial: %s", driver_config.system_information.motherboard_serial);
DEBUG_LOG("Drive 0 serial: %s", driver_config.system_information.drive_0_serial);
return status;
}
NTSTATUS
NTSTATUS
InitialiseProcessConfigOnProcessLaunch(
_In_ PIRP Irp
)
@ -595,43 +595,43 @@ InitialiseProcessConfigOnProcessLaunch(
PDRIVER_INITIATION_INFORMATION information;
PEPROCESS eprocess;
information = ( PDRIVER_INITIATION_INFORMATION )Irp->AssociatedIrp.SystemBuffer;
information = (PDRIVER_INITIATION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
status = PsLookupProcessByProcessId( information->protected_process_id, &eprocess );
status = PsLookupProcessByProcessId(information->protected_process_id, &eprocess);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
return status;
KeAcquireGuardedMutex( &process_config.lock );
KeAcquireGuardedMutex(&process_config.lock);
process_config.protected_process_eprocess = eprocess;
process_config.um_handle = information->protected_process_id;
process_config.km_handle = PsGetProcessId( eprocess );
process_config.km_handle = PsGetProcessId(eprocess);
process_config.initialised = TRUE;
KeReleaseGuardedMutex( &process_config.lock );
KeReleaseGuardedMutex(&process_config.lock);
return status;
}
STATIC
VOID
VOID
InitialiseProcessConfigOnDriverEntry()
{
KeInitializeGuardedMutex( &process_config.lock );
KeInitializeGuardedMutex(&process_config.lock);
}
STATIC
VOID
VOID
CleanupDriverConfigOnUnload()
{
FreeDriverConfigurationStringBuffers();
FreeGlobalReportQueueObjects();
IoDeleteSymbolicLink( &driver_config.device_symbolic_link );
IoDeleteSymbolicLink(&driver_config.device_symbolic_link);
}
STATIC
VOID
VOID
DriverUnload(
_In_ PDRIVER_OBJECT DriverObject
)
@ -650,39 +650,39 @@ DriverUnload(
//IoDeleteDevice( DriverObject->DeviceObject );
}
VOID
VOID
TerminateProtectedProcessOnViolation()
{
NTSTATUS status;
ULONG process_id;
GetProtectedProcessId( &process_id );
GetProtectedProcessId(&process_id);
if ( !process_id )
if (!process_id)
{
DEBUG_ERROR( "Failed to terminate process as process id is null" );
DEBUG_ERROR("Failed to terminate process as process id is null");
return;
}
/*
* Make sure we pass a km handle to ZwTerminateProcess and NOT a usermode handle.
*/
status = ZwTerminateProcess( process_id, STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION );
status = ZwTerminateProcess(process_id, STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
/*
* We don't want to clear the process config if ZwTerminateProcess fails
* We don't want to clear the process config if ZwTerminateProcess fails
* so we can try again.
*/
DEBUG_ERROR( "ZwTerminateProcess failed with status %x", status );
DEBUG_ERROR("ZwTerminateProcess failed with status %x", status);
return;
}
ClearProcessConfigOnProcessTermination();
}
NTSTATUS
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
@ -691,11 +691,11 @@ DriverEntry(
BOOLEAN flag = FALSE;
NTSTATUS status;
status = InitialiseDriverConfigOnDriverEntry( RegistryPath );
status = InitialiseDriverConfigOnDriverEntry(RegistryPath);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "InitialiseDriverConfigOnDriverEntry failed with status %x", status );
DEBUG_ERROR("InitialiseDriverConfigOnDriverEntry failed with status %x", status);
return status;
}
@ -711,9 +711,9 @@ DriverEntry(
&DriverObject->DeviceObject
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "IoCreateDevice failed with status %x", status );
DEBUG_ERROR("IoCreateDevice failed with status %x", status);
FreeDriverConfigurationStringBuffers();
return STATUS_FAILED_DRIVER_ENTRY;
}
@ -723,35 +723,35 @@ DriverEntry(
&driver_config.device_name
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "failed to create symbolic link" );
DEBUG_ERROR("failed to create symbolic link");
FreeDriverConfigurationStringBuffers();
IoDeleteDevice( DriverObject->DeviceObject );
IoDeleteDevice(DriverObject->DeviceObject);
return STATUS_FAILED_DRIVER_ENTRY;
}
DriverObject->MajorFunction[ IRP_MJ_CREATE ] = DeviceCreate;
DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = DeviceClose;
DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DeviceControl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->DriverUnload = DriverUnload;
InitialiseGlobalReportQueue(&flag);
if ( !flag )
if (!flag)
{
DEBUG_ERROR( "failed to init report queue" );
DEBUG_ERROR("failed to init report queue");
FreeDriverConfigurationStringBuffers();
IoDeleteSymbolicLink( &driver_config.device_symbolic_link );
IoDeleteDevice( DriverObject->DeviceObject );
IoDeleteSymbolicLink(&driver_config.device_symbolic_link);
IoDeleteDevice(DriverObject->DeviceObject);
return STATUS_FAILED_DRIVER_ENTRY;
}
UNICODE_STRING string = RTL_CONSTANT_STRING( L"ExAllocatePoolWithTag" );
UNICODE_STRING string = RTL_CONSTANT_STRING(L"ExAllocatePoolWithTag");
DetectEptHooksInKeyFunctions();
DEBUG_LOG( "DonnaAC Driver Entry Complete" );
DEBUG_LOG("DonnaAC Driver Entry Complete");
return STATUS_SUCCESS;
}

View file

@ -21,8 +21,8 @@
typedef struct _SYSTEM_INFORMATION
{
CHAR motherboard_serial[ MOTHERBOARD_SERIAL_CODE_LENGTH ];
CHAR drive_0_serial[ DEVICE_DRIVE_0_SERIAL_CODE_LENGTH ];
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
}SYSTEM_INFORMATION, * PSYSTEM_INFORMATION;
@ -80,10 +80,10 @@ FreeApcAndDecrementApcCount(
NTSTATUS
QueryActiveApcContextsForCompletion();
VOID
VOID
TerminateProtectedProcessOnViolation();
VOID
VOID
ClearProcessConfigOnProcessTermination();
#endif

View file

@ -7,39 +7,39 @@
#define TOTAL_ITERATION_COUNT 20
/*
* TODO: Perform the test in a loop and average the delta out, then compare it
* TODO: Perform the test in a loop and average the delta out, then compare it
* to an instruction such as FYL2XP1 (source: secret.club) which has an average
* execution time slightly higher then the CPUID instruction then compare the two.
* If the average time for the CPUID instruction is higher then the average time
* for the FYL2XP1 instruction it is a dead giveaway we are running on a
* If the average time for the CPUID instruction is higher then the average time
* for the FYL2XP1 instruction it is a dead giveaway we are running on a
* virtualized system.
*
*
* reference: https://secret.club/2020/01/12/battleye-hypervisor-detection.html
*/
STATIC
INT
INT
APERFMsrTimingCheck()
{
KAFFINITY new_affinity = { 0 };
KAFFINITY old_affinity = { 0 };
ULONG64 old_irql;
INT cpuid_result[ 4 ];
INT cpuid_result[4];
/*
* First thing we do is we lock the current thread to the logical processor
* its executing on.
* its executing on.
*/
new_affinity = ( KAFFINITY )( 1 << KeGetCurrentProcessorNumber() );
old_affinity = KeSetSystemAffinityThreadEx( new_affinity );
new_affinity = (KAFFINITY)(1 << KeGetCurrentProcessorNumber());
old_affinity = KeSetSystemAffinityThreadEx(new_affinity);
/*
* Once we've locked our thread to the current core, we save the old irql
* and raise to HIGH_LEVEL to ensure the chance our thread is preempted
* and raise to HIGH_LEVEL to ensure the chance our thread is preempted
* by a thread with a higher IRQL is extremely low.
*/
old_irql = __readcr8();
__writecr8( HIGH_LEVEL );
__writecr8(HIGH_LEVEL);
/*
* Then we also disable interrupts, once again making sure our thread
@ -48,37 +48,37 @@ APERFMsrTimingCheck()
_disable();
/*
* Once our thread is ready for the test, we read the APERF from the
* Once our thread is ready for the test, we read the APERF from the
* MSR register and store it. We then execute a CPUID instruction
* which we don't really care about and immediately after read the APERF
* counter once again and store it in a seperate variable.
*/
UINT64 aperf_before = __readmsr( IA32_APERF_MSR ) << 32;
__cpuid( cpuid_result, 1 );
UINT64 aperf_after = __readmsr( IA32_APERF_MSR ) << 32;
UINT64 aperf_before = __readmsr(IA32_APERF_MSR) << 32;
__cpuid(cpuid_result, 1);
UINT64 aperf_after = __readmsr(IA32_APERF_MSR) << 32;
/*
* Once we have performed our test, we want to make sure we are not
* Once we have performed our test, we want to make sure we are not
* hogging the cpu time from other threads, so we reverse the initial
* preparation process. i.e we first enable interrupts, lower our irql
* to the threads previous irql before it was raised and then restore the
* threads affinity back to its original affinity.
*/
_enable();
__writecr8( old_irql );
KeRevertToUserAffinityThreadEx( old_affinity );
__writecr8(old_irql);
KeRevertToUserAffinityThreadEx(old_affinity);
/*
* Now the only thing left to do is calculate the change. Now, on some VMs
* Now the only thing left to do is calculate the change. Now, on some VMs
* such as VMWARE the aperf value will be 0, meaning the change will be 0.
* This is a dead giveaway we are executing in a VM.
* This is a dead giveaway we are executing in a VM.
*/
UINT64 aperf_delta = aperf_after - aperf_before;
return aperf_delta == 0 ? TRUE : FALSE;
}
NTSTATUS
NTSTATUS
PerformVirtualizationDetection(
_In_ PIRP Irp
)
@ -87,12 +87,12 @@ PerformVirtualizationDetection(
report.aperf_msr_timing_check = APERFMsrTimingCheck();
report.invd_emulation_check = TestINVDEmulation();
Irp->IoStatus.Information = sizeof( HYPERVISOR_DETECTION_REPORT );
Irp->IoStatus.Information = sizeof(HYPERVISOR_DETECTION_REPORT);
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&report,
sizeof( HYPERVISOR_DETECTION_REPORT )
sizeof(HYPERVISOR_DETECTION_REPORT)
);
return STATUS_SUCCESS;

View file

@ -9,15 +9,15 @@ typedef struct _HYPERVISOR_DETECTION_REPORT
INT aperf_msr_timing_check;
INT invd_emulation_check;
}HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
}HYPERVISOR_DETECTION_REPORT, * PHYPERVISOR_DETECTION_REPORT;
NTSTATUS
NTSTATUS
PerformVirtualizationDetection(
_In_ PIRP Irp
);
extern
INT
extern
INT
TestINVDEmulation();
#endif

File diff suppressed because it is too large Load diff

View file

@ -4,27 +4,27 @@
#include <ntifs.h>
#include "common.h"
NTSTATUS
NTSTATUS
GetDriverImageSize(
_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
VerifyInMemoryImageVsDiskImage(
//_In_ PIRP Irp
//_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
RetrieveInMemoryModuleExecutableSections(
_In_ PIRP Irp
_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
ValidateProcessLoadedModule(
_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
GetHardDiskDriveSerialNumber(
_In_ PVOID ConfigDrive0Serial,
_In_ SIZE_T ConfigDrive0MaxSize

View file

@ -29,68 +29,68 @@
#define APC_OPERATION_STACKWALK 0x1
STATIC
NTSTATUS
DispatchApcOperation( PAPC_OPERATION_ID Operation )
NTSTATUS
DispatchApcOperation(PAPC_OPERATION_ID Operation)
{
NTSTATUS status;
switch ( Operation->operation_id )
switch (Operation->operation_id)
{
case APC_OPERATION_STACKWALK:
DEBUG_LOG( "Initiating APC stackwalk operation with operation id %i", Operation->operation_id );
DEBUG_LOG("Initiating APC stackwalk operation with operation id %i", Operation->operation_id);
status = ValidateThreadsViaKernelApc();
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "ValidateThreadsViaKernelApc failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateThreadsViaKernelApc failed with status %x", status);
return status;
default:
DEBUG_ERROR( "Invalid operation ID passed" );
DEBUG_ERROR("Invalid operation ID passed");
return STATUS_INVALID_PARAMETER;
}
return status;
}
NTSTATUS
NTSTATUS
DeviceControl(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PIRP Irp
)
{
UNREFERENCED_PARAMETER( DriverObject );
UNREFERENCED_PARAMETER(DriverObject);
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation( Irp );
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
HANDLE handle;
PKTHREAD thread;
BOOLEAN security_flag = FALSE;
/*
* The purpose of this is to prevent programs from opening a handle to our driver
* and trying to fuzz the IOCTL access or codes. This definitely isnt a perfect
* and trying to fuzz the IOCTL access or codes. This definitely isnt a perfect
* solution though... xD
*/
ReadProcessInitialisedConfigFlag( &security_flag );
ReadProcessInitialisedConfigFlag(&security_flag);
if ( security_flag == FALSE &&
stack_location->Parameters.DeviceIoControl.IoControlCode != IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH )
if (security_flag == FALSE &&
stack_location->Parameters.DeviceIoControl.IoControlCode != IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH)
{
status = STATUS_ABANDONED;
goto end;
}
switch ( stack_location->Parameters.DeviceIoControl.IoControlCode )
switch (stack_location->Parameters.DeviceIoControl.IoControlCode)
{
case IOCCTL_RUN_NMI_CALLBACKS:
status = HandleNmiIOCTL( Irp );
status = HandleNmiIOCTL(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "RunNmiCallbacks failed with status %lx", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("RunNmiCallbacks failed with status %lx", status);
break;
@ -114,9 +114,9 @@ DeviceControl(
Irp
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "Failed to start thread to validate system drivers" );
DEBUG_ERROR("Failed to start thread to validate system drivers");
goto end;
}
@ -135,20 +135,20 @@ DeviceControl(
NULL
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "ObReferenceObjectbyhandle failed with status %lx", status );
ZwClose( handle );
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
ZwClose(handle);
goto end;
}
/* KeWaitForSingleObject with infinite time must be called from IRQL <= APC_LEVEL */
PAGED_CODE();
KeWaitForSingleObject( thread, Executive, KernelMode, FALSE, NULL );
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
ZwClose( handle );
ObDereferenceObject( thread );
ZwClose(handle);
ObDereferenceObject(thread);
break;
@ -156,44 +156,44 @@ DeviceControl(
status = InitialiseProcessConfigOnProcessLaunch(Irp);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "Failed to initialise driver config on proc launch with status %x", status );
DEBUG_ERROR("Failed to initialise driver config on proc launch with status %x", status);
goto end;
}
status = InitiateDriverCallbacks();
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "InitiateDriverCallbacks failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("InitiateDriverCallbacks failed with status %x", status);
break;
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
status = QueryActiveApcContextsForCompletion();
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "QueryActiveApcContextsForCompletion filed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("QueryActiveApcContextsForCompletion filed with status %x", status);
status = HandlePeriodicGlobalReportQueueQuery(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "Failed to handle period callback report queue" );
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to handle period callback report queue");
break;
case IOCTL_PERFORM_VIRTUALIZATION_CHECK:
status = PerformVirtualizationDetection( Irp );
status = PerformVirtualizationDetection(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "PerformVirtualizationDetection failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("PerformVirtualizationDetection failed with status %x", status);
break;
case IOCTL_ENUMERATE_HANDLE_TABLES:
/* can maybe implement this better so we can extract a status value */
EnumerateProcessListWithCallbackFunction(
EnumerateProcessHandles,
@ -214,9 +214,9 @@ DeviceControl(
Irp
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "Failed to start system thread to get executable regions" );
DEBUG_ERROR("Failed to start system thread to get executable regions");
goto end;
}
@ -229,31 +229,31 @@ DeviceControl(
NULL
);
if ( !NT_SUCCESS( status ) )
if (!NT_SUCCESS(status))
{
DEBUG_ERROR( "ObReferenceObjectbyhandle failed with status %lx", status );
ZwClose( handle );
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
ZwClose(handle);
goto end;
}
PAGED_CODE();
KeWaitForSingleObject( thread, Executive, KernelMode, FALSE, NULL );;
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);;
ZwClose( handle );
ObDereferenceObject( thread );
ZwClose(handle);
ObDereferenceObject(thread);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "Failed to retrieve executable regions" );
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to retrieve executable regions");
break;
case IOCTL_REQUEST_TOTAL_MODULE_SIZE:
status = GetDriverImageSize( Irp );
status = GetDriverImageSize(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "Failed to retrieve driver image size" );
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to retrieve driver image size");
break;
@ -266,16 +266,16 @@ DeviceControl(
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
status = FindUnlinkedProcesses( Irp );
status = FindUnlinkedProcesses(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "FindUNlinekdProcesses failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUNlinekdProcesses failed with status %x", status);
break;
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD:
ValidateKPCRBThreads( Irp );
ValidateKPCRBThreads(Irp);
break;
@ -283,8 +283,8 @@ DeviceControl(
status = VerifyInMemoryImageVsDiskImage();
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "VerifyInMemoryImageVsDisk failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("VerifyInMemoryImageVsDisk failed with status %x", status);
break;
@ -296,30 +296,30 @@ DeviceControl(
case IOCTL_VALIDATE_PROCESS_LOADED_MODULE:
status = ValidateProcessLoadedModule( Irp );
status = ValidateProcessLoadedModule(Irp);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "ValidateProcessLoadedModule failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateProcessLoadedModule failed with status %x", status);
break;
case IOCTL_REQUEST_HARDWARE_INFORMATION:;
PSYSTEM_INFORMATION system_information = NULL;
GetDriverConfigSystemInformation( &system_information );
GetDriverConfigSystemInformation(&system_information);
if ( system_information == NULL )
if (system_information == NULL)
{
DEBUG_ERROR( "GetDriverConfigSystemInformation failed" );
DEBUG_ERROR("GetDriverConfigSystemInformation failed");
goto end;
}
Irp->IoStatus.Information = sizeof( SYSTEM_INFORMATION );
Irp->IoStatus.Information = sizeof(SYSTEM_INFORMATION);
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
system_information,
sizeof( SYSTEM_INFORMATION )
sizeof(SYSTEM_INFORMATION)
);
break;
@ -328,33 +328,33 @@ DeviceControl(
PAPC_OPERATION_ID operation = (PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
status = DispatchApcOperation( operation );
status = DispatchApcOperation(operation);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "DispatchApcOperation failed with status %x", status );
if (!NT_SUCCESS(status))
DEBUG_ERROR("DispatchApcOperation failed with status %x", status);
break;
default:
DEBUG_ERROR( "Invalid IOCTL passed to driver" );
DEBUG_ERROR("Invalid IOCTL passed to driver");
status = STATUS_INVALID_PARAMETER;
break;
}
end:
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
NTSTATUS
DeviceClose(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp
)
{
DEBUG_LOG( "Handle closed to DonnaAC" );
DEBUG_LOG("Handle closed to DonnaAC");
/*
* For now its fine, but this will need to be moved to our process load callbacks
@ -366,17 +366,17 @@ DeviceClose(
ClearProcessConfigOnProcessTermination();
UnregisterCallbacksOnProcessTermination();
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
NTSTATUS
NTSTATUS
DeviceCreate(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp
)
{
DEBUG_LOG( "Handle opened to DonnaAC" );
IoCompleteRequest( Irp, IO_NO_INCREMENT );
DEBUG_LOG("Handle opened to DonnaAC");
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}

View file

@ -12,19 +12,19 @@ typedef struct _DRIVER_INITIATION_INFORMATION
} DRIVER_INITIATION_INFORMATION, * PDRIVER_INITIATION_INFORMATION;
NTSTATUS
NTSTATUS
DeviceControl(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
DeviceClose(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp
);
NTSTATUS
NTSTATUS
DeviceCreate(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp

File diff suppressed because it is too large Load diff

View file

@ -22,9 +22,9 @@ typedef struct _MODULE_VALIDATION_FAILURE
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[ 128 ];
CHAR driver_name[128];
}MODULE_VALIDATION_FAILURE, *PMODULE_VALIDATION_FAILURE;
}MODULE_VALIDATION_FAILURE, * PMODULE_VALIDATION_FAILURE;
#define APC_STACKWALK_BUFFER_SIZE 4096
@ -33,15 +33,15 @@ typedef struct _APC_STACKWALK_REPORT
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[ APC_STACKWALK_BUFFER_SIZE ];
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
}APC_STACKWALK_REPORT, *PAPC_STACKWALK_REPORT;
}APC_STACKWALK_REPORT, * PAPC_STACKWALK_REPORT;
typedef struct _APC_OPERATION_ID
{
int operation_id;
}APC_OPERATION_ID, *PAPC_OPERATION_ID;
}APC_OPERATION_ID, * PAPC_OPERATION_ID;
/* system modules information */
@ -69,23 +69,23 @@ typedef struct _APC_STACKWALK_CONTEXT
}APC_STACKWALK_CONTEXT, * PAPC_STACKWALK_CONTEXT;
NTSTATUS
NTSTATUS
GetSystemModuleInformation(
_Inout_ PSYSTEM_MODULES ModuleInformation
);
NTSTATUS
NTSTATUS
HandleValidateDriversIOCTL(
_In_ PIRP Irp
);
PRTL_MODULE_EXTENDED_INFO
PRTL_MODULE_EXTENDED_INFO
FindSystemModuleByName(
_In_ LPCSTR ModuleName,
_In_ PSYSTEM_MODULES SystemModules
);
NTSTATUS
NTSTATUS
HandleNmiIOCTL(
_In_ PIRP Irp
);
@ -95,7 +95,7 @@ FreeApcContextStructure(
_Inout_ PAPC_CONTEXT_HEADER Context
);
NTSTATUS
NTSTATUS
ValidateThreadsViaKernelApc();
VOID

View file

@ -32,7 +32,7 @@
#define INDEX_DRIVERS_POOL_TAG 6
#define INDEX_SYMBOLIC_LINKS_POOL_TAG 7
CHAR EXECUTIVE_OBJECT_POOL_TAGS[ EXECUTIVE_OBJECT_COUNT ][ POOL_TAG_LENGTH ] =
CHAR EXECUTIVE_OBJECT_POOL_TAGS[EXECUTIVE_OBJECT_COUNT][POOL_TAG_LENGTH] =
{
"\x50\x72\x6f\x63", /* Process */
"\x54\x68\x72\x64", /* Thread */
@ -47,7 +47,7 @@ CHAR EXECUTIVE_OBJECT_POOL_TAGS[ EXECUTIVE_OBJECT_COUNT ][ POOL_TAG_LENGTH ] =
PVOID process_buffer = NULL;
ULONG process_count = NULL;
PKDDEBUGGER_DATA64
PKDDEBUGGER_DATA64
GetGlobalDebuggerData()
{
CONTEXT context = { 0 };
@ -57,11 +57,11 @@ GetGlobalDebuggerData()
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext( &context );
RtlCaptureContext(&context);
dump_header = ExAllocatePool2( POOL_FLAG_NON_PAGED, DUMP_BLOCK_SIZE, POOL_DUMP_BLOCK_TAG );
dump_header = ExAllocatePool2(POOL_FLAG_NON_PAGED, DUMP_BLOCK_SIZE, POOL_DUMP_BLOCK_TAG);
if ( !dump_header )
if (!dump_header)
goto end;
KeCapturePersistentThreadState(
@ -75,70 +75,70 @@ GetGlobalDebuggerData()
dump_header
);
debugger_data = ( PKDDEBUGGER_DATA64 )ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( KDDEBUGGER_DATA64 ), POOL_DEBUGGER_DATA_TAG );
debugger_data = (PKDDEBUGGER_DATA64)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(KDDEBUGGER_DATA64), POOL_DEBUGGER_DATA_TAG);
if ( !debugger_data )
if (!debugger_data)
goto end;
RtlCopyMemory( debugger_data, dump_header->KdDebuggerDataBlock, sizeof( KDDEBUGGER_DATA64 ) );
RtlCopyMemory(debugger_data, dump_header->KdDebuggerDataBlock, sizeof(KDDEBUGGER_DATA64));
end:
if ( dump_header )
ExFreePoolWithTag( dump_header, POOL_DUMP_BLOCK_TAG );
if (dump_header)
ExFreePoolWithTag(dump_header, POOL_DUMP_BLOCK_TAG);
return debugger_data;
}
VOID
VOID
GetPsActiveProcessHead(
_In_ PUINT64 Address
)
{
PKDDEBUGGER_DATA64 debugger_data = GetGlobalDebuggerData();
*Address = *( UINT64* )( debugger_data->PsActiveProcessHead );
*Address = *(UINT64*)(debugger_data->PsActiveProcessHead);
ExFreePoolWithTag( debugger_data, POOL_DEBUGGER_DATA_TAG );
ExFreePoolWithTag(debugger_data, POOL_DEBUGGER_DATA_TAG);
}
/*
* Here we define a signature that can be used to find EPROCESS structures consistently across
* major windows versions. The fields we test have proven to be consistent in the following study:
*
*
* https://www.cise.ufl.edu/~traynor/papers/ccs09b.pdf
*
*
* Aswell as some of my own additional research and testing. The following signature is used:
*
*
* PeakVirtualSize must be greater then 0 for any valid process:
* -> EPROCESS->PeakVirtualSize > 0
*
*
* The DirectoryTableBase must be 0x20 aligned:
* -> EPROCESS->DirectoryTableBase % 20 == 0
*
* The pool allocation size must be greater then the size of an EPROCESS allocation and
*
* The pool allocation size must be greater then the size of an EPROCESS allocation and
* less then the size of a page. Allocation size can be found with the following formula:
* -> AllocationSize = POOL_HEADER->BlockSize * CHUNK_SIZE - sizeof(POOL_HEADER)
* -> AllocationSize > sizeof(EPROCESS)
* -> AllocationSize > sizeof(EPROCESS)
* -> AllocationSize < PAGE_SIZE (4096)
*
*
* Pool type must be non-null:
* -> POOL_HEADER->PoolType != NULL
*
*
* The process PEB must be a usermode address and 0x1000 aligned:
* -> EPROCESS->Peb & 0x7ffd0000 == 0x7ffd0000 && EPROCESS->Peb % 0x1000 == 0
*
*
* The object table must have the following properties and be 0x8 aligned:
* -> EPROCESS->ObjectTable & 0xe0000000 == 0xe0000000 && EPROCESS->ObjectTable % 0x8 == 0
*
*
* The allocation size, when AND'd with 0xfff0 must not equal 0xfff0:
* -> AllocationSize & 0xfff0 != 0xfff0
*
*
* This signature will allow us to consistently and accurately determine if a given pool allocation is
* indeed an executive process allocation across major versions of Windows.
*/
STATIC
BOOLEAN
BOOLEAN
ValidateIfAddressIsProcessStructure(
_In_ PVOID Address,
_In_ PPOOL_HEADER PoolHeader
@ -153,28 +153,28 @@ ValidateIfAddressIsProcessStructure(
BOOLEAN object_table_test = FALSE;
UINT64 allocation_size_test = NULL;
if ( MmIsAddressValid( ( UINT64 )Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET ) )
dir_table_base = *( UINT64* )( ( UINT64 )Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET );
if (MmIsAddressValid((UINT64)Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET))
dir_table_base = *(UINT64*)((UINT64)Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET);
if ( MmIsAddressValid( ( UINT64 )Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET ) )
peak_virtual_size = *( UINT64* )( ( UINT64 )Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET );
if (MmIsAddressValid((UINT64)Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET))
peak_virtual_size = *(UINT64*)((UINT64)Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET);
if ( MmIsAddressValid( ( UINT64 )PoolHeader + POOL_HEADER_BLOCK_SIZE_OFFSET ) )
allocation_size = PoolHeader->BlockSize * CHUNK_SIZE - sizeof( POOL_HEADER );
if (MmIsAddressValid((UINT64)PoolHeader + POOL_HEADER_BLOCK_SIZE_OFFSET))
allocation_size = PoolHeader->BlockSize * CHUNK_SIZE - sizeof(POOL_HEADER);
if ( MmIsAddressValid( ( UINT64 )Address + EPROCESS_PEB_OFFSET ) )
peb = *( UINT64* )( ( UINT64 )Address + EPROCESS_PEB_OFFSET );
if (MmIsAddressValid((UINT64)Address + EPROCESS_PEB_OFFSET))
peb = *(UINT64*)((UINT64)Address + EPROCESS_PEB_OFFSET);
if ( MmIsAddressValid((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET ) )
object_table = *( UINT64* )( ( UINT64 )Address + EPROCESS_OBJECT_TABLE_OFFSET );
if (MmIsAddressValid((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET))
object_table = *(UINT64*)((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET);
peb_test = peb == NULL || ( peb & 0x7ffd0000 == 0x7ffd0000 && peb % 0x1000 == NULL );
object_table_test = object_table == NULL || ( object_table & 0xe0000000 == 0xe0000000 && object_table % 0x8 == 0 );
peb_test = peb == NULL || (peb & 0x7ffd0000 == 0x7ffd0000 && peb % 0x1000 == NULL);
object_table_test = object_table == NULL || (object_table & 0xe0000000 == 0xe0000000 && object_table % 0x8 == 0);
allocation_size_test = allocation_size & 0xfff0;
if ( peak_virtual_size > 0 && ( dir_table_base & 0x20 ) == 0 &&
allocation_size > ( EPROCESS_SIZE + OBJECT_HEADER_SIZE + sizeof( POOL_HEADER ) ) &&
PoolHeader->PoolType != NULL && !( allocation_size_test == 0xfff0 ) && !peb_test && !object_table_test )
if (peak_virtual_size > 0 && (dir_table_base & 0x20) == 0 &&
allocation_size > (EPROCESS_SIZE + OBJECT_HEADER_SIZE + sizeof(POOL_HEADER)) &&
PoolHeader->PoolType != NULL && !(allocation_size_test == 0xfff0) && !peb_test && !object_table_test)
{
return TRUE;
}
@ -206,7 +206,7 @@ ValidateIfAddressIsProcessStructure(
* Also use the full name so we get the file extension and path not the 15 char long one
*/
STATIC
VOID
VOID
ScanPageForKernelObjectAllocation(
_In_ UINT64 PageBase,
_In_ ULONG PageSize,
@ -225,58 +225,58 @@ ScanPageForKernelObjectAllocation(
LPCSTR process_name;
PUINT64 address_list;
ULONG allocation_size;
ULONG minimum_process_allocation_size = EPROCESS_SIZE - sizeof( POOL_HEADER ) - OBJECT_HEADER_SIZE;
ULONG minimum_process_allocation_size = EPROCESS_SIZE - sizeof(POOL_HEADER) - OBJECT_HEADER_SIZE;
if ( !PageBase || !PageSize )
if (!PageBase || !PageSize)
return;
for ( INT offset = 0; offset <= PageSize - POOL_TAG_LENGTH - minimum_process_allocation_size; offset++ )
for (INT offset = 0; offset <= PageSize - POOL_TAG_LENGTH - minimum_process_allocation_size; offset++)
{
for ( INT sig_index = 0; sig_index < POOL_TAG_LENGTH + 1; sig_index++ )
for (INT sig_index = 0; sig_index < POOL_TAG_LENGTH + 1; sig_index++)
{
if ( !MmIsAddressValid( PageBase + offset + sig_index ) )
if (!MmIsAddressValid(PageBase + offset + sig_index))
break;
current_char = *( PCHAR )( PageBase + offset + sig_index );
current_sig_byte = EXECUTIVE_OBJECT_POOL_TAGS[ ObjectIndex ][ sig_index ];
current_char = *(PCHAR)(PageBase + offset + sig_index);
current_sig_byte = EXECUTIVE_OBJECT_POOL_TAGS[ObjectIndex][sig_index];
if ( sig_index == POOL_TAG_LENGTH )
if (sig_index == POOL_TAG_LENGTH)
{
pool_header = ( UINT64 )PageBase + offset - POOL_HEADER_TAG_OFFSET;
pool_header = (UINT64)PageBase + offset - POOL_HEADER_TAG_OFFSET;
if ( !MmIsAddressValid( ( PVOID )pool_header ) )
if (!MmIsAddressValid((PVOID)pool_header))
break;
/*
/*
* 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 )
for (ULONG header_size = OBJECT_HEADER_SIZE; header_size < 0xb0; header_size += 0x10)
{
test_process = ( PEPROCESS )( ( UINT64 )pool_header + sizeof( POOL_HEADER ) + header_size );
test_process = (PEPROCESS)((UINT64)pool_header + sizeof(POOL_HEADER) + header_size);
if ( ValidateIfAddressIsProcessStructure( test_process, pool_header ) )
if (ValidateIfAddressIsProcessStructure(test_process, pool_header))
{
process = test_process;
break;
}
}
if ( process == NULL )
if (process == NULL)
break;
DEBUG_LOG( "Process: %llx", (UINT64)process );
DEBUG_LOG("Process: %llx", (UINT64)process);
address_list = ( PUINT64 )AddressBuffer;
address_list = (PUINT64)AddressBuffer;
for ( INT i = 0; i < process_count; i++ )
for (INT i = 0; i < process_count; i++)
{
if ( address_list[ i ] == NULL )
if (address_list[i] == NULL)
{
address_list[ i ] = ( UINT64 )process;
address_list[i] = (UINT64)process;
break;
}
}
@ -284,7 +284,7 @@ ScanPageForKernelObjectAllocation(
break;
}
if ( current_char != current_sig_byte )
if (current_char != current_sig_byte)
break;
}
}
@ -297,7 +297,7 @@ ScanPageForKernelObjectAllocation(
* physical memory, so this function is to check for exactly that.
*/
STATIC
BOOLEAN
BOOLEAN
IsPhysicalAddressInPhysicalMemoryRange(
_In_ UINT64 PhysicalAddress,
_In_ PPHYSICAL_MEMORY_RANGE PhysicalMemoryRanges
@ -307,12 +307,12 @@ IsPhysicalAddressInPhysicalMemoryRange(
UINT64 start_address = 0;
UINT64 end_address = 0;
while ( PhysicalMemoryRanges[ page_index ].NumberOfBytes.QuadPart != NULL )
while (PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart != NULL)
{
start_address = PhysicalMemoryRanges[ page_index ].BaseAddress.QuadPart;
end_address = start_address + PhysicalMemoryRanges[ page_index ].NumberOfBytes.QuadPart;
start_address = PhysicalMemoryRanges[page_index].BaseAddress.QuadPart;
end_address = start_address + PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart;
if ( PhysicalAddress >= start_address && PhysicalAddress <= end_address )
if (PhysicalAddress >= start_address && PhysicalAddress <= end_address)
return TRUE;
page_index++;
@ -322,7 +322,7 @@ IsPhysicalAddressInPhysicalMemoryRange(
}
STATIC
VOID
VOID
EnumerateKernelLargePages(
_In_ UINT64 PageBase,
_In_ ULONG PageSize,
@ -333,10 +333,10 @@ EnumerateKernelLargePages(
/*
* Split the large pages up into blocks of 0x1000 and scan each block
*/
for ( INT page_index = 0; page_index < PageSize; page_index++ )
for (UINT64 page_index = 0; page_index < PageSize; page_index++)
{
ScanPageForKernelObjectAllocation(
PageBase + ( page_index * PAGE_SIZE ),
PageBase + (page_index * PAGE_SIZE),
PAGE_SIZE,
ObjectIndex,
AddressBuffer
@ -368,8 +368,8 @@ EnumerateKernelLargePages(
* and extract the physical address from the value at each virtual address page entry.
*/
STATIC
VOID
WalkKernelPageTables( PVOID AddressBuffer )
VOID
WalkKernelPageTables(PVOID AddressBuffer)
{
CR3 cr3;
PML4E pml4_base;
@ -390,11 +390,11 @@ WalkKernelPageTables( PVOID AddressBuffer )
PPHYSICAL_MEMORY_RANGE physical_memory_ranges;
KIRQL irql;
physical_memory_ranges = MmGetPhysicalMemoryRangesEx2( NULL, NULL );
physical_memory_ranges = MmGetPhysicalMemoryRangesEx2(NULL, NULL);
if ( physical_memory_ranges == NULL )
if (physical_memory_ranges == NULL)
{
DEBUG_ERROR( "LOL stupid cunt not working" );
DEBUG_ERROR("LOL stupid cunt not working");
return;
}
@ -402,51 +402,51 @@ WalkKernelPageTables( PVOID AddressBuffer )
physical.QuadPart = cr3.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
pml4_base.BitAddress = MmGetVirtualForPhysical( physical );
pml4_base.BitAddress = MmGetVirtualForPhysical(physical);
if ( !MmIsAddressValid( pml4_base.BitAddress ) || !pml4_base.BitAddress )
if (!MmIsAddressValid(pml4_base.BitAddress) || !pml4_base.BitAddress)
return;
for ( INT pml4_index = 0; pml4_index < PML4_ENTRY_COUNT; pml4_index++ )
for (INT pml4_index = 0; pml4_index < PML4_ENTRY_COUNT; pml4_index++)
{
if ( !MmIsAddressValid( pml4_base.BitAddress + pml4_index * sizeof( UINT64 ) ) )
if (!MmIsAddressValid(pml4_base.BitAddress + pml4_index * sizeof(UINT64)))
continue;
pml4_entry.BitAddress = *( UINT64* )( pml4_base.BitAddress + pml4_index * sizeof( UINT64 ) );
pml4_entry.BitAddress = *(UINT64*)(pml4_base.BitAddress + pml4_index * sizeof(UINT64));
if ( pml4_entry.Bits.Present == NULL )
if (pml4_entry.Bits.Present == NULL)
continue;
physical.QuadPart = pml4_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
pdpt_base = MmGetVirtualForPhysical( physical );
pdpt_base = MmGetVirtualForPhysical(physical);
if ( !pdpt_base || !MmIsAddressValid( pdpt_base ) )
if (!pdpt_base || !MmIsAddressValid(pdpt_base))
continue;
for ( INT pdpt_index = 0; pdpt_index < PDPT_ENTRY_COUNT; pdpt_index++ )
for (INT pdpt_index = 0; pdpt_index < PDPT_ENTRY_COUNT; pdpt_index++)
{
if ( !MmIsAddressValid( pdpt_base + pdpt_index * sizeof( UINT64 ) ) )
if (!MmIsAddressValid(pdpt_base + pdpt_index * sizeof(UINT64)))
continue;
pdpt_entry.BitAddress = *( UINT64* )( pdpt_base + pdpt_index * sizeof( UINT64 ) );
pdpt_entry.BitAddress = *(UINT64*)(pdpt_base + pdpt_index * sizeof(UINT64));
if ( pdpt_entry.Bits.Present == NULL )
if (pdpt_entry.Bits.Present == NULL)
continue;
if ( IS_LARGE_PAGE( pdpt_entry.BitAddress ) )
if (IS_LARGE_PAGE(pdpt_entry.BitAddress))
{
/* 1gb size page */
pdpt_large_entry.BitAddress = pdpt_entry.BitAddress;
physical.QuadPart = pdpt_large_entry.Bits.PhysicalAddress << PAGE_1GB_SHIFT;
if ( IsPhysicalAddressInPhysicalMemoryRange( physical.QuadPart, physical_memory_ranges ) == FALSE )
if (IsPhysicalAddressInPhysicalMemoryRange(physical.QuadPart, physical_memory_ranges) == FALSE)
continue;
base_1gb_virtual_page = MmGetVirtualForPhysical( physical );
base_1gb_virtual_page = MmGetVirtualForPhysical(physical);
if ( !base_1gb_virtual_page || !MmIsAddressValid( base_1gb_virtual_page ) )
if (!base_1gb_virtual_page || !MmIsAddressValid(base_1gb_virtual_page))
continue;
EnumerateKernelLargePages(
@ -461,34 +461,34 @@ WalkKernelPageTables( PVOID AddressBuffer )
physical.QuadPart = pdpt_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
pd_base = MmGetVirtualForPhysical( physical );
pd_base = MmGetVirtualForPhysical(physical);
if ( !pd_base || !MmIsAddressValid( pd_base ) )
if (!pd_base || !MmIsAddressValid(pd_base))
continue;
for ( INT pd_index = 0; pd_index < PD_ENTRY_COUNT; pd_index++ )
for (INT pd_index = 0; pd_index < PD_ENTRY_COUNT; pd_index++)
{
if ( !MmIsAddressValid( pd_base + pd_index * sizeof( UINT64 ) ) )
if (!MmIsAddressValid(pd_base + pd_index * sizeof(UINT64)))
continue;
pd_entry.BitAddress = *( UINT64* )( pd_base + pd_index * sizeof( UINT64 ) );
pd_entry.BitAddress = *(UINT64*)(pd_base + pd_index * sizeof(UINT64));
if ( pd_entry.Bits.Present == NULL )
if (pd_entry.Bits.Present == NULL)
continue;
if ( IS_LARGE_PAGE( pd_entry.BitAddress ) )
if (IS_LARGE_PAGE(pd_entry.BitAddress))
{
/* 2MB size page */
pd_large_entry.BitAddress = pd_entry.BitAddress;
physical.QuadPart = pd_large_entry.Bits.PhysicalAddress << PAGE_2MB_SHIFT;
if ( IsPhysicalAddressInPhysicalMemoryRange( physical.QuadPart, physical_memory_ranges ) == FALSE )
if (IsPhysicalAddressInPhysicalMemoryRange(physical.QuadPart, physical_memory_ranges) == FALSE)
continue;
base_2mb_virtual_page = MmGetVirtualForPhysical( physical );
base_2mb_virtual_page = MmGetVirtualForPhysical(physical);
if ( !base_2mb_virtual_page || !MmIsAddressValid( base_2mb_virtual_page ) )
if (!base_2mb_virtual_page || !MmIsAddressValid(base_2mb_virtual_page))
continue;
EnumerateKernelLargePages(
@ -503,34 +503,34 @@ WalkKernelPageTables( PVOID AddressBuffer )
physical.QuadPart = pd_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
if ( !MmIsAddressValid( pd_base + pd_index * sizeof( UINT64 ) ) )
if (!MmIsAddressValid(pd_base + pd_index * sizeof(UINT64)))
continue;
pt_base = MmGetVirtualForPhysical( physical );
pt_base = MmGetVirtualForPhysical(physical);
if ( !pt_base || !MmIsAddressValid( pt_base ) )
if (!pt_base || !MmIsAddressValid(pt_base))
continue;
for ( INT pt_index = 0; pt_index < PT_ENTRY_COUNT; pt_index++ )
for (INT pt_index = 0; pt_index < PT_ENTRY_COUNT; pt_index++)
{
if ( !MmIsAddressValid( pt_base + pt_index * sizeof( UINT64 ) ) )
if (!MmIsAddressValid(pt_base + pt_index * sizeof(UINT64)))
continue;
pt_entry.BitAddress = *( UINT64* )( pt_base + pt_index * sizeof( UINT64 ) );
pt_entry.BitAddress = *(UINT64*)(pt_base + pt_index * sizeof(UINT64));
if ( pt_entry.Bits.Present == NULL )
if (pt_entry.Bits.Present == NULL)
continue;
physical.QuadPart = pt_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
/* if the page base isnt in a legit region, go next */
if ( IsPhysicalAddressInPhysicalMemoryRange( physical.QuadPart, physical_memory_ranges ) == FALSE )
if (IsPhysicalAddressInPhysicalMemoryRange(physical.QuadPart, physical_memory_ranges) == FALSE)
continue;
base_virtual_page = MmGetVirtualForPhysical( physical );
base_virtual_page = MmGetVirtualForPhysical(physical);
/* stupid fucking intellisense error GO AWAY! */
if ( base_virtual_page == NULL || !MmIsAddressValid( base_virtual_page ) )
if (base_virtual_page == NULL || !MmIsAddressValid(base_virtual_page))
continue;
ScanPageForKernelObjectAllocation(
@ -544,37 +544,37 @@ WalkKernelPageTables( PVOID AddressBuffer )
}
}
DEBUG_LOG( "Finished scanning memory" );
DEBUG_LOG("Finished scanning memory");
}
STATIC
VOID
VOID
IncrementProcessCounter()
{
process_count++;
}
STATIC
VOID
VOID
CheckIfProcessAllocationIsInProcessList(
_In_ PEPROCESS Process
)
{
PUINT64 allocation_address;
for ( INT i = 0; i < process_count; i++ )
for (INT i = 0; i < process_count; i++)
{
allocation_address = ( PUINT64 )process_buffer;
allocation_address = (PUINT64)process_buffer;
if ( ( UINT64 )Process >= allocation_address[ i ] - PROCESS_OBJECT_ALLOCATION_MARGIN &&
( UINT64 )Process <= allocation_address[ i ] + PROCESS_OBJECT_ALLOCATION_MARGIN )
if ((UINT64)Process >= allocation_address[i] - PROCESS_OBJECT_ALLOCATION_MARGIN &&
(UINT64)Process <= allocation_address[i] + PROCESS_OBJECT_ALLOCATION_MARGIN)
{
RtlZeroMemory( ( UINT64 )process_buffer + i * sizeof( UINT64 ), sizeof( UINT64 ) );
RtlZeroMemory((UINT64)process_buffer + i * sizeof(UINT64), sizeof(UINT64));
}
}
}
NTSTATUS
NTSTATUS
FindUnlinkedProcesses(
_In_ PIRP Irp
)
@ -587,29 +587,29 @@ FindUnlinkedProcesses(
NULL
);
if ( process_count == NULL )
if (process_count == NULL)
{
DEBUG_ERROR( "Faield to get process count " );
DEBUG_ERROR("Faield to get process count ");
return STATUS_ABANDONED;
}
process_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, process_count * 2 * sizeof( UINT64 ), PROCESS_ADDRESS_LIST_TAG );
process_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, process_count * 2 * sizeof(UINT64), PROCESS_ADDRESS_LIST_TAG);
if ( !process_buffer )
if (!process_buffer)
return STATUS_ABANDONED;
WalkKernelPageTables( process_buffer );
WalkKernelPageTables(process_buffer);
EnumerateProcessListWithCallbackFunction(
CheckIfProcessAllocationIsInProcessList,
NULL
);
allocation_address = ( PUINT64 )process_buffer;
allocation_address = (PUINT64)process_buffer;
for ( INT i = 0; i < process_count; i++ )
for (INT i = 0; i < process_count; i++)
{
if ( allocation_address[ i ] == NULL )
if (allocation_address[i] == NULL)
continue;
/*
@ -617,28 +617,28 @@ FindUnlinkedProcesses(
* an unlinked process allocation. It is better to have a few false positives that can be later
* analysed rather then enforce a strict signature and potentially miss a real unlinked process.
*/
DEBUG_ERROR( "INVALID POOL proc OMGGG" );
DEBUG_ERROR("INVALID POOL proc OMGGG");
report_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( INVALID_PROCESS_ALLOCATION_REPORT ), REPORT_POOL_TAG );
report_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
if ( !report_buffer )
if (!report_buffer)
goto end;
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
RtlCopyMemory(
report_buffer->process,
(UINT64)allocation_address[ i ] - OBJECT_HEADER_SIZE,
REPORT_INVALID_PROCESS_BUFFER_SIZE
(UINT64)allocation_address[i] - OBJECT_HEADER_SIZE,
REPORT_INVALID_PROCESS_BUFFER_SIZE
);
InsertReportToQueue( report_buffer );
InsertReportToQueue(report_buffer);
}
end:
if ( process_buffer )
ExFreePoolWithTag( process_buffer, PROCESS_ADDRESS_LIST_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;

View file

@ -9,21 +9,21 @@
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
{
INT report_code;
CHAR process[ REPORT_INVALID_PROCESS_BUFFER_SIZE ];
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
}INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
}INVALID_PROCESS_ALLOCATION_REPORT, * PINVALID_PROCESS_ALLOCATION_REPORT;
NTSTATUS
NTSTATUS
FindUnlinkedProcesses(
_In_ PIRP Irp
);
VOID
VOID
GetPsActiveProcessHead(
_In_ PUINT64 Address
);
PKDDEBUGGER_DATA64
PKDDEBUGGER_DATA64
GetGlobalDebuggerData();
#endif

View file

@ -22,11 +22,11 @@ typedef struct _REPORT_QUEUE_CONFIGURATION
QUEUE_HEAD head;
KGUARDED_MUTEX lock;
}REPORT_QUEUE_CONFIGURATION, *PREPORT_QUEUE_CONFIGURATION;
}REPORT_QUEUE_CONFIGURATION, * PREPORT_QUEUE_CONFIGURATION;
REPORT_QUEUE_CONFIGURATION report_queue_config = { 0 };
VOID
VOID
InitialiseGlobalReportQueue(
_In_ PBOOLEAN Status
)
@ -35,8 +35,8 @@ InitialiseGlobalReportQueue(
report_queue_config.head.end = NULL;
report_queue_config.head.entries = 0;
KeInitializeSpinLock( &report_queue_config.head.lock );
KeInitializeGuardedMutex( &report_queue_config.lock );
KeInitializeSpinLock(&report_queue_config.head.lock);
KeInitializeGuardedMutex(&report_queue_config.lock);
*Status = TRUE;
}
@ -57,48 +57,48 @@ InitialiseGlobalReportQueue(
// return head;
//}
VOID
QueuePush(
VOID
QueuePush(
_In_ PQUEUE_HEAD Head,
_In_ PVOID Data
)
{
KIRQL irql = KeGetCurrentIrql();
KeAcquireSpinLock( &Head->lock, &irql );
KeAcquireSpinLock(&Head->lock, &irql);
PQUEUE_NODE temp = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_NODE ), QUEUE_POOL_TAG );
PQUEUE_NODE temp = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(QUEUE_NODE), QUEUE_POOL_TAG);
if ( !temp )
if (!temp)
goto end;
Head->entries += 1;
temp->data = Data;
if ( Head->end != NULL )
if (Head->end != NULL)
Head->end->next = temp;
Head->end = temp;
if ( Head->start == NULL )
if (Head->start == NULL)
Head->start = temp;
end:
KeReleaseSpinLock( &Head->lock, irql );
KeReleaseSpinLock(&Head->lock, irql);
}
PVOID
PVOID
QueuePop(
_In_ PQUEUE_HEAD Head
)
{
KIRQL irql = KeGetCurrentIrql();
KeAcquireSpinLock( &Head->lock, &irql );
KeAcquireSpinLock(&Head->lock, &irql);
PVOID data = NULL;
PQUEUE_NODE temp = Head->start;
if ( temp == NULL )
if (temp == NULL)
goto end;
Head->entries = Head->entries - 1;
@ -106,41 +106,41 @@ QueuePop(
data = temp->data;
Head->start = temp->next;
if ( Head->end == temp )
if (Head->end == temp)
Head->end = NULL;
ExFreePoolWithTag( temp, QUEUE_POOL_TAG );
ExFreePoolWithTag(temp, QUEUE_POOL_TAG);
end:
KeReleaseSpinLock( &Head->lock, irql );
KeReleaseSpinLock(&Head->lock, irql);
return data;
}
VOID
VOID
InsertReportToQueue(
_In_ PVOID Report
)
{
KeAcquireGuardedMutex( &report_queue_config.lock );
QueuePush( &report_queue_config.head, Report );
KeReleaseGuardedMutex( &report_queue_config.lock );
KeAcquireGuardedMutex(&report_queue_config.lock);
QueuePush(&report_queue_config.head, Report);
KeReleaseGuardedMutex(&report_queue_config.lock);
}
VOID
VOID
FreeGlobalReportQueueObjects()
{
KeAcquireGuardedMutex( &report_queue_config.lock );
KeAcquireGuardedMutex(&report_queue_config.lock);
PVOID report = QueuePop( &report_queue_config.head );
PVOID report = QueuePop(&report_queue_config.head);
while ( report != NULL )
while (report != NULL)
{
ExFreePoolWithTag( report, REPORT_POOL_TAG );
report = QueuePop( &report_queue_config.head );
ExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop(&report_queue_config.head);
}
end:
KeReleaseGuardedMutex( &report_queue_config.lock );
KeReleaseGuardedMutex(&report_queue_config.lock);
}
/*
@ -151,7 +151,7 @@ end:
* reports as a result of a single usermode request and hence it makes dealing with
* reports generated from ObRegisterCallbacks for example much easier.
*/
NTSTATUS
NTSTATUS
HandlePeriodicGlobalReportQueueQuery(
_In_ PIRP Irp
)
@ -163,186 +163,186 @@ HandlePeriodicGlobalReportQueueQuery(
PREPORT_HEADER report_header;
SIZE_T total_size = NULL;
KeAcquireGuardedMutex( &report_queue_config.lock );
report = QueuePop( &report_queue_config.head );
KeAcquireGuardedMutex(&report_queue_config.lock);
report = QueuePop(&report_queue_config.head);
report_buffer = ExAllocatePool2(
POOL_FLAG_NON_PAGED,
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
);
if ( !report_buffer )
if (!report_buffer)
{
KeReleaseGuardedMutex( &report_queue_config.lock );
KeReleaseGuardedMutex(&report_queue_config.lock);
return STATUS_MEMORY_NOT_ALLOCATED;
}
if ( report == NULL )
if (report == NULL)
{
DEBUG_LOG( "callback report queue is empty, returning" );
DEBUG_LOG("callback report queue is empty, returning");
goto end;
}
while ( report != NULL )
while (report != NULL)
{
if ( count >= MAX_REPORTS_PER_IRP )
if (count >= MAX_REPORTS_PER_IRP)
goto end;
report_header = ( PREPORT_HEADER )report;
report_header = (PREPORT_HEADER)report;
switch ( report_header->report_id )
switch (report_header->report_id)
{
case REPORT_ILLEGAL_HANDLE_OPERATION:
RtlCopyMemory(
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
report,
sizeof( OPEN_HANDLE_FAILURE_REPORT )
sizeof(OPEN_HANDLE_FAILURE_REPORT)
);
total_size += sizeof( OPEN_HANDLE_FAILURE_REPORT );
total_size += sizeof(OPEN_HANDLE_FAILURE_REPORT);
break;
case REPORT_ILLEGAL_ATTACH_PROCESS:
RtlCopyMemory(
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
report,
sizeof( ATTACH_PROCESS_REPORT )
sizeof(ATTACH_PROCESS_REPORT)
);
total_size += sizeof( ATTACH_PROCESS_REPORT );
total_size += sizeof(ATTACH_PROCESS_REPORT);
break;
case REPORT_INVALID_PROCESS_ALLOCATION:
RtlCopyMemory(
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
report,
sizeof( INVALID_PROCESS_ALLOCATION_REPORT )
sizeof(INVALID_PROCESS_ALLOCATION_REPORT)
);
total_size += sizeof( INVALID_PROCESS_ALLOCATION_REPORT );
total_size += sizeof(INVALID_PROCESS_ALLOCATION_REPORT);
break;
case REPORT_APC_STACKWALK:
RtlCopyMemory(
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
report,
sizeof( APC_STACKWALK_REPORT )
sizeof(APC_STACKWALK_REPORT)
);
total_size += sizeof( APC_STACKWALK_REPORT );
total_size += sizeof(APC_STACKWALK_REPORT);
break;
}
/* QueuePop frees the node, but we still need to free the returned data */
ExFreePoolWithTag( report, REPORT_POOL_TAG );
ExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop( &report_queue_config.head );
report = QueuePop(&report_queue_config.head);
count += 1;
}
end:
KeReleaseGuardedMutex( &report_queue_config.lock );
KeReleaseGuardedMutex(&report_queue_config.lock);
Irp->IoStatus.Information = sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size;
Irp->IoStatus.Information = sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size;
header.count = count;
RtlCopyMemory(
report_buffer,
&header,
sizeof( GLOBAL_REPORT_QUEUE_HEADER ) );
sizeof(GLOBAL_REPORT_QUEUE_HEADER));
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
report_buffer,
sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size
sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size
);
if ( report_buffer )
ExFreePoolWithTag( report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG );
if (report_buffer)
ExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
DEBUG_LOG( "Moved all reports into the IRP, sending !" );
DEBUG_LOG("Moved all reports into the IRP, sending !");
return STATUS_SUCCESS;
}
VOID
VOID
ListInit(
_In_ PLIST_HEAD ListHead
)
{
KeInitializeSpinLock( &ListHead->lock );
KeInitializeSpinLock(&ListHead->lock);
ListHead->start = NULL;
}
PLIST_ITEM
PLIST_ITEM
ListInsert(
_In_ PLIST_HEAD ListHead,
_In_ PLIST_ITEM NewEntry
)
{
KIRQL irql = KeGetCurrentIrql();
KeAcquireSpinLock( &ListHead->lock, &irql );
KeAcquireSpinLock(&ListHead->lock, &irql);
PLIST_ITEM old_entry = ListHead->start;
ListHead->start = NewEntry;
NewEntry->next = old_entry;
KeReleaseSpinLock( &ListHead->lock, irql );
KeReleaseSpinLock(&ListHead->lock, irql);
}
PVOID
PVOID
ListRemoveFirst(
_In_ PLIST_HEAD ListHead
)
{
KIRQL irql = KeGetCurrentIrql();
KeAcquireSpinLock( &ListHead->lock, &irql );
KeAcquireSpinLock(&ListHead->lock, &irql);
if ( ListHead->start )
if (ListHead->start)
{
PLIST_ITEM entry = ListHead->start;
ListHead->start = ListHead->start->next;
ExFreePoolWithTag( entry, POOL_TAG_APC );
ExFreePoolWithTag(entry, POOL_TAG_APC);
}
KeReleaseSpinLock( &ListHead->lock, irql );
KeReleaseSpinLock(&ListHead->lock, irql);
}
PVOID
PVOID
ListRemoveItem(
_In_ PLIST_HEAD ListHead,
_Inout_ PLIST_ITEM ListItem
)
{
KIRQL irql = KeGetCurrentIrql();
KeAcquireSpinLock( &ListHead->lock, &irql );
KeAcquireSpinLock(&ListHead->lock, &irql);
PLIST_ITEM entry = ListHead->start;
if ( !entry )
if (!entry)
goto unlock;
if ( entry == ListItem )
if (entry == ListItem)
{
ListHead->start = entry->next;
ExFreePoolWithTag( ListItem, POOL_TAG_APC );
ExFreePoolWithTag(ListItem, POOL_TAG_APC);
goto unlock;
}
while ( entry->next )
while (entry->next)
{
if ( entry->next == ListItem )
if (entry->next == ListItem)
{
entry->next = ListItem->next;
ExFreePoolWithTag( ListItem, POOL_TAG_APC );
ExFreePoolWithTag(ListItem, POOL_TAG_APC);
goto unlock;
}
@ -350,5 +350,5 @@ ListRemoveItem(
}
unlock:
KeReleaseSpinLock( &ListHead->lock, irql);
KeReleaseSpinLock(&ListHead->lock, irql);
}

View file

@ -11,7 +11,7 @@ typedef struct _QUEUE_NODE
struct _QUEUE_NODE* next;
PVOID data;
}QUEUE_NODE, *PQUEUE_NODE;
}QUEUE_NODE, * PQUEUE_NODE;
typedef struct QUEUE_HEAD
{
@ -20,7 +20,7 @@ typedef struct QUEUE_HEAD
KSPIN_LOCK lock;
INT entries;
}QUEUE_HEAD, *PQUEUE_HEAD;
}QUEUE_HEAD, * PQUEUE_HEAD;
typedef struct _GLOBAL_REPORT_QUEUE_HEADER
{
@ -49,52 +49,52 @@ typedef struct _LIST_HEAD
#define LIST_POOL_TAG 'list'
VOID
VOID
QueuePush(
_In_ PQUEUE_HEAD Head,
_In_ PVOID Data
);
PVOID
QueuePop(
PVOID
QueuePop(
_In_ PQUEUE_HEAD Head
);
VOID
VOID
InitialiseGlobalReportQueue(
_In_ PBOOLEAN Status
);
VOID
VOID
InsertReportToQueue(
_In_ PVOID Report
);
NTSTATUS
NTSTATUS
HandlePeriodicGlobalReportQueueQuery(
_In_ PIRP Irp
);
VOID
VOID
FreeGlobalReportQueueObjects();
VOID
VOID
ListInit(
_In_ PLIST_HEAD ListHead
);
PLIST_ITEM
PLIST_ITEM
ListInsert(
_In_ PLIST_HEAD ListHead,
_In_ PLIST_ITEM Data
);
PVOID
PVOID
ListRemoveFirst(
_In_ PLIST_HEAD ListHead
);
PVOID
PVOID
ListRemoveItem(
_In_ PLIST_HEAD ListHead,
_Inout_ PLIST_ITEM ListItem

View file

@ -14,10 +14,10 @@ typedef struct _KPRCB_THREAD_VALIDATION_CTX
UINT8 thread_found_in_kthreadlist;
BOOLEAN finished;
}KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
}KPRCB_THREAD_VALIDATION_CTX, * PKPRCB_THREAD_VALIDATION_CTX;
STATIC
VOID
VOID
KPRCBThreadValidationProcessCallback(
_In_ PEPROCESS Process,
_Inout_ PVOID Context
@ -28,25 +28,25 @@ KPRCBThreadValidationProcessCallback(
PLIST_ENTRY thread_list_entry;
PETHREAD current_thread;
UINT32 thread_id;
PKPRCB_THREAD_VALIDATION_CTX context = ( PKPRCB_THREAD_VALIDATION_CTX )Context;
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
if ( context->finished == TRUE )
if (context->finished == TRUE)
return;
thread_list_head = ( PLIST_ENTRY )( ( UINT64 )Process + KPROCESS_THREADLIST_OFFSET );
thread_list_head = (PLIST_ENTRY)((UINT64)Process + KPROCESS_THREADLIST_OFFSET);
thread_list_entry = thread_list_head->Flink;
while ( thread_list_entry != thread_list_head )
while (thread_list_entry != thread_list_head)
{
current_thread = ( PETHREAD )( ( UINT64 )thread_list_entry - KTHREAD_THREADLIST_OFFSET );
current_thread = (PETHREAD)((UINT64)thread_list_entry - KTHREAD_THREADLIST_OFFSET);
if ( current_thread == context->current_kpcrb_thread )
if (current_thread == context->current_kpcrb_thread)
{
context->thread_found_in_kthreadlist = TRUE;
thread_id = PsGetThreadId( current_thread );
thread_id = PsGetThreadId(current_thread);
if ( thread_id != NULL )
if (thread_id != NULL)
{
context->thread_found_in_pspcidtable = TRUE;
context->finished = TRUE;
@ -79,7 +79,7 @@ KPRCBThreadValidationProcessCallback(
*
*/
VOID
VOID
ValidateKPCRBThreads(
_In_ PIRP Irp
)
@ -90,15 +90,15 @@ ValidateKPCRBThreads(
KAFFINITY old_affinity = { 0 };
KPRCB_THREAD_VALIDATION_CTX context = { 0 };
for ( LONG processor_index = 0; processor_index < KeQueryActiveProcessorCount( 0 ); processor_index++ )
for (LONG processor_index = 0; processor_index < KeQueryActiveProcessorCount(0); processor_index++)
{
old_affinity = KeSetSystemAffinityThreadEx( ( KAFFINITY )( 1 << processor_index ) );
old_affinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1 << processor_index));
kpcr = __readmsr( IA32_GS_BASE );
kpcr = __readmsr(IA32_GS_BASE);
kprcb = kpcr + KPRCB_OFFSET_FROM_GS_BASE;
context.current_kpcrb_thread = *( UINT64* )( kprcb + KPCRB_CURRENT_THREAD );
context.current_kpcrb_thread = *(UINT64*)(kprcb + KPCRB_CURRENT_THREAD);
if (!context.current_kpcrb_thread )
if (!context.current_kpcrb_thread)
continue;
EnumerateProcessListWithCallbackFunction(
@ -106,40 +106,40 @@ ValidateKPCRBThreads(
&context
);
if ( context.current_kpcrb_thread == FALSE || context.thread_found_in_pspcidtable == FALSE )
if (context.current_kpcrb_thread == FALSE || context.thread_found_in_pspcidtable == FALSE)
{
Irp->IoStatus.Information = sizeof( HIDDEN_SYSTEM_THREAD_REPORT );
Irp->IoStatus.Information = sizeof(HIDDEN_SYSTEM_THREAD_REPORT);
HIDDEN_SYSTEM_THREAD_REPORT report;
report.report_code = REPORT_HIDDEN_SYSTEM_THREAD;
report.found_in_kthreadlist = context.thread_found_in_kthreadlist;
report.found_in_pspcidtable = context.thread_found_in_pspcidtable;
report.thread_id = PsGetThreadId( context.current_kpcrb_thread );
report.thread_id = PsGetThreadId(context.current_kpcrb_thread);
report.thread_address = context.current_kpcrb_thread;
RtlCopyMemory(
report.thread,
context.current_kpcrb_thread,
sizeof( report.thread ));
sizeof(report.thread));
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&report,
sizeof( HIDDEN_SYSTEM_THREAD_REPORT ) );
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&report,
sizeof(HIDDEN_SYSTEM_THREAD_REPORT));
}
KeRevertToUserAffinityThreadEx( old_affinity );
KeRevertToUserAffinityThreadEx(old_affinity);
}
}
STATIC
VOID
VOID
DetectAttachedThreadsProcessCallback(
_In_ PEPROCESS Process,
_In_ PVOID Context
)
{
UNREFERENCED_PARAMETER( Context );
UNREFERENCED_PARAMETER(Context);
NTSTATUS status;
PLIST_ENTRY thread_list_head;
@ -149,34 +149,37 @@ DetectAttachedThreadsProcessCallback(
PKAPC_STATE apc_state;
PEPROCESS protected_process = NULL;
GetProtectedProcessEProcess( &protected_process );
GetProtectedProcessEProcess(&protected_process);
if ( protected_process == NULL )
if (protected_process == NULL)
return;
thread_list_head = ( PLIST_ENTRY )( ( UINT64 )Process + KPROCESS_THREADLIST_OFFSET );
thread_list_head = (PLIST_ENTRY)((UINT64)Process + KPROCESS_THREADLIST_OFFSET);
thread_list_entry = thread_list_head->Flink;
while ( thread_list_entry != thread_list_head )
while (thread_list_entry != thread_list_head)
{
current_thread = ( PETHREAD )( ( UINT64 )thread_list_entry - KTHREAD_THREADLIST_OFFSET );
current_thread = (PETHREAD)((UINT64)thread_list_entry - KTHREAD_THREADLIST_OFFSET);
apc_state = ( PKAPC_STATE )( ( UINT64 )current_thread + KTHREAD_APC_STATE_OFFSET );
apc_state = (PKAPC_STATE)((UINT64)current_thread + KTHREAD_APC_STATE_OFFSET);
if ( apc_state->Process == protected_process )
if (apc_state->Process == protected_process)
{
DEBUG_LOG( "Program attached to notepad: %llx", ( UINT64 )current_thread );
DEBUG_LOG("Program attached to notepad: %llx", (UINT64)current_thread);
PATTACH_PROCESS_REPORT report = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( ATTACH_PROCESS_REPORT ), REPORT_POOL_TAG );
PATTACH_PROCESS_REPORT report = ExAllocatePool2(
POOL_FLAG_NON_PAGED,
sizeof(ATTACH_PROCESS_REPORT),
REPORT_POOL_TAG);
if ( !report )
if (!report)
return;
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
report->thread_id = PsGetThreadId( current_thread );
report->thread_id = PsGetThreadId(current_thread);
report->thread_address = current_thread;
InsertReportToQueue( report );
InsertReportToQueue(report);
}
thread_list_entry = thread_list_entry->Flink;
@ -186,15 +189,15 @@ DetectAttachedThreadsProcessCallback(
/*
* I did not reverse this myself and previously had no idea how you would go about
* detecting KiAttachProcess so credits to KANKOSHEV for the explanation:
*
*
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
*
*
* To expand on his writeup a little, the offset that he provides is equivalent to PKAPC_STATE->Process.
* This is where KiAttachProcess writes the process that thread is attaching to when it's called.
* The APC_STATE structure holds relevant information about the thread's APC state and is quite
* important during context switch scenarios as it's how the thread determines if it has any APC's
* queued.
* queued.
*/
VOID DetectThreadsAttachedToProtectedProcess()
{
@ -203,4 +206,3 @@ VOID DetectThreadsAttachedToProtectedProcess()
NULL
);
}

View file

@ -12,24 +12,24 @@ typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
INT found_in_pspcidtable;
UINT64 thread_address;
LONG thread_id;
CHAR thread[ 4096 ];
CHAR thread[4096];
}HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
}HIDDEN_SYSTEM_THREAD_REPORT, * PHIDDEN_SYSTEM_THREAD_REPORT;
typedef struct _ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
UINT32 thread_id;
UINT64 thread_address;
}ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
}ATTACH_PROCESS_REPORT, * PATTACH_PROCESS_REPORT;
VOID
VOID
ValidateKPCRBThreads(
_In_ PIRP Irp
);
VOID
VOID
DetectThreadsAttachedToProtectedProcess();
#endif