How can I get a signature for a Windows system that will remain unchanged even if the user reinstalls Windows?


The System­Identification runtime class (introduced in the Windows 10 Anniversary Update) gives you a signature for a Windows system that will remain unchanged even if the user reinstalls Windows. There are some caveats, though.

To obtain a value that is consistent across reinstalls of Windows, the method uses the Trusted Platform Module (TPM), or if a TPM is not available, the Unified Extensible Firmware Interface (UEFI). If neither is available, then starting in the Fall Creators Update, the method creates a unique ID and saves it in the registry. The registry value is preserved across upgrades, but is lost if the user performs a clean install of Windows. You can use the Source property to determine how the signature was generated.

The value you receive is specific to the publisher specified in your application manifest. If you are a classic Win32 app with no manifest, then the system will use a generic "publisher" that is used for all publisher-less apps. Signatures generated for apps with the same publisher will match. Signatures generated for apps with different publishers will not match.

Here's some sample code:

// JavaScript

var buffer = Windows.System.Profile.SystemIdentification.
                                      getSystemIdForPublisher();
var id  = buffer.id;
var asHex = Windows.Security.Cryptography.CryptographicBuffer.
                                      encodeToHexString(id);
var asBase64 = Windows.Security.Cryptography.CryptographicBuffer.
                                      encodeToBase64String(id);

// C#

var buffer = Windows.System.Profile.SystemIdentification.
                                      GetSystemIdForPublisher();
var id = buffer.Id;
var asHex = Windows.Security.Cryptography.CryptographicBuffer.
                                      EncodeToHexString(id);
var asBase64 = Windows.Security.Cryptography.CryptographicBuffer.
                                      EncodeToBase64String(id);

// C++/CX

auto buffer = Windows::System::Profile::SystemIdentification::
                                      GetSystemIdForPublisher();
auto id = buffer->Id;
auto asHex = Windows::Security::Cryptography::CryptographicBuffer::
                                      EncodeToHexString(id);
auto asBase64 = Windows::Security::Cryptography::CryptographicBuffer.
                                      EncodeToBase64String(id);
// C++/WinRT

auto buffer = Windows::System::Profile::SystemIdentification::
                                      GetSystemIdForPublisher();
auto id = buffer.Id();
auto asHex = Windows::Security::Cryptography::CryptographicBuffer::
                                      EncodeToHexString(id);
auto asBase64 = Windows::Security::Cryptography::CryptographicBuffer.
                                      EncodeToBase64String(id);

// Raw C++ with WRL

using namespace ABI::Windows::Storage::Streams;
using namespace ABI::Windows::System::Profile;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

ComPtr<ISystemIdentificationStatics> systemIdStatics;
RoGetActivationFactory(HStringReference(
    RuntimeClass_Windows_System_Profile_SystemIdentification).Get(),
    IID_PPV_ARGS(&systemIdStatics));

ComPtr<ISystemIdentificationInfo> info;
systemIdStatics->GetSystemIdForPublisher(&info);

ComPtr<IBuffer> id;
info->get_Id(&id);

ComPtr<ICryptographicBufferStatics> cryptoBufferStatics;
RoGetActivationFactory(HStringReference(
    RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
    IID_PPV_ARGS(&cryptoBufferStatics));

HString asHex;
cryptoBufferStatics->EncodeToHexString(id.Get(),
                                       asHex.GetAddressOf());

HString asBase64;
cryptoBufferStatics->EncodeToBase64String(id.Get(),
                                          asBase64.GetAddressOf());

If you want to operate with the raw bytes instead of just encoding them into hex or base64, you can use the IBufferByteAccess interface or the Cryptographic­Buffer.Copy­To­Byte­Array method.

Comments (12)
  1. Mason Wheeler says:

    You ask how, I ask why.

    What is the legitimate use case for this technology? I can think of plenty of reasons why I’d love to see something like this if I was writing malware, (or advertising, but I repeat myself,) but no reasons to want to do it that don’t involve causing problems for the person on whose computer this code is running.

    1. From what I can gather, the intended audience is mobile device management. If the phone gets wiped and then re-enrolls, the enrollment utility can detect this and reuse the provisioning resources.

      1. Brian_EE says:

        Could this also be used for “Trial-Ware” where time-limited versions of programs can’t have the clock reset by reinstalling?

    2. Licensing. Like it or not, Windows, Quickbooks, Oracle, and so many others pin activation to some magic mix of hardware and software; no one has to use it, but at least Microsoft is providing a transparent API instead of some wholly private one.

  2. Joshua says:

    Thou has summoned the third rail.

    About 20 years ago Intel wanted to put a per-CPU identifier in the processor and the consumer market said NO!

    This time it got done silently. Expect in a couple of years a consumer demand at the system level to break this trick.

  3. Nik says:

    How is this different from Intel’s processor ID that made everyone so angry in the 1990s ?

  4. Thiago Macieira says:

    How does that compare to HKLM\Software\Microsoft\Cryptography\MachineGuid? That has been available for longer

    1. skSdnW says:

      This is one of two things people call “the machine guid” and you can reset this one by deleting the registry value (you will probably loose the ability to decrypt certain secrets already stored on the machine by crypto stuff). It might also be the same value on different machines when a machine is cloned etc.

  5. SomeGuyOnTheInternet says:

    What would be the implications if the identifier was the same for all publishers, rather than being publisher-specific?

    1. JDG says:

      The code libraries published by advertisers for inclusion in sundry applications would be able to positively identify when different instances in different apps were in fact running on the same device. That in turn would allow the advertiser to aggregate information across uses and interests spanning different apps by different publishers, which by many is seen as a violation of individuals’ expectations of privacy.

  6. Jeroen says:

    I can sort of see the argument, Real Men Use Raw C++

  7. hyperman says:

    The times they are a-changing. I remember when the Pentium CPU introduced a serial number to identify customers at the end of the nineties. A huge backlash caused Intel to disable it. 20 years later, no one seems to care.

    Anyway, https://en.wikipedia.org/wiki/Pentium_III#Controversy_about_privacy_issues if you want to know more

Comments are closed.

Skip to main content