Aktualizacja: 2025-10-02 01:08:10

This commit is contained in:
wesmar
2025-10-02 01:08:10 +02:00
parent 0ccfead131
commit de135c0487
9 changed files with 1327 additions and 170 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include "SessionManager.h"
#include "kvcDrv.h"
#include "OffsetFinder.h"
#include "TrustedInstallerIntegrator.h"
@@ -107,6 +108,14 @@ public:
bool UnprotectBySigner(const std::wstring& signerName) noexcept;
bool ListProcessesBySigner(const std::wstring& signerName) noexcept;
// Session state restoration
bool RestoreProtectionBySigner(const std::wstring& signerName) noexcept;
bool RestoreAllProtection() noexcept;
void ShowSessionHistory() noexcept;
bool SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept;
SessionManager m_sessionMgr;
bool UnprotectAllProcesses() noexcept;
bool UnprotectMultipleProcesses(const std::vector<std::wstring>& targets) noexcept;
@@ -227,7 +236,6 @@ private:
// Internal kernel process management (implementation details)
std::optional<ULONG_PTR> GetInitialSystemProcessAddress() noexcept;
bool SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept;
// Process pattern matching with regex support
std::vector<ProcessMatch> FindProcessesByName(const std::wstring& pattern) noexcept;

View File

@@ -847,107 +847,121 @@ bool Controller::SetProcessProtection(DWORD pid, const std::wstring& protectionL
// MASS PROTECTION OPERATIONS
// ============================================================================
bool Controller::UnprotectAllProcesses() noexcept {
bool Controller::UnprotectAllProcesses() noexcept
{
if (!BeginDriverSession()) {
EndDriverSession(true);
return false;
}
auto processes = GetProcessList();
DWORD totalCount = 0;
DWORD successCount = 0;
INFO(L"Starting mass unprotection of all protected processes...");
// Group processes by signer type
std::unordered_map<std::wstring, std::vector<ProcessEntry>> groupedProcesses;
for (const auto& entry : processes) {
if (entry.ProtectionLevel > 0) {
totalCount++;
if (SetProcessProtection(entry.KernelAddress, 0)) {
successCount++;
SUCCESS(L"Removed protection from PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
} else {
ERROR(L"Failed to remove protection from PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
}
if (g_interrupted) {
INFO(L"Mass unprotection interrupted by user");
break;
}
for (const auto& entry : processes)
{
if (entry.ProtectionLevel > 0)
{
std::wstring signerName = Utils::GetSignerTypeAsString(entry.SignerType);
groupedProcesses[signerName].push_back(entry);
}
}
if (totalCount == 0) {
if (groupedProcesses.empty())
{
INFO(L"No protected processes found");
} else {
INFO(L"Mass unprotection completed: %d/%d processes successfully unprotected", successCount, totalCount);
}
EndDriverSession(true);
return successCount == totalCount;
}
bool Controller::UnprotectMultipleProcesses(const std::vector<std::wstring>& targets) noexcept {
if (targets.empty()) {
ERROR(L"No targets specified for batch unprotection");
EndDriverSession(true);
return false;
}
INFO(L"Starting mass unprotection (%zu signer groups)", groupedProcesses.size());
DWORD totalSuccess = 0;
DWORD totalProcessed = 0;
// Process each signer group
for (const auto& [signerName, processes] : groupedProcesses)
{
INFO(L"Processing signer group: %s (%zu processes)", signerName.c_str(), processes.size());
// Save state before modification
m_sessionMgr.SaveUnprotectOperation(signerName, processes);
// Unprotect all in this group
for (const auto& entry : processes)
{
totalProcessed++;
if (SetProcessProtection(entry.KernelAddress, 0))
{
totalSuccess++;
SUCCESS(L"Removed protection from PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
}
else
{
ERROR(L"Failed to remove protection from PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
}
if (g_interrupted)
{
INFO(L"Mass unprotection interrupted by user");
EndDriverSession(true);
return false;
}
}
}
INFO(L"Mass unprotection completed: %d/%d processes successfully unprotected", totalSuccess, totalProcessed);
EndDriverSession(true);
return totalSuccess > 0;
}
// ControllerProcessOperations.cpp
// DODAJ tę funkcję (po funkcji UnprotectAllProcesses, przed końcem pliku):
bool Controller::UnprotectMultipleProcesses(const std::vector<std::wstring>& targets) noexcept
{
if (targets.empty())
return false;
if (!BeginDriverSession()) {
EndDriverSession(true);
return false;
}
DWORD successCount = 0;
DWORD totalCount = static_cast<DWORD>(targets.size());
INFO(L"Starting batch unprotection of %d targets...", totalCount);
for (const auto& target : targets) {
for (const auto& target : targets)
{
bool result = false;
// Check if target is numeric (PID)
if (Utils::IsNumeric(target)) {
auto pid = Utils::ParsePid(target);
if (pid) {
auto kernelAddr = GetCachedKernelAddress(pid.value());
if (kernelAddr) {
auto currentProtection = GetProcessProtection(kernelAddr.value());
if (currentProtection && currentProtection.value() > 0) {
if (SetProcessProtection(kernelAddr.value(), 0)) {
SUCCESS(L"Removed protection from PID %d", pid.value());
result = true;
} else {
ERROR(L"Failed to remove protection from PID %d", pid.value());
}
} else {
INFO(L"PID %d is not protected", pid.value());
result = true; // Consider this a success
bool isNumeric = true;
for (wchar_t ch : target)
{
if (!iswdigit(ch))
{
isNumeric = false;
break;
}
}
} else {
ERROR(L"Invalid PID format: %s", target.c_str());
if (isNumeric)
{
try {
DWORD pid = std::stoul(target);
result = UnprotectProcess(pid);
}
} else {
// Target is process name
auto matches = FindProcessesByName(target);
if (matches.size() == 1) {
auto match = matches[0];
auto currentProtection = GetProcessProtection(match.KernelAddress);
if (currentProtection && currentProtection.value() > 0) {
if (SetProcessProtection(match.KernelAddress, 0)) {
SUCCESS(L"Removed protection from %s (PID %d)", match.ProcessName.c_str(), match.Pid);
result = true;
} else {
ERROR(L"Failed to remove protection from %s (PID %d)", match.ProcessName.c_str(), match.Pid);
catch (...) {
ERROR(L"Invalid PID: %s", target.c_str());
}
} else {
INFO(L"%s (PID %d) is not protected", match.ProcessName.c_str(), match.Pid);
result = true; // Consider this a success
}
} else {
ERROR(L"Could not resolve process name: %s", target.c_str());
}
else
{
result = UnprotectProcessByName(target);
}
if (result) successCount++;
@@ -973,15 +987,27 @@ bool Controller::UnprotectBySigner(const std::wstring& signerName) noexcept {
}
auto processes = GetProcessList();
std::vector<ProcessEntry> affectedProcesses;
DWORD totalCount = 0;
DWORD successCount = 0;
INFO(L"Starting batch unprotection of processes signed by: %s", signerName.c_str());
// Collect processes that will be affected
for (const auto& entry : processes) {
if (entry.ProtectionLevel > 0 && entry.SignerType == signerType.value()) {
affectedProcesses.push_back(entry);
totalCount++;
}
}
// Save state before modification
if (!affectedProcesses.empty()) {
m_sessionMgr.SaveUnprotectOperation(signerName, affectedProcesses);
}
// POPRAWIONE: Usunięte błędne zagnieżdżenie
for (const auto& entry : affectedProcesses) {
if (SetProcessProtection(entry.KernelAddress, 0)) {
successCount++;
SUCCESS(L"Removed protection from PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
@@ -994,13 +1020,13 @@ bool Controller::UnprotectBySigner(const std::wstring& signerName) noexcept {
break;
}
}
}
if (totalCount == 0) {
INFO(L"No protected processes found with signer: %s", signerName.c_str());
} else {
INFO(L"Batch unprotection completed: %d/%d processes successfully unprotected", successCount, totalCount);
}
EndDriverSession(true);
return successCount > 0;
}
@@ -1121,3 +1147,35 @@ bool Controller::SetProcessProtectionByName(const std::wstring& processName, con
return SetProcessProtection(match->Pid, protectionLevel, signerType);
}
// Session state restoration operations
bool Controller::RestoreProtectionBySigner(const std::wstring& signerName) noexcept
{
if (!BeginDriverSession()) {
EndDriverSession(true);
return false;
}
bool result = m_sessionMgr.RestoreBySigner(signerName, this);
EndDriverSession(true);
return result;
}
bool Controller::RestoreAllProtection() noexcept
{
if (!BeginDriverSession()) {
EndDriverSession(true);
return false;
}
bool result = m_sessionMgr.RestoreAll(this);
EndDriverSession(true);
return result;
}
void Controller::ShowSessionHistory() noexcept
{
m_sessionMgr.ShowHistory();
}

View File

@@ -38,6 +38,7 @@ void HelpSystem::PrintUsage(std::wstring_view programName) noexcept
PrintBasicCommands();
PrintProcessTerminationCommands();
PrintProtectionCommands();
PrintSessionManagement();
PrintSystemCommands();
PrintBrowserCommands();
PrintDefenderCommands();
@@ -141,6 +142,10 @@ void HelpSystem::PrintProtectionCommands() noexcept
PrintCommandLine(L"unprotect <PID|process_name>", L"Remove protection from specific process");
PrintCommandLine(L"unprotect all", L"Remove protection from ALL processes");
PrintCommandLine(L"unprotect <PID1,PID2,PID3>", L"Remove protection from multiple processes");
PrintCommandLine(L"restore <signer_name>", L"Restore protection for specific signer group");
PrintCommandLine(L"restore all", L"Restore all saved protection states");
PrintCommandLine(L"history", L"Show saved session history (max 16 sessions)");
PrintCommandLine(L"cleanup-sessions", L"Delete all sessions except current");
std::wcout << L"\n";
}
@@ -181,6 +186,18 @@ void HelpSystem::PrintSecurityEngineCommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintSessionManagement() noexcept
{
PrintSectionHeader(L"Session Management System");
std::wcout << L" - Automatic boot detection and session tracking (max 16 sessions)\n";
std::wcout << L" - Each 'unprotect' operation saves process states grouped by signer\n";
std::wcout << L" - 'restore' commands reapply protection from saved session state\n";
std::wcout << L" - Session history persists across reboots until limit reached\n";
std::wcout << L" - Oldest sessions auto-deleted when exceeding 16 session limit\n";
std::wcout << L" - Manual cleanup available via 'cleanup-sessions' command\n";
std::wcout << L" - Status tracking: UNPROTECTED (after unprotect) -> RESTORED (after restore)\n\n";
}
void HelpSystem::PrintBrowserCommands() noexcept
{
PrintSectionHeader(L"Browser Password Extraction Commands");
@@ -330,6 +347,14 @@ void HelpSystem::PrintUsageExamples(std::wstring_view programName) noexcept
printLine(L"unprotect lsass", L"Remove protection from LSASS");
printLine(L"unprotect 1,2,3,lsass", L"Batch unprotect multiple targets");
// Session restoration examples
printLine(L"unprotect Antimalware", L"Remove protection from all Antimalware processes");
printLine(L"unprotect all", L"Remove protection from ALL processes (grouped by signer)");
printLine(L"history", L"Show saved sessions (max 16, with status tracking)");
printLine(L"restore Antimalware", L"Restore protection for Antimalware group");
printLine(L"restore all", L"Restore all saved protection states from current session");
printLine(L"cleanup-sessions", L"Delete all old sessions (keep only current)");
// Process termination examples
printLine(L"kill 1234", L"Terminate process with PID 1234");
printLine(L"kill total", L"Terminate Total Commander by name");

View File

@@ -29,6 +29,7 @@ public:
static void PrintTechnicalFeatures() noexcept;
static void PrintDefenderNotes() noexcept;
static void PrintSecurityEngineCommands() noexcept;
static void PrintSessionManagement() noexcept;
static void PrintStickyKeysInfo() noexcept;
static void PrintUndumpableProcesses() noexcept;
static void PrintUsageExamples(std::wstring_view programName) noexcept;

View File

@@ -204,6 +204,25 @@ int wmain(int argc, wchar_t* argv[])
{
INFO(L"Uninstalling Kernel Vulnerability Capabilities Framework service...");
bool success = ServiceManager::UninstallService();
// Wyczyść całą konfigurację z rejestru
INFO(L"Cleaning up registry configuration...");
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software", 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
LONG result = RegDeleteTreeW(hKey, L"kvc");
if (result == ERROR_SUCCESS) {
SUCCESS(L"Registry configuration cleaned successfully");
}
else if (result == ERROR_FILE_NOT_FOUND) {
INFO(L"No registry configuration found to clean");
}
else {
ERROR(L"Failed to clean registry configuration: %d", result);
}
RegCloseKey(hKey);
}
return success ? 0 : 1;
}
@@ -417,7 +436,9 @@ int wmain(int argc, wchar_t* argv[])
// Process information commands with color-coded protection status output
else if (command == L"list")
{
return g_controller->ListProtectedProcesses() ? 0 : 2;
// Detect reboot and enforce session limit on first list after boot
g_controller->m_sessionMgr.DetectAndHandleReboot();
return g_controller->ListProtectedProcesses() ? 0 : 2;;
}
else if (command == L"get")
@@ -514,6 +535,7 @@ int wmain(int argc, wchar_t* argv[])
return g_controller->ClearSystemEventLogs() ? 0 : 2;
}
// Process protection commands with atomic driver operations
// Process protection commands with atomic driver operations
else if (command == L"set" || command == L"protect")
{
@@ -527,6 +549,65 @@ int wmain(int argc, wchar_t* argv[])
std::wstring level = argv[3];
std::wstring signer = argv[4];
// Handle comma-separated list of PIDs for batch operations
std::wstring targetStr(target);
if (targetStr.find(L',') != std::wstring::npos)
{
std::vector<DWORD> pids;
std::wstring current;
// Parse comma-separated PIDs with whitespace handling
for (wchar_t ch : targetStr)
{
if (ch == L',')
{
if (!current.empty())
{
if (IsNumeric(current))
{
auto pid = ParsePid(current);
if (pid) pids.push_back(pid.value());
}
current.clear();
}
}
else if (ch != L' ' && ch != L'\t')
{
current += ch;
}
}
// Last token
if (!current.empty() && IsNumeric(current))
{
auto pid = ParsePid(current);
if (pid) pids.push_back(pid.value());
}
if (pids.empty())
{
ERROR(L"No valid PIDs found in comma-separated list");
return 1;
}
// Batch operation
INFO(L"Batch %s operation: %zu processes", command.data(), pids.size());
int successCount = 0;
for (DWORD pid : pids)
{
bool result = (command == L"set") ?
g_controller->SetProcessProtection(pid, level, signer) :
g_controller->ProtectProcess(pid, level, signer);
if (result) successCount++;
}
INFO(L"Batch %s completed: %d/%zu processes", command.data(), successCount, pids.size());
return successCount == pids.size() ? 0 : 2;
}
// Single target (PID or name)
bool result = false;
if (IsNumeric(target))
@@ -624,6 +705,42 @@ int wmain(int argc, wchar_t* argv[])
}
}
// Restore process protection from saved session state
else if (command == L"restore")
{
if (argc < 3)
{
ERROR(L"Missing argument: <signer_name|all>");
return 1;
}
std::wstring_view target = argv[2];
if (target == L"all")
{
return g_controller->RestoreAllProtection() ? 0 : 2;
}
else
{
std::wstring signerName(target);
return g_controller->RestoreProtectionBySigner(signerName) ? 0 : 2;
}
}
// Display session history
else if (command == L"history")
{
g_controller->ShowSessionHistory();
return 0;
}
// Cleanup all sessions except current
else if (command == L"cleanup-sessions")
{
g_controller->m_sessionMgr.CleanupAllSessionsExceptCurrent();
return 0;
}
else if (command == L"list-signer") {
if (argc < 3) {
ERROR(L"Missing signer type argument");

View File

@@ -121,6 +121,7 @@
<ClCompile Include="Utils.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="ReportExporter.cpp" />
<ClCompile Include="SessionManager.cpp" />
<ClCompile Include="ServiceManager.cpp" />
<ClCompile Include="DefenderManager.cpp" />
<ClCompile Include="KeyboardHook.cpp" />
@@ -137,6 +138,7 @@
<ClInclude Include="kvcDrv.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="ReportExporter.h" />
<ClCompile Include="SessionManager.h" />
<ClInclude Include="ServiceManager.h" />
<ClInclude Include="KeyboardHook.h" />
<ClInclude Include="HelpSystem.h" />

876
kvc/SessionManager.cpp Normal file
View File

@@ -0,0 +1,876 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ V /| |___
|_|\_\ \_/ \____|
The **Kernel Vulnerability Capabilities (KVC)** framework represents a paradigm shift in Windows security research,
offering unprecedented access to modern Windows internals through sophisticated ring-0 operations. Originally conceived
as "Kernel Process Control," the framework has evolved to emphasize not just control, but the complete **exploitation
of kernel-level primitives** for legitimate security research and penetration testing.
KVC addresses the critical gap left by traditional forensic tools that have become obsolete in the face of modern Windows
security hardening. Where tools like ProcDump and Process Explorer fail against Protected Process Light (PPL) and Antimalware
Protected Interface (AMSI) boundaries, KVC succeeds by operating at the kernel level, manipulating the very structures
that define these protections.
-----------------------------------------------------------------------------
Author : Marek Wesołowski
Email : marek@wesolowski.eu.org
Phone : +48 607 440 283 (Tel/WhatsApp)
Date : 04-09-2025
*******************************************************************************/
// SessionManager.cpp
#include "SessionManager.h"
#include "Controller.h"
#include "Utils.h"
#include <algorithm>
#include <sstream>
#include <iomanip>
// Static cache cleared on reboot detection
static std::wstring g_cachedBootSession;
// Calculate current boot time as unique session ID
std::wstring SessionManager::CalculateBootTime() noexcept
{
FILETIME ftNow;
GetSystemTimeAsFileTime(&ftNow);
ULONGLONG currentTime = (static_cast<ULONGLONG>(ftNow.dwHighDateTime) << 32) | ftNow.dwLowDateTime;
ULONGLONG tickCount = GetTickCount64();
ULONGLONG bootTime = currentTime - (tickCount * 10000ULL);
std::wostringstream oss;
oss << bootTime;
return oss.str();
}
ULONGLONG SessionManager::GetLastBootIdFromRegistry() noexcept
{
std::wstring basePath = GetRegistryBasePath();
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return 0;
ULONGLONG lastBootId = 0;
DWORD dataSize = sizeof(ULONGLONG);
RegQueryValueExW(hKey, L"LastBootId", nullptr, nullptr, reinterpret_cast<BYTE*>(&lastBootId), &dataSize);
RegCloseKey(hKey);
return lastBootId;
}
void SessionManager::SaveLastBootId(ULONGLONG bootId) noexcept
{
std::wstring basePath = GetRegistryBasePath();
HKEY hKey = OpenOrCreateKey(basePath);
if (hKey)
{
RegSetValueExW(hKey, L"LastBootId", 0, REG_QWORD, reinterpret_cast<const BYTE*>(&bootId), sizeof(ULONGLONG));
RegCloseKey(hKey);
}
}
ULONGLONG SessionManager::GetLastTickCountFromRegistry() noexcept
{
std::wstring basePath = GetRegistryBasePath();
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return 0;
ULONGLONG lastTickCount = 0;
DWORD dataSize = sizeof(ULONGLONG);
RegQueryValueExW(hKey, L"LastTickCount", nullptr, nullptr, reinterpret_cast<BYTE*>(&lastTickCount), &dataSize);
RegCloseKey(hKey);
return lastTickCount;
}
void SessionManager::SaveLastTickCount(ULONGLONG tickCount) noexcept
{
std::wstring basePath = GetRegistryBasePath();
HKEY hKey = OpenOrCreateKey(basePath);
if (hKey)
{
RegSetValueExW(hKey, L"LastTickCount", 0, REG_QWORD, reinterpret_cast<const BYTE*>(&tickCount), sizeof(ULONGLONG));
RegCloseKey(hKey);
}
}
std::wstring SessionManager::GetCurrentBootSession() noexcept
{
if (!g_cachedBootSession.empty())
return g_cachedBootSession;
ULONGLONG lastBootId = GetLastBootIdFromRegistry();
if (lastBootId == 0)
{
// First run ever - calculate and save
std::wstring calculatedSession = CalculateBootTime();
ULONGLONG calculatedBootId = std::stoull(calculatedSession);
SaveLastBootId(calculatedBootId);
g_cachedBootSession = calculatedSession;
return g_cachedBootSession;
}
// Use LastBootId from registry as session ID
std::wostringstream oss;
oss << lastBootId;
g_cachedBootSession = oss.str();
return g_cachedBootSession;
}
void SessionManager::DetectAndHandleReboot() noexcept
{
ULONGLONG currentTick = GetTickCount64();
ULONGLONG lastTick = GetLastTickCountFromRegistry();
ULONGLONG lastBootId = GetLastBootIdFromRegistry();
if (lastBootId == 0)
{
// First run ever
std::wstring calculatedSession = CalculateBootTime();
ULONGLONG calculatedBootId = std::stoull(calculatedSession);
SaveLastBootId(calculatedBootId);
SaveLastTickCount(currentTick);
g_cachedBootSession = calculatedSession;
return;
}
// Detect reboot: tickCount decreased
if (currentTick < lastTick)
{
// New boot detected
std::wstring calculatedSession = CalculateBootTime();
ULONGLONG calculatedBootId = std::stoull(calculatedSession);
SaveLastBootId(calculatedBootId);
SaveLastTickCount(currentTick);
g_cachedBootSession = calculatedSession;
// Enforce session limit
EnforceSessionLimit(MAX_SESSIONS);
}
else
{
// Same boot - use LastBootId as session ID
SaveLastTickCount(currentTick);
std::wostringstream oss;
oss << lastBootId;
g_cachedBootSession = oss.str();
}
}
std::vector<std::wstring> SessionManager::GetAllSessionIds() noexcept
{
std::vector<std::wstring> sessionIds;
std::wstring basePath = GetRegistryBasePath() + L"\\Sessions";
HKEY hSessions;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ, &hSessions) != ERROR_SUCCESS)
return sessionIds;
DWORD index = 0;
wchar_t sessionName[256];
DWORD sessionNameSize;
while (true)
{
sessionNameSize = 256;
if (RegEnumKeyExW(hSessions, index, sessionName, &sessionNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
sessionIds.push_back(sessionName);
index++;
}
RegCloseKey(hSessions);
return sessionIds;
}
void SessionManager::EnforceSessionLimit(int maxSessions) noexcept
{
auto sessions = GetAllSessionIds();
if (static_cast<int>(sessions.size()) <= maxSessions)
return;
// Sort sessions by ID (oldest first)
std::sort(sessions.begin(), sessions.end(), [](const std::wstring& a, const std::wstring& b) {
try {
return std::stoull(a) < std::stoull(b);
} catch (...) {
return a < b;
}
});
std::wstring currentSession = GetCurrentBootSession();
std::wstring basePath = GetRegistryBasePath() + L"\\Sessions";
HKEY hSessions;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_WRITE, &hSessions) != ERROR_SUCCESS)
return;
int toDelete = static_cast<int>(sessions.size()) - maxSessions;
int deleted = 0;
for (const auto& sessionId : sessions)
{
if (deleted >= toDelete)
break;
if (sessionId != currentSession)
{
DeleteKeyRecursive(hSessions, sessionId);
DEBUG(L"Deleted old session: %s", sessionId.c_str());
deleted++;
}
}
RegCloseKey(hSessions);
if (deleted > 0)
{
INFO(L"Enforced session limit: deleted %d old sessions", deleted);
}
}
void SessionManager::CleanupAllSessionsExceptCurrent() noexcept
{
std::wstring currentSession = GetCurrentBootSession();
std::wstring basePath = GetRegistryBasePath() + L"\\Sessions";
HKEY hSessions;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ | KEY_WRITE, &hSessions) != ERROR_SUCCESS)
{
INFO(L"No sessions to cleanup");
return;
}
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
std::vector<std::wstring> keysToDelete;
while (true)
{
subKeyNameSize = 256;
if (RegEnumKeyExW(hSessions, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
std::wstring keyName = subKeyName;
if (keyName != currentSession)
keysToDelete.push_back(keyName);
index++;
}
for (const auto& key : keysToDelete)
{
DeleteKeyRecursive(hSessions, key);
}
RegCloseKey(hSessions);
if (!keysToDelete.empty())
{
SUCCESS(L"Cleaned up %zu old sessions (kept current session)", keysToDelete.size());
}
else
{
INFO(L"No old sessions to cleanup");
}
}
std::wstring SessionManager::GetRegistryBasePath() noexcept
{
return L"Software\\kvc";
}
std::wstring SessionManager::GetSessionPath(const std::wstring& sessionId) noexcept
{
return GetRegistryBasePath() + L"\\Sessions\\" + sessionId;
}
// Remove all session keys except current boot session
void SessionManager::CleanupStaleSessions() noexcept
{
std::wstring currentSession = GetCurrentBootSession();
std::wstring basePath = GetRegistryBasePath() + L"\\Sessions";
HKEY hSessions;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ | KEY_WRITE, &hSessions) != ERROR_SUCCESS)
return;
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
std::vector<std::wstring> keysToDelete;
while (true)
{
subKeyNameSize = 256;
if (RegEnumKeyExW(hSessions, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
std::wstring keyName = subKeyName;
if (keyName != currentSession)
keysToDelete.push_back(keyName);
index++;
}
// Delete stale sessions
for (const auto& key : keysToDelete)
{
DeleteKeyRecursive(hSessions, key);
}
RegCloseKey(hSessions);
}
// Save process state before unprotect operation
bool SessionManager::SaveUnprotectOperation(const std::wstring& signerName,
const std::vector<ProcessEntry>& affectedProcesses) noexcept
{
if (affectedProcesses.empty())
return true;
// Use original signer name (no normalization)
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
std::wstring signerPath = sessionPath + L"\\" + signerName;
HKEY hKey = OpenOrCreateKey(signerPath);
if (!hKey)
{
ERROR(L"Failed to create registry key for session state");
return false;
}
DWORD index = 0;
for (const auto& proc : affectedProcesses)
{
SessionEntry entry;
entry.Pid = proc.Pid;
entry.ProcessName = proc.ProcessName;
entry.OriginalProtection = Utils::GetProtection(proc.ProtectionLevel, proc.SignerType);
entry.SignatureLevel = proc.SignatureLevel;
entry.SectionSignatureLevel = proc.SectionSignatureLevel;
entry.Status = L"UNPROTECTED";
if (!WriteSessionEntry(signerName, index, entry))
{
RegCloseKey(hKey);
return false;
}
index++;
}
// Write count
DWORD count = static_cast<DWORD>(affectedProcesses.size());
RegSetValueExW(hKey, L"Count", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&count), sizeof(DWORD));
RegCloseKey(hKey);
SUCCESS(L"Session state saved to registry (%d processes tracked)", count);
return true;
}
bool SessionManager::WriteSessionEntry(const std::wstring& signerName, DWORD index, const SessionEntry& entry) noexcept
{
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
std::wstring signerPath = sessionPath + L"\\" + signerName;
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, signerPath.c_str(), 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
return false;
// Format: "PID|ProcessName|Protection|SigLevel|SecSigLevel|Status"
std::wostringstream oss;
oss << entry.Pid << L"|"
<< entry.ProcessName << L"|"
<< static_cast<int>(entry.OriginalProtection) << L"|"
<< static_cast<int>(entry.SignatureLevel) << L"|"
<< static_cast<int>(entry.SectionSignatureLevel) << L"|"
<< entry.Status;
std::wstring valueName = L"Proc_" + std::to_wstring(index);
std::wstring valueData = oss.str();
LONG result = RegSetValueExW(hKey, valueName.c_str(), 0, REG_SZ,
reinterpret_cast<const BYTE*>(valueData.c_str()),
static_cast<DWORD>((valueData.length() + 1) * sizeof(wchar_t)));
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
bool SessionManager::UpdateEntryStatus(const std::wstring& signerName, DWORD index, const std::wstring& newStatus) noexcept
{
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
std::wstring signerPath = sessionPath + L"\\" + signerName;
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, signerPath.c_str(), 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS)
return false;
std::wstring valueName = L"Proc_" + std::to_wstring(index);
wchar_t valueData[512];
DWORD valueSize = sizeof(valueData);
if (RegQueryValueExW(hKey, valueName.c_str(), nullptr, nullptr,
reinterpret_cast<BYTE*>(valueData), &valueSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
// Parse existing entry
std::wstring data = valueData;
std::vector<std::wstring> parts;
std::wstring current;
for (wchar_t ch : data)
{
if (ch == L'|')
{
parts.push_back(current);
current.clear();
}
else
{
current += ch;
}
}
if (!current.empty())
parts.push_back(current);
if (parts.size() < 5)
{
RegCloseKey(hKey);
return false;
}
// Rebuild with new status
std::wostringstream oss;
oss << parts[0] << L"|" << parts[1] << L"|" << parts[2] << L"|"
<< parts[3] << L"|" << parts[4] << L"|" << newStatus;
std::wstring newValueData = oss.str();
LONG result = RegSetValueExW(hKey, valueName.c_str(), 0, REG_SZ,
reinterpret_cast<const BYTE*>(newValueData.c_str()),
static_cast<DWORD>((newValueData.length() + 1) * sizeof(wchar_t)));
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
std::vector<SessionEntry> SessionManager::LoadSessionEntries(const std::wstring& signerName) noexcept
{
std::vector<SessionEntry> entries;
// Normalize signer name for case-insensitive comparison
std::wstring normalizedSigner = signerName;
std::transform(normalizedSigner.begin(), normalizedSigner.end(),
normalizedSigner.begin(), ::towlower);
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
HKEY hSession;
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionPath.c_str(), 0, KEY_READ, &hSession) != ERROR_SUCCESS)
return entries;
// Search all subkeys for matching signer (case-insensitive)
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
std::wstring foundSignerKey;
while (true)
{
subKeyNameSize = 256;
LONG result = RegEnumKeyExW(hSession, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr);
if (result != ERROR_SUCCESS)
break;
std::wstring candidate = subKeyName;
std::wstring normalizedCandidate = candidate;
std::transform(normalizedCandidate.begin(), normalizedCandidate.end(),
normalizedCandidate.begin(), ::towlower);
if (normalizedCandidate == normalizedSigner) {
foundSignerKey = candidate;
break;
}
index++;
}
if (foundSignerKey.empty()) {
RegCloseKey(hSession);
DEBUG(L"No signer key found for: %s (normalized: %s)", signerName.c_str(), normalizedSigner.c_str());
return entries;
}
// Use found key name
entries = LoadSessionEntriesFromPath(sessionPath, foundSignerKey);
RegCloseKey(hSession);
DEBUG(L"Loaded %zu entries for signer: %s (key: %s)", entries.size(), signerName.c_str(), foundSignerKey.c_str());
return entries;
}
std::vector<SessionEntry> SessionManager::LoadSessionEntriesFromPath(const std::wstring& sessionPath, const std::wstring& signerName) noexcept
{
std::vector<SessionEntry> entries;
std::wstring signerPath = sessionPath + L"\\" + signerName;
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, signerPath.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return entries;
DWORD count = 0;
DWORD dataSize = sizeof(DWORD);
if (RegQueryValueExW(hKey, L"Count", nullptr, nullptr, reinterpret_cast<BYTE*>(&count), &dataSize) != ERROR_SUCCESS) {
count = 0;
}
for (DWORD i = 0; i < count; i++)
{
std::wstring valueName = L"Proc_" + std::to_wstring(i);
wchar_t valueData[512];
DWORD valueSize = sizeof(valueData);
if (RegQueryValueExW(hKey, valueName.c_str(), nullptr, nullptr,
reinterpret_cast<BYTE*>(valueData), &valueSize) == ERROR_SUCCESS)
{
// Parse: "PID|ProcessName|Protection|SigLevel|SecSigLevel|Status"
std::wstring data = valueData;
std::vector<std::wstring> parts;
std::wstring current;
for (wchar_t ch : data)
{
if (ch == L'|')
{
parts.push_back(current);
current.clear();
}
else
{
current += ch;
}
}
if (!current.empty())
parts.push_back(current);
if (parts.size() >= 5)
{
SessionEntry entry;
entry.Pid = static_cast<DWORD>(std::stoul(parts[0]));
entry.ProcessName = parts[1];
entry.OriginalProtection = static_cast<UCHAR>(std::stoi(parts[2]));
entry.SignatureLevel = static_cast<UCHAR>(std::stoi(parts[3]));
entry.SectionSignatureLevel = static_cast<UCHAR>(std::stoi(parts[4]));
entry.Status = (parts.size() >= 6) ? parts[5] : L"UNPROTECTED";
entries.push_back(entry);
}
}
}
RegCloseKey(hKey);
return entries;
}
// Restore protection for specific signer group
bool SessionManager::RestoreBySigner(const std::wstring& signerName, Controller* controller) noexcept
{
if (!controller)
{
ERROR(L"Controller not available for restoration");
return false;
}
// Find actual signer key name in registry (case-insensitive search)
std::wstring normalizedSigner = signerName;
std::transform(normalizedSigner.begin(), normalizedSigner.end(),
normalizedSigner.begin(), ::towlower);
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
HKEY hSession;
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionPath.c_str(), 0, KEY_READ, &hSession) != ERROR_SUCCESS)
{
INFO(L"No saved state found for signer: %s", signerName.c_str());
return false;
}
// Find actual key name in registry
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
std::wstring foundSignerKey;
while (true)
{
subKeyNameSize = 256;
LONG result = RegEnumKeyExW(hSession, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr);
if (result != ERROR_SUCCESS)
break;
std::wstring candidate = subKeyName;
std::wstring normalizedCandidate = candidate;
std::transform(normalizedCandidate.begin(), normalizedCandidate.end(),
normalizedCandidate.begin(), ::towlower);
if (normalizedCandidate == normalizedSigner) {
foundSignerKey = candidate;
break;
}
index++;
}
RegCloseKey(hSession);
if (foundSignerKey.empty())
{
INFO(L"No saved state found for signer: %s", signerName.c_str());
return false;
}
// Load entries using actual key name
auto entries = LoadSessionEntriesFromPath(sessionPath, foundSignerKey);
if (entries.empty())
{
INFO(L"No saved state found for signer: %s", signerName.c_str());
return false;
}
INFO(L"Restoring protection for %s (%zu processes)", signerName.c_str(), entries.size());
DWORD successCount = 0;
DWORD skipCount = 0;
DWORD entryIndex = 0;
for (const auto& entry : entries)
{
// Skip if already restored
if (entry.Status == L"RESTORED")
{
skipCount++;
entryIndex++;
continue;
}
// Check if process still exists
auto kernelAddr = controller->GetProcessKernelAddress(entry.Pid);
if (!kernelAddr)
{
INFO(L"Skipping PID %d (%s) - process no longer exists", entry.Pid, entry.ProcessName.c_str());
skipCount++;
entryIndex++;
continue;
}
// Restore original protection
if (controller->SetProcessProtection(kernelAddr.value(), entry.OriginalProtection))
{
UpdateEntryStatus(foundSignerKey, entryIndex, L"RESTORED");
SUCCESS(L"Restored protection for PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
successCount++;
}
else
{
ERROR(L"Failed to restore protection for PID %d (%s)", entry.Pid, entry.ProcessName.c_str());
}
entryIndex++;
}
INFO(L"Restoration completed: %d restored, %d skipped", successCount, skipCount);
return successCount > 0;
}
// Restore all saved protection states
bool SessionManager::RestoreAll(Controller* controller) noexcept
{
if (!controller)
{
ERROR(L"Controller not available for restoration");
return false;
}
std::wstring sessionPath = GetSessionPath(GetCurrentBootSession());
HKEY hSession;
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionPath.c_str(), 0, KEY_READ, &hSession) != ERROR_SUCCESS)
{
INFO(L"No saved session state found");
return false;
}
// Enumerate all signer subkeys
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
std::vector<std::wstring> signers;
while (true)
{
subKeyNameSize = 256;
if (RegEnumKeyExW(hSession, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
signers.push_back(subKeyName);
index++;
}
RegCloseKey(hSession);
if (signers.empty())
{
INFO(L"No saved state found in current session");
return false;
}
INFO(L"Restoring all protection states (%zu groups)", signers.size());
bool anySuccess = false;
for (const auto& signer : signers)
{
if (RestoreBySigner(signer, controller))
anySuccess = true;
}
return anySuccess;
}
// Display saved session history
void SessionManager::ShowHistory() noexcept
{
std::wstring basePath = GetRegistryBasePath() + L"\\Sessions";
HKEY hSessions;
if (RegOpenKeyExW(HKEY_CURRENT_USER, basePath.c_str(), 0, KEY_READ, &hSessions) != ERROR_SUCCESS)
{
INFO(L"No saved session state found (cannot open sessions key)");
return;
}
// Show current calculated boot session ID
std::wstring currentSession = GetCurrentBootSession();
INFO(L"Current boot session ID: %s", currentSession.c_str());
INFO(L"All sessions found in registry:");
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize;
bool foundSessions = false;
while (true)
{
subKeyNameSize = 256;
if (RegEnumKeyExW(hSessions, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
std::wstring sessionId = subKeyName;
std::wcout << L"\nSession: " << sessionId;
if (sessionId == currentSession) {
std::wcout << L" [CURRENT]";
}
std::wcout << L"\n";
std::wstring sessionPath = basePath + L"\\" + sessionId;
HKEY hSession;
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionPath.c_str(), 0, KEY_READ, &hSession) == ERROR_SUCCESS)
{
DWORD signerIndex = 0;
wchar_t signerName[256];
DWORD signerNameSize;
while (true)
{
signerNameSize = 256;
if (RegEnumKeyExW(hSession, signerIndex, signerName, &signerNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
std::wstring signer = signerName;
auto entries = LoadSessionEntriesFromPath(sessionPath, signer);
std::wcout << L" [" << signer << L"] - " << entries.size() << L" processes\n";
for (const auto& entry : entries)
{
std::wcout << L" PID " << entry.Pid << L": " << entry.ProcessName
<< L" (protection: 0x" << std::hex << static_cast<int>(entry.OriginalProtection)
<< std::dec << L", status: " << entry.Status << L")\n";
}
signerIndex++;
foundSessions = true;
}
RegCloseKey(hSession);
}
index++;
}
RegCloseKey(hSessions);
if (!foundSessions) {
INFO(L"No session data found in registry");
}
}
HKEY SessionManager::OpenOrCreateKey(const std::wstring& path) noexcept
{
HKEY hKey;
DWORD disposition;
if (RegCreateKeyExW(HKEY_CURRENT_USER, path.c_str(), 0, nullptr,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr,
&hKey, &disposition) != ERROR_SUCCESS)
{
return nullptr;
}
return hKey;
}
bool SessionManager::DeleteKeyRecursive(HKEY hKeyParent, const std::wstring& subKey) noexcept
{
HKEY hKey;
if (RegOpenKeyExW(hKeyParent, subKey.c_str(), 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS)
return false;
// Delete all subkeys first
wchar_t childName[256];
DWORD childNameSize;
while (true)
{
childNameSize = 256;
if (RegEnumKeyExW(hKey, 0, childName, &childNameSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
DeleteKeyRecursive(hKey, childName);
}
RegCloseKey(hKey);
RegDeleteKeyW(hKeyParent, subKey.c_str());
return true;
}

68
kvc/SessionManager.h Normal file
View File

@@ -0,0 +1,68 @@
// SessionManager.h
#pragma once
#include "common.h"
#include <string>
#include <vector>
#include <optional>
struct ProcessEntry;
// Session state entry for restoration tracking
struct SessionEntry
{
DWORD Pid;
std::wstring ProcessName;
UCHAR OriginalProtection; // Combined level + signer
UCHAR SignatureLevel;
UCHAR SectionSignatureLevel;
std::wstring Status; // "UNPROTECTED" or "RESTORED"
};
// Manages process protection state across boot sessions
class SessionManager
{
public:
SessionManager() = default;
~SessionManager() = default;
// Session lifecycle management
void CleanupStaleSessions() noexcept;
void CleanupAllSessionsExceptCurrent() noexcept;
void DetectAndHandleReboot() noexcept;
void EnforceSessionLimit(int maxSessions) noexcept;
// State tracking operations
bool SaveUnprotectOperation(const std::wstring& signerName,
const std::vector<ProcessEntry>& affectedProcesses) noexcept;
// Restoration operations
bool RestoreBySigner(const std::wstring& signerName, class Controller* controller) noexcept;
bool RestoreAll(class Controller* controller) noexcept;
// Query operations
void ShowHistory() noexcept;
private:
std::wstring GetCurrentBootSession() noexcept;
std::wstring CalculateBootTime() noexcept;
ULONGLONG GetLastBootIdFromRegistry() noexcept;
void SaveLastBootId(ULONGLONG bootId) noexcept;
ULONGLONG GetLastTickCountFromRegistry() noexcept;
void SaveLastTickCount(ULONGLONG tickCount) noexcept;
std::wstring GetRegistryBasePath() noexcept;
std::wstring GetSessionPath(const std::wstring& sessionId) noexcept;
std::vector<SessionEntry> LoadSessionEntries(const std::wstring& signerName) noexcept;
std::vector<SessionEntry> LoadSessionEntriesFromPath(const std::wstring& sessionPath, const std::wstring& signerName) noexcept;
bool WriteSessionEntry(const std::wstring& signerName, DWORD index, const SessionEntry& entry) noexcept;
bool UpdateEntryStatus(const std::wstring& signerName, DWORD index, const std::wstring& newStatus) noexcept;
std::vector<std::wstring> GetAllSessionIds() noexcept;
// Registry helpers
HKEY OpenOrCreateKey(const std::wstring& path) noexcept;
bool DeleteKeyRecursive(HKEY hKeyParent, const std::wstring& subKey) noexcept;
};

View File

@@ -15,6 +15,9 @@
#include <chrono>
#include <memory>
// Session management constants
inline constexpr int MAX_SESSIONS = 16;
#ifdef BUILD_DATE
#define __DATE__ BUILD_DATE
#endif
@@ -29,7 +32,6 @@
#undef ERROR
#endif
#ifndef SHTDN_REASON_MAJOR_SOFTWARE
#define SHTDN_REASON_MAJOR_SOFTWARE 0x00030000
#endif
@@ -56,7 +58,7 @@ struct SystemModuleDeleter {
using ModuleHandle = std::unique_ptr<std::remove_pointer_t<HMODULE>, ModuleDeleter>;
using SystemModuleHandle = std::unique_ptr<std::remove_pointer_t<HMODULE>, SystemModuleDeleter>;
// Logging system with message formatting
// Fixed logging system with proper buffer size and variadic handling
template<typename... Args>
void PrintMessage(const wchar_t* prefix, const wchar_t* format, Args&&... args)
{
@@ -70,7 +72,7 @@ void PrintMessage(const wchar_t* prefix, const wchar_t* format, Args&&... args)
else
{
wchar_t buffer[1024];
swprintf_s(buffer, format, std::forward<Args>(args)...);
swprintf_s(buffer, 1024, format, std::forward<Args>(args)...);
ss << buffer;
}
@@ -79,19 +81,19 @@ void PrintMessage(const wchar_t* prefix, const wchar_t* format, Args&&... args)
}
#if kvc_DEBUG_ENABLED
#define DEBUG(format, ...) PrintMessage(L"[DEBUG] ", format, __VA_ARGS__)
#define DEBUG(format, ...) PrintMessage(L"[DEBUG] ", format, ##__VA_ARGS__)
#else
#define DEBUG(format, ...) do {} while(0)
#endif
#define ERROR(format, ...) PrintMessage(L"[-] ", format, __VA_ARGS__)
#define INFO(format, ...) PrintMessage(L"[*] ", format, __VA_ARGS__)
#define SUCCESS(format, ...) PrintMessage(L"[+] ", format, __VA_ARGS__)
#define ERROR(format, ...) PrintMessage(L"[-] ", format, ##__VA_ARGS__)
#define INFO(format, ...) PrintMessage(L"[*] ", format, ##__VA_ARGS__)
#define SUCCESS(format, ...) PrintMessage(L"[+] ", format, ##__VA_ARGS__)
#define LASTERROR(f) \
do { \
wchar_t buf[256]; \
swprintf_s(buf, L"[-] The function '%s' failed with error code 0x%08x.\r\n", L##f, GetLastError()); \
swprintf_s(buf, 256, L"[-] The function '%s' failed with error code 0x%08x.\r\n", L##f, GetLastError()); \
std::wcout << buf; \
} while(0)
@@ -119,22 +121,22 @@ enum class PS_PROTECTED_SIGNER : UCHAR
// Service-related constants
namespace ServiceConstants {
constexpr const wchar_t* SERVICE_NAME = L"KernelVulnerabilityControl";
constexpr const wchar_t* SERVICE_DISPLAY_NAME = L"Kernel Vulnerability Capabilities Framework";
constexpr const wchar_t* SERVICE_PARAM = L"--service";
inline constexpr wchar_t SERVICE_NAME[] = L"KernelVulnerabilityControl";
inline constexpr wchar_t SERVICE_DISPLAY_NAME[] = L"Kernel Vulnerability Capabilities Framework";
inline constexpr wchar_t SERVICE_PARAM[] = L"--service";
// Keyboard hook settings
constexpr int CTRL_SEQUENCE_LENGTH = 5;
constexpr DWORD CTRL_SEQUENCE_TIMEOUT_MS = 2000;
constexpr DWORD CTRL_DEBOUNCE_MS = 50;
inline constexpr int CTRL_SEQUENCE_LENGTH = 5;
inline constexpr DWORD CTRL_SEQUENCE_TIMEOUT_MS = 2000;
inline constexpr DWORD CTRL_DEBOUNCE_MS = 50;
}
// DPAPI constants for password extraction
namespace DPAPIConstants {
constexpr int SQLITE_OK = 0;
constexpr int SQLITE_ROW = 100;
constexpr int SQLITE_DONE = 101;
constexpr int SQLITE_OPEN_READONLY = 0x00000001;
inline constexpr int SQLITE_OK = 0;
inline constexpr int SQLITE_ROW = 100;
inline constexpr int SQLITE_DONE = 101;
inline constexpr int SQLITE_OPEN_READONLY = 0x00000001;
inline std::string GetChromeV10Prefix() { return "v10"; }
inline std::string GetChromeDPAPIPrefix() { return "DPAPI"; }
@@ -259,7 +261,7 @@ inline std::wstring GetDriverStorePathSafe() noexcept {
}
// KVC combined binary processing constants
constexpr std::array<BYTE, 7> KVC_XOR_KEY = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
constexpr wchar_t KVC_DATA_FILE[] = L"kvc.dat";
constexpr wchar_t KVC_PASS_FILE[] = L"kvc_pass.exe";
constexpr wchar_t KVC_CRYPT_FILE[] = L"kvc_crypt.dll";
inline constexpr std::array<BYTE, 7> KVC_XOR_KEY = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
inline constexpr wchar_t KVC_DATA_FILE[] = L"kvc.dat";
inline constexpr wchar_t KVC_PASS_FILE[] = L"kvc_pass.exe";
inline constexpr wchar_t KVC_CRYPT_FILE[] = L"kvc_crypt.dll";