Skip to main content

Hardware Identification

Hardware identification is a critical component of ACHCE Client’s ban enforcement system. By identifying players through unique hardware characteristics rather than easily-changeable IP addresses, the system creates a robust defense against ban evasion through VPNs, proxies, or dynamic IP addresses.
The README documentation specifically mentions using BIOS UUID as the primary hardware identifier, though the current codebase collects IP addresses as a foundation for future hardware ID implementation.

The IP Address Problem

Traditional anti-cheat systems often rely on IP addresses to identify and ban players. However, this approach has critical vulnerabilities:

Why IP-Based Bans Fail

IP addresses can be changed in seconds using readily available VPN services, making IP-based bans ineffective against determined cheaters.

Current IP Collection Implementation

The existing codebase demonstrates IP collection as a starting point:
// PublicIPAddress.cs - Retrieves player's public IP
public class PublicIPAddress
{
    public string GetPublicIPAddress()
    {
        try
        {
            // Use external service to retrieve public IP
            using (var client = new WebClient())
            {
                string publicIP = client.DownloadString("http://ipinfo.io/ip").Trim();
                return publicIP;
            }
        }
        catch (Exception ex)
        {
            return "No se pudo obtener la dirección IP pública: " + ex.Message;
        }
    }
}
// Form1.cs - IP collection during initialization
public void Form1_Load(object sender, EventArgs e)
{
    // ... Firebase connection code ...
    
    // Obtain player's public IP address
    PublicIPAddress IpAddressPlayer = new PublicIPAddress();
    IpPlayer = IpAddressPlayer.GetPublicIPAddress();
    
    PlayAcON();  // Register session with IP
}
While the current implementation collects IP addresses, the architecture is designed to support hardware identification as the primary ban enforcement mechanism.

Hardware ID: The Solution

Hardware identification creates a unique fingerprint for each computer based on characteristics that cannot be easily changed:

Common Hardware Identifiers

ComponentIdentifierDifficulty to Change
BIOS UUIDSystem UUIDVery High
Motherboard SerialMB Serial NumberVery High
CPU IDProcessor IDExtremely High
MAC AddressNetwork Adapter IDMedium
Hard Drive SerialDisk Serial NumberHigh
Windows Product IDOS Installation IDMedium
Combining multiple hardware identifiers creates an even stronger fingerprint that is virtually impossible to spoof completely.

BIOS UUID Implementation

According to the project documentation, ACHCE Client uses BIOS UUID as the primary hardware identifier:

What is BIOS UUID?

The BIOS UUID (Universally Unique Identifier) is a unique identifier stored in the computer’s firmware. Key characteristics:
  • Permanent: Set during manufacturing, rarely changes
  • Unique: Each motherboard has a different UUID
  • Accessible: Can be queried via WMI (Windows Management Instrumentation)
  • Difficult to Spoof: Requires BIOS flashing or hardware replacement

Retrieving BIOS UUID

using System.Management;

public class HardwareIdentification
{
    /// <summary>
    /// Retrieves the BIOS UUID for the current system
    /// </summary>
    /// <returns>BIOS UUID string or error message</returns>
    public string GetBiosUUID()
    {
        try
        {
            string uuid = string.Empty;
            
            using (ManagementObjectSearcher searcher = 
                new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct"))
            {
                foreach (ManagementObject obj in searcher.Get())
                {
                    uuid = obj["UUID"]?.ToString();
                    break;
                }
            }
            
            if (string.IsNullOrEmpty(uuid))
            {
                throw new Exception("Unable to retrieve BIOS UUID");
            }
            
            return uuid;
        }
        catch (Exception ex)
        {
            return $"Error retrieving BIOS UUID: {ex.Message}";
        }
    }
}
The WMI query Win32_ComputerSystemProduct provides access to system hardware information including the BIOS UUID.

BIOS UUID Format

A typical BIOS UUID looks like:
03000200-0400-0500-0006-000700080009
Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  • 32 hexadecimal digits
  • Separated by hyphens
  • Guaranteed unique per system

Enhanced Hardware Fingerprinting

For maximum security, combine multiple hardware identifiers:

Comprehensive Hardware ID Class

using System.Management;
using System.Security.Cryptography;
using System.Text;

public class HardwareFingerprint
{
    /// <summary>
    /// Generates a comprehensive hardware fingerprint
    /// </summary>
    public string GenerateFingerprint()
    {
        StringBuilder fingerprint = new StringBuilder();
        
        // Collect multiple hardware identifiers
        fingerprint.Append(GetBiosUUID());
        fingerprint.Append(GetMotherboardSerial());
        fingerprint.Append(GetCpuId());
        fingerprint.Append(GetPrimaryMacAddress());
        fingerprint.Append(GetDiskSerial());
        
        // Create hash of combined identifiers
        return ComputeHash(fingerprint.ToString());
    }
    
    private string GetBiosUUID()
    {
        return QueryWMI("Win32_ComputerSystemProduct", "UUID");
    }
    
    private string GetMotherboardSerial()
    {
        return QueryWMI("Win32_BaseBoard", "SerialNumber");
    }
    
    private string GetCpuId()
    {
        return QueryWMI("Win32_Processor", "ProcessorId");
    }
    
    private string GetPrimaryMacAddress()
    {
        return QueryWMI("Win32_NetworkAdapter", "MACAddress", 
            "WHERE PhysicalAdapter = TRUE");
    }
    
    private string GetDiskSerial()
    {
        return QueryWMI("Win32_DiskDrive", "SerialNumber");
    }
    
    private string QueryWMI(string table, string property, string condition = "")
    {
        try
        {
            string query = $"SELECT {property} FROM {table} {condition}";
            
            using (ManagementObjectSearcher searcher = 
                new ManagementObjectSearcher(query))
            {
                foreach (ManagementObject obj in searcher.Get())
                {
                    object value = obj[property];
                    if (value != null)
                    {
                        return value.ToString();
                    }
                }
            }
        }
        catch
        {
            // Fail silently and return empty string
        }
        
        return string.Empty;
    }
    
    private string ComputeHash(string input)
    {
        using (SHA256 sha256 = SHA256.Create())
        {
            byte[] bytes = Encoding.UTF8.GetBytes(input);
            byte[] hash = sha256.ComputeHash(bytes);
            
            return BitConverter.ToString(hash).Replace("-", "").ToLower();
        }
    }
}
WMI queries require appropriate permissions. Ensure the application runs with sufficient privileges to access hardware information.

Integration with Player Model

Extend the Player class to include hardware identification:
// Player.cs - Enhanced with hardware ID
class Player
{
    public string IP { get; set; }
    public string HardwareID { get; set; }
    public DateTime FirstSeen { get; set; }
    public DateTime LastSeen { get; set; }
    public bool IsBanned { get; set; }
    public string BanReason { get; set; }
}

Session Registration with Hardware ID

// Form1.cs - Modified to include hardware ID
public void Form1_Load(object sender, EventArgs e)
{
    try
    {
        client = new FireSharp.FirebaseClient(fcon);
    }
    catch
    {
        MessageBox.Show("there was problem in the internet.");
    }

    // Generate random session name
    GenerateRandomNames names = new GenerateRandomNames();
    Random rand = new Random();
    randomName = names.GenerateRandomName(rand);

    // Obtain player's public IP address
    PublicIPAddress IpAddressPlayer = new PublicIPAddress();
    IpPlayer = IpAddressPlayer.GetPublicIPAddress();
    
    // Generate hardware fingerprint
    HardwareFingerprint hwFingerprint = new HardwareFingerprint();
    string hardwareId = hwFingerprint.GenerateFingerprint();

    // Register player with both IP and hardware ID
    PlayAcON(hardwareId);
}

private void PlayAcON(string hardwareId)
{
    Player ply = new Player()
    {
        IP = IpPlayer,
        HardwareID = hardwareId,
        FirstSeen = DateTime.UtcNow,
        LastSeen = DateTime.UtcNow,
        IsBanned = false
    };
    
    // Store player data in Firebase
    var setter = client.Set("PlayerIpList/" + randomName, ply);
    
    // Check if hardware ID is banned
    CheckBanStatus(hardwareId);
}

Ban Checking System

Implement hardware ID-based ban verification:
public class BanChecker
{
    private IFirebaseClient client;
    
    public BanChecker(IFirebaseClient firebaseClient)
    {
        client = firebaseClient;
    }
    
    /// <summary>
    /// Checks if a hardware ID is banned
    /// </summary>
    public async Task<BanStatus> CheckHardwareIdBan(string hardwareId)
    {
        try
        {
            // Query ban database for hardware ID
            var response = await client.GetAsync($"BannedPlayers/{hardwareId}");
            
            if (response.Body != "null")
            {
                // Player is banned
                BanRecord ban = response.ResultAs<BanRecord>();
                
                return new BanStatus
                {
                    IsBanned = true,
                    BanReason = ban.Reason,
                    BanDate = ban.BanDate,
                    IsPermanent = ban.IsPermanent,
                    ExpiryDate = ban.ExpiryDate
                };
            }
            
            // Player is not banned
            return new BanStatus { IsBanned = false };
        }
        catch (Exception ex)
        {
            throw new Exception($"Error checking ban status: {ex.Message}");
        }
    }
}

public class BanRecord
{
    public string HardwareID { get; set; }
    public string Reason { get; set; }
    public DateTime BanDate { get; set; }
    public bool IsPermanent { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string BannedBy { get; set; }
}

public class BanStatus
{
    public bool IsBanned { get; set; }
    public string BanReason { get; set; }
    public DateTime BanDate { get; set; }
    public bool IsPermanent { get; set; }
    public DateTime? ExpiryDate { get; set; }
}

Ban Enforcement Flow

private async void CheckBanStatus(string hardwareId)
{
    BanChecker banChecker = new BanChecker(client);
    BanStatus status = await banChecker.CheckHardwareIdBan(hardwareId);
    
    if (status.IsBanned)
    {
        // Display ban message and prevent access
        if (status.IsPermanent)
        {
            MessageBox.Show(
                $"Your account has been permanently banned.\n\n" +
                $"Reason: {status.BanReason}\n" +
                $"Ban Date: {status.BanDate:yyyy-MM-dd}",
                "Access Denied",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error
            );
        }
        else
        {
            MessageBox.Show(
                $"Your account is temporarily banned.\n\n" +
                $"Reason: {status.BanReason}\n" +
                $"Ban Expires: {status.ExpiryDate:yyyy-MM-dd HH:mm}",
                "Access Denied",
                MessageBoxButtons.OK,
                MessageBoxIcon.Warning
            );
        }
        
        // Close application
        Application.Exit();
    }
}
Hardware ID bans should be checked before launching the game and TopMost protection window to prevent resource usage by banned players.

Handling Hardware Changes

Legitimate hardware changes (upgrades, repairs) can affect hardware fingerprints:

Fuzzy Matching Approach

public class FuzzyHardwareMatch
{
    /// <summary>
    /// Calculates similarity between two hardware fingerprints
    /// </summary>
    public double CalculateSimilarity(string fingerprint1, string fingerprint2)
    {
        // Compare individual components
        var components1 = DecomposeFingerprint(fingerprint1);
        var components2 = DecomposeFingerprint(fingerprint2);
        
        int matches = 0;
        int total = components1.Count;
        
        for (int i = 0; i < total; i++)
        {
            if (components1[i] == components2[i])
            {
                matches++;
            }
        }
        
        return (double)matches / total;
    }
    
    /// <summary>
    /// Determines if fingerprints are similar enough to be the same system
    /// </summary>
    public bool IsSameSystem(string fingerprint1, string fingerprint2, 
        double threshold = 0.6)
    {
        // If 60% or more components match, consider it the same system
        return CalculateSimilarity(fingerprint1, fingerprint2) >= threshold;
    }
}

Hardware Change Verification

public async Task<bool> VerifyHardwareChange(string oldHwId, string newHwId)
{
    FuzzyHardwareMatch matcher = new FuzzyHardwareMatch();
    
    // Check if hardware is similar enough
    if (matcher.IsSameSystem(oldHwId, newHwId, 0.6))
    {
        // Update hardware ID in database
        await UpdatePlayerHardwareId(oldHwId, newHwId);
        return true;
    }
    
    // Too many changes - require manual verification
    return false;
}
Allow 1-2 hardware component changes without requiring reverification, as players commonly upgrade RAM or storage drives.

Privacy Considerations

Hardware identification raises privacy concerns:

Best Practices

1

Hash Hardware IDs

Always hash hardware identifiers before storage to prevent reverse engineering
2

Minimize Data Collection

Only collect hardware information necessary for identification
3

Secure Transmission

Use HTTPS/TLS for all hardware ID transmissions to Firebase
4

Data Retention Policies

Implement automatic deletion of old hardware IDs after inactivity periods
5

Transparent Disclosure

Inform users that hardware identification is used for anti-cheat purposes

GDPR Compliance

public class PrivacyCompliance
{
    /// <summary>
    /// Anonymizes hardware ID before storage
    /// </summary>
    public string AnonymizeHardwareId(string hardwareId)
    {
        using (SHA256 sha256 = SHA256.Create())
        {
            byte[] bytes = Encoding.UTF8.GetBytes(hardwareId + GetSalt());
            byte[] hash = sha256.ComputeHash(bytes);
            return Convert.ToBase64String(hash);
        }
    }
    
    /// <summary>
    /// Deletes all data associated with a hardware ID
    /// </summary>
    public async Task DeletePlayerData(string hardwareId)
    {
        // Remove from active sessions
        await client.DeleteAsync($"PlayerIpList/{hardwareId}");
        
        // Remove from ban database
        await client.DeleteAsync($"BannedPlayers/{hardwareId}");
        
        // Remove from historical records
        await client.DeleteAsync($"PlayerHistory/{hardwareId}");
    }
}

Performance Optimization

Hardware identification should not impact startup time:

Caching Strategy

public class HardwareIdCache
{
    private static string cachedHardwareId = null;
    private static DateTime cacheTime;
    private static readonly TimeSpan CacheExpiry = TimeSpan.FromHours(24);
    
    public string GetCachedHardwareId()
    {
        if (cachedHardwareId != null && 
            DateTime.Now - cacheTime < CacheExpiry)
        {
            return cachedHardwareId;
        }
        
        // Regenerate hardware ID
        HardwareFingerprint fingerprint = new HardwareFingerprint();
        cachedHardwareId = fingerprint.GenerateFingerprint();
        cacheTime = DateTime.Now;
        
        return cachedHardwareId;
    }
}
Caching reduces WMI query overhead. Hardware rarely changes, so daily regeneration is sufficient.

Advantages Over IP-Based Identification

AspectIP AddressHardware ID
VPN Bypass❌ Easy✅ Impossible
Proxy Bypass❌ Easy✅ Impossible
Dynamic IP❌ Problematic✅ No Issue
Shared Networks❌ False Positives✅ Unique Per Device
Cost to Evade$ Low$$$ High
Persistence❌ Temporary✅ Permanent
While hardware ID is much more resistant to evasion, determined attackers can still spoof hardware identifiers using specialized tools. Combine with behavior analysis for best results.

Testing Hardware Identification

Unit Tests

[TestClass]
public class HardwareIdTests
{
    [TestMethod]
    public void TestBiosUuidRetrieval()
    {
        HardwareIdentification hwId = new HardwareIdentification();
        string uuid = hwId.GetBiosUUID();
        
        Assert.IsFalse(string.IsNullOrEmpty(uuid), 
            "BIOS UUID should not be empty");
        Assert.IsTrue(uuid.Contains("-"), 
            "BIOS UUID should contain hyphens");
    }
    
    [TestMethod]
    public void TestFingerprintConsistency()
    {
        HardwareFingerprint fingerprint = new HardwareFingerprint();
        
        string id1 = fingerprint.GenerateFingerprint();
        string id2 = fingerprint.GenerateFingerprint();
        
        Assert.AreEqual(id1, id2, 
            "Hardware fingerprint should be consistent");
    }
}

Summary

Hardware identification provides:
  • VPN-Resistant Bans: Cannot be evaded by changing IP addresses
  • Unique Per Device: Each computer has a distinct fingerprint
  • Permanent Tracking: Hardware changes are rare and expensive
  • Automated Management: No manual registration required
The system works by:
  1. Collecting hardware identifiers (primarily BIOS UUID)
  2. Generating a unique fingerprint hash
  3. Checking fingerprint against ban database
  4. Enforcing bans based on hardware rather than IP
For production deployment, implement hardware ID collection alongside the existing IP address tracking for a comprehensive player identification system.

Build docs developers (and LLMs) love