Uniquely identify PC based on software/hardware - c++

For a requirement to generate per-PC license keys, I need some code which will return a stable and (near) unique key on any PC. It doesn't have to be guaranteed unique, but close. It does need to be reasonably stable though, so that a given PC always generates the same result unless the hardware is substantially changed.
This is for a Windows application, using wxWidgets but a Win32 or other option is fine.
I was thinking about MAC address but what about laptops which can routinely disable the network card in power-saving mode? I came across GetCurrentHwProfile but it doesn't quite look like what I want?

One idea I had a while back for this is to use CryptProtectData as a way to identify a machine. Behind-the-scenes in that API, Microsoft has done what you're looking for. I never tested it though and I'm curious if it's actually viable.
Basically you would encode a constant magic value with CryptProtectData with CRYPTPROTECT_LOCAL_MACHINE, and the result is your machine ID.

I would just go with the MAC address method; when the wireless / LAN cards are turned off they still show up in Network Connections. You should therefore still be able to get the MAC.
Consider this: Any time you'd be able to contact your webserver or whatever you're cataloging these IDs with, the user is going to have to have some form of network card available.
Oh, and you might be able to use CPU serial number of the customer's computer supports it.

I think there no really easy and unique method so far discovered here.
GetVolumeInformation retrieves not even close to unique ID.....
To use any hardware serial is problematic because manufactures are not committed to supported it always and especially to keep it globally unique
GetCurrentHwProfile retrieves GUID but it's value affected by minor! hardware changes...
Using Product Key ... will bring U to deal with the stolen software - there lot of pirate installations over the globe.
Creation of own GUID and preserving it under registry (in any place) will not prevent duplication by cloning of image ....
etc...
From my perspective of view the best way is combine:
Volume ID + MAC's list + Machine SID + Machine Name. And obviously manage license policy on the server side ;0)
Regards
Mickel.

If you want something a bit harder to spoof than whatever the machine itself can tell you, you'll probably need to provide a USB dongle dedicated for this purpose (not just a flash drive).

For a pretty brain dead test I am using the ProductID code of the OS and the computer name - both extracted from the registry. Not really secure, but its all pretend security anyway.
edit
To answer John's question about what keys I am reading:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID
SYSTEM\CurrentControlset\Control\ComputerName\ComputerName\ComputerName

How about using the serial number of the harddisk where windows is installed?
The function GetVolumeInformation() will give you such serial number.
To access the ID assigned by the harddisk vendor instead of the ID assigned by Windows, you can use the Win32_PhysicalMedia Class.
To determine the drive where windows is installed, you could expand the variable %windir" by using the function ExpandEnvironmentStrings()
Another option, if your architecture allows, is to use UuidCreate() to generate a random GUID at installation time and save it permanently in the registry. This GUID can then be used as the ID as long as the registry remains. A new registry database is generally considered as a new installation.
A third option is to have a well-known server assigning the IDs. Upon starting up, the software could look up for the ID in the registry and if not found, would contact the server and supply it with its MAC address, hostname, harddisk serial number, Machine SID and any number of indentifyable information (keys).
The server then determines if the client is already registered or not based on the information given. The server could have a relaxed policy and for example only require most of the keys for a match, so that the mechanism would work even in the event of a complete wipe out of the registry and if part (but not all) of the hardware was replaced.

How about using the serial number of a CPU. I remember Microsoft used to provide an api for this that would run the necessary assembler code and give you back all sorts of info about the CPU including serial number. Not sure if it'd work with AMD chips or not, I think it was intel specific.
Surely CPU Id is secure and static enough!!

Related

Linux Equivalent of MachineGuid

I have program that needs OS installation fingerprint like one in MSW stored at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid
In Microsoft Windows I have it ready for me but I cannot find equivalent for Linux. Is there anything close to this in Linux? I will not have root access so anything like dmidecode -s system-uuid becomes out of the question.
An example will be nice but no necessary.
One possibility would be to read /etc/ssh/ssh_host_{d,r}sa_key.pub, which are readable by all, and are randomly generated during installation.
Obviously the problem is that those files may not exist at all, if there is no SSH (server) installed. They are also often copied from an older installation.
I believe MAC addresses are not a good choice for identifying a machine. There are many USB dongles which may be plugged into a PC to provide a mobile/3G/H+/etc. network interface, so while such a dongle is plugged into the machine, it will have a different id derived from available network interface MAC addresses.
Is /etc/machine-id (/var/lib/dbus/machine-id) available on your target system?
see: http://man7.org/linux/man-pages/man5/machine-id.5.html
see: http://0pointer.de/blog/projects/ids.html
The canonical Unix'y answer is the Host ID, but in practice, this often ends up falling back on a hash of the IP address…
#include <unistd.h>
long gethostid(void);
int sethostid(long hostid);
DESCRIPTION
gethostid() and sethostid() respectively get or set a unique 32-bit identifier for
the current machine. The 32-bit identifier is intended to be unique among all UNIX
systems in existence. This normally resembles the Internet address for the local
machine, as returned by gethostbyname(3), and thus usually never needs to be set.
NOTES
In the glibc implementation, the hostid is stored in the file /etc/hostid. (In glibc
versions before 2.2, the file /var/adm/hostid was used.)
In the glibc implementation, if gethostid() cannot open the file containing the host
ID, then it obtains the hostname using gethostname(2), passes that hostname to geth‐
ostbyname_r(3) in order to obtain the host's IPv4 address, and returns a value
obtained by bit-twiddling the IPv4 address. (This value may not be unique.)
I assume you're trying to do this because you want to "lock" the software to a specific piece of hardware?
One option is to use the MAC address of a network interface to identify the current machine. The MAC address is fairly easy to get at, see this Stackoverflow question.
This nicely works around issues with changing IPs etc as the MAC address of an interface is much less likely to change unless someone replaces the network card.

Is it possible to programmatically alter a USB<->Serial converter's 'BM' latency option?

Is there any way to programmatically alter the 'BM Options Latency Timer' of a USB<->Serial adapter? Needs to work on embedded windows xp. Can be a .net 2.0 or native windows solution...
I think you are using an FTDI USB serial converter. Then you can use libftdi
And check out the Application Notes (especially AN232B-04) because they contain lots of useful information.
This is driver specific. Your best bet is to do what romkyns says and try to figure out where the driver stores this setting. You will probably need to close and reopen the serial port after changing the setting assuming you are able to find out how it is stored and are able to change it.
As of 2016, the advice in AN232B-04 may be outdated due to changes in the Windows driver infrastructure. Nowadays, there's a requirement to sign all files in a driver package, which means that editing values in a inf/cat file while otherwise using the stock FTDI driver is not possible without re-signing the driver.
If you're using libftdi, you can configure this value at runtime, as per rve's answer. If you prefer to use FTDI's own driver and Windows' standard COM port API, and you need to configure this value, you can still change it permanently and programmatically by editing the registry.
If you go this route, you need to change the DWORD value LatencyTimer under the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_0403+PID_6001+KBxxxxxxx\0000\Device Parameters. KBxxxxxxx in this example needs to be replaced by the serial number of your device. You would need higher privileges to change this value, eg by raising a UAC prompt. The device driver may need to be restarted at that point for the changes to take effect, for example by unplugging and replugging the device.

Restrict application usage

I would like to restrict people using my application to one Computer, so I was thinking about IP's.. but people in some countries get new IP's after they reboot their Internet.. so I need something better to identify the users, like some value that doesn't change until the user performs a format.
Thanks
The MAC address of e.g. an ethernet interface typically doesn't change even across formats (only if the user changes ethernet interface card). Don't worry, nothing to do with Apple Macs, MAC stands for Media Access Control;-).
You will probably need some registration process, so you could tell the user that you will connect to get some update, and in that process send the serial number of the application and the mac address. If the serial number has already been registered then return an error to the user.
Ideally you should perhaps download some needed dll that is tied to a specific serial number and perhaps mac address, so that if the user copies the dll to a different program it will require more work to get it to work.
It depends on how much you want to inconvenience the user as to the best approach, I believe.
Where I specified dll could be any assembly, jar file, etc, that the language in question uses for running the application.

EnumPorts() returns strange error on some machines

I maintain an application that uses the win32 EnumPorts() function to help determine the set of serial ports installed on the computer. I have seen cases on some computers where the call to get this information fails with a GetLastError() code of 1722 (RPC server is unavailable). I assume that this has something to do with either registry settings or a required service being disabled but my search so far has been rather fruitless. Has anyonw else encountered this issue?
In answer to Euro Micelli's comments. I am specifically attempting to fill a pick list that will allow the user to choose an available picklist. To begin with, I relied exclusively on EnumPorts() to provide me a list of potential serial port names. It has proven to be unreliable, however in several senses: It has not always provided the complete set of port names and, as I have recently seen, it can fail to function altogether when the "RPC service is unavailable". Why RPC is needed to find out what ports are available on the local machine is completely beyond me but there it is. This latter problem was the final straw. So far as relying completely on the list of names provided, i filter these names using the GetDefaultCommConfig() function to determine the exact nature of each of the names that I came up with.
In my experience, the list of names provided by the previously mentioned registry key has been the most reliable method for getting port names. As a matter of fact, I can see the key get updated as I disable port drivers in the device device manager. Under normal experiences, I would agree with the assessment that relying upon a particular key is fraught with peril. In this case, however, M$ has never provided a decent mechanism to evaluate the names of available ports.
I should point out that I have already replaced the call to EnumPorts() with an algorithm that scans the registry key: HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM for serial port names. This should resolve the issue once my software is released. What I am after is pointers that can be given to customers who are using the released package at the present.
I'm not an expert on EnumPorts, but I strongly advice against relying on registry keys.
Key definitions might change in the future.
Key definitions might not be what you think.
There might be ways to "be a serial port" which don't include those keys.
The keys might not reflect up-to-date status, etc. etc.
You should always rely on the APIs available.
If an API doesn't behave for you, let's try to figure out why. Maybe with a little extra information we can help better:
What is it exactly that you need to do with the serial port?
There are a lot of weird serial ports these days: USB serial cables, Bluetooth, cell phone modems with GPS,... It might be something plugged into the computer and long forgotten since.
To find out which port is causing the problem you could try going into device manager, select "Show hidden devices" in the "View" tab and deleting them until the problem goes away. That might allow you to zero in on the problem.
I know it's not a direct answer to your question, but have you considered using a different method for enumerating the serial ports? In my applications I use the Setup API, using code from P J Naughter's website: http://www.naughter.com/enumser.html, and I find it works well.
I know this question is extremely old, but I stumbled onto it today, and noticed no-one gave an explanation.
The reason for RPC is because you're calling a spooler function - you are asking the print spooler to return a list of printer ports, which happens to include the COM ports in most cases. I believe this may explain your slightly unreliable results.
RPC is used to pass the request from your process to the active spooler process, and the RPC Server is unavailable message occurs when the spooler service is not running (or not responding properly).

How do you detect dialup, broadband or wireless Internet connections in C++ for Windows?

I have an installation program (just a regular C++ MFC program, not Windows Installer based) that needs to set some registry values based on the type of Internet connection: broadband, dialup, and/or wireless. Right now this information is being determined by asking a series of yes or no questions. The problem is that the person doing the installations is not the same person that owns and uses the computer, so they're not always sure what the answers to these questions should be. Is there a way to programatically determine any of this information? The code is written in C++ (and optionally MFC) for Windows XP and up. .NET-based solutions are not an option because I don't want to have to determine if the framework is installed before our installation program can run.
To clarify, the issue is mainly that wireless and dialup connections are not "always-on", which creates a need for our product to behave a different way because our server is not always available. So a strictly speed-measuring solution wouldn't help, though there is a setting that's speed dependent so that the product doesn't try to send MB of information through a dialup connection as soon as it connects.
[I have no idea how to get exactly the information you asked for, but...] Maybe you could rephrase (for yourself) what you try to accomplish? Like, instead of asking "does the user have broadband or dialup", ask "how much bandwidth does the user's internet connection have" - and then you can try to answer the rephrased question without any user input (like by measuring bandwidth).
Btw. if you ask the user just for "broadband or dialup", you might encounter some problems:
what if the user has some connection type you didn't anticipate?
what if the user doesn't know (because there's just an ethernet cable going to a PPPoE DSL modem/router)?
what if the user is connected through a series of connections (VPN via dialup, to some other network which has broadband?)
Asking for "capabilities" instead of "type" might be more useful in those cases.
Use InternetGetConnectedState API to retrieve internet connection state.
I tested it and it works fine.
I found this document which can help:
http://www.pcausa.com/resources/InetActive.txt
Regarding the question "is the internet connection permanent or not?":
best way would be probably to make the app robust enough to always cope with a non-permanent connection :-) which would work the same with dialup and broadband...
alternatively, maybe you can find out how long the user's internet connection has been established already, and compare with system uptime? If the connection has been online for almost as long as the computer was running, it's probably a permanent connection.
Anyway, these heuristics will probably fail for obscure connection types.
Also, regarding the point about not sending lots of data: if people have a "broadband + low traffic limit" tariff, you shouldn't send lots of data either even if bandwidth allows :-)
Best bet would be to grab the default active network connection, ensure it is an internet connection (ping google.com or similar) and then ask it what type of device it is. You should be able to determine from that what connection the user has.
I'm fairly confident this is possible, but not sure how to go about it though.
I think you should just do a quick connection-speed test. Just download some specific sized files, time how long it takes, and you'll know the speed. I agree with the other guy, don't ask them what type of connection they have, what's more important is the speed. Perhaps next year they come out with 100mbit dialup...do you want everyone using this amazing new device to get the crappy lowbandwidth version of your app?
I would agree with oliver, as you imply: you have the functionality already to cope with connection loss, why not enable it by default.
Broadband connections can get messed up to: routersoftware that freezes (happens a lot to me), or poweradapter that fries, ...