From aadbbc0a6b1f0ae9e6456db14011790f1ba92d9b Mon Sep 17 00:00:00 2001 From: wesmar Date: Fri, 3 Oct 2025 00:14:00 +0200 Subject: [PATCH] Aktualizacja: 2025-10-03 00:14:00 --- kvc/Controller.h | 1 + kvc/ControllerProcessOperations.cpp | 135 ++++++++++++++++-- kvc/Kvc.cpp | 90 ++++-------- kvc/Utils.cpp | 204 +++++++++++++++------------- kvc/Utils.h | 5 +- 5 files changed, 267 insertions(+), 168 deletions(-) diff --git a/kvc/Controller.h b/kvc/Controller.h index 846c50c..33d8d5e 100644 --- a/kvc/Controller.h +++ b/kvc/Controller.h @@ -94,6 +94,7 @@ public: bool ListProtectedProcesses() noexcept; bool GetProcessProtection(DWORD pid) noexcept; bool GetProcessProtectionByName(const std::wstring& processName) noexcept; + bool PrintProcessInfo(DWORD pid) noexcept; // Process protection manipulation with atomic operations bool SetProcessProtection(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept; diff --git a/kvc/ControllerProcessOperations.cpp b/kvc/ControllerProcessOperations.cpp index bfe43f0..cd08cbc 100644 --- a/kvc/ControllerProcessOperations.cpp +++ b/kvc/ControllerProcessOperations.cpp @@ -620,39 +620,73 @@ bool Controller::IsPatternMatch(const std::wstring& processName, const std::wstr bool Controller::GetProcessProtection(DWORD pid) noexcept { if (!BeginDriverSession()) { - EndDriverSession(true); + EndDriverSession(true); return false; } auto kernelAddr = GetProcessKernelAddress(pid); if (!kernelAddr) { ERROR(L"Failed to get kernel address for PID %d", pid); - EndDriverSession(true); // Force cleanup + EndDriverSession(true); return false; } auto currentProtection = GetProcessProtection(kernelAddr.value()); if (!currentProtection) { ERROR(L"Failed to read protection for PID %d", pid); - EndDriverSession(true); // Force cleanup + EndDriverSession(true); return false; } UCHAR protLevel = Utils::GetProtectionLevel(currentProtection.value()); UCHAR signerType = Utils::GetSignerType(currentProtection.value()); + // Get signature levels for color determination + auto sigLevelOffset = m_of->GetOffset(Offset::ProcessSignatureLevel); + auto secSigLevelOffset = m_of->GetOffset(Offset::ProcessSectionSignatureLevel); + + UCHAR signatureLevel = sigLevelOffset ? m_rtc->Read8(kernelAddr.value() + sigLevelOffset.value()).value_or(0) : 0; + UCHAR sectionSignatureLevel = secSigLevelOffset ? m_rtc->Read8(kernelAddr.value() + secSigLevelOffset.value()).value_or(0) : 0; + + std::wstring processName = Utils::GetProcessName(pid); + + // Get console handle + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + WORD originalColor = csbi.wAttributes; + if (currentProtection.value() == 0) { - INFO(L"PID %d (%s) is not protected", pid, Utils::GetProcessName(pid).c_str()); + INFO(L"PID %d (%s) is not protected", pid, processName.c_str()); } else { - INFO(L"PID %d (%s) protection: %s-%s (raw: 0x%02x)", - pid, - Utils::GetProcessName(pid).c_str(), - Utils::GetProtectionLevelAsString(protLevel), - Utils::GetSignerTypeAsString(signerType), - currentProtection.value()); + // Same color logic as list + WORD protectionColor; + bool hasUncheckedSignatures = (signatureLevel == 0x00 || sectionSignatureLevel == 0x00); + + if (hasUncheckedSignatures) { + protectionColor = FOREGROUND_BLUE | FOREGROUND_INTENSITY; + } else { + bool isUserProcess = (signerType != static_cast(PS_PROTECTED_SIGNER::Windows) && + signerType != static_cast(PS_PROTECTED_SIGNER::WinTcb) && + signerType != static_cast(PS_PROTECTED_SIGNER::WinSystem) && + signerType != static_cast(PS_PROTECTED_SIGNER::Lsa)); + + protectionColor = isUserProcess ? + (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY) : + (FOREGROUND_GREEN | FOREGROUND_INTENSITY); + } + + SetConsoleTextAttribute(hConsole, protectionColor); + wprintf(L"[*] PID %d (%s) protection: %s-%s (raw: 0x%02x)\n", + pid, + processName.c_str(), + Utils::GetProtectionLevelAsString(protLevel), + Utils::GetSignerTypeAsString(signerType), + currentProtection.value()); + SetConsoleTextAttribute(hConsole, originalColor); } - EndDriverSession(true); // Force cleanup + EndDriverSession(true); return true; } @@ -1175,4 +1209,83 @@ bool Controller::RestoreAllProtection() noexcept void Controller::ShowSessionHistory() noexcept { m_sessionMgr.ShowHistory(); +} + +bool Controller::PrintProcessInfo(DWORD pid) noexcept { + std::wstring processName = Utils::GetProcessName(pid); + + if (!BeginDriverSession()) { + EndDriverSession(true); + return false; + } + + auto kernelAddr = GetProcessKernelAddress(pid); + if (!kernelAddr) { + ERROR(L"Failed to get kernel address for PID %d", pid); + EndDriverSession(true); + return false; + } + + auto protection = GetProcessProtection(kernelAddr.value()); + if (!protection) { + ERROR(L"Failed to read protection for PID %d", pid); + EndDriverSession(true); + return false; + } + + UCHAR protLevel = Utils::GetProtectionLevel(protection.value()); + UCHAR signerType = Utils::GetSignerType(protection.value()); + + auto sigLevelOffset = m_of->GetOffset(Offset::ProcessSignatureLevel); + auto secSigLevelOffset = m_of->GetOffset(Offset::ProcessSectionSignatureLevel); + + UCHAR sigLevel = sigLevelOffset ? m_rtc->Read8(kernelAddr.value() + sigLevelOffset.value()).value_or(0) : 0; + UCHAR secSigLevel = secSigLevelOffset ? m_rtc->Read8(kernelAddr.value() + secSigLevelOffset.value()).value_or(0) : 0; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + WORD originalColor = csbi.wAttributes; + + // Display protection with color + if (protection.value() == 0) { + INFO(L"PID %d (%s) is not protected", pid, processName.c_str()); + } else { + // Determine color based on signer (same logic as list) + WORD protectionColor; + bool hasUncheckedSignatures = (sigLevel == 0x00 || secSigLevel == 0x00); + + if (hasUncheckedSignatures) { + protectionColor = FOREGROUND_BLUE | FOREGROUND_INTENSITY; + } else { + bool isUserProcess = (signerType != static_cast(PS_PROTECTED_SIGNER::Windows) && + signerType != static_cast(PS_PROTECTED_SIGNER::WinTcb) && + signerType != static_cast(PS_PROTECTED_SIGNER::WinSystem) && + signerType != static_cast(PS_PROTECTED_SIGNER::Lsa)); + + protectionColor = isUserProcess ? + (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY) : // yellow + (FOREGROUND_GREEN | FOREGROUND_INTENSITY); // green + } + + SetConsoleTextAttribute(hConsole, protectionColor); + wprintf(L"[*] PID %d (%s) protection: %s-%s (raw: 0x%02x)\n", + pid, processName.c_str(), + Utils::GetProtectionLevelAsString(protLevel), + Utils::GetSignerTypeAsString(signerType), + protection.value()); + SetConsoleTextAttribute(hConsole, originalColor); + } + + // Dumpability with inverse colors (black on white) + auto dumpability = Utils::CanDumpProcess(pid, processName, protLevel, signerType); + + SetConsoleTextAttribute(hConsole, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + wprintf(L" Dumpability: %s - %s \n", + dumpability.CanDump ? L"Yes" : L"No", + dumpability.Reason.c_str()); + SetConsoleTextAttribute(hConsole, originalColor); + + EndDriverSession(true); + return true; } \ No newline at end of file diff --git a/kvc/Kvc.cpp b/kvc/Kvc.cpp index aca8b40..65c6d7f 100644 --- a/kvc/Kvc.cpp +++ b/kvc/Kvc.cpp @@ -469,68 +469,36 @@ int wmain(int argc, wchar_t* argv[]) } } - else if (command == L"info") - { - if (argc < 3) - { - ERROR(L"Missing PID/process name argument for detailed information"); - return 1; - } + else if (command == L"info") + { + if (argc < 3) + { + ERROR(L"Missing PID/process name argument for detailed information"); + return 1; + } - std::wstring_view target = argv[2]; - - DWORD targetPid = 0; - std::wstring targetProcessName; - bool protectionResult = false; - - // Get comprehensive process info and analyze dumpability with detailed reporting - if (IsNumeric(target)) - { - auto pid = ParsePid(target); - if (!pid) - { - ERROR(L"Invalid PID format: %s", target.data()); - return 1; - } - targetPid = pid.value(); - targetProcessName = Utils::GetProcessName(targetPid); - protectionResult = g_controller->GetProcessProtection(targetPid); - } - else - { - targetProcessName = std::wstring(target); - auto match = g_controller->ResolveNameWithoutDriver(targetProcessName); - if (match) - { - targetPid = match->Pid; - targetProcessName = match->ProcessName; - protectionResult = g_controller->GetProcessProtection(targetPid); - } - else - { - return 2; - } - } - - // Additional dumpability analysis with detailed reasoning for security assessment - if (protectionResult && targetPid != 0) - { - auto dumpability = Utils::CanDumpProcess(targetPid, targetProcessName); - - if (dumpability.CanDump) - { - SUCCESS(L"Process is dumpable: %s", dumpability.Reason.c_str()); - } - else - { - ERROR(L"Process is NOT dumpable: %s", dumpability.Reason.c_str()); - } - } - - return protectionResult ? 0 : 2; - } - - // Event log clearing with administrative privileges for forensic cleanup + std::wstring_view target = argv[2]; + DWORD targetPid = 0; + + if (IsNumeric(target)) + { + auto pid = ParsePid(target); + if (!pid) + { + ERROR(L"Invalid PID format: %s", target.data()); + return 1; + } + targetPid = pid.value(); + } + else + { + auto match = g_controller->ResolveNameWithoutDriver(std::wstring(target)); + if (!match) return 2; + targetPid = match->Pid; + } + + return g_controller->PrintProcessInfo(targetPid) ? 0 : 2; + } // Event log clearing with administrative privileges for forensic cleanup else if (command == L"evtclear") { return g_controller->ClearSystemEventLogs() ? 0 : 2; diff --git a/kvc/Utils.cpp b/kvc/Utils.cpp index 2cb8258..1af43d0 100644 --- a/kvc/Utils.cpp +++ b/kvc/Utils.cpp @@ -541,111 +541,127 @@ namespace Utils } // Comprehensive process dumpability analysis with detailed reasoning - ProcessDumpability CanDumpProcess(DWORD pid, const std::wstring& processName) noexcept - { - ProcessDumpability result; - result.CanDump = false; // Initialize + ProcessDumpability CanDumpProcess(DWORD pid, const std::wstring& processName, + UCHAR protectionLevel, UCHAR signerType) noexcept + { + ProcessDumpability result; + result.CanDump = false; - // Known undumpable system processes - static const std::unordered_set undumpablePids = { - 4, // System process - 188, // Secure System - 232, // Registry process - 3052 // Memory Compression - }; + // Known undumpable system processes + static const std::unordered_set undumpablePids = { + 4, 188, 232, 3052 + }; - static const std::unordered_set undumpableNames = { - L"System", - L"Secure System", - L"Registry", - L"Memory Compression" - }; + static const std::unordered_set undumpableNames = { + L"System", L"Secure System", L"Registry", L"Memory Compression" + }; - if (undumpablePids.find(pid) != undumpablePids.end()) - { - result.CanDump = false; - result.Reason = L"System kernel process - undumpable by design"; - return result; - } + if (undumpablePids.find(pid) != undumpablePids.end()) + { + result.CanDump = false; + result.Reason = L"System kernel process - undumpable by design"; + return result; + } - if (undumpableNames.find(processName) != undumpableNames.end()) - { - result.CanDump = false; - - if (processName == L"System") - result.Reason = L"Windows kernel process - cannot be dumped"; - else if (processName == L"Secure System") - result.Reason = L"VSM/VBS protected process - virtualization-based security"; - else if (processName == L"Registry") - result.Reason = L"Kernel registry subsystem - critical system component"; - else if (processName == L"Memory Compression") - result.Reason = L"Kernel memory manager - system critical process"; - else - result.Reason = L"System process - protected by Windows kernel"; - - return result; - } + if (undumpableNames.find(processName) != undumpableNames.end()) + { + result.CanDump = false; + + if (processName == L"System") + result.Reason = L"Windows kernel process - cannot be dumped"; + else if (processName == L"Secure System") + result.Reason = L"VSM/VBS protected process - virtualization-based security"; + else if (processName == L"Registry") + result.Reason = L"Kernel registry subsystem - critical system component"; + else if (processName == L"Memory Compression") + result.Reason = L"Kernel memory manager - system critical process"; + else + result.Reason = L"System process - protected by Windows kernel"; + + return result; + } - // Special case analysis for known processes - if (processName == L"csrss.exe" || processName == L"csrss") - { - result.CanDump = true; - result.Reason = L"CSRSS (Win32 subsystem) - dumpable with PPL-WinTcb or higher protection"; - return result; - } + // Special case analysis for known processes + if (processName == L"csrss.exe" || processName == L"csrss") + { + result.CanDump = true; + result.Reason = L"CSRSS (Win32 subsystem) - dumpable with PPL-WinTcb or higher"; + return result; + } - if (pid < 100 && pid != 0) - { - result.CanDump = true; - result.Reason = L"Low PID system process - dumping may fail due to protection"; - return result; - } + if (pid < 100 && pid != 0) + { + result.CanDump = true; + result.Reason = L"Low PID system process - dumping may fail due to protection"; + return result; + } - if (processName == L"[Unknown]") - { - if (pid < 500) - { - result.CanDump = true; - result.Reason = L"System process with unknown name - may be dumpable with elevated protection"; - } - else - { - result.CanDump = true; - result.Reason = L"Process with unknown name - likely dumpable with appropriate privileges"; - } - return result; - } + if (processName == L"[Unknown]") + { + if (pid < 500) + { + result.CanDump = true; + result.Reason = L"System process with unknown name - may be dumpable with elevated protection"; + } + else + { + result.CanDump = true; + result.Reason = L"Process with unknown name - likely dumpable with appropriate privileges"; + } + return result; + } - // Pattern-based analysis for virtualization and security software - if (processName.find(L"vmms") != std::wstring::npos || - processName.find(L"vmwp") != std::wstring::npos || - processName.find(L"vmcompute") != std::wstring::npos) - { - result.CanDump = true; - result.Reason = L"Hyper-V process - may require elevated protection to dump"; - return result; - } + // Pattern-based analysis for virtualization and security software + if (processName.find(L"vmms") != std::wstring::npos || + processName.find(L"vmwp") != std::wstring::npos || + processName.find(L"vmcompute") != std::wstring::npos) + { + result.CanDump = true; + result.Reason = L"Hyper-V component - dumpable with PPL-WinTcb or higher"; + return result; + } - if (processName.find(L"MsMpEng") != std::wstring::npos || - processName.find(L"NisSrv") != std::wstring::npos || - processName.find(L"SecurityHealthService") != std::wstring::npos) - { - result.CanDump = true; - result.Reason = L"Security software - may require Antimalware protection level to dump"; - return result; - } + // LSASS - dynamically generate required protection + if (processName == L"lsass.exe" || processName == L"lsass") + { + result.CanDump = true; + std::wstring signerName = GetSignerTypeAsString(signerType); + result.Reason = L"Protected - requires PPL-" + signerName + L" or higher"; + return result; + } - if (processName == L"lsass.exe" || processName == L"lsass") - { - result.CanDump = true; - result.Reason = L"LSASS process - typically protected, may require PPL-WinTcb or higher"; - return result; - } + // Defender processes - dynamically generate required protection + if (processName == L"MsMpEng.exe" || processName == L"MpDefenderCoreService.exe" || + processName == L"NisSrv.exe") + { + result.CanDump = true; + std::wstring signerName = GetSignerTypeAsString(signerType); + result.Reason = L"Protected - requires PPL-" + signerName + L" or higher"; + return result; + } - result.CanDump = true; - result.Reason = L"Standard user process - should be dumpable with appropriate privileges"; - return result; - } + // SecurityHealthService + if (processName == L"SecurityHealthService.exe") + { + result.CanDump = true; + result.Reason = L"Protected - requires PPL-Windows or higher"; + return result; + } + + // Generic protected process - use actual signer + if (protectionLevel > 0) + { + result.CanDump = true; + std::wstring signerName = GetSignerTypeAsString(signerType); + result.Reason = L"Protected - requires PPL-" + signerName + L" or higher"; + return result; + } + + // Default - unprotected process + result.CanDump = true; + result.Reason = L"Unprotected process - standard dump privileges sufficient"; + return result; + } // Universal hex string converter - handles registry exports, debug output, and various formats bool HexStringToBytes(const std::wstring& hexString, std::vector& bytes) noexcept diff --git a/kvc/Utils.h b/kvc/Utils.h index 704055f..ecf92fc 100644 --- a/kvc/Utils.h +++ b/kvc/Utils.h @@ -74,7 +74,8 @@ namespace Utils std::wstring Reason; }; - ProcessDumpability CanDumpProcess(DWORD pid, const std::wstring& processName) noexcept; + ProcessDumpability CanDumpProcess(DWORD pid, const std::wstring& processName, + UCHAR protectionLevel, UCHAR signerType) noexcept; // Hex string processing utilities for kernel tools bool HexStringToBytes(const std::wstring& hexString, std::vector& bytes) noexcept; @@ -99,4 +100,4 @@ namespace Utils bool EnableConsoleVirtualTerminal() noexcept; const wchar_t* GetProcessDisplayColor(UCHAR signerType, UCHAR signatureLevel, UCHAR sectionSignatureLevel) noexcept; -} +} \ No newline at end of file