All posts

Licensing security

Hardware IDs break. We're here to fix that.

SL-HWID makes hardware locking more resilient for legitimate customers and more difficult to forge.

By System Locker 5 min read

Locking licenses to a single machine is core to piracy prevention for most of the developers we support. Yet, this lock creates a single point of failure. Computers don't ship with a single trustworthy serial number stamped on the case, so licensing systems derive a hardware ID from whatever seems the most stable (and hardest to fake). This creates a squeeze, where the strongest locks are often the most brittle, and the weakest locks become the easiest to bypass.

This post covers why hardware IDs are so finicky in practice, why attackers spend so much effort on them, and how our SL-HWID module handles both problems better than hashing a machine GUID or a CPU serial number.

Copy this tutorial and its code examples as plain text for an AI assistant or a clarifying question.

Why hardware IDs are finicky

A hardware ID has one job: stay the same for as long as the customer owns the computer, and change if the software moves to a different one. Real hardware refuses to cooperate.

Parts change for innocent reasons all the time. A GPU upgrade, a new monitor, a swapped network card, a second stick of RAM. Reinstalling Windows regenerates the machine GUID from nothing. Cloning a drive isn't guaranteed to bring the volume serial string along; it depends entirely on the tool. Some motherboards report a BIOS serial of literally "To be filled by O.E.M.," which is exactly as useful as it sounds. Virtual machines complicate things further, because a clone inherits its template's identifiers until something regenerates them.

Every one of these events looks identical to theft from the server's point of view. The key is the same, the hardware ID is different, so the server rejects the request. Now your customer is creating tickets and blowing up your DMs, and you're deciding whether they're telling the truth about the "new router" they just bought. That's unsustainable, because it frustrates real users and wastes support time as you try to determine whether the user is being genuine.

Why hardware IDs get attacked

Hardware locking exists because license keys leak. A key posted to a forum or Discord server gets picked up by hundreds of people within hours. If your server checks only the key, all of them get in. Checking the key against a hardware ID is what turns one stolen key into one working installation, which is precisely why the hardware ID becomes the target.

Attackers have an easy time with single-source identifiers. The Windows machine GUID sits in the registry where any process can read it, and spoofing tools will happily set it to anything. CPU serial numbers are frequently disabled by the firmware, so half the industry falls back to values that are even easier to alter. Even worse is the MAC address, which can change with a USB dongle or a software toggle.

There's a subtler problem too: if an attacker captures one legitimate pair of key and hardware ID, perhaps from a friend with a shared account, they know the exact value the server expects. With a hashed machine GUID, they don't need to understand your scheme at all. They set the GUID on their own machine, and the check passes. A single identifier is both brittle against honest hardware changes and trivially forgeable against dishonest ones. It fails in both directions at once.

How SL-HWID is different

SL-HWID takes a different approach: instead of trusting one identifier, it combines fourteen hardware factors by default: machine GUID, CPU identifier, GPU driver, OS build, and more. Any two of them can fail and the hardware ID stays stable.

Critically, our combination isn't a hash. Why? Because the entire point of hashes is that they're sensitive to any change, so a single character difference produces a completely different ID, which puts us right back in the false-positive quagmire. SL-HWID instead uses a cryptographic threshold scheme. When it first runs, the module generates a random secret and splits it into chunks, with each chunk bound to a discrete hardware factor. On subsequent runs, it can only recreate the random key if enough factors are still present and correct. The secret key remains available even after changing a couple of parts, but if too many change, it cannot be retrieved.

Another benefit over older HWID schemes: the ID sent to the server is completely unrelated to any personal or machine-specific data, because it's random. Unlike a raw serial number, it reveals nothing about your hardware to anyone who intercepts it, and the value we store locally to verify recovery is cryptographically separated from the value that leaves the house.

For an attacker, the economics shift. Faking a machine GUID takes just one registry write. But fooling SL-HWID means making a different machine agree on enough live hardware factors while also possessing the locally stored device state, which is massively harder. At the same time, your legitimate customers can stop getting locked out when they replace a hard drive.

What SL-HWID doesn't do

No client-side control makes software unbreakable, and we'd rather be honest about this than imply otherwise. An attacker who copies the entire storage location and matches the hardware can still share a license, the same as with any hardware lock. And advanced techniques involving binary patching and memory manipulation are still real threats, which is why we recommend using virtualization, string encryption, and other obfuscation techniques.

What SL-HWID does is raise the cost of forgery substantially while cutting false positives for paying customers. We've made these two goals, which are usually in tension, work in your favor.

Using it

SL-HWID is built into the Bedrock authentication libraries for .NET, Go, Node.js, and Python, and it derives the hardware ID by default once you're on version 1.0.0. The C++ library requires it to be enabled specifically. A standalone C++ and .NET library is also available on GitHub for anyone to use as part of their own protection stack, even if you aren't a System Locker user. The Bedrock documentation covers configuration and migration details.

How to set up SL-HWID with Bedrock C++

The Bedrock C++ client leaves hardware locking disabled by default. Set hwid to an empty string to opt into SL-HWID; sl-hwid is already the default mode. The client prepares the identifier during authentication and commits any ordinary hardware drift only after the server authorizes the session.

#include <syslocker/bedrock/client.hpp>

syslocker::bedrock::Config config;
config.systemId = "YOUR_SYSTEM_ID";
config.signingPublicKey = "YOUR_BEDROCK_SIGNING_PUBLIC_KEY";
config.version = "1.0.0";
config.hwid = ""; // Empty opts into SL-HWID; "1" disables device locking.

syslocker::bedrock::Client client(config);
const auto result = client.authenticateWithKey("YOUR_LICENSE_KEY");
if (!result) {
    // Do not grant access when Bedrock cannot authenticate the session.
    return ShowAccessError(result.error().message);
}
if (!result->sessionStarted) {
    return ShowAccessError(result->response.humanResponse);
}

How to set up SL-HWID with Bedrock C#

The Bedrock .NET client uses SL-HWID by default from version 1.0.0. Leave Hwid empty and do not replace HwidMode; a custom value overrides SL-HWID, while "1" deliberately disables device locking.

using SystemLocker.Bedrock;

var config = new BedrockConfig
{
    SystemId = "YOUR_SYSTEM_ID",
    SigningPublicKey = "YOUR_BEDROCK_SIGNING_PUBLIC_KEY",
    Version = "1.0.0",
    Hwid = "", // Empty is the default and enables SL-HWID.
    HwidMode = "sl-hwid",
};

await using var client = new BedrockClient(config);
var result = await client.AuthenticateWithKeyAsync("YOUR_LICENSE_KEY");
if (!result.SessionStarted)
{
    ShowAccessError(result.Response.HumanResponse);
}

Migrating an existing system? Reset every existing HWID after deploying SL-HWID to your customers. SL-HWID intentionally produces a new identifier, so existing device claims would otherwise report an HWID mismatch.

Ready to stop chasing HWID support tickets and worrying about cracks?

SL-HWID ships built into the Bedrock libraries. Create a developer account to try it, or talk through your setup with us on Discord.