293 lines
10 KiB
C++
293 lines
10 KiB
C++
/*******************************************************************************
|
|
_ ____ ______
|
|
| |/ /\ \ / / ___|
|
|
| ' / \ \ / / |
|
|
| . \ \ 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
|
|
|
|
*******************************************************************************/
|
|
|
|
// common.cpp - Core system utilities and dynamic API management
|
|
// Implements service management, system path resolution, and Windows API abstraction
|
|
|
|
#include "common.h"
|
|
#include "ServiceManager.h"
|
|
#include <shlwapi.h>
|
|
|
|
// 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 interrupt flag for graceful shutdown handling
|
|
volatile bool g_interrupted = false;
|
|
|
|
// Service mode flag - indicates NT service execution context
|
|
bool g_serviceMode = false;
|
|
|
|
// Dynamic API loading globals for service and driver management
|
|
// Using smart pointers for automatic cleanup and exception safety
|
|
ModuleHandle g_advapi32;
|
|
SystemModuleHandle g_kernel32;
|
|
|
|
// Function pointers for Windows Service Control Manager APIs
|
|
decltype(&CreateServiceW) g_pCreateServiceW = nullptr;
|
|
decltype(&OpenServiceW) g_pOpenServiceW = nullptr;
|
|
decltype(&StartServiceW) g_pStartServiceW = nullptr;
|
|
decltype(&DeleteService) g_pDeleteService = nullptr;
|
|
decltype(&CreateFileW) g_pCreateFileW = nullptr;
|
|
decltype(&ControlService) g_pControlService = nullptr;
|
|
|
|
// Initialize dynamic API loading for service management operations
|
|
// Returns: true if all required APIs successfully loaded, false on failure
|
|
bool InitDynamicAPIs() noexcept
|
|
{
|
|
// Load advapi32.dll only once using lazy initialization
|
|
if (!g_advapi32) {
|
|
HMODULE raw_advapi32 = LoadLibraryA("advapi32.dll");
|
|
if (!raw_advapi32) {
|
|
DEBUG(L"Failed to load advapi32.dll: %d", GetLastError());
|
|
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<decltype(&CreateServiceW)>(
|
|
GetProcAddress(g_advapi32.get(), "CreateServiceW"));
|
|
|
|
g_pOpenServiceW = reinterpret_cast<decltype(&OpenServiceW)>(
|
|
GetProcAddress(g_advapi32.get(), "OpenServiceW"));
|
|
|
|
g_pStartServiceW = reinterpret_cast<decltype(&StartServiceW)>(
|
|
GetProcAddress(g_advapi32.get(), "StartServiceW"));
|
|
|
|
g_pDeleteService = reinterpret_cast<decltype(&DeleteService)>(
|
|
GetProcAddress(g_advapi32.get(), "DeleteService"));
|
|
|
|
g_pControlService = reinterpret_cast<decltype(&ControlService)>(
|
|
GetProcAddress(g_advapi32.get(), "ControlService"));
|
|
|
|
if (!g_pCreateServiceW || !g_pOpenServiceW || !g_pStartServiceW ||
|
|
!g_pDeleteService || !g_pControlService) {
|
|
DEBUG(L"Failed to resolve advapi32 function pointers");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Load kernel32.dll functions (system modules don't need manual free)
|
|
if (!g_kernel32) {
|
|
HMODULE raw_kernel32 = GetModuleHandleA("kernel32.dll");
|
|
if (raw_kernel32) {
|
|
g_kernel32.reset(raw_kernel32);
|
|
|
|
g_pCreateFileW = reinterpret_cast<decltype(&CreateFileW)>(
|
|
GetProcAddress(g_kernel32.get(), "CreateFileW"));
|
|
|
|
if (!g_pCreateFileW) {
|
|
DEBUG(L"Failed to resolve kernel32 CreateFileW");
|
|
return false;
|
|
}
|
|
} else {
|
|
DEBUG(L"Failed to get kernel32.dll handle: %d", GetLastError());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Verify all function pointers are valid before proceeding
|
|
return g_pCreateServiceW && g_pOpenServiceW && g_pStartServiceW &&
|
|
g_pDeleteService && g_pCreateFileW && g_pControlService;
|
|
}
|
|
|
|
// RAII wrapper for SC_HANDLE management to prevent resource leaks
|
|
class ServiceHandle {
|
|
private:
|
|
SC_HANDLE handle_;
|
|
|
|
public:
|
|
explicit ServiceHandle(SC_HANDLE handle = nullptr) noexcept : handle_(handle) {}
|
|
|
|
~ServiceHandle() noexcept {
|
|
if (handle_) {
|
|
CloseServiceHandle(handle_);
|
|
}
|
|
}
|
|
|
|
// Move semantics for efficient transfer of ownership
|
|
ServiceHandle(ServiceHandle&& other) noexcept : handle_(other.handle_) {
|
|
other.handle_ = nullptr;
|
|
}
|
|
|
|
ServiceHandle& operator=(ServiceHandle&& other) noexcept {
|
|
if (this != &other) {
|
|
if (handle_) {
|
|
CloseServiceHandle(handle_);
|
|
}
|
|
handle_ = other.handle_;
|
|
other.handle_ = nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Non-copyable for safety - prevents double-close bugs
|
|
ServiceHandle(const ServiceHandle&) = delete;
|
|
ServiceHandle& operator=(const ServiceHandle&) = delete;
|
|
|
|
// Access operators for SC_HANDLE compatibility
|
|
operator SC_HANDLE() const noexcept { return handle_; }
|
|
explicit operator bool() const noexcept { return handle_ != nullptr; }
|
|
SC_HANDLE get() const noexcept { return handle_; }
|
|
};
|
|
|
|
// Check if KVC service is installed in the system
|
|
// Returns: true if service registry entry exists, false otherwise
|
|
bool IsServiceInstalled() noexcept
|
|
{
|
|
if (!InitDynamicAPIs()) {
|
|
DEBUG(L"InitDynamicAPIs failed in IsServiceInstalled");
|
|
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<bool>(service);
|
|
}
|
|
|
|
// Check if KVC service is currently running
|
|
// Returns: true if service state is SERVICE_RUNNING, false otherwise
|
|
bool IsServiceRunning() noexcept
|
|
{
|
|
if (!InitDynamicAPIs()) {
|
|
DEBUG(L"InitDynamicAPIs failed in IsServiceRunning");
|
|
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);
|
|
}
|
|
|
|
// Get full path to current executable for service installation
|
|
// Returns: Wide string path to current EXE, empty string on failure
|
|
std::wstring GetCurrentExecutablePath() noexcept
|
|
{
|
|
wchar_t path[MAX_PATH];
|
|
if (GetModuleFileNameW(nullptr, path, MAX_PATH) == 0) {
|
|
DEBUG(L"GetModuleFileNameW failed: %d", GetLastError());
|
|
return L"";
|
|
}
|
|
return std::wstring(path);
|
|
}
|
|
|
|
// Get kernel driver service name for RTCore64 operations
|
|
// Returns: Wide string containing driver service identifier
|
|
std::wstring GetServiceName() noexcept
|
|
{
|
|
return L"RTCore64";
|
|
}
|
|
|
|
// Get kernel driver filename for file operations
|
|
// Returns: Wide string containing driver file name
|
|
std::wstring GetDriverFileName() noexcept
|
|
{
|
|
return L"kvc.sys";
|
|
}
|
|
|
|
// Get secure system temp directory for DPAPI and driver operations
|
|
// Uses Windows temp directory with TrustedInstaller privileges
|
|
// Returns: Wide string path to system temp directory
|
|
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";
|
|
}
|
|
|
|
// Generate innocuous system activity to mask driver operations from EDR
|
|
// Creates legitimate registry access and file enumeration patterns
|
|
// Purpose: Blend driver loading with normal Windows background activity
|
|
void GenerateFakeActivity() noexcept
|
|
{
|
|
// Registry access to common Windows version key (normal behavior)
|
|
HKEY hKey;
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
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;
|
|
std::wstring system32Pattern = std::wstring(systemDir) + L"\\*.dll";
|
|
|
|
HANDLE hFind = FindFirstFileW(system32Pattern.c_str(), &findData);
|
|
if (hFind != INVALID_HANDLE_VALUE) {
|
|
FindClose(hFind);
|
|
}
|
|
}
|
|
|
|
// Random delay to vary timing patterns (anti-detection measure)
|
|
Sleep(50 + (GetTickCount() % 100));
|
|
} |