Aktualizacja: 2025-10-03 00:14:00
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<UCHAR>(PS_PROTECTED_SIGNER::Windows) &&
|
||||
signerType != static_cast<UCHAR>(PS_PROTECTED_SIGNER::WinTcb) &&
|
||||
signerType != static_cast<UCHAR>(PS_PROTECTED_SIGNER::WinSystem) &&
|
||||
signerType != static_cast<UCHAR>(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<UCHAR>(PS_PROTECTED_SIGNER::Windows) &&
|
||||
signerType != static_cast<UCHAR>(PS_PROTECTED_SIGNER::WinTcb) &&
|
||||
signerType != static_cast<UCHAR>(PS_PROTECTED_SIGNER::WinSystem) &&
|
||||
signerType != static_cast<UCHAR>(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;
|
||||
}
|
||||
90
kvc/Kvc.cpp
90
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;
|
||||
|
||||
204
kvc/Utils.cpp
204
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<DWORD> undumpablePids = {
|
||||
4, // System process
|
||||
188, // Secure System
|
||||
232, // Registry process
|
||||
3052 // Memory Compression
|
||||
};
|
||||
// Known undumpable system processes
|
||||
static const std::unordered_set<DWORD> undumpablePids = {
|
||||
4, 188, 232, 3052
|
||||
};
|
||||
|
||||
static const std::unordered_set<std::wstring> undumpableNames = {
|
||||
L"System",
|
||||
L"Secure System",
|
||||
L"Registry",
|
||||
L"Memory Compression"
|
||||
};
|
||||
static const std::unordered_set<std::wstring> 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<BYTE>& bytes) noexcept
|
||||
|
||||
@@ -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<BYTE>& bytes) noexcept;
|
||||
@@ -99,4 +100,4 @@ namespace Utils
|
||||
|
||||
bool EnableConsoleVirtualTerminal() noexcept;
|
||||
const wchar_t* GetProcessDisplayColor(UCHAR signerType, UCHAR signatureLevel, UCHAR sectionSignatureLevel) noexcept;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user