Detailed best practices, design patterns, and implementation strategies for the fdebug anti-debug protection system.
- Architectural Design Patterns
- Integration Strategies
- Real-World Use Cases
- Performance Optimization
- Testing and Validation
- Security Considerations
- Troubleshooting
Protect the most critical assets with nested security layers:
use fdebug::protector::{Protector, SecureVault, ShieldedExecution, CoupledLogic, Corruptible};
/// Critical encryption key - maximum protection
struct CryptoMaterial {
master_key: [u8; 32],
initialization_vector: [u8; 16],
}
impl Corruptible for CryptoMaterial {
fn corrupt_if_needed(mut self, token: u64) -> Self {
// Extreme corruption if token is invalid
if token & 0xFFFFFFFF == 0 || token == u64::MAX {
self.master_key = [0; 32];
self.initialization_vector = [0; 16];
}
self
}
}
fn get_crypto_material(protector: &Protector) -> CryptoMaterial {
// Layer 1: Run as coupled logic (automatic corruption)
// Layer 2: Wrap in SecureVault (requires token)
// Layer 3: Use XOR with token (additional mixing)
let vault = SecureVault::new(vec![
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
]);
protector.run_secure(&vault, |seed, token| {
// XOR seed with token for additional protection
let mut master_key = [0u8; 32];
for i in 0..32 {
master_key[i] = seed[i % 16] ^ ((token >> (i % 8 * 8)) as u8);
}
let mut iv = [0u8; 16];
for i in 0..16 {
iv[i] = seed[i] ^ ((token.rotate_left(i as u32) as u8));
}
CryptoMaterial {
master_key,
initialization_vector: iv,
}
})
}
fn main() {
let protector = fdebug::setup_anti_debug!(fdebug::protector::get_dynamic_seed());
let material = get_crypto_material(&protector);
// If running under debugger:
// - token is corrupted by VEH
// - master_key and IV are garbage
// - encryption produces garbage
// Application appears to work but is worthless
}Continuously verify protected operations are executing correctly:
use fdebug::protector::{Protector, SecureVault, ShieldedExecution};
use std::sync::atomic::{AtomicBool, Ordering};
static LAST_OPERATION_VALID: AtomicBool = AtomicBool::new(true);
fn protected_operation(protector: &Protector, data: &[u8]) -> u32 {
// Get score before operation
let score_before = get_suspicion_score();
// Execute protected operation
let vault = SecureVault::new(data.to_vec());
let result = protector.run_secure(&vault, |data, token| {
let mut sum = 0u32;
for (i, byte) in data.iter().enumerate() {
sum = sum.wrapping_add((*byte as u32).wrapping_mul(token as u32));
}
sum ^ (token as u32)
});
// Verify result consistency
let score_after = get_suspicion_score();
// Sentinel check: if suspicion increased, operation may be compromised
if score_after > score_before {
LAST_OPERATION_VALID.store(false, Ordering::SeqCst);
eprintln!("[!] Sentinel check failed - operation compromised");
return 0;
}
LAST_OPERATION_VALID.store(true, Ordering::SeqCst);
result
}
fn is_system_healthy(protector: &Protector) -> bool {
// Check if last operation was valid AND current state is clean
LAST_OPERATION_VALID.load(Ordering::SeqCst) &&
get_suspicion_score() == 0
}Data structures that validate their own integrity:
use std::num::Wrapping;
#[derive(Clone)]
struct ProtectedValue<T: Clone + Copy> {
value: T,
checksum: u32,
}
impl<T: Clone + Copy> ProtectedValue<T>
where
T: Into<u64> + From<u64>,
{
fn new(value: T) -> Self {
let check = Self::calculate_checksum(value);
ProtectedValue { value, checksum: check }
}
fn calculate_checksum(value: T) -> u32 {
let val_u64: u64 = value.into();
let mut check = 0u32;
for i in 0..8 {
let byte = ((val_u64 >> (i * 8)) & 0xFF) as u8;
check = check.wrapping_mul(31).wrapping_add(byte as u32);
}
check ^ 0xDEADBEEF
}
fn validate(&self) -> bool {
let expected = Self::calculate_checksum(self.value);
self.checksum == expected
}
fn get_safe(&self, protector: &Protector) -> Option<T> {
if !self.validate() {
return None;
}
let vault = SecureVault::new(self.value);
protector.run_secure(&vault, |val, token| {
if token == 0 || token == u64::MAX {
None
} else {
Some(*val)
}
})
}
}
fn main() {
let protector = Protector::new(0xACE);
let protected = ProtectedValue::new(42u32);
match protected.get_safe(&protector) {
Some(value) => println!("Value: {}", value),
None => eprintln!("[!] Value integrity check failed"),
}
}Start with low-risk areas, then expand:
// Phase 1: Protect only initialization
fn init_with_protection(protector: &Protector) {
println!("[*] System initializing with anti-debug enabled...");
// Minimal protection during startup
}
// Phase 2: Protect business-critical operations
fn process_transaction(protector: &Protector, amount: f64) -> bool {
protector.run_secure(&SecureVault::new(amount), |val, token| {
validate_amount(*val, token as f64)
})
}
// Phase 3: Protect everything
fn comprehensive_protection(protector: &Protector) {
// All operations use run_secure or run_coupled
}// In Cargo.toml
// [features]
// max-protection = ["fdebug"]
// default = []
#[cfg(feature = "max-protection")]
use fdebug::protector::Protector;
#[cfg(feature = "max-protection")]
fn protect_operation<T, F>(protector: &Protector, operation: F) -> T
where
F: FnOnce() -> T,
{
protector.run_secure(&SecureVault::new(()), |_, _| {
operation()
})
}
#[cfg(not(feature = "max-protection"))]
fn protect_operation<T, F>(_protector: &Protector, operation: F) -> T
where
F: FnOnce() -> T,
{
operation()
}
fn main() {
let protector = Protector::new(0xBEEFCAFE);
let result = protect_operation(&protector, || {
// Business logic
42
});
println!("Result: {}", result);
}pub struct ProtectionConfig {
enabled: bool,
level: ProtectionLevel,
monitor_interval: std::time::Duration,
}
pub enum ProtectionLevel {
None,
Low,
Medium,
High,
Maximum,
}
impl ProtectionConfig {
fn should_protect_operation(&self, operation_risk: u32) -> bool {
if !self.enabled {
return false;
}
let protection_threshold = match self.level {
ProtectionLevel::None => u32::MAX,
ProtectionLevel::Low => 100,
ProtectionLevel::Medium => 50,
ProtectionLevel::High => 25,
ProtectionLevel::Maximum => 0,
};
operation_risk > protection_threshold
}
}
fn process_with_config(
protector: &Protector,
config: &ProtectionConfig,
data: &[u8],
) -> Vec<u8> {
let operation_risk = data.len() as u32;
if config.should_protect_operation(operation_risk) {
// Protect high-risk operations
let vault = SecureVault::new(data.to_vec());
protector.run_secure(&vault, |data, token| {
transform_with_token(data, token)
})
} else {
// Low-risk operations skip protection
data.to_vec()
}
}
fn transform_with_token(data: &[u8], token: u64) -> Vec<u8> {
let mut result = data.to_vec();
for i in 0..result.len() {
result[i] ^= ((token >> (i % 8 * 8)) as u8);
}
result
}use fdebug::protector::{Protector, SecureVault, ShieldedExecution};
use chrono::{DateTime, Utc, Duration};
#[derive(Clone)]
struct License {
key: String,
expiration: DateTime<Utc>,
product_id: u32,
checksum: u64,
}
impl License {
fn calculate_checksum(key: &str, exp: DateTime<Utc>, product: u32) -> u64 {
let mut hash = 0u64;
for byte in key.as_bytes() {
hash = hash.wrapping_mul(31).wrapping_add(*byte as u64);
}
hash = hash.wrapping_add(exp.timestamp() as u64);
hash = hash.wrapping_add(product as u64);
hash ^ 0xDEADBEEFCAFEBABE
}
fn new(key: String, product_id: u32, days_valid: i64) -> Self {
let expiration = Utc::now() + Duration::days(days_valid);
let checksum = Self::calculate_checksum(&key, expiration, product_id);
License {
key,
expiration,
product_id,
checksum,
}
}
fn verify(&self, protector: &Protector) -> bool {
// Verify integrity
let expected = Self::calculate_checksum(&self.key, self.expiration, self.product_id);
if expected != self.checksum {
return false;
}
// Verify with security token
let vault = SecureVault::new(self.clone());
protector.run_secure(&vault, |lic, token| {
// Check expiration
if Utc::now() > lic.expiration {
return false;
}
// Token-based verification
let key_hash: u64 = lic.key.as_bytes().iter()
.fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(*b as u64));
(key_hash ^ token ^ lic.product_id as u64) != 0
})
}
}
fn main() {
let protector = Protector::new(0xDEADBEEF);
let license = License::new(
"ABC123DEF456GHI789JKL012MNO345PQR".to_string(),
1001,
30,
);
if license.verify(&protector) {
println!("[+] License valid - feature unlocked");
} else {
println!("[-] License invalid or running under debugger");
}
}use fdebug::protector::{Protector, SecureVault, ShieldedExecution};
use std::sync::Mutex;
struct APIKeyManager {
protector: Protector,
keys: Mutex<Vec<String>>,
}
impl APIKeyManager {
fn new(seed: u32) -> Self {
APIKeyManager {
protector: Protector::new(seed),
keys: Mutex::new(Vec::new()),
}
}
fn add_key(&self, key: String) {
let vault = SecureVault::new(key.clone());
let validated = self.protector.run_secure(&vault, |key, token| {
// Validate key format (typical: 32+ alphanumeric)
key.len() >= 32 &&
key.chars().all(|c| c.is_alphanumeric()) &&
(token % 7 == 0) // Token validation
});
if validated {
if let Ok(mut keys) = self.keys.lock() {
keys.push(key);
}
}
}
fn use_key<F, T>(&self, index: usize, operation: F) -> Option<T>
where
F: FnOnce(&str) -> T,
{
let keys = self.keys.lock().ok()?;
let key = keys.get(index)?;
let vault = SecureVault::new(key.clone());
Some(self.protector.run_secure(&vault, |key, token| {
if token == 0 {
// Corrupted by debugger
return operation(""); // Use empty key
}
operation(key)
}))
}
}
fn main() {
let manager = APIKeyManager::new(0xACE123);
manager.add_key("your_api_key_here".to_string());
manager.add_key("your_api_key_here".to_string());
manager.use_key(0, |api_key| {
if api_key.is_empty() {
eprintln!("[!] API key corrupted - environment compromised");
} else {
println!("[+] API key loaded safely: {}", &api_key[..16]);
}
});
}use fdebug::protector::{Protector, SecureVault, ShieldedExecution, CoupledLogic, Corruptible};
#[derive(Clone)]
struct UserData {
name: String,
email: String,
phone: String,
ssn: String,
}
impl Corruptible for UserData {
fn corrupt_if_needed(mut self, token: u64) -> Self {
if token & 0xFF == 0 {
// Corrupt sensitive data if running under debugger
self.ssn = "000-00-0000".to_string();
self.email = "redacted@example.com".to_string();
self.phone = "555-1234".to_string();
}
self
}
}
fn display_user_info(protector: &Protector, user: UserData) {
let protected = protector.run_coupled(|token| {
user
});
println!("Name: {}", protected.name);
println!("Email: {}***", &protected.email[..3]);
println!("Phone: {}***", &protected.phone[..3]);
println!("SSN: {}***", &protected.ssn[..5]);
if protected.ssn == "000-00-0000" {
eprintln!("[!] Sensitive data has been masked - security check triggered");
}
}
fn main() {
let protector = Protector::new(0xBEEFCAFE);
let user = UserData {
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
phone: "555-1234-5678".to_string(),
ssn: "123-45-6789".to_string(),
};
display_user_info(&protector, user);
}use std::sync::Once;
static INIT: Once = Once::new();
static mut PROTECTOR: Option<Protector> = None;
fn get_protector() -> &'static Protector {
unsafe {
INIT.call_once(|| {
PROTECTOR = Some(Protector::new(get_dynamic_seed()));
});
PROTECTOR.as_ref().unwrap()
}
}
fn main() {
let protector = get_protector();
// Use protector
let vault = SecureVault::new(42u32);
protector.run_secure(&vault, |val, _| {
println!("Value: {}", val);
});
}fn process_batch(protector: &Protector, items: Vec<String>) -> Vec<u32> {
items
.into_iter()
.map(|item| {
let vault = SecureVault::new(item);
protector.run_secure(&vault, |item, token| {
(item.len() as u64 ^ token) as u32
})
})
.collect()
}
// More efficient: Single run_secure wrapping the loop
fn process_batch_optimized(protector: &Protector, items: Vec<String>) -> Vec<u32> {
let vault = SecureVault::new(items);
protector.run_secure(&vault, |items, token| {
items
.iter()
.enumerate()
.map(|(i, item)| {
((item.len() as u64 ^ token).wrapping_add(i as u64)) as u32
})
.collect()
})
}fn process_data_selective(protector: &Protector, data: &[u8]) -> Vec<u8> {
const PROTECTION_THRESHOLD: usize = 1024; // Protect data > 1KB
if data.len() > PROTECTION_THRESHOLD {
// Large data: full protection
let vault = SecureVault::new(data.to_vec());
protector.run_secure(&vault, |data, token| {
transform_data(data, token)
})
} else {
// Small data: skip protection overhead
transform_data(data, 0xDEADBEEFCAFEBABE)
}
}
fn transform_data(data: &[u8], token: u64) -> Vec<u8> {
data.iter()
.enumerate()
.map(|(i, byte)| byte ^ ((token >> (i % 8 * 8)) as u8))
.collect()
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_protection_changes_result() {
let protector = Protector::new(0xACE123);
let vault = SecureVault::new(42u32);
let result1 = protector.run_secure(&vault, |val, token| {
val ^ (token as u32)
});
// Under debugger, result would be different
// (but hard to test without actually running under debugger)
assert!(result1 > 0 || result1 == 0); // Always true, just checking no panic
}
#[test]
fn test_corruption_trait() {
#[derive(Clone)]
struct TestData(u32);
impl Corruptible for TestData {
fn corrupt_if_needed(mut self, token: u64) -> Self {
if token == 0 {
self.0 = 0;
}
self
}
}
let data = TestData(42);
let corrupted = data.corrupt_if_needed(0);
assert_eq!(corrupted.0, 0);
let intact = data.corrupt_if_needed(1);
assert_eq!(intact.0, 42);
}
}#[cfg(test)]
mod score_tests {
use super::*;
#[test]
fn test_suspicion_accumulates() {
use fdebug::protector::{add_suspicion, get_suspicion_score, DetectionSeverity};
let initial_score = get_suspicion_score();
add_suspicion(DetectionSeverity::Low);
let after_low = get_suspicion_score();
assert!(after_low >= initial_score + 10);
add_suspicion(DetectionSeverity::Critical);
let after_critical = get_suspicion_score();
assert!(after_critical > after_low);
}
}// ✅ GOOD - Use get_dynamic_seed() (changes every build)
let protector = Protector::new(get_dynamic_seed());
// ❌ POOR - Hardcoded seed (same across all builds)
let protector = Protector::new(0x12345678);
// ❌ VERY BAD - Predictable seed (uses time)
let seed = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
let protector = Protector::new(seed);// ❌ DANGEROUS - Data persists after secure_execution
let vault = SecureVault::new(secret_key.clone());
let cached_result = protector.run_secure(&vault, |key, _| {
key.clone() // Caching is bad!
});
// Data is no longer protected!
// ✅ GOOD - Data only used within secure context
protector.run_secure(&vault, |key, token| {
if token % 7 == 0 {
use_key_immediately(key); // Consumed immediately
}
});// ❌ CARELESS - Assumes token is always valid
fn decrypt_with_token(data: &[u8], token: u64) -> Vec<u8> {
data.iter()
.map(|b| b ^ ((token >> (b % 8 * 8)) as u8))
.collect()
}
// ✅ SAFE - Validates token bounds
fn decrypt_with_token_safe(data: &[u8], token: u64) -> Option<Vec<u8>> {
if token == 0 || token == u64::MAX {
return None; // Token invalid
}
Some(data.iter()
.map(|b| b ^ ((token >> (b % 8 * 8)) as u8))
.collect())
}Problem: Application triggers detection in legitimate virtual machines.
Solution:
use fdebug::protector::global_state::DIAGNOSTIC_MODE;
use std::sync::atomic::Ordering;
fn check_environment() {
// Enable diagnostic mode to see what's triggering
DIAGNOSTIC_MODE.store(true, Ordering::Relaxed);
let protector = Protector::new(get_dynamic_seed());
// Check which checkpoints triggered
use fdebug::protector::global_state::TRIGGERED_CHECKPOINTS;
for (i, checkpoint) in TRIGGERED_CHECKPOINTS.iter().enumerate() {
let score = checkpoint.load(Ordering::Relaxed);
if score > 0 {
eprintln!("Checkpoint {}: {} points", i, score);
}
}
}Problem: Legitimate use is getting corrupted.
Solution: Check if suspicion score is baseline:
use fdebug::protector::get_suspicion_score;
fn diagnose_corruption() {
loop {
let score = get_suspicion_score();
println!("[*] Current suspicion: {}", score);
if score > 50 {
eprintln!("[!] High suspicion - check for:");
eprintln!(" - Breakpoints in decoy functions");
eprintln!(" - Hardware debugger (WinDbg)");
eprintln!(" - VM environment");
break;
}
std::thread::sleep(std::time::Duration::from_secs(5));
}
}Problem: Application is slow with protection enabled.
Solution: Profile and optimize:
use std::time::Instant;
fn benchmark_protected_operation(protector: &Protector) {
let vault = SecureVault::new(vec![0u8; 1024]);
let start = Instant::now();
for _ in 0..1000 {
let _ = protector.run_secure(&vault, |data, token| {
data.len() as u64 ^ token
});
}
let elapsed = start.elapsed();
println!("[*] 1000 operations: {:?}", elapsed);
println!("[*] Per-operation: {:?}", elapsed / 1000);
// If > 1ms per operation, consider selective protection
if elapsed > std::time::Duration::from_millis(1000) {
eprintln!("[!] Consider reducing protection scope");
}
}The fdebug module provides enterprise-grade protection against debugging and reverse engineering. By following these patterns and best practices, you can:
- Detect debugging attempts with multi-vector detection
- Obfuscate security logic with polymorphic VM bytecode
- Protect critical data with cryptographic tokens
- Validate integration with automated tests
- Monitor system health with built-in watchdog
The key principle: make debugging so costly and unrewarding that attackers move on to easier targets.