Windows WMI -- find a unique identifier for each hardware component? - windows

I'm currently writing an application that retrieves hardware information about a computer.
I need some sort of unique identifier for each hardware component, such as an UID or S/N. I can see this "DeviceID" member in almost every component (inherited from CIM_LogicalDevice), and it says:
"Address or other identifying information to uniquely name the logical device."
Sounds good! Does this mean that it's unique for just that specific computer; or is it unique for "all computers in the world" (which is what I need).
Thanks!

Turns out this was not the best way of uniqely name a device, since it COULD be the same UID across different computers.
Instead, I collected a whole bunch of data from each components in the computer (motherboard, CPU, GPU, memory, NIC etc.), hashed them with MD5 to create a sort of "identifier". Works pretty well.

Related

GetFileInformationByHandleEx/FileIdInfo vs DeviceIoControl/FSCTL_CREATE_OR_GET_OBJECT_ID for OpenFileById

Recently I've stumbled upon "If you want to use GUIDs to identify your files, then nobody's stopping you" article by Raymond Chen and wanted to implement this method. But then I found that there is another way to get file ID and this is GetFileInformationByHandleEx with FILE_INFO_BY_HANDLE_CLASS::FileIdInfo and using the FileId field (128 bit).
I tried both, both methods works as expected but I have a few questions I cannot find any answers to:
These methods return different IDs (and the id from GetFileInformationByHandleEx seems to use only the low 64 bit leaving the high part as zero). What each of them represent? Are they essentially the same thing or just two independent mechanisms to achieve the same goal?
Edit: Actually I've just found some information. So the ObjectID from DeviceIoControl is NTFS object ID but what is the other ID then? How do they relate (if at all)? Are both methods available only on NTFS or at least one of them will work on FAT16/32, exFAT, etc?
Documentation for FILE_INFO_BY_HANDLE_CLASS::FileIdInfo doesn't tell us that the ID may not exist unlike FSCTL_CREATE_OR_GET_OBJECT_ID where I need to explicitly state that I want the ID to be created if there isn't one already. Will it have any bad consequences if I'd just blindly request creation of object IDs for any file I'll be working with?
I found a comment for this question that these IDs remain unchanged if a file is moved to another volume (logical or physical). I did test only the DeviceIoControl method but they indeed don't chnage across drives but if I do move the file I'm required to supply OpenFileById with the destination volume handle, otherwise it won't open the file. So, is there a way to make OpenFileById find a file without keeping the volume reference?
I'm thinking of enumerating all connected volumes to try to open the file by ID for each until it succeed but I'm not sure how reliable is this. Could it be that there could exist two equal IDs that reference different files on different volumes?
How fast it is to ask system to get (or create) an ID? Will it hurt performance if I add the ID query to regular file enumeration procedures or I'd better to do that only on demand when I really need this?

How "Unique" and safe actually is WMI Win32_xxxxx serial number property? (aka is it possible to change it by any way?)

As read on topic here How to find the unique serial number of a flash device? and especially here How to get manufacturer serial number of an USB flash drive? I know it is possible to get properties of hardware devices (particularly hard drives and usb drives...) using WMI Win32_PhysicalMedia and Win32_DiskDrive, which I'm getting done successfully.
However, I really want to know about the safety of these informations.
PhysicalMedia property SerialNumber returns the actual serial number of the main hard drive, while using other Win32_LogicalDisk and other calls we can map the drive letter of flash storage to actual Win32_DiskDrive device, and from there read properties like Name, Model, FirmwareRevision, SerialNumber, DeviceID, Manufacturer...
Now, DeviceID is generated by Windows / Pc itself, while SerialNumber should be the one that manufacturer added to the physical flash drive.
Manufacturer in most cases returns "Standard" something, Name is also of no use, while SerialNumber actually gets me a something that looks like unique ID, (I've read that in some cases this is not returned, so PNPDeviceID should be used instead? , Model gives the actual model of the flash drive, and FirmwareRevision just a number that could be used to add safety switch to the licensing, but is not vital.
However, the only one of these that seems / should be actually safe to use is SerialNumber, right?
So, the question here goes: Which level is Win32_DiskDrive actually reading this info from? Is it possible to fake that at all (Ok, letalone the actual lowlevel hacking stuff or driver injection etc...(??)), and if so, how hard it is?
If there's a known way / guide / example, I'd be also happy to read it. (not necessary info looking for here though.)
This is not for intention of bypassing some licensing. I'm making licensing for my SW, and am curious, whether it would be safe enough to use USB drive's SerialNumber property, and lock license against the presence of that USB flash, for which the license was bought for? Basically to use it as kind of a dongle, but not like the dongles actually work (using communication with the actual hardware inside the dongle...)
I know it may not seem as a safe solution, as flash drives dies quite often these days, or get lost etc, but this is just to add an option to my licensing from "Per PC" to "Portable - per USB device".
Thanks for any info!!!
EDIT:
I am completely aware that bypassing these kind of safety switches is very possible. Of course, even Windows itself is not licensed in a way that couldn't be hacked, nor Adobe, ProTools etc, (software that is widely used and costs a lot!).
But that wasn't a real question, and also, that's not the case for me -> the software will not be that expensive and not used by that much people, that I'd be afraid to drag interest in someone who will do extensive programming to make a patch/crack for it. Regular debugger use and workaround is pretty unlikely to be used by regular client who would need the software, ( and also, since it is something to be used in business environment, where stability is vital, I doubt they will really play around that...).
Main point here:
It is possible for sure, but: HOW hard is it to do for a regular person? (I know, the answer is: depending on your code.)
Main question of the post: Is it possible to change the ID on the USB itself, OR to make an app that will fake that data to my app? If it is, I'm sure it might be easier than making a crack/patch, that's why I wanted to know, whether WMI reads explicitly from hardware, or could one make an app that would pass fake data to it?
WMI just returns what the hardware tells it. It's as unique as the hardware. Which ultimately depends on the vendor.
But...
If someone has an administrator account to the computer†, then there are very few things that can be done to keep them from just hooking up the kernel debugger to your program and overriding your checks, or recording the raw USB communication session and replaying it on an unauthorized system. The real dongles do some to mitigate this, by having the hardware generate a response to a particular challenge. The challenge/response changes for each request, so it's not as susceptible to replay attacks, but the debugger tricks still work.
This is the real problem with the serial number approach. Uniqueness is not the primary concern for dongled software. The primary concern is unpredictability.
An illustrative example-
Let's say that I'm a bouncer at an exclusive night club. We're so exclusive that you have to answer a question to get in. You really want to get in, but no one will tell you the answer to the question. One night, you hatch a plan. You hang out in the alley and listen to the conversations that I'm having with the patrons trying to enter the club. It doesn't take you long to realize that I'm asking everyone the exact same question, and you're in. (This is the serial number approach)
After a while, I notice that there are a lot of people coming into the club that I've never seen before, and begin to suspect something. The people we really want to allow in are all given a card with a formula‡ on it. Whenever they come to the door of the club, I give them a number and they apply their formula and tell me the result. Since I also know the formula, I can tell if they are really allowed in. Now, even if you hear the entire challenge and response, without the formula, you aren't getting in. (This is one common approach taken by dongles.)
But what about the debugger? The debugger just made herself the club's owner, fired me, and can come and go as she pleases.
†Or has physical access to the machine and a password reset disk.
‡Stop laughing, this could totally happen. :)
Photo credit: Guillaume Paumier, CC-BY. Found on the Wikimedia Commons 7-Oct-15
Edit to address the question edit:
HOW hard is it to do for a regular person? (I know, the answer is: depending on your code.)
The question is how skilled is the 'regular person'? If you're talking about software/electrical engineers, then this is a trivial task. If you're talking about sales/marketing then it's a challenging task.
Is it possible to change the ID on the USB itself, OR to make an app that will fake that data to my app?
It depends and Yes. Changing the ID on the device itself is possible with some devices, and impossible with others. Software to spoof/man-in-the-middle the USB communication, or to create a virtual USB device is possible.
If it is, I'm sure it might be easier than making a crack/patch, that's why I wanted to know, whether WMI reads explicitly from hardware, or could one make an app that would pass fake data to it?
As I led with above, WMI reads from the hardware. This can be intercepted or bypassed.
Some ways to bypass the check:
Make a virtual USB device
Modify the USB MSD device driver to report the same serial number for all devices.
Build hardware using commercially available cheap host controllers that identifies with the same information as the authorized device. ($10 worth of raw components and a little bit of time.)
Redirect the system calls to/from USB to a compromised library.
Note also that:
Some places have restrictions on USB storage devices, ranging from discouraging their use, to outright bans. This would prevent your software from being used in sensitive computing environments processing private data, like credit cards, PII, trade secrets, classified information, etc. (In the US many governmental agencies have outright bans on USB storage devices, and block the install of any MSD.)
The Mass Storage specification doesn't require serial numbers. They are usually there, but they don't have to be, and many low-cost vendors
A USB PKI token costs a little bit more, but would probably do what you want. Here's an example from Safenet (Disclaimer: I am in no way affiliated with Safenet Inc, and you should evaluate all the possible options from all vendors. I suggested this because it was the first thing that came up through CDW, and the price was ~$30)

BIOS Serial Number: Is it populated, constant and reliable

I intend to use the users BIOS/Motherboard Serial Number to uniquely identify a user. When I refer to the BIOS/Motherboard Serial Number I am referring to the number returned when you type in: wmic BIOS get SerialNumber
Regarding the BIOS/Motherboard' Serial Number:
Can the user change this serial number? Either using third party applications or through Windows.
According to this forum post, not all vendors supply a motherboard UUID so I cannot use this to uniquely identify the user. Do venders mostly/always supply/fill out the BIOS/Motherboard Serial Number or will I also find some computers dont have a serial number?
I have tried to uniquely identify a user using the Hard Drive's Serial Number. But I have first hand run into the issue that it can change and that Windows API is unreliable and can return different values. See my post here. Do you know if I may experience the same issue for the BIOS/Motherboard's Serial Number?
Can a standard process (Standard Windows User) retrieve the BIOS/Motherboard Serial Number? Or does the process need to be elevated (Admin User)?
Just to confirm the BIOS is the motherboard, correct? I am a little unclear because I thought the BIOS is the simple software installed on the motherboard.
Yes, a power user can change nearly all serial numbers using either service utilities like AMI DMIEdit or by editing BIOS chip contents manually.
Most desktop motherboards right now are coming with empty MBSN and UUID, except for ASUS ones. The only PCs that almost always have valid identification data are branded ones (i.e. Dell or HP workstations).
Nearly all "individual" data can be changed somehow, and virtual devices makes the whole situation even more complex.
It depends on how you will try to access it, but general answer is "No, you need administrator rights". Read more here.
My 5 cents on this: just don't use HW-based identification, it brings more problems then solves.

Trying to uniquely ID a USB device from WMI query using DeviceID field

When WMI is queried and returns a list of devices, I've noted some information at the END of the DeviceID string that isn't documented anywhere I've looked so far. Here's an example of a DeviceID string returned from a WMI query looking at Win32_PnPEntity:
USB\VID_046D&PID_082D&MI_00\7&3538A2BF&0&0000
Now, the first two parts - both the 'USB' and the VID and PID are really well documented, as is the 'interface number' - the &MI_XX. However, the last part of the string (shown below) isn't documented anywhere I've looked. I don't even know what to call this part of the DeviceID string:
\7&3538A2BF&0&0000
Curiously, it comes in several flavors. I've noted that if I have two identical devices plugged into the PC, I'll get different values, which I've defaulted to calling 'instance id's' for lack of better documented reference info. Here's what I see when I have two identical USB Web cameras plugged into my PC:
USB\VID_046D&PID_082D&MI_00\6&DB509D0&0&0000
USB\VID_046D&PID_082D&MI_00\7&3538A2BF&0&0000
So far, so good. I can pick out that I have two identical devices plugged into the PC and can parse against these unique values. But wait! When the OS sees these devices, it also loads anything the drivers offers for different 'interfaces' or modes of operation, so along with the above entries when I make a WMI query against Win32_PnPEntity, I also get these nice entries in the DeviceID field as well:
USB\VID_046D&PID_082D\195825EF
USB\VID_046D&PID_082D\36149BBF
So the problem is that without documentation that describes what this last part of the DeviceID is, I don't know to expect, and can't associate or separate these 'duplicate' entries from their brethren in the query results.
The goal is to be able to scan through the WMI result, identify ONE 'primary' entry for a given device and discard anything else. I could likely HACK the filtering by looking for "USB Composite Device" in the Description field, but this is rather ugly and would discard some devices that do not have an appropriate or vendor-specified 'description.'
MSDN only provides that the DeviceID is a "Unique identifier of the USB controller. This property is inherited from CIM_LogicalDevice." -- and CIM_LogicalDevice doesn't detail the makeup of this field either.
Anyone been down this path or know which hole to look in? Similar questions in here and in other forums remain unanswered. (Hey M$, Why is this so %$##! mystical???)
It looks like this webcam is a composite device.
I think the node with the ID of USB\VID_046D&PID_082D\36149BBF is the parent device. The part after the second slash in this case is most likely the serial number of the device. (I have made Windows software for composite devices for years and we always get the serial number by parsing that part). This node probably uses usbccgp.sys as the driver, which allows it to parse the interface descriptors of the device and produce child nodes.
The node with ID USB\VID_046D&PID_082D&MI_00\6&DB509D0&0&0000 is the child node corresponding to USB interface 0. From my experience, I believe that the part after the second slash is some kind of unique identifier that depends on what USB port the device is plugged in to.
For the WMI query, you should probably just ignore the child nodes altogether. Just discard anything with MI_ in it before the second slash. The parent node tells you everything you need to know about the identity of the device.

retrieving the serial number of a USB keyboard under Windows

Many USB devices contain a unique serial number (which is actually a Unicode string) which the host can use in conjunction with the 16-bit vendor and product ID numbers to uniquely identify the device.
I'm trying to figure out how to write a Windows application that would be able to display a list of all USB human interface devices attached to the system. The list would have one row for each HID, including system keyboards. There would be columns in the list for the vendor ID, product ID, and serial number.
I can get a list of USB HIDs by calling SetupDiGetClassDevs with the GUID returned by HidD_GetHidGuid and looping through the result by repeatedly calling SetupDiEnumDeviceInterfaces. I can then call SetupDiGetDeviceInterfaceDetail to get the path to each device, which I can open with CreateFile, so long as I am careful to request neither read nor write permission, which would be denied for a system keyboard. From there I can get the vendor and product ID numbers by invoking HidD_GetAttributes.
What I'm having trouble figuring out is how to retrieve the serial number string. When I search for solutions to this problem, I find a lot of information about how to get serial numbers for USB mass storage devices, but nothing that looks like it might apply to any other type of USB device. I would be happy to discover either a generic method or a HID-specific method of retrieving the serial number string.
I have a feeling that the Win32 port of libusb could manage this without too much trouble, but unfortunately I need a solution that depends only on libraries that come with Windows, such as the setupapi and hid DLLs that contain the functions mentioned above.
Any suggestions would be very much appreciated!
It turns out that HID.dll defines a function called HidD_GetSerialNumberString that does exactly what I want, given the handle I got from CreateFile as described above. Just tried it out and it works great. There are also HidD_GetManufacturerString and HidD_GetProductString functions to retrieve the other string descriptors referred to in the device descriptor, and even a HidD_GetIndexedString to get an arbitrary string descriptor given its index (presumably because the HID descriptor is allowed to contain string descriptor indices). I feel pretty silly now -- the answer was right there under my nose this whole time.
Thank you all for taking the time to read and answer my question! I'm going to go ahead and accept Alphaneo's answer since it sounds quite promising, and in fact I was waiting for the DDK to download when I stumbled across this answer.
Have you tried the USBVIew source code that comes along with the DDK. The USBView tool displays serial number for any USB device, and the source is shipped with the DDK.
Have you tried searching for the documentation of the HID definition of input records, output records and features records for Hid keyboards. This should show you the list of "things" you can get out/in of a keyboard through HID.
Also, I know it is possible to enumerate the HID record definition by software. I did something similar about 1 year ago, but I cannot remember the details at the top of my head. Doing so would allow you to see what the keyboard USB class is publishing as a standard interface.
I hope it can get you a few pointers to find out what you are looking for. Sorry I could not be more precise!
I recommend this book USB Complete. Chapter 4 Enumeration: How the Host Learns about Devices has the information you need.
This page has many links to information and for you links to libraries and utilities you can use.
you can use GetVolumeInformation for getting the serial number of any hardware attached.

Resources