7

I want to bind a program to a specific computer, and for that I want to use the serial number of the motherboard as unique identifier.

Although I could find some examples for C# and Java, I couldn't find anything reliable for C++ (I read WMI can fail depending on the hardware), but surely there's a way to do this in C++ too?

Edit : What I want is, in other words, like a simple and rudimentary licensing system. To make it more clear, here's how it would look like :

#define USER_SERIAL 123456789

double GetMotherBoardSerialNumber();
// ...

double currentSerial = GetMotherBoardSerialNumber();

if(currentSerial != USER_SERIAL) {
    exit 1;
}

It is obviously not perfect, but I don't have any server atm to set up an account system so this could be a temporary solution.

AlexAngc
  • 311
  • 2
  • 3
  • 11
  • Related: http://stackoverflow.com/questions/23675550/motherboard-id-wmi-c-reliable and http://stackoverflow.com/questions/1290533/wmi-win32-baseboard-serialnumber – Rakete1111 Apr 18 '17 at 13:16
  • 1
    Yeap, I read those already, but as mentioned in the first answer (about WMI) : _"What I have found is that retrieving the serial number of the mother board can result in very different results depending on the manufacturer and the distribution channel. "_ – AlexAngc Apr 18 '17 at 13:17
  • @Ðаn My thought process was that, the serial number being by definition unique, it would make a decent identifier. And yes, the purpose is to avoid "free propagation", I want to compile once for a specific user only. – AlexAngc Apr 18 '17 at 13:28
  • 1
    @Angry Club just generate GUID – Kamila Szewczyk Apr 18 '17 at 13:29
  • 1
    You might also want to consider that repairing the computer being a license violation will make some customers extremely frustrated. – Bo Persson Apr 18 '17 at 13:38
  • 1
    @BoPersson makes a good point. And this questions is getting worse. Of course get the server up and running. And use the cpuid and mac address to track which computers your users have, and to detect hacked accounts. – Jeff Apr 18 '17 at 14:04
  • 2
    *"I want to compile once for a specific user only."* - If you are serious about your software, you will have to keep debug symbols in your office **for each and every release**. It doesn't take an insane number of customers to require terabytes of storage for the debug symbols alone. This approach doesn't scale well. – IInspectable Apr 18 '17 at 14:20
  • 1
    Besides, you don't need a server to implement identity management. There are ready-made solutions out there already (like [Auth0](https://auth0.com/)) that you can use without setting up, managing, and securing your own server. – IInspectable Apr 18 '17 at 14:26
  • I reckon you've all made valid points that I mostly agree with, however you only provided work-around or alternative solutions. I maintain that **what I want** is to know whether or not it is possible to reliably get serial numbers from hardware components in C++, and ideally from the motherboard. Keep in mind my program is only an incomplete prototype atm. I want users to use it and give feedback, but I also want to keep some sort of "control" over it, without having to spend more time on the control solution than on the program itself. – AlexAngc Apr 18 '17 at 16:35
  • @AngryCub See my answer that someone down voted with no explanation. The SMBIOS is reliable and you can pick and choose which things you want to use as an identifier. This is what WMI is built upon. – djgandy Apr 18 '17 at 17:49
  • @djgandy Thanks, I will investigate it tomorrow, as it seems that this would need a bit of reading before I understand it ! – AlexAngc Apr 18 '17 at 18:34
  • @AngryCub It may look scary to start with but its pretty easy to parse the table and you can just ignore things you don't care about. Another alternative is the hard drive serial number which can be read from SMART iirc. – djgandy Apr 19 '17 at 08:39

2 Answers2

5

If you want real serial numbers I recommended parsing the SMBIOS table.

The first time I dived into getting reliable real hardware id's I ended up reading the SMBIOS directly from mapped Physical Memory (Windows XP). I had tried other approaches that many recommend before this but some were very unreliable and in deployment it was noted that there were duplicates across clients with some of the other methods. How could 20+ people have identical serials? It made no sense and seemed like OEM's had set fields.

From Windows Vista onwards the correct method to retrieve the table is through GetSystemFirmwareTable. This is because it is no longer possible to map Physical Memory on Windows Vista from user-mode (XP64 & Server 2003 were the same too)

GetSystemFirmwareTable can be used to get the SMBIOS data which you can then parse according to the SMBIOS spec. There's a fair amount of data in the table so generating a unique identifier shouldn't be too difficult. IIRC you generally even get serials for DRAM etc...

I would also recommend testing this thoroughly and having a backup plan if the call fails. There are instances where it just fails and having a good idea of the environment that causes failures will save you a lot of time. If my memory serves me right in the Vista days I had issues with UAC and elevated privileges, however MS may have have changed that since then!

djgandy
  • 1,125
  • 6
  • 15
2

You can look at this registry key: [HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS]. You will see following:

"BiosMajorRelease"
"BiosMinorRelease"
"ECFirmwareMajorRelease"
"ECFirmwareMinorRelease"
"BaseBoardManufacturer"
"BaseBoardProduct"
"BaseBoardVersion"
"BIOSReleaseDate"
"BIOSVendor"
"BIOSVersion"
"SystemFamily"
"SystemManufacturer"
"SystemProductName"
"SystemSKU"
"SystemVersion"

If this doesn't satisfy you, you can still use GetSystemInfo function. I think this use of motherboard information wouldn't help you as unique id. If you want to get unique computer identifier, use GUID or something. To create GUID you need to just:

GUID gidReference;
HRESULT hCreateGuid = CoCreateGuid( &gidReference );
Kamila Szewczyk
  • 1,874
  • 1
  • 16
  • 33
  • 1
    Good information, but the serial number is not included – Jeff Apr 18 '17 at 13:27
  • @Jeff Do you want it to generate computer UID? – Kamila Szewczyk Apr 18 '17 at 13:28
  • @Joel Yes, the purpose of the serial number is to serve as unique identifier – AlexAngc Apr 18 '17 at 13:30
  • @AngryCub so look at my edit, with this you can obtain Unique identifier, write to registry and read this uid from registry. – Kamila Szewczyk Apr 18 '17 at 13:31
  • @Joel Oh wait, I see now you edited your answer, let me look into that new elements – AlexAngc Apr 18 '17 at 13:31
  • @Joel - Associating a guid with a user id is not a very good solution. – Jeff Apr 18 '17 at 13:40
  • @Jeff If you will write it to registry and protect key somewhat (put it into meaningless place), it looks like pretty good alternative. – Kamila Szewczyk Apr 18 '17 at 13:41
  • The CoCreateGuid() solution actually doesn't solve my problem, I will edit my question to make what I want more clear ! – AlexAngc Apr 18 '17 at 13:41
  • @Joel - guids in a registry are easily copied, and your solution is easily manipulated. – Jeff Apr 18 '17 at 13:43
  • 1
    @Jeff using some programs you can force OP's soft to think that computer's motherboard id is explicitly the same as OP passes in code (Remember, you can't hide anything from reverse-engineers) – Kamila Szewczyk Apr 18 '17 at 13:46
  • @Joel - your reminder should be directed toward yourself, as it helps my point against associating guids in the registry. A proper solution should be verifyable. I expected you to suggest cpuid, which is very easy to get. – Jeff Apr 18 '17 at 13:54
  • Original question edited. About potential bypass, ofc this idea isn't foolproof (but what offline program can say it's uncrackable anyway ?), but I think it's a good base to begin with. – AlexAngc Apr 18 '17 at 13:57
  • Also the reason why I favoured motherboard serial to other component's id is that it's usually the component that you change the least often. – AlexAngc Apr 18 '17 at 13:58