mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
da
This commit is contained in:
parent
c4c42c3e56
commit
9da18de49f
18 changed files with 2116 additions and 2042 deletions
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
412
driver/driver.c
412
driver/driver.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
46
driver/hv.c
46
driver/hv.c
|
@ -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;
|
||||
|
|
|
@ -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
|
2104
driver/integrity.c
2104
driver/integrity.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
154
driver/ioctl.c
154
driver/ioctl.c
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
574
driver/modules.c
574
driver/modules.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
276
driver/pool.c
276
driver/pool.c
|
@ -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;
|
||||
|
|
|
@ -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
|
166
driver/queue.c
166
driver/queue.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
@ -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
|
Loading…
Reference in a new issue