logging + readme + other

This commit is contained in:
lhodges1 2023-12-24 05:52:55 +11:00
parent 84c4f5137f
commit 1040289914
16 changed files with 586 additions and 377 deletions

109
README.md
View file

@ -1,5 +1,7 @@
# ac
open source anti cheat (lol) which I made for fun.
# features
- Attached thread detection
@ -22,47 +24,104 @@
# planned features
- Heartbeat between components
- ntoskrnl integrity checks (currently in progress)
- some way of identifying spoofed stacks
- some way of dynamically resolving offsets. Will probably use a pdb parser but i am working on a debuglib atm using the windows debug api. We will see.
- some form of cr3 protection
- some more detection methods other then stackwalking xD
- various forms of encryption and other things
- Heartbeat
- ntoskrnl integrity checks, or atleast a small subset of the kernel encompasing critical functions
- spoofed stack identifier
- process module inline hook detection (this would include checking whether the hook is valid, as many legimate programs hook user mode modules such as discord, nvidia overlay etc.)
- cr3 protection
- string, packet and other encryption
- tpm ek extraction
- tpm spoofer detection
- pcileech firmware detection
- testing program to test the features
# known issues
- The system module integrity checks on win11 fail due to MmCopyMemory error for around 80% of the modules. While it doesn't cause a blue screen, this is a pretty pathetic success rate. Am looking into it.
- KPRCB thread check rn is kinda broken
Ive thoroughly tested the driver with verifier in addition to extended testing on my main pc (non vm) so at the least there shouldn't be any bluescreens (hopefully...). If you do find any, feel free to open an issue with the minidump :)
- [See the issues page](https://github.com/donnaskiez/ac/issues)
- Feel free to open a new issue if you find any bugs
# windows versions tested:
- Win10 22H2
- Win11 22H2
# logs example
# how to build
video of example logs + running on my machine no vm: [video](https://youtu.be/htY83WsMEcc)
# how 2 use
Requires [Visual Studio](https://visualstudio.microsoft.com/downloads/) and the [WDK](https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk) for compilation.
1. Build the project in visual studio, if you experience any build issues - check the drivers project settings are the following:
- `Inf2Cat -> General -> Use Local Time` to `Yes`
- `C/C++ -> Treat Warnings As Errors` to `No`
- `C/C++ -> Spectre Mitigation` to `Disabled`
2. Move the `driver.sys` file into `Windows/System32/Drivers` directory
3. Use the osr loader to load the driver at "system" load.
- Osr loader can be found here: https://www.osronline.com/article.cfm%5Earticle=157.htm
2. Move the `driver.sys` file located in `ac\x64\Release` into the `Windows\System32\Drivers` directory
3. Use the [OSR Loader](https://www.osronline.com/article.cfm%5Earticle=157.htm) and select `driver.sys` that you moved to the Windows drivers folder. DO NOT REGISTER THE SERVICE YET.
- driver must be named "driver.sys" (sorry.. will be fixed soon (i am lazy))
- IMPORTANT: its important that you only click "Register" in the OSR loader, dont actually load the driver only register it. Then restart. This is very important as the driver needs an accurate representation of system threads and processes in order for many of the detection methods to work.
4. inject dll into program you want to protect, i used notepad for testing.
- IMPORTANT: it is important that this process is started as administrator, which in turn means the injector you use must also be started as administrator. This is a design flaw. Will be fixed in the future.
- Obviously in a "real" program, the dll would be embedded into the application - for now this is what we work with.
5. Logs can be seen both in the terminal and either dbgview or WinDbg depending on what you use.
- If for some reason you can't see logs in DbgView, you may need to properly set your debugging mask. Tutorial here: https://www.osronline.com/article.cfm%5Earticle=295.htm
6. The server and service arent needed, youll just see a bunch of "failed to write to pipe" if you dont launch the service, this is fine and the core anti cheat + user mode is still working.
4. Under `Service Start` select `System`. This is VERY important!
5. Click `Register Service`. *Do NOT click* `Start Service`!
6. Restart Windows.
7. Once restarted, open the program you would like to protect as Administrator.
- Yes I understand this is not realistic
8. Open your dll injector program of choice as administrator (I simply use [Process Hacker](https://processhacker.sourceforge.io/))
9. Inject the dll found in `ac\x64\Release` named `user.dll` into the target program
Logs will be printed to both the terminal output and the kernel debugger. See below for configuring kernel debugger output.
Note: The server is not needed for the program to function properly.
# how to configure kernel debugging output
The kernel driver is setup to log at 4 distinct levels:
```C
#define DPFLTR_ERROR_LEVEL
#define DPFLTR_WARNING_LEVEL
#define DPFLTR_INFO_LEVEL
#define DPFLTR_VERBOSE_LEVEL
```
As the names suggest, `ERROR_LEVEL` is for errors, `WARNING_LEVEL` is for warnings. `INFO_LEVEL` is for general information regarding what requests the driver is processing and `VERBOSE_LEVEL` contains very detailed information for each request.
## creating the registry key
If you are unfamiliar with the kernel debugging mask, you probably need to set one up. If you already have a debugging mask setup, you can skip to `setting the mask` below.
1. Open the Registry Editor
2. Copy and pase `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager` into the bar at the top and press enter
3. On the left hand side, right click `Session Manager` and select `New -> Key`
4. Name the key `Debug Print Filter`
5. On the left hand side you should now see `Debug Print Filter`, right click and select `New -> DWORD (32 bit) Value`
6. Name the key `DEFAULT`
## setting the mask
1. Within the `Debug Print Filter` registry, double click the key named `DEFAULT`
2. Determine the level(s) of logging you would like to see. For most people interested I would set either `INFO_LEVEL` or `VERBOSE_LEVEL`. Remember that if you set `INFO_LEVEL`, you will see all `INFO_LEVEL`, `WARNING_LEVEL` and `ERROR_LEVEL` logs. Ie you see all logs above and including your set level.
```
ERROR_LEVEL = 0x2
WARNING_LEVEL = 0x7
INFO_LEVEL = 0xf
VERBOSE_LEVEL = 0x1f
```
3. Enter the value for the given logging level (seen above)
4. Click `Ok` and restart Windows.
## filtering debug output
If you choose to use `INFO_LEVEL` or `VERBOSE_LEVEL` there may be many logs from the kernel so we want to filter them out.
### windbg
With WinDbg connected to the target:
1. Pause the target using the `Break` button
2. Use the command: `.ofilter donna-ac*`
### debugview
1. Click `Edit -> Filter/Highlight`
2. Set the `Include` string to `donna-ac*`
# contact

View file

@ -556,7 +556,7 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
if (strcmp(process_name, protected_process_name))
goto end;
DEBUG_LOG("Handle references our protected process with access mask: %lx",
DEBUG_VERBOSE("Handle references our protected process with access mask: %lx",
(ACCESS_MASK)Entry->GrantedAccessBits);
handle_access_mask = (ACCESS_MASK)Entry->GrantedAccessBits;
@ -565,42 +565,42 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
if (handle_access_mask & PROCESS_CREATE_PROCESS)
{
Entry->GrantedAccessBits &= ~PROCESS_CREATE_PROCESS;
DEBUG_LOG("Stripped PROCESS_CREATE_PROCESS");
DEBUG_VERBOSE("Stripped PROCESS_CREATE_PROCESS");
}
if (handle_access_mask & PROCESS_CREATE_THREAD)
{
Entry->GrantedAccessBits &= ~PROCESS_CREATE_THREAD;
DEBUG_LOG("Stripped PROCESS_CREATE_THREAD");
DEBUG_VERBOSE("Stripped PROCESS_CREATE_THREAD");
}
if (handle_access_mask & PROCESS_DUP_HANDLE)
{
Entry->GrantedAccessBits &= ~PROCESS_DUP_HANDLE;
DEBUG_LOG("Stripped PROCESS_DUP_HANDLE");
DEBUG_VERBOSE("Stripped PROCESS_DUP_HANDLE");
}
if (handle_access_mask & PROCESS_QUERY_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_QUERY_INFORMATION;
DEBUG_LOG("Stripped PROCESS_QUERY_INFORMATION");
DEBUG_VERBOSE("Stripped PROCESS_QUERY_INFORMATION");
}
if (handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_QUERY_LIMITED_INFORMATION;
DEBUG_LOG("Stripped PROCESS_QUERY_LIMITED_INFORMATION");
DEBUG_VERBOSE("Stripped PROCESS_QUERY_LIMITED_INFORMATION");
}
if (handle_access_mask & PROCESS_VM_READ)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_READ;
DEBUG_LOG("Stripped PROCESS_VM_READ");
DEBUG_VERBOSE("Stripped PROCESS_VM_READ");
}
if (!strcmp(process_name, "csrss.exe") || !strcmp(process_name, "lsass.exe"))
{
DEBUG_LOG(
DEBUG_VERBOSE(
"Required system process allowed, only stripping some permissions");
goto end;
}
@ -609,37 +609,37 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
if (handle_access_mask & PROCESS_SET_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_SET_INFORMATION;
DEBUG_LOG("Stripped PROCESS_SET_INFORMATION");
DEBUG_VERBOSE("Stripped PROCESS_SET_INFORMATION");
}
if (handle_access_mask & PROCESS_SET_QUOTA)
{
Entry->GrantedAccessBits &= ~PROCESS_SET_QUOTA;
DEBUG_LOG("Stripped PROCESS_SET_QUOTA");
DEBUG_VERBOSE("Stripped PROCESS_SET_QUOTA");
}
if (handle_access_mask & PROCESS_SUSPEND_RESUME)
{
Entry->GrantedAccessBits &= ~PROCESS_SUSPEND_RESUME;
DEBUG_LOG("Stripped PROCESS_SUSPEND_RESUME ");
DEBUG_VERBOSE("Stripped PROCESS_SUSPEND_RESUME ");
}
if (handle_access_mask & PROCESS_TERMINATE)
{
Entry->GrantedAccessBits &= ~PROCESS_TERMINATE;
DEBUG_LOG("Stripped PROCESS_TERMINATE");
DEBUG_VERBOSE("Stripped PROCESS_TERMINATE");
}
if (handle_access_mask & PROCESS_VM_OPERATION)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_OPERATION;
DEBUG_LOG("Stripped PROCESS_VM_OPERATION");
DEBUG_VERBOSE("Stripped PROCESS_VM_OPERATION");
}
if (handle_access_mask & PROCESS_VM_WRITE)
{
Entry->GrantedAccessBits &= ~PROCESS_VM_WRITE;
DEBUG_LOG("Stripped PROCESS_VM_WRITE");
DEBUG_VERBOSE("Stripped PROCESS_VM_WRITE");
}
POPEN_HANDLE_FAILURE_REPORT report = ExAllocatePool2(
@ -661,6 +661,7 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
report->process_id = PsGetProcessId(process);
report->thread_id = 0;
report->access = handle_access_mask;
RtlCopyMemory(
&report->process_name, process_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);

View file

@ -4,10 +4,38 @@
#include <ntifs.h>
#include <wdftypes.h>
#define DEBUG_LOG(fmt, ...) \
DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "donna-ac [INFO] " fmt "\n", ##__VA_ARGS__)
/*
* For numbers < 32, these are equivalent to 0ul < x.
*
* For an item to be printed, its bitwise AND'd with the set filter. If the result is non zero the
* log will be printed.
*/
#define LOG_ERROR_LEVEL 1
#define LOG_WARNING_LEVEL 2
#define LOG_INFO_LEVEL 3
#define LOG_VERBOSE_LEVEL 4
#define DPFLTR_MASK 0x80000000
#define DEBUG_ERROR(fmt, ...) \
DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "donna-ac [ERROR] " fmt "\n", ##__VA_ARGS__)
DbgPrintEx( \
DPFLTR_DEFAULT_ID, LOG_ERROR_LEVEL, "donna-ac : [ERROR] ::: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_WARNING(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
LOG_WARNING_LEVEL, \
"donna-ac : [WARNING] : " fmt "\n", \
##__VA_ARGS__)
#define DEBUG_INFO(fmt, ...) \
DbgPrintEx( \
DPFLTR_DEFAULT_ID, LOG_INFO_LEVEL, "donna-ac : [INFO] :::: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_VERBOSE(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
LOG_VERBOSE_LEVEL, \
"donna-ac : [VERBOSE] : " fmt "\n", \
##__VA_ARGS__)
#define STATIC static
@ -360,7 +388,7 @@ typedef struct _HANDLE_TABLE_ENTRY // Size=16
ULONG_PTR RefCnt : 16; // Size=8 Offset=0 BitOffset=1 BitCount=16
ULONG_PTR Attributes : 3; // Size=8 Offset=0 BitOffset=17 BitCount=3
ULONG_PTR
ObjectPointerBits : 44; // Size=8 Offset=0 BitOffset=20 BitCount=44
ObjectPointerBits : 44; // Size=8 Offset=0 BitOffset=20 BitCount=44
};
};
union

View file

@ -69,7 +69,7 @@ DrvLoadInitialiseProcessConfig();
STATIC
NTSTATUS
DrvLoadInitialiseDriverConfig(_In_ PUNICODE_STRING RegistryPath);
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath);
#ifdef ALLOC_PRAGMA
# pragma alloc_text(INIT, DriverEntry)
@ -103,6 +103,29 @@ DrvLoadInitialiseDriverConfig(_In_ PUNICODE_STRING RegistryPath);
#define MAXIMUM_APC_CONTEXTS 10
/*
* Determines whether a protection routine is active. This allows us to deactivate a method based on
* some criteria, such as windows version. Some things should never be disabled though, so having
* them as an option here such as the integrity check is probably not the best idea.
*/
typedef struct _PROTECTION_METHOD_FLAGS
{
BOOLEAN process_module_verification;
BOOLEAN nmi_callbacks;
BOOLEAN apc_stackwalk;
BOOLEAN ipi_stackwalk;
BOOLEAN validate_driver_objects;
BOOLEAN virtualization_check;
BOOLEAN enumerate_handle_tables;
BOOLEAN unlinked_process_scan;
BOOLEAN kpcrb_validation;
BOOLEAN driver_integrity_check;
BOOLEAN attached_threads;
BOOLEAN validate_system_modules;
BOOLEAN ept_hook;
} PROTECTION_METHOD_FLAGS, *PPROTECTION_METHOD_FLAGS;
typedef struct _DRIVER_CONFIG
{
UNICODE_STRING unicode_driver_name;
@ -113,6 +136,8 @@ typedef struct _DRIVER_CONFIG
UNICODE_STRING registry_path;
SYSTEM_INFORMATION system_information;
PVOID apc_contexts[MAXIMUM_APC_CONTEXTS];
PDRIVER_OBJECT driver_object;
PDEVICE_OBJECT device_object;
volatile BOOLEAN unload_in_progress;
KGUARDED_MUTEX lock;
@ -251,6 +276,33 @@ RegistryPathQueryCallbackRoutine(IN PWSTR ValueName,
*
*/
NTSTATUS
SelfReferenceDriver()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE handle = NULL;
UNICODE_STRING path = {0};
OBJECT_ATTRIBUTES oa = {0};
IO_STATUS_BLOCK io = {0};
DEBUG_VERBOSE("Opening self referencing handle");
GetDriverPath(&path);
__debugbreak();
InitializeObjectAttributes(
&oa, &path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenFile(&handle, GENERIC_READ, &oa, &io, NULL, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ZwOpenFile failed with status %x", status);
return status;
}
__debugbreak();
return status;
}
/*
* No need to hold the lock here as the thread freeing the APCs will
* already hold the configuration lock. We also dont want to release and
@ -263,7 +315,7 @@ FreeApcContextStructure(_Inout_ PAPC_CONTEXT_HEADER Context)
{
BOOLEAN result = FALSE;
DEBUG_LOG("All APCs executed, freeing context structure");
DEBUG_VERBOSE("All APCs executed, freeing context structure");
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
@ -277,6 +329,8 @@ FreeApcContextStructure(_Inout_ PAPC_CONTEXT_HEADER Context)
ExFreePoolWithTag(Context, POOL_TAG_APC);
entry[index] = NULL;
result = TRUE;
ObDereferenceObject(driver_config.driver_object);
ObDereferenceObject(driver_config.device_object);
goto unlock;
}
}
@ -365,8 +419,8 @@ QueryActiveApcContextsForCompletion()
continue;
}
DEBUG_LOG("APC Context Id: %lx", entry->context_id);
DEBUG_LOG("Active APC Count: %i", entry->count);
DEBUG_VERBOSE("APC Context Id: %lx", entry->context_id);
DEBUG_VERBOSE("Active APC Count: %i", entry->count);
if (entry->count > 0 || entry->allocation_in_progress == TRUE)
{
@ -400,8 +454,8 @@ InsertApcContext(_In_ PVOID Context)
* is attempted to start, ensuring that even if it holds
*/
if (InterlockedExchange(&driver_config.unload_in_progress,
driver_config.unload_in_progress))
return STATUS_ABANDONED;
driver_config.unload_in_progress) == TRUE)
return STATUS_UNSUCCESSFUL;
KeAcquireGuardedMutex(&driver_config.lock);
@ -414,6 +468,18 @@ InsertApcContext(_In_ PVOID Context)
if (entry[index] == NULL)
{
entry[index] = Context;
/*
* When we insert a new APC context, lets increment our drivers reference
* count. When we remove an APC context, we will decrement this reference
* count. This allows us to queue the driver for deletion but the unload
* routine wont execute until all APC contexts have been completed, allowing
* us to cleanup everything properly. The old strategy of blocking the
* unload routine method was not very nice and I think this is a much better
* method of going about it.
*/
ObReferenceObject(driver_config.driver_object);
ObReferenceObject(driver_config.device_object);
goto end;
}
}
@ -653,7 +719,8 @@ ProcCloseClearProcessConfiguration()
{
PAGED_CODE();
DEBUG_LOG("Process closed, clearing driver process_configuration");
DEBUG_INFO("Protected process closed. Clearing process configuration.");
KeAcquireGuardedMutex(&process_config.lock);
process_config.km_handle = NULL;
process_config.um_handle = NULL;
@ -685,7 +752,9 @@ ProcLoadEnableObCallbacks()
{
PAGED_CODE();
NTSTATUS status;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DEBUG_VERBOSE("Enabling ObRegisterCallbacks.");
KeAcquireGuardedMutex(&process_config.lock);
@ -709,7 +778,7 @@ ProcLoadEnableObCallbacks()
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to launch obregisters with status %x", status);
DEBUG_ERROR("ObRegisterCallbacks failed with status %x", status);
goto end;
}
@ -745,7 +814,7 @@ ProcLoadInitialiseProcessConfig(_In_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS process = NULL;
PDRIVER_INITIATION_INFORMATION information = NULL;
@ -753,7 +822,7 @@ ProcLoadInitialiseProcessConfig(_In_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate input buffer");
DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x", status);
return status;
}
@ -930,17 +999,17 @@ STATIC
VOID
DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
InterlockedExchange(&driver_config.unload_in_progress, TRUE);
DEBUG_VERBOSE("Unloading...");
DEBUG_LOG("Unloading driver...");
InterlockedExchange(&driver_config.unload_in_progress, TRUE);
/*
* This blocks the thread dispatching the unload routine, which I don't think is ideal.
* This is the issue with using APCs, we have very little safe control over when they
* complete and thus when we can free them.. For now, thisl do.
*/
while (DrvUnloadFreeAllApcContextStructures() == FALSE)
YieldProcessor();
while (DrvUnloadFreeAllApcContextStructures() == FALSE)
YieldProcessor();
DrvUnloadUnregisterObCallbacks();
DrvUnloadFreeThreadList();
@ -951,7 +1020,7 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
IoDeleteDevice(DriverObject->DeviceObject);
DEBUG_LOG("Driver unloaded");
DEBUG_INFO("Driver successfully unloaded.");
}
/*
@ -966,7 +1035,9 @@ DrvLoadEnableNotifyRoutines()
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DEBUG_VERBOSE("Enabling driver wide notify routines.");
status = InitialiseThreadList();
@ -1018,6 +1089,8 @@ DrvLoadEnableNotifyRoutines()
// return status;
// }
DEBUG_VERBOSE("Successfully enabled driver wide notify routines.");
return status;
}
@ -1054,16 +1127,23 @@ DrvLoadInitialiseProcessConfig()
STATIC
NTSTATUS
DrvLoadInitialiseDriverConfig(_In_ PUNICODE_STRING RegistryPath)
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
PAGED_CODE();
NTSTATUS status;
NTSTATUS status = STATUS_UNSUCCESSFUL;
/* 3rd page acts as a null terminator for the callback routine */
RTL_QUERY_REGISTRY_TABLE query_table[3] = {0};
DEBUG_VERBOSE("Initialising driver configuration");
KeInitializeGuardedMutex(&driver_config.lock);
/*
* Lets do something cheeky and not reference our driver object here even though we do hold
* a reference to it, purely for APC reasons...
*/
driver_config.unload_in_progress = FALSE;
RtlInitUnicodeString(&driver_config.device_name, L"\\Device\\DonnaAC");
@ -1101,7 +1181,7 @@ DrvLoadInitialiseDriverConfig(_In_ PUNICODE_STRING RegistryPath)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to convert unicode string to ansi string");
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
@ -1136,8 +1216,9 @@ DrvLoadInitialiseDriverConfig(_In_ PUNICODE_STRING RegistryPath)
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_VERBOSE("Motherboard serial: %s",
driver_config.system_information.motherboard_serial);
DEBUG_VERBOSE("Drive 0 serial: %s", driver_config.system_information.drive_0_serial);
return status;
}
@ -1147,11 +1228,11 @@ NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
BOOLEAN flag = FALSE;
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DEBUG_LOG("Beginning driver entry lolz");
DEBUG_VERBOSE("Beginning driver entry routine...");
status = DrvLoadInitialiseDriverConfig(RegistryPath);
status = DrvLoadInitialiseDriverConfig(DriverObject, RegistryPath);
if (!NT_SUCCESS(status))
{
@ -1176,12 +1257,15 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
return STATUS_FAILED_DRIVER_ENTRY;
}
driver_config.driver_object = DriverObject;
driver_config.device_object = DriverObject->DeviceObject;
status =
IoCreateSymbolicLink(&driver_config.device_symbolic_link, &driver_config.device_name);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to create symbolic link");
DEBUG_ERROR("IoCreateSymbolicLink failed with status %x", status);
DrvUnloadFreeConfigStrings();
IoDeleteDevice(DriverObject->DeviceObject);
return STATUS_FAILED_DRIVER_ENTRY;
@ -1196,7 +1280,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
if (!flag)
{
DEBUG_ERROR("failed to init report queue");
DEBUG_ERROR("InitialiseReportQueue failed with no status.");
DrvUnloadFreeConfigStrings();
IoDeleteSymbolicLink(&driver_config.device_symbolic_link);
IoDeleteDevice(DriverObject->DeviceObject);
@ -1207,7 +1291,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to init callback routines on driver entry");
DEBUG_ERROR("EnablenotifyRoutines failed with status %x", status);
DrvUnloadFreeGlobalReportQueue();
DrvUnloadFreeConfigStrings();
IoDeleteSymbolicLink(&driver_config.device_symbolic_link);
@ -1219,7 +1303,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
// ValidateNtoskrnl();
// LaunchInterProcessInterrupt(NULL);
// EnumerateBigPoolAllocations();
DEBUG_LOG("DonnaAC Driver Entry Complete");
DEBUG_VERBOSE("Driver Entry Complete.");
return STATUS_SUCCESS;
}

View file

@ -162,4 +162,7 @@ _Releases_lock_(_Lock_kind_mutex_)
VOID
GetDriverSymbolicLink(_Out_ PUNICODE_STRING DeviceSymbolicLink);
NTSTATUS
SelfReferenceDriver();
#endif

View file

@ -141,7 +141,6 @@
<ClCompile Include="pool.c" />
<ClCompile Include="queue.c" />
<ClCompile Include="thread.c" />
<ClCompile Include="version.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h" />
@ -154,7 +153,6 @@
<ClInclude Include="pool.h" />
<ClInclude Include="queue.h" />
<ClInclude Include="thread.h" />
<ClInclude Include="version.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="asm.asm" />

View file

@ -51,9 +51,6 @@
<ClCompile Include="thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="version.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="driver.h">
@ -86,9 +83,6 @@
<ClInclude Include="thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="asm.asm">

View file

@ -90,7 +90,7 @@ PerformVirtualizationDetection(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate IRP output buffer");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
return status;
}

View file

@ -143,7 +143,7 @@ GetDriverImageSize(_Inout_ PIRP Irp)
if (!driver_info)
{
DEBUG_ERROR("FindSystemModuleByName failed");
DEBUG_ERROR("FindSystemModuleByName failed with no status code");
ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
return STATUS_NOT_FOUND;
}
@ -152,7 +152,7 @@ GetDriverImageSize(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate IRP output buffer");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
goto end;
}
@ -189,7 +189,7 @@ GetModuleInformationByName(_Out_ PRTL_MODULE_EXTENDED_INFO ModuleInfo, _In_ LPCS
if (!driver_info)
{
DEBUG_ERROR("FindSystemModuleByName failed");
DEBUG_ERROR("FindSystemModuleByName failed with no status");
ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
return STATUS_NOT_FOUND;
}
@ -336,7 +336,7 @@ MapDiskImageIntoVirtualAddressSpace(_Inout_ PHANDLE Sec
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE file_handle = NULL;
OBJECT_ATTRIBUTES object_attributes = {0};
PIO_STATUS_BLOCK pio_block = NULL;
@ -350,12 +350,11 @@ MapDiskImageIntoVirtualAddressSpace(_Inout_ PHANDLE Sec
InitializeObjectAttributes(
&object_attributes, &path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
status =
ZwOpenFile(&file_handle, FILE_GENERIC_READ, &object_attributes, &pio_block, NULL, NULL);
status = ZwOpenFile(&file_handle, GENERIC_READ, &object_attributes, &pio_block, NULL, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ZwOpenFile failed with statsu %x", status);
DEBUG_ERROR("ZwOpenFile failed with status %x", status);
return status;
}
@ -640,7 +639,7 @@ VerifyInMemoryImageVsDiskImage(
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("StoreModuleExecutableRegionsInBuffe failed with status %x", status);
DEBUG_ERROR("StoreModuleExecutableRegionsInBuffer failed with status %x", status);
goto end;
}
@ -656,14 +655,14 @@ VerifyInMemoryImageVsDiskImage(
if (!disk_base || !memory_base || !disk_buffer || !in_memory_buffer)
{
DEBUG_ERROR("buffers are null lmao");
DEBUG_ERROR("Buffer(s) are null. An error has occured.");
goto end;
}
if (disk_text_header->SizeOfRawData != memory_text_header->SizeOfRawData)
{
/* report or bug check etc. */
DEBUG_LOG("Executable section size differs, LOL");
DEBUG_WARNING("Executable section sizes differ between images.");
goto end;
}
@ -689,7 +688,8 @@ VerifyInMemoryImageVsDiskImage(
if (memory_text_hash_size != disk_text_hash_size)
{
DEBUG_ERROR("Error with the hash algorithm, hash sizes are different.");
DEBUG_WARNING(
"Error with the hash algorithm, hash sizes are different. An error has occured.");
goto end;
}
@ -698,11 +698,11 @@ VerifyInMemoryImageVsDiskImage(
if (result != memory_text_hash_size)
{
/* report etc. bug check etc. */
DEBUG_ERROR("Text sections are different from each other!!");
DEBUG_WARNING("Text section hashes are different, the section has been modified.");
goto end;
}
DEBUG_LOG("Text sections are fine, integrity check complete.");
DEBUG_INFO("Text sections are valid. Integrity check has been complete.");
end:
@ -732,7 +732,7 @@ RetrieveInMemoryModuleExecutableSections(_Inout_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
SIZE_T bytes_written = NULL;
PVOID buffer = NULL;
RTL_MODULE_EXTENDED_INFO module_info = {0};
@ -758,7 +758,7 @@ RetrieveInMemoryModuleExecutableSections(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate IRP output buffer");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
goto end;
}
@ -882,7 +882,7 @@ ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID firmware_table_buffer = NULL;
ULONG firmware_table_buffer_size = 0;
ULONG bytes_returned = 0;
@ -890,8 +890,7 @@ ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
PSMBIOS_TABLE_HEADER smbios_table_header = NULL;
PRAW_SMBIOS_TABLE_01 smbios_baseboard_information = NULL;
status =
ExGetSystemFirmwareTable(SMBIOS_TABLE, NULL, NULL, NULL, &firmware_table_buffer_size);
status = ExGetSystemFirmwareTable(SMBIOS_TABLE, 0, NULL, 0, &firmware_table_buffer_size);
/*
* Because we pass a null buffer here, the NTSTATUS result will be a BUFFER_TOO_SMALL error,
@ -974,7 +973,7 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOLEAN bstatus = FALSE;
PROCESS_MODULE_VALIDATION_RESULT validation_result = {0};
PPROCESS_MODULE_INFORMATION module_info = NULL;
@ -996,7 +995,7 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate IRP input buffer");
DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x", status);
return status;
}
@ -1025,7 +1024,7 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ComputeHashOfBuffer failed with status %x:", status);
DEBUG_ERROR("ComputeHashOfBuffer failed with status %x", status);
goto end;
}
@ -1116,7 +1115,7 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE handle = NULL;
OBJECT_ATTRIBUTES attributes = {0};
IO_STATUS_BLOCK status_block = {0};
@ -1143,7 +1142,7 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
if (!NT_SUCCESS(status))
{
DEBUG_LOG("ZwOpenFile on PhysicalDrive0 failed with status %x", status);
DEBUG_ERROR("ZwOpenFile on PhysicalDrive0 failed with status %x", status);
goto end;
}
@ -1163,7 +1162,7 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
if (!NT_SUCCESS(status))
{
DEBUG_LOG("ZwDeviceIoControlFile first call failed with status %x", status);
DEBUG_ERROR("ZwDeviceIoControlFile first call failed with status %x", status);
goto end;
}
@ -1189,7 +1188,7 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
if (!NT_SUCCESS(status))
{
DEBUG_LOG("ZwDeviceIoControlFile second call failed with status %x", status);
DEBUG_ERROR("ZwDeviceIoControlFile second call failed with status %x", status);
goto end;
}
@ -1201,7 +1200,8 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
if (serial_length > ConfigDrive0MaxSize)
{
DEBUG_ERROR("Serial length is greater then config drive 0 buffer size");
DEBUG_ERROR(
"Serial length is greater then the allocated buffer size for the drives serial number.");
status = STATUS_BUFFER_TOO_SMALL;
goto end;
}
@ -1209,6 +1209,7 @@ GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T Confi
RtlCopyMemory(ConfigDrive0Serial, serial_number, serial_length);
}
DEBUG_INFO("Successfully retrieved hard disk serial number.");
end:
if (handle)
@ -1332,7 +1333,7 @@ MeasureReads(_In_ PVOID Address, _In_ ULONG Count)
_enable();
__writecr8(old_irql);
DEBUG_LOG("REad average: %llx", read_average);
DEBUG_VERBOSE("EPT Detection - Read Average: %llx", read_average);
return read_average / Count;
}
@ -1360,11 +1361,11 @@ NTSTATUS
GetAverageReadTimeAtRoutine(_In_ PVOID RoutineAddress, _Out_ PUINT64 AverageTime)
{
if (!RoutineAddress || !AverageTime)
return STATUS_ABANDONED;
return STATUS_UNSUCCESSFUL;
*AverageTime = MeasureReads(RoutineAddress, EPT_CHECK_NUM_ITERATIONS);
return *AverageTime == 0 ? STATUS_ABANDONED : STATUS_SUCCESS;
return *AverageTime == 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
}
/*
@ -1420,7 +1421,7 @@ InitiateEptFunctionAddressArrays()
CONTROL_FUNCTION_ADDRESSES[index] = MmGetSystemRoutineAddress(&current_function);
if (!CONTROL_FUNCTION_ADDRESSES[index])
return STATUS_ABANDONED;
return STATUS_UNSUCCESSFUL;
}
for (INT index = 0; index < EPT_PROTECTED_FUNCTIONS_COUNT; index++)
@ -1429,7 +1430,7 @@ InitiateEptFunctionAddressArrays()
PROTECTED_FUNCTION_ADDRESSES[index] = MmGetSystemRoutineAddress(&current_function);
if (!PROTECTED_FUNCTION_ADDRESSES[index])
return STATUS_ABANDONED;
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
@ -1440,7 +1441,7 @@ DetectEptHooksInKeyFunctions()
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
UINT32 control_fails = 0;
UINT64 instruction_time = 0;
UINT64 control_time_sum = 0;
@ -1492,7 +1493,7 @@ DetectEptHooksInKeyFunctions()
* 149b7777777 */
if (control_average * EPT_EXECUTION_TIME_MULTIPLIER < instruction_time)
{
DEBUG_LOG(
DEBUG_WARNING(
"EPT hook detected at function: %llx with execution time of: %llx",
PROTECTED_FUNCTION_ADDRESSES[index],
instruction_time);
@ -1501,8 +1502,8 @@ DetectEptHooksInKeyFunctions()
}
else
{
DEBUG_LOG("No ept hook detected at function: %llx",
PROTECTED_FUNCTION_ADDRESSES[index]);
DEBUG_INFO("No ept hook detected at function: %llx",
PROTECTED_FUNCTION_ADDRESSES[index]);
}
}
@ -1523,7 +1524,8 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
if (!strcmp(process_name, "winlogon.exe"))
{
DEBUG_LOG("Found winlogon: %llx", (UINT64)Entry->process);
DEBUG_VERBOSE("32 bit WinLogon.exe process found at address: %llx",
(UINT64)Entry->process);
*process = Entry->process;
}
}
@ -1534,7 +1536,7 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
NTSTATUS
ValidateSystemModules()
{
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOLEAN bstatus = FALSE;
ANSI_STRING ansi_string = {0};
UNICODE_STRING path = {0};
@ -1552,6 +1554,7 @@ ValidateSystemModules()
ULONG memory_hash_size = 0;
PVOID memory_buffer = NULL;
ULONG memory_buffer_size = 0;
ULONG result = 0;
PEPROCESS process = NULL;
KAPC_STATE apc_state = {0};
SYSTEM_MODULES modules = {0};
@ -1559,7 +1562,7 @@ ValidateSystemModules()
PIMAGE_SECTION_HEADER disk_text_header = NULL;
PIMAGE_SECTION_HEADER memory_text_header = NULL;
DEBUG_LOG("Validating system modules");
DEBUG_VERBOSE("Beginning to validate system modules.");
status = GetSystemModuleInformation(&modules);
@ -1626,15 +1629,14 @@ ValidateSystemModules()
*/
if (!MmIsAddressValid(module_info->ImageBase))
{
DEBUG_LOG("Win32k process");
DEBUG_VERBOSE(
"Win32k related module found, acquiring 32 bit address space...");
EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process);
if (!process)
goto free_iteration;
DEBUG_LOG("WinLogonPRocess: %llx", (UINT64)process);
KeStackAttachProcess(process, &apc_state);
status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
@ -1671,15 +1673,16 @@ ValidateSystemModules()
memory_text_header =
(PIMAGE_SECTION_HEADER)((UINT64)memory_buffer + sizeof(INTEGRITY_CHECK_HEADER));
if (!disk_text_base || !memory_text_base || !disk_buffer || !memory_buffer)
if (!disk_text_base || !memory_text_base || !disk_buffer || !memory_buffer ||
!MmIsAddressValid(disk_buffer) || !MmIsAddressValid(memory_buffer))
{
DEBUG_ERROR("buffers are null lmao");
goto free_iteration;
DEBUG_ERROR("Buffer(s) are null. An error has occured.");
goto free_section;
}
if (disk_text_header->SizeOfRawData != memory_text_header->SizeOfRawData)
{
DEBUG_LOG("Executable section size differs, LOL");
DEBUG_WARNING("Executable section sizes differ between images.");
goto free_iteration;
}
@ -1703,16 +1706,41 @@ ValidateSystemModules()
goto free_iteration;
}
SIZE_T test = RtlCompareMemory(
memory_text_base, disk_text_base, memory_text_header->SizeOfRawData);
if (!MmIsAddressValid(memory_hash) || !MmIsAddressValid(disk_hash))
goto free_iteration;
if (test = memory_text_header->SizeOfRawData)
DEBUG_LOG("Modules regions are valid!");
result =
RtlCompareMemory(memory_hash, disk_hash, memory_hash_size);
if (result = memory_text_header->SizeOfRawData)
DEBUG_VERBOSE("Module executable sections are valid for the module: %s",
module_info->FullPathName);
else
DEBUG_ERROR("Module regions are NOT valid LOL!");
DEBUG_WARNING("Module regions are not valid for module: %s",
module_info->FullPathName);
free_iteration:
if (memory_buffer)
ExFreePoolWithTag(memory_buffer, POOL_TAG_INTEGRITY);
if (memory_hash)
ExFreePoolWithTag(memory_hash, POOL_TAG_INTEGRITY);
if (disk_buffer)
ExFreePoolWithTag(disk_buffer, POOL_TAG_INTEGRITY);
if (disk_hash)
ExFreePoolWithTag(disk_hash, POOL_TAG_INTEGRITY);
free_section:
if (section_handle)
ZwClose(section_handle);
if (section)
ZwUnmapViewOfSection(ZwCurrentProcess(), section);
/*
* Its times like this where you see why allocating all local variables at the
* beginning of the function may not be so ideal...
@ -1729,24 +1757,6 @@ ValidateSystemModules()
ansi_string.Length = 0;
ansi_string.MaximumLength = 0;
if (section_handle)
ZwClose(section_handle);
if (section)
ZwUnmapViewOfSection(ZwCurrentProcess(), section);
if (memory_buffer)
ExFreePoolWithTag(memory_buffer, POOL_TAG_INTEGRITY);
if (memory_hash)
ExFreePoolWithTag(memory_hash, POOL_TAG_INTEGRITY);
if (disk_buffer)
ExFreePoolWithTag(disk_buffer, POOL_TAG_INTEGRITY);
if (disk_hash)
ExFreePoolWithTag(disk_hash, POOL_TAG_INTEGRITY);
section_handle = NULL;
section = NULL;
memory_buffer = NULL;
@ -1774,7 +1784,7 @@ ValidateSystemModules()
NTSTATUS
ValidateNtoskrnl()
{
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
SIZE_T bytes_written = 0;
KAPC_STATE apc_state = {0};
PVOID memory_buffer = NULL;
@ -1792,7 +1802,7 @@ ValidateNtoskrnl()
module_info = (PRTL_MODULE_EXTENDED_INFO)modules.address;
DEBUG_LOG("Module base: %llx", module_info->ImageBase);
DEBUG_VERBOSE("Module base: %llx", module_info->ImageBase);
PVOID buffer =
ExAllocatePool2(POOL_FLAG_NON_PAGED, module_info->ImageSize, POOL_TAG_INTEGRITY);
@ -1823,7 +1833,7 @@ ValidateNtoskrnl()
goto end;
}
DEBUG_LOG("buf size: %lx", memory_buffer_size);
DEBUG_VERBOSE("buf size: %lx", memory_buffer_size);
end:
@ -1833,5 +1843,34 @@ end:
if (modules.address)
ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
return status;
}
NTSTATUS
GetOsVersionInformation(_Out_ PRTL_OSVERSIONINFOW VersionInfo)
{
NTSTATUS status = STATUS_ABANDONED;
RTL_OSVERSIONINFOW info = {0};
if (!VersionInfo)
return STATUS_INVALID_PARAMETER;
status = RtlGetVersion(&info);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("RtlGetVersion failed with status %x", status);
return status;
}
VersionInfo->dwBuildNumber = info.dwBuildNumber;
VersionInfo->dwMajorVersion = info.dwMajorVersion;
VersionInfo->dwMinorVersion = info.dwMinorVersion;
VersionInfo->dwOSVersionInfoSize = info.dwOSVersionInfoSize;
VersionInfo->dwPlatformId = info.dwPlatformId;
RtlCopyMemory(
VersionInfo->szCSDVersion, info.szCSDVersion, sizeof(VersionInfo->szCSDVersion));
return status;
}

View file

@ -67,14 +67,16 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation)
{
PAGED_CODE();
NTSTATUS status;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DEBUG_VERBOSE("Dispatching APC Operation...");
switch (Operation->operation_id)
{
case APC_OPERATION_STACKWALK:
DEBUG_LOG("Initiating APC stackwalk operation with operation id %i",
Operation->operation_id);
DEBUG_INFO("Initiating APC stackwalk operation with operation id %i",
Operation->operation_id);
status = ValidateThreadsViaKernelApc();
@ -83,7 +85,7 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation)
return status;
default: DEBUG_ERROR("Invalid operation ID passed"); return STATUS_INVALID_PARAMETER;
default: DEBUG_WARNING("Invalid operation ID passed"); return STATUS_INVALID_PARAMETER;
}
return status;
@ -176,6 +178,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
{
case IOCCTL_RUN_NMI_CALLBACKS:
DEBUG_INFO("IOCTL_RUN_NMI_CALLBACKS Received.");
status = HandleNmiIOCTL(Irp);
if (!NT_SUCCESS(status))
@ -185,6 +189,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_VALIDATE_DRIVER_OBJECTS:
DEBUG_INFO("IOCTL_VALIDATE_DRIVER_OBJECTS Received.");
/*
* The reason this function is run in a new thread and not the thread
* issuing the IOCTL is because ZwOpenDirectoryObject issues a
@ -198,7 +204,7 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to start thread to validate system drivers");
DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
goto end;
}
@ -227,40 +233,45 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:;
DEBUG_INFO("IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH Received");
status = ProcLoadInitialiseProcessConfig(Irp);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR(
"Failed to initialise driver config on proc launch with status %x",
status);
DEBUG_ERROR("InitialiseProcessConfig failed with status %x", status);
goto end;
}
status = ProcLoadEnableObCallbacks();
if (!NT_SUCCESS(status))
DEBUG_ERROR("InitiateDriverCallbacks failed with status %x", status);
DEBUG_ERROR("EnableObCallbacks failed with status %x", status);
break;
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
DEBUG_INFO("IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE Received");
status = QueryActiveApcContextsForCompletion();
if (!NT_SUCCESS(status))
DEBUG_ERROR("QueryActiveApcContextsForCompletion filed with status %x",
DEBUG_ERROR("QueryActiveApcContextsForCompletion failed with status %x",
status);
status = HandlePeriodicGlobalReportQueueQuery(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to handle period callback report queue");
DEBUG_ERROR("HandlePeriodicGlobalReportQueueQuery failed with status %x",
status);
break;
case IOCTL_PERFORM_VIRTUALIZATION_CHECK:
DEBUG_INFO("IOCTL_PERFORM_VIRTUALIZATION_CHECK Received");
status = PerformVirtualizationDetection(Irp);
if (!NT_SUCCESS(status))
@ -270,6 +281,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_ENUMERATE_HANDLE_TABLES:
DEBUG_INFO("IOCTL_ENUMERATE_HANDLE_TABLES Received");
/* can maybe implement this better so we can extract a status value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL);
@ -277,6 +290,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS:
DEBUG_VERBOSE("IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS Received");
status = PsCreateSystemThread(&handle,
PROCESS_ALL_ACCESS,
NULL,
@ -287,7 +302,7 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to start system thread to get executable regions");
DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
goto end;
}
@ -302,27 +317,27 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
}
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
;
ZwClose(handle);
ObDereferenceObject(thread);
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to retrieve executable regions");
break;
case IOCTL_REQUEST_TOTAL_MODULE_SIZE:
DEBUG_INFO("IOCTL_REQUEST_TOTAL_MODULE_SIZE Received");
status = GetDriverImageSize(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to retrieve driver image size");
DEBUG_ERROR("GetDriverImageSize failed with status %x", status);
break;
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION:
DEBUG_INFO("IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION Received");
ProcCloseClearProcessConfiguration();
ProcCloseDisableObCallbacks();
@ -330,28 +345,46 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
DEBUG_INFO("IOCTL_SCAN_FOR_UNLINKED_PROCESS Received");
status = FindUnlinkedProcesses();
if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUNlinekdProcesses failed with status %x", status);
DEBUG_ERROR("FindUnlinkedProcesses failed with status %x", status);
break;
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD: ValidateKPCRBThreads(); break;
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD:
DEBUG_INFO("IOCTL_VALIDATE_KPRCB_CURRENT_THREAD Received");
ValidateKPCRBThreads();
break;
case IOCTL_PERFORM_INTEGRITY_CHECK:
DEBUG_INFO("IOCTL_PERFORM_INTEGRITY_CHECK Received");
status = VerifyInMemoryImageVsDiskImage();
if (!NT_SUCCESS(status))
DEBUG_ERROR("VerifyInMemoryImageVsDisk failed with status %x", status);
DEBUG_ERROR("VerifyInMemoryImageVsDiskImage failed with status %x", status);
break;
case IOCTL_DETECT_ATTACHED_THREADS: DetectThreadsAttachedToProtectedProcess(); break;
case IOCTL_DETECT_ATTACHED_THREADS:
DEBUG_INFO("IOCTL_DETECT_ATTACHED_THREADS Received");
DetectThreadsAttachedToProtectedProcess();
break;
case IOCTL_VALIDATE_PROCESS_LOADED_MODULE:
DEBUG_INFO("IOCTL_VALIDATE_PROCESS_LOADED_MODULE Received");
status = ValidateProcessLoadedModule(Irp);
if (!NT_SUCCESS(status))
@ -361,12 +394,15 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_REQUEST_HARDWARE_INFORMATION:;
DEBUG_INFO("IOCTL_REQUEST_HARDWARE_INFORMATION Received");
PSYSTEM_INFORMATION system_information = NULL;
GetDriverConfigSystemInformation(&system_information);
if (system_information == NULL)
if (!system_information)
{
DEBUG_ERROR("GetDriverConfigSystemInformation failed");
DEBUG_ERROR("GetDriverConfigSystemInformation failed with no status.");
goto end;
}
@ -374,7 +410,7 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate IRP output buffer");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
goto end;
}
@ -388,6 +424,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_INITIATE_APC_OPERATION:;
DEBUG_INFO("IOCTL_INITIATE_APC_OPERATION Received");
PAPC_OPERATION_ID operation = (PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
status = DispatchApcOperation(operation);
@ -399,6 +437,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_CHECK_FOR_EPT_HOOK:
DEBUG_INFO("IOCTL_CHECK_FOR_EPT_HOOK Received");
status = DetectEptHooksInKeyFunctions();
if (!NT_SUCCESS(status))
@ -408,6 +448,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_LAUNCH_IPI_INTERRUPT:
DEBUG_INFO("IOCTL_LAUNCH_IPI_INTERRUPT Received");
status = LaunchInterProcessInterrupt(Irp);
if (!NT_SUCCESS(status))
@ -417,6 +459,8 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
case IOCTL_VALIDATE_SYSTEM_MODULES:
DEBUG_INFO("IOCTL_VALIDATE_SYSTEM_MODULES Received");
/*
* Currently the validation is buggy, once the validation is better will
* probably bugcheck the system.
@ -429,13 +473,15 @@ DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
break;
default:
DEBUG_ERROR("Invalid IOCTL passed to driver: %lx",
DEBUG_WARNING("Invalid IOCTL passed to driver: %lx",
stack_location->Parameters.DeviceIoControl.IoControlCode);
status = STATUS_INVALID_PARAMETER;
break;
}
end:
DEBUG_VERBOSE("Completing IRP with status %x", status);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
@ -448,7 +494,7 @@ _Dispatch_type_(IRP_MJ_CLOSE) NTSTATUS
UNREFERENCED_PARAMETER(DeviceObject);
DEBUG_LOG("Handle closed to DonnaAC");
DEBUG_INFO("Handle to driver closed.");
/*
* For now its fine, but this will need to be moved to our process load callbacks
@ -469,7 +515,7 @@ _Dispatch_type_(IRP_MJ_CREATE) NTSTATUS
{
PAGED_CODE();
DEBUG_LOG("Handle opened to DonnaAC");
DEBUG_INFO("Handle to driver opened.");
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;

View file

@ -255,9 +255,9 @@ PopulateWhitelistedModuleBuffer(_Inout_ PVOID Buffer, _In_ PSYSTEM_MODULES Syste
if (!module)
continue;
WHITELISTED_REGIONS region;
region.base = (UINT64)module->ImageBase;
region.end = region.base + module->ImageSize;
WHITELISTED_REGIONS region = {0};
region.base = (UINT64)module->ImageBase;
region.end = region.base + module->ImageSize;
RtlCopyMemory((UINT64)Buffer + index * sizeof(WHITELISTED_REGIONS),
&region,
@ -279,9 +279,9 @@ ValidateDriverIOCTLDispatchRegion(_In_ PDRIVER_OBJECT Driver,
if (!Modules || !Driver || !Flag || !WhitelistedRegions)
return STATUS_INVALID_PARAMETER;
UINT64 dispatch_function;
UINT64 module_base;
UINT64 module_end;
UINT64 dispatch_function = 0;
UINT64 module_base = 0;
UINT64 module_end = 0;
*Flag = TRUE;
@ -330,12 +330,8 @@ ValidateDriverIOCTLDispatchRegion(_In_ PDRIVER_OBJECT Driver,
return STATUS_SUCCESS;
}
DEBUG_LOG("name: %s, base: %p, size: %lx, dispatch: %llx, type: %lx",
system_module->FullPathName,
system_module->ImageBase,
system_module->ImageSize,
dispatch_function,
Driver->DeviceObject->DeviceType);
DEBUG_WARNING("Driver with invalid dispatch routine found: %s",
system_module->FullPathName);
*Flag = FALSE;
return STATUS_SUCCESS;
@ -400,7 +396,7 @@ EnumerateInvalidDrivers(_In_ PINVALID_DRIVERS_HEAD InvalidDriversHead)
while (entry != NULL)
{
DEBUG_LOG("Invalid Driver: %wZ", entry->driver->DriverName);
DEBUG_VERBOSE("Invalid Driver: %wZ", entry->driver->DriverName);
entry = entry->next;
}
}
@ -432,9 +428,10 @@ ValidateDriverObjectHasBackingModule(_In_ PSYSTEM_MODULES ModuleInformation,
}
}
DEBUG_LOG("invalid driver found");
*Result = FALSE;
DEBUG_WARNING("Driver found with no backing system image at address: %llx",
(UINT64)DriverObject->DriverStart);
*Result = FALSE;
return STATUS_SUCCESS;
}
@ -447,16 +444,19 @@ GetSystemModuleInformation(_Out_ PSYSTEM_MODULES ModuleInformation)
if (!ModuleInformation)
return STATUS_INVALID_PARAMETER;
ULONG size = 0;
ULONG size = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
/*
* query system module information without an output buffer to get
* number of bytes required to store all module info structures
*/
if (!NT_SUCCESS(RtlQueryModuleInformation(&size, sizeof(RTL_MODULE_EXTENDED_INFO), NULL)))
status = RtlQueryModuleInformation(&size, sizeof(RTL_MODULE_EXTENDED_INFO), NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to query module information");
return STATUS_ABANDONED;
DEBUG_ERROR("RtlQueryModuleInformation failed with status %x", status);
return status;
}
/* Allocate a pool equal to the output size of RtlQueryModuleInformation */
@ -470,10 +470,12 @@ GetSystemModuleInformation(_Out_ PSYSTEM_MODULES ModuleInformation)
}
/* Query the modules again this time passing a pointer to the allocated buffer */
if (!NT_SUCCESS(RtlQueryModuleInformation(
&size, sizeof(RTL_MODULE_EXTENDED_INFO), driver_information)))
status =
RtlQueryModuleInformation(&size, sizeof(RTL_MODULE_EXTENDED_INFO), driver_information);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed lolz");
DEBUG_ERROR("RtlQueryModuleInformation 2 failed with status %x", status);
ExFreePoolWithTag(driver_information, SYSTEM_MODULES_POOL);
return STATUS_ABANDONED;
}
@ -481,7 +483,7 @@ GetSystemModuleInformation(_Out_ PSYSTEM_MODULES ModuleInformation)
ModuleInformation->address = driver_information;
ModuleInformation->module_count = size / sizeof(RTL_MODULE_EXTENDED_INFO);
return STATUS_SUCCESS;
return status;
}
_IRQL_requires_max_(APC_LEVEL)
@ -497,28 +499,34 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES SystemModules,
if (!SystemModules || !InvalidDriverListHead)
return STATUS_INVALID_PARAMETER;
HANDLE handle = NULL;
OBJECT_ATTRIBUTES attributes = {0};
PVOID directory = {0};
UNICODE_STRING directory_name = {0};
NTSTATUS status = STATUS_ABANDONED;
HANDLE handle = NULL;
OBJECT_ATTRIBUTES attributes = {0};
PVOID directory = {0};
UNICODE_STRING directory_name = {0};
PVOID whitelisted_regions_buffer = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
POBJECT_DIRECTORY directory_object = NULL;
RtlInitUnicodeString(&directory_name, L"\\Driver");
InitializeObjectAttributes(&attributes, &directory_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(ZwOpenDirectoryObject(&handle, DIRECTORY_ALL_ACCESS, &attributes)))
status = ZwOpenDirectoryObject(&handle, DIRECTORY_ALL_ACCESS, &attributes);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to query directory object");
return STATUS_ABANDONED;
DEBUG_ERROR("ZwOpenDirectoryObject failed with status %x", status);
return status;
}
if (!NT_SUCCESS(ObReferenceObjectByHandle(
handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &directory, NULL)))
status = ObReferenceObjectByHandle(
handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &directory, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to reference directory by handle");
DEBUG_ERROR("ObReferenceObjectByHandle failed with status %x", status);
ZwClose(handle);
return STATUS_ABANDONED;
return status;
}
/*
@ -534,11 +542,11 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES SystemModules,
* accessed quickly
*/
POBJECT_DIRECTORY directory_object = (POBJECT_DIRECTORY)directory;
directory_object = (POBJECT_DIRECTORY)directory;
ExAcquirePushLockExclusiveEx(&directory_object->Lock, NULL);
PVOID whitelisted_regions_buffer =
whitelisted_regions_buffer =
ExAllocatePool2(POOL_FLAG_NON_PAGED,
WHITELISTED_MODULE_COUNT * MODULE_MAX_STRING_SIZE,
WHITELISTED_MODULE_TAG);
@ -550,13 +558,13 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES SystemModules,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PopulateWhiteListedBuffer failed with status %x", status);
DEBUG_ERROR("PopulateWhitelistedModuleBuffer failed with status %x", status);
goto end;
}
for (INT i = 0; i < NUMBER_HASH_BUCKETS; i++)
for (INT index = 0; index < NUMBER_HASH_BUCKETS; index++)
{
POBJECT_DIRECTORY_ENTRY entry = directory_object->HashBuckets[i];
POBJECT_DIRECTORY_ENTRY entry = directory_object->HashBuckets[index];
if (!entry)
continue;
@ -570,14 +578,15 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES SystemModules,
/* validate driver has backing module */
if (!NT_SUCCESS(ValidateDriverObjectHasBackingModule(
SystemModules, current_driver, &flag)))
status = ValidateDriverObjectHasBackingModule(
SystemModules, current_driver, &flag);
if (!NT_SUCCESS(status))
{
DEBUG_LOG("Error validating driver object");
ExReleasePushLockExclusiveEx(&directory_object->Lock, 0);
ObDereferenceObject(directory);
ZwClose(handle);
return STATUS_ABANDONED;
DEBUG_ERROR(
"ValidateDriverObjectHasBackingModule failed with status %x",
status);
goto end;
}
if (!flag)
@ -595,17 +604,14 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES SystemModules,
/* validate drivers IOCTL dispatch routines */
if (!NT_SUCCESS(ValidateDriverIOCTLDispatchRegion(
current_driver,
SystemModules,
(PWHITELISTED_REGIONS)whitelisted_regions_buffer,
&flag)))
status = ValidateDriverIOCTLDispatchRegion(
current_driver, SystemModules, whitelisted_regions_buffer, &flag);
if (!NT_SUCCESS(status))
{
DEBUG_LOG("Error validating drivers IOCTL routines");
ExReleasePushLockExclusiveEx(&directory_object->Lock, 0);
ObDereferenceObject(directory);
ZwClose(handle);
return STATUS_ABANDONED;
DEBUG_ERROR("ValidateDriverIOCTLDispatchRegion failed with status %x",
status);
goto end;
}
if (!flag)
@ -641,10 +647,12 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
PVOID buffer = NULL;
ULONG buffer_size = 0;
SYSTEM_MODULES system_modules = {0};
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID buffer = NULL;
ULONG buffer_size = 0;
SYSTEM_MODULES system_modules = {0};
MODULE_VALIDATION_FAILURE_HEADER header = {0};
PINVALID_DRIVERS_HEAD head = NULL;
/* Fix annoying visual studio linting error */
RtlZeroMemory(&system_modules, sizeof(SYSTEM_MODULES));
@ -653,17 +661,17 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Error retriving system module information");
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
return status;
}
PINVALID_DRIVERS_HEAD head = ExAllocatePool2(
head = ExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(INVALID_DRIVERS_HEAD), INVALID_DRIVER_LIST_HEAD_POOL);
if (!head)
{
ExFreePoolWithTag(system_modules.address, SYSTEM_MODULES_POOL);
return STATUS_ABANDONED;
return STATUS_MEMORY_NOT_ALLOCATED;
}
/*
@ -674,22 +682,21 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
InitDriverList(head);
if (!NT_SUCCESS(ValidateDriverObjects(&system_modules, head)))
status = ValidateDriverObjects(&system_modules, head);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate driver objects");
status = STATUS_ABANDONED;
DEBUG_ERROR("ValidateDriverObjects failed with status %x", status);
goto end;
}
MODULE_VALIDATION_FAILURE_HEADER header = {0};
header.module_count = head->count >= MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT
? MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT
: head->count;
if (head->count > 0)
{
DEBUG_LOG("found INVALID drivers with count: %i", head->count);
DEBUG_VERBOSE("System has an invalid driver count of: %i", head->count);
buffer_size =
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
@ -718,10 +725,10 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
RtlCopyMemory(buffer, &header, sizeof(MODULE_VALIDATION_FAILURE_HEADER));
for (INT i = 0; i < head->count; i++)
for (INT index = 0; index < head->count; index++)
{
/* make sure we free any non reported modules */
if (i >= MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT)
if (index >= MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT)
{
RemoveInvalidDriverFromList(head);
continue;
@ -743,11 +750,11 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
/* still continue if we fail to get the driver name */
if (!NT_SUCCESS(status))
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with statsu %x",
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x",
status);
RtlCopyMemory((UINT64)buffer + sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
i * sizeof(MODULE_VALIDATION_FAILURE),
index * sizeof(MODULE_VALIDATION_FAILURE),
&report,
sizeof(MODULE_VALIDATION_FAILURE));
@ -764,7 +771,7 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
}
else
{
DEBUG_LOG("No INVALID drivers found :)");
DEBUG_INFO("Found no invalid drivers on the system.");
}
end:
@ -805,6 +812,9 @@ IsInstructionPointerInInvalidRegion(_In_ UINT64 RIP,
return STATUS_SUCCESS;
}
/*
* todo: rename this to analyse stackwalk or something
*/
STATIC
NTSTATUS
AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules, _Inout_ PIRP Irp)
@ -814,6 +824,8 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules,
if (!NmiContext || !SystemModules)
return STATUS_INVALID_PARAMETER;
NTSTATUS status = STATUS_UNSUCCESSFUL;
for (INT core = 0; core < NmiContext->core_count; core++)
{
PNMI_CORE_CONTEXT context =
@ -828,7 +840,8 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate output buffer.");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x",
status);
return status;
}
@ -850,31 +863,37 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules,
(PNMI_CALLBACK_DATA)((uintptr_t)NmiContext->thread_data_pool +
core * sizeof(NMI_CALLBACK_DATA));
DEBUG_LOG("cpu number: %i callback count: %i", core, context->nmi_callbacks_run);
DEBUG_VERBOSE("Analysing Nmi Data for: cpu number: %i callback count: %i",
core,
context->nmi_callbacks_run);
/* Walk the stack */
for (INT frame = 0; frame < thread_data->num_frames_captured; frame++)
{
BOOLEAN flag;
BOOLEAN flag = TRUE;
DWORD64 stack_frame =
*(DWORD64*)(((uintptr_t)NmiContext->stack_frames +
thread_data->stack_frames_offset + frame * sizeof(PVOID)));
if (!NT_SUCCESS(IsInstructionPointerInInvalidRegion(
stack_frame, SystemModules, &flag)))
status =
IsInstructionPointerInInvalidRegion(stack_frame, SystemModules, &flag);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("errro checking RIP for current stack address");
DEBUG_ERROR(
"IsInstructionPointerInInvalidRegion failed with status %x",
status);
continue;
}
if (flag == FALSE)
{
NTSTATUS status =
ValidateIrpOutputBuffer(Irp, sizeof(NMI_CALLBACK_FAILURE));
status = ValidateIrpOutputBuffer(Irp, sizeof(NMI_CALLBACK_FAILURE));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate output buffer.");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x",
status);
return status;
}
@ -962,6 +981,8 @@ NmiCallback(_Inout_opt_ PVOID Context, _In_ BOOLEAN Handled)
return TRUE;
}
#define NMI_DELAY_TIME 100 * 10000
STATIC
NTSTATUS
LaunchNonMaskableInterrupt(_Inout_ PNMI_CONTEXT NmiContext)
@ -999,7 +1020,7 @@ LaunchNonMaskableInterrupt(_Inout_ PNMI_CONTEXT NmiContext)
}
LARGE_INTEGER delay = {0};
delay.QuadPart -= 100 * 10000;
delay.QuadPart -= NMI_DELAY_TIME;
for (ULONG core = 0; core < NmiContext->core_count; core++)
{
@ -1025,7 +1046,7 @@ HandleNmiIOCTL(_Inout_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
SYSTEM_MODULES system_modules = {0};
NMI_CONTEXT nmi_context = {0};
PVOID callback_handle = NULL;
@ -1047,9 +1068,9 @@ HandleNmiIOCTL(_Inout_ PIRP Irp)
if (!callback_handle)
{
DEBUG_ERROR("KeRegisterNmiCallback failed");
DEBUG_ERROR("KeRegisterNmiCallback failed with no status.");
ExFreePoolWithTag(nmi_context.nmi_core_context, NMI_CONTEXT_POOL);
return STATUS_ABANDONED;
return STATUS_UNSUCCESSFUL;
}
/*
@ -1060,14 +1081,14 @@ HandleNmiIOCTL(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Error retriving system module information");
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
return status;
}
status = LaunchNonMaskableInterrupt(&nmi_context);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Error running NMI callbacks");
DEBUG_ERROR("LaunchNonMaskableInterrupt failed with status %x", status);
if (system_modules.address)
ExFreePoolWithTag(system_modules.address, SYSTEM_MODULES_POOL);
@ -1077,7 +1098,7 @@ HandleNmiIOCTL(_Inout_ PIRP Irp)
status = AnalyseNmiData(&nmi_context, &system_modules, Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("Error analysing nmi data");
DEBUG_ERROR("AnalyseNmiData failed with status %x", status);
if (system_modules.address)
ExFreePoolWithTag(system_modules.address, SYSTEM_MODULES_POOL);
@ -1125,10 +1146,10 @@ ApcKernelRoutine(_In_ PRKAPC Apc,
{
PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID buffer = NULL;
INT frames_captured = 0;
UINT64 stack_frame = 0;
NTSTATUS status = STATUS_ABANDONED;
BOOLEAN flag = FALSE;
PAPC_STACKWALK_CONTEXT context = NULL;
PTHREAD_LIST_ENTRY thread_list_entry = NULL;
@ -1263,7 +1284,9 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
!strcmp(process_name, "WerFault.exe"))
return;
DEBUG_LOG("Process: %s", process_name);
DEBUG_VERBOSE("Validating thread: %llx, process name: %s via kernel APC stackwalk.",
ThreadListEntry->thread,
process_name);
if (ThreadListEntry->thread == KeGetCurrentThread() || !ThreadListEntry->thread)
return;
@ -1299,31 +1322,6 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
if (!apc)
return;
/*
* KTHREAD->State values:
*
* 0 is INITIALIZED;
* 1 is READY;
* 2 is RUNNING;
* 3 is STANDBY;
* 4 is TERMINATED;
* 5 is WAIT;
* 6 is TRANSITION.
*
* Since we are unsafely enumerating the threads linked list, it's best just
* to make sure we don't queue an APC to a terminated thread. We also check after
* we've allocated memory for the apc to ensure the window between queuing our APC
* and checking the thread state is as small as possible.
*/
// if (*state == THREAD_STATE_TERMINATED || THREAD_STATE_INIT)
//{
// ExFreePoolWithTag(apc, POOL_TAG_APC);
// return;
// }
DEBUG_LOG("Apc: %llx", (UINT64)apc);
KeInitializeApc(apc,
ThreadListEntry->thread,
OriginalApcEnvironment,
@ -1337,7 +1335,7 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
if (!apc_status)
{
DEBUG_ERROR("KeInsertQueueApc failed");
DEBUG_ERROR("KeInsertQueueApc failed with no status.");
ExFreePoolWithTag(apc, POOL_TAG_APC);
return;
}
@ -1359,7 +1357,7 @@ ValidateThreadsViaKernelApc()
{
PAGED_CODE();
NTSTATUS status;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAPC_STACKWALK_CONTEXT context = NULL;
/* First, ensure we dont already have an ongoing operation */
@ -1367,7 +1365,7 @@ ValidateThreadsViaKernelApc()
if (context)
{
DEBUG_LOG("Existing APC_STACKWALK operation already in progress.");
DEBUG_WARNING("Existing APC_STACKWALK operation already in progress.");
return STATUS_ALREADY_INITIALIZED;
}
@ -1390,6 +1388,7 @@ ValidateThreadsViaKernelApc()
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
ExFreePoolWithTag(context->modules, POOL_TAG_APC);
ExFreePoolWithTag(context, POOL_TAG_APC);
return STATUS_MEMORY_NOT_ALLOCATED;
@ -1399,15 +1398,14 @@ ValidateThreadsViaKernelApc()
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InsertApcContext failed with status %x", status);
ExFreePoolWithTag(context->modules, POOL_TAG_APC);
ExFreePoolWithTag(context, POOL_TAG_APC);
return status;
}
context->header.allocation_in_progress = TRUE;
EnumerateThreadListWithCallbackRoutine(ValidateThreadViaKernelApcCallback, context);
context->header.allocation_in_progress = FALSE;
return status;
@ -1434,12 +1432,12 @@ LaunchInterProcessInterrupt(_In_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS status = STATUS_UNSUCCESSFUL;
SYSTEM_MODULES system_modules = {0};
NMI_CONTEXT ipi_context = {0};
PVOID callback_handle = NULL;
DEBUG_LOG("Launching interprocess interrupt");
DEBUG_VERBOSE("Launching Inter Process Interrupt");
ipi_context.core_count = KeQueryActiveProcessorCountEx(0);
ipi_context.nmi_core_context =
@ -1478,7 +1476,7 @@ LaunchInterProcessInterrupt(_In_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Error retriving system module information");
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
goto end;
}
@ -1491,7 +1489,7 @@ LaunchInterProcessInterrupt(_In_ PIRP Irp)
status = AnalyseNmiData(&ipi_context, &system_modules, Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("Error analysing ipi interrupt data");
DEBUG_ERROR("AnalyseNmiData failed with status %x", status);
end:
if (system_modules.address)

View file

@ -319,7 +319,7 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
if (process == NULL)
break;
DEBUG_LOG("Process: %llx", (UINT64)process);
DEBUG_VERBOSE("Found process via pt walk: %llx", (UINT64)process);
address_list = (PUINT64)Context->process_buffer;
@ -438,9 +438,9 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
physical_memory_ranges = MmGetPhysicalMemoryRangesEx2(NULL, NULL);
if (physical_memory_ranges == NULL)
if (!physical_memory_ranges)
{
DEBUG_ERROR("LOL stupid cunt not working");
DEBUG_ERROR("MmGetPhysicalMemoryRangesEx2 failed with no status.");
return;
}
@ -596,7 +596,7 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
}
}
DEBUG_LOG("Finished scanning memory");
DEBUG_VERBOSE("Finished scanning memory for unlinked processes.");
}
STATIC
@ -656,7 +656,7 @@ FindUnlinkedProcesses()
if (context.process_count == 0)
{
DEBUG_ERROR("Failed to get process count");
DEBUG_ERROR("IncrementProcessCounter failed with no status.");
return STATUS_ABANDONED;
}
@ -678,13 +678,16 @@ FindUnlinkedProcesses()
if (allocation_address[index] == NULL)
continue;
UINT64 allocation = (UINT64)allocation_address[index] - OBJECT_HEADER_SIZE;
/*
* It's important to remember that at this point it is still not guaranteed that we
* have found 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_WARNING("Potentially found an unlinked process allocation at address: %llx",
allocation);
report_buffer = ExAllocatePool2(
POOL_FLAG_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
@ -694,9 +697,8 @@ FindUnlinkedProcesses()
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
RtlCopyMemory(report_buffer->process,
(UINT64)allocation_address[index] - OBJECT_HEADER_SIZE,
REPORT_INVALID_PROCESS_BUFFER_SIZE);
RtlCopyMemory(
report_buffer->process, allocation, REPORT_INVALID_PROCESS_BUFFER_SIZE);
InsertReportToQueue(report_buffer);
}
@ -718,7 +720,7 @@ NTSTATUS
EnumerateBigPoolAllocations()
{
ULONG return_length = 0;
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSYSTEM_BIGPOOL_ENTRY entry = NULL;
SYSTEM_BIGPOOL_INFORMATION pool_information = {0};
PSYSTEM_BIGPOOL_INFORMATION pool_entries = NULL;
@ -727,8 +729,8 @@ EnumerateBigPoolAllocations()
if (!pZwQuerySystemInformation)
{
DEBUG_ERROR("MmGetSystemRoutineAddress failed.");
return STATUS_ABANDONED;
DEBUG_ERROR("MmGetSystemRoutineAddress failed with no status.");
return status;
}
status = pZwQuerySystemInformation(SYSTEM_BIGPOOL_INFORMATION_ID,

View file

@ -45,7 +45,7 @@ InitialiseGlobalReportQueue(_Out_ PBOOLEAN Status)
// PQUEUE_HEAD QueueCreate()
//{
// PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_HEAD ),
//QUEUE_POOL_TAG );
// QUEUE_POOL_TAG );
//
// if ( !head )
// return NULL;
@ -147,7 +147,8 @@ FreeGlobalReportQueueObjects()
{
ExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop(&report_queue_config.head);
DEBUG_LOG("Queu Unload Remaining Entries: %i", report_queue_config.head.entries);
DEBUG_VERBOSE("Unloading report queue. Entries remaining: %i",
report_queue_config.head.entries);
}
end:
@ -169,7 +170,7 @@ NTSTATUS
HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp)
{
INT count = 0;
NTSTATUS status = STATUS_ABANDONED;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID report = NULL;
SIZE_T total_size = 0;
PVOID report_buffer = NULL;
@ -186,7 +187,7 @@ HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate Irp output buffer");
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
KeReleaseGuardedMutex(&report_queue_config.lock);
return status;
}
@ -204,7 +205,7 @@ HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp)
if (report == NULL)
{
DEBUG_LOG("callback report queue is empty, returning");
DEBUG_VERBOSE("Callback report queue is empty. No reports to be sent to usermode.");
goto end;
}
@ -292,7 +293,7 @@ end:
if (report_buffer)
ExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
DEBUG_LOG("Moved all reports into the IRP, sending !");
DEBUG_VERBOSE("All reports moved into the IRP, sending to usermode.");
return STATUS_SUCCESS;
}

View file

@ -26,7 +26,7 @@ _IRQL_always_function_min_(DISPATCH_LEVEL) STATIC VOID
_Inout_opt_ PVOID Context)
{
UINT32 thread_id = 0;
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
if (!Context || context->finished == TRUE)
return;
@ -93,9 +93,9 @@ ValidateKPCRBThreads()
context.current_kpcrb_thread = *(UINT64*)(kprcb + KPCRB_CURRENT_THREAD);
DEBUG_LOG("Proc number: %lx, Current thread: %llx",
processor_index,
context.current_kpcrb_thread);
DEBUG_VERBOSE("Proc number: %lx, Current thread: %llx",
processor_index,
context.current_kpcrb_thread);
if (!context.current_kpcrb_thread)
continue;
@ -103,9 +103,9 @@ ValidateKPCRBThreads()
EnumerateThreadListWithCallbackRoutine(KPRCBThreadValidationProcessCallback,
&context);
DEBUG_LOG("Found in kthread: %lx, found in pspcid: %lx",
(UINT32)context.thread_found_in_kthreadlist,
(UINT32)context.thread_found_in_pspcidtable);
DEBUG_VERBOSE("Was thread found in kthread: %lx, Was thread found in cid table: %lx",
(UINT32)context.thread_found_in_kthreadlist,
(UINT32)context.thread_found_in_pspcidtable);
if (context.current_kpcrb_thread == FALSE ||
context.thread_found_in_pspcidtable == FALSE)
@ -153,7 +153,8 @@ _IRQL_always_function_min_(DISPATCH_LEVEL) STATIC VOID
if (apc_state->Process == protected_process)
{
DEBUG_LOG("Program attached to notepad: %llx", (UINT64)ThreadListEntry->thread);
DEBUG_WARNING("Thread is attached to our protected process: %llx",
(UINT64)ThreadListEntry->thread);
PATTACH_PROCESS_REPORT report = ExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);

View file

@ -1,11 +0,0 @@
#include "version.h"
NTSTATUS
PopulateGlobalOffsets()
{
NTSTATUS status = STATUS_SUCCESS;
return status;
}

View file

@ -1,34 +0,0 @@
#ifndef VERSION_H
#define VERSION_H
#include <ntddk.h>
extern UINT32 KTHREAD_STACK_BASE_OFFSET = 0;
extern UINT32 KTHREAD_STACK_LIMIT_OFFSET = 0;
extern UINT32 KTHREAD_THREADLIST_OFFSET = 0;
extern UINT32 KTHREAD_APC_STATE_OFFSET = 0;
extern UINT32 KTHREAD_START_ADDRESS_OFFSET = 0;
extern UINT32 KTHREAD_MISC_FLAGS_OFFSET = 0;
extern UINT32 KTHREAD_WAIT_IRQL_OFFSET = 0;
extern UINT32 KTHREAD_PREVIOUS_MODE_OFFSET = 0;
extern UINT32 KTHREAD_STATE_OFFSET = 0;
extern UINT32 KTHREAD_MISC_FLAGS_APC_QUEUEABLE = 0;
extern UINT32 KTHREAD_MISC_FLAGS_ALERTABLE = 0;
extern UINT32 EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET = 0;
extern UINT32 EPROCESS_VAD_ROOT_OFFSET = 0;
extern UINT32 EPROCESS_OBJECT_TABLE_OFFSET = 0;
extern UINT32 EPROCESS_IMAGE_NAME_OFFSET = 0;
extern UINT32 EPROCESS_PEB_OFFSET = 0;
extern UINT32 KPROCESS_THREADLIST_OFFSET = 0;
extern UINT32 KPROCESS_DIRECTORY_TABLE_BASE_OFFSET = 0;
extern UINT32 OBJECT_HEADER_TYPE_INDEX_OFFSET = 0;
extern UINT32 POOL_HEADER_BLOCK_SIZE_OFFSET = 0;
extern UINT32 POOL_HEADER_TAG_OFFSET = 0;
extern UINT32 KPCRB_CURRENT_THREAD_OFFSET = 0;
#endif