How do I find the UUID of a virtual machine? [duplicate] - c++

I need to write a function that generates an id that is unique for a given machine running a Windows OS.
Currently, I'm using WMI to query various hardware parameters and concatenate them together and hash them to derive the unique id. My question is, what are the suggested parameters I should use?
Currently, I'm using a combination of bios\cpu\disk data to generate the unique id. And am using the first result if multiple results are there for each metric.
However, I ran into an issue where a machine that dual boots into 2 different Windows OS generates different site codes on each OS, which should ideally not happen.
For reference, these are the metrics I'm currently using:
Win32_Processor:UniqueID,ProcessorID,Name,Manufacturer,MaxClockSpeed
Win32_BIOS:Manufacturer
Win32_BIOS:SMBIOSBIOSVersion,IdentificationCode,SerialNumber,ReleaseDate,Version
Win32_DiskDrive:Model, Manufacturer, Signature, TotalHeads
Win32_BaseBoard:Model, Manufacturer, Name, SerialNumber
Win32_VideoController:DriverVersion, Name

I had the same problem and after a little research I decided the best would be to read MachineGuid in registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography, as #Agnus suggested. It is generated during OS installation and won't change unless you make another fresh OS install. Depending on the OS version it may contain the network adapter MAC address embedded (plus some other numbers, including random), or a pseudorandom number, the later for newer OS versions (after XP SP2, I believe, but not sure). If it's a pseudorandom theoretically it can be forged - if two machines have the same initial state, including real time clock. In practice, this will be rare, but be aware if you expect it to be a base for security that can be attacked by hardcore hackers.
Of course a registry entry can also be easily changed by anyone to forge a machine GUID, but what I found is that this would disrupt normal operation of so many components of Windows that in most cases no regular user would do it (again, watch out for hardcore hackers).

With our licensing tool we consider the following components
MAC Address
CPU (Not the serial number, but the actual CPU profile like stepping and model)
System Drive Serial Number (Not Volume Label)
Memory
CD-ROM model & vendor
Video Card model & vendor
IDE Controller
SCSI Controller
However, rather than just hashing the components and creating a pass/fail system, we create a comparable fingerprint that can be used to determine how different two machine profiles are. If the difference rating is above a specified tolerance then ask the user to activate again.
We've found over the last 8 years in use with hundreds of thousands of end-user installs that this combination works well to provide a reliably unique machine id - even for virtual machines and cloned OS installs.

Parse the SMBIOS yourself and hash it to an arbitrary length. See the PDF specification for all SMBIOS structures available.
To query the SMBIOS info from Windows you could use EnumSystemFirmwareEntries, EnumSystemFirmwareTables and GetSystemFirmwareTable.
IIRC, the "unique id" from the CPUID instruction is deprecated from P3 and newer.

What about just using the UniqueID of the processor?

I hate to be the guy who says, "you're just doing it wrong" (I always hate that guy ;) but...
Does it have to be repeatably generated for the unique machine? Could you just assign the identifier or do a public/private key? Maybe if you could generate and store the value, you could access it from both OS installs on the same disk?
You've probably explored these options and they doesn't work for you, but if not, it's something to consider.
If it's not a matter of user trust, you could just use MAC addresses.

You should look into using the MAC address on the network card (if it exists). Those are usually unique but can be fabricated. I've used software that generates its license file based on your network adapter MAC address, so it's considered a fairly reliable way to distinguish between computers.

For one of my applications, I either use the computer name if it is non-domain computer, or the domain machine account SID for domain computers. Mark Russinovich talks about it in this blog post, Machine SID:
The final case where SID duplication would be an issue is if a distributed application used machine SIDs to uniquely identify computers. No Microsoft software does so and using the machine SID in that way doesn’t work just for the fact that all DC’s have the same machine SID. Software that relies on unique computer identities either uses computer names or computer Domain SIDs (the SID of the computer accounts in the Domain).
You can access the domain machine account SID via LDAP or System.DirectoryServices.

In my program I first check for Terminal Server and use the WTSClientHardwareId. Else the MAC address of the local PC should be adequate.
If you really want to use the list of properties you provided leave out things like Name and DriverVersion, Clockspeed, etc. since it's possibly OS dependent. Try outputting the same info on both operating systems and leave out that which differs between.

There is a library available for getting hardware specific informations: Hardware serial number extractor (CPU, RAM, HDD, BIOS)

Maybe cheating a little, but the MAC Address of a machines Ethernet adapter rarely changes without the motherboard changing these days.

Can you pull some kind of manufacturer serial number or service tag?
Our shop is a Dell shop, so we use the service tag which is unique to each machine to identify them. I know it can be queried from the BIOS, at least in Linux, but I don't know offhand how to do it in Windows.

I had an additional constraint, I was using .net express so I couldn't use the standard hardware query mechanism. So I decided to use power shell to do the query. The full code looks like this:
Private Function GetUUID() As String
Dim GetDiskUUID As String = "get-wmiobject Win32_ComputerSystemProduct | Select-Object -ExpandProperty UUID"
Dim X As String = ""
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("powershell.exe", GetDiskUUID)
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardInput = True
oStartInfo.RedirectStandardOutput = True
oStartInfo.CreateNoWindow = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
oProcess.WaitForExit()
X = oProcess.StandardOutput.ReadToEnd
Return X.Trim()
End Function

Look up CPUID for one option. There might be some issues with multi-CPU systems.

Try this one, it gives a unique hard disk ID: Port of DiskId32 for Delphi 7-2010.

Related

WMI filter to exclude/include a specific version of an application

I am trying to write a WQL query to filter computers on a version of a specific software : Firefox.
I want to use this WMI filter on GPO to check if the version is earlier or equal or upper a specific version : 60.8.0.0 esr.
The goal is to separate computers and users which have old versions and computers with the new one.
Hundreds of computers are being reinstalled in few days with a last version 68.0 esr. Using SCCM, it is easy to perform a clean install of a specific product like Firefox with the latest version 68esr in our case and block upgrade for the other one.
The computers which have an earlier version are in version 60.7.0.2 for the most up to date. Other older versions are also present.
Actually some parameters and homemade scripts are used to configure the browser (computers and users scope) through group policies and some parameters doesn't seem to works. I have to choose a version to apply the official ADMX from Mozilla. Since the last version, firefox.exe is able to directly read registry policies edited in a GPO and stored in HKLM/SOFTWARE/Policies/Firefox.
In my case I have to deal with 2 kind of Firefox:
New computers with a simple new GPO (computers scope)
Old computers with a GPO (users and computers scope) which copy some files with home made scripts.
Unfortunately, it is not possible to separate computers or users in different Organization Unit.
One the one hand, WMI filter seems to be the best way to do it for the new computers.
On the second hand, it will be easy to the computers which update Firefox via SCCM to be included with the new parameters without having to do it manually.
I tried this kind of WQL request:
SELECT * FROM Win32Reg_AddRemovePrograms
WHERE (DisplayName LIKE '%Firefox%') AND (Version LIKE '60.8.0%')
I am not able to do it unless by listing each version to exclude/include them because Version seems to be a string value and I do not know how to convert it in integer or to split with the character ".".
I've can define multiple queries on a single WMI filter and keeping in mind that querying the same WMI class multiple times can decrease performance.
It seems to work as a AND relationship as describe here.
Unfortunately it doesn't solve my problem.
So i start to use WMI LIKE operators and different range of character.
In my case :
New computers with a newer version of Firefox ESR (older than 68.0)
SELECT DisplayName, Version
FROM Win32Reg_AddRemovePrograms
WHERE (DisplayName LIKE '%Firefox%')
AND ((NOT Version LIKE '[0-5][0-9].[0-9]%')
AND (NOT Version LIKE '6[0-7].[0-9]%'))
Old computers with a newer version of Firefox ESR (greater than 68.0)
SELECT DisplayName, Version
FROM Win32Reg_AddRemovePrograms
WHERE (DisplayName LIKE '%Firefox%')
AND ((Version LIKE '[0-5][0-9].[0-9]%') OR (Version LIKE '6[0-7].[0-9]%'))

Creating c++ application where secret information can be stored

I want to create portable c++ application for myself [CLI] which will store my secret project information.
But i am not sure, how can i store information in my program, as whatever i will update in program when i am using it will be stored in buffer and when i will close it, it will get deleted and same informations will not be available at any place.
I want to store information persistently, what is the best way to do it. [Considering my application will be portable, i.e, i can carry it in my pen drive in any place and i can fetch my information from program].
Option i found was Datbase , but i have certain problem with database :-
1). sqlite => If any one gets my sqlite.db file, he will know all my secret project.
2). mysql/sql or any other database => They are not portable, it needs to be installed in system too and i need to import , export everytime in system wherever i will have to use it.
How such application stores information in crypted format, so that no one can read it easily.
Any help will be great.
Thanks
If you want your data to remain secret then you must encrypt it.
How you persist the data (sqlite, text file, etc.) makes no difference whatsoever.
See also:
encrypt- decrypt with AES using C/C++
This is not REALLY an answer, but it's far too long "discussion about your subject" to fit as a comment, and I'd rather break the rules by writing one "non-answer answer" (especially now that you have already accepted another answer) than write 6 comments.
First of all, if it's written in C++, it won't be truly portable in the sense that you can carry it around and plug it in anywhere you like and just access the ifnormation, because different systems will have different OS and processor architecture. Fine if you restrict being able to "plug in" on Windows and Linux with x86 - you only need to build two copies of your code. But covering more architectures - e.g. being able to plug into a iPad or a MacBook will require two more builds of the software. Soon you'll be looking at quite a lot of code to carry around (never mind that you need the relevant C++ compiler and development environment to built the original copy). Yes, C++ is a portable language, but it doesn't mean that the executable file will "work on anything" directly - it will need to be compiled for that architecture.
One solution here may of course be to use something other than C++ - for example Java, that only needs a Java VM on the target system - it's often available on a customer system already, so less of an issue. But that won't work on for example an ipad.
Another solution is to have your own webserver at home, and just connect to your server from your customer's site. That way, none of the information (except the parts you actually show the customer) ever leaves your house. Make it secure by studying internet/web-site security, and using good passwords [and of course, you could even set it up so that it's only available at certain times when you need it, and not available 24/7]. Of course, if the information is really top-secret (nuclear weapons, criminal activities, etc), you may not want to do that for fear of someone accessing it when you don't want it to be accessed. But it's also less likely to "drop out of your pocket" if it's well protected with logins and passwords.
Encrypting data is not very hard - just download the relevant library, and go from there - crypt++ is one of those libraries.
If you store it in a database, you will need either a database that encrypts on itself, or a very good way to avoid "leaking" the clear-text information (e.g. storing files on /tmp on a linux machine), or worse, you need to decrypt the whole database before you can access it - which means that something could, at least in theory, "slurp" your entire database.
Depending on how secret your projects are, you may also need to consider that entering for example a password will be readable by the computer you are using - unless you bring your own computer as well [and in that case, there are some really good "encrypt my entire disk" software out there that is pretty much ready to use].
Also, if someone says "Can I plug in my memory stick on your computer and run some of my from it", I'm not sure I'd let that person do that.
In other words, your TECHNICAL challenges to write the code itself may not be the hardest nut to crack in your project - although interesting and challenging.

Protect an executable / application for licensing

I was considering the various options that i have when i want to protect a generic chunk of data to apply this principles to the distribution of a generic application.
Encryption doesn't make sense, it's like giving something unusable for the user or i have to give both the encrypted file and the key do decrypt it which make even less sense.
Generating entropy does not make sense because this process will only re-arrange the data in other way without breaking the business logic of the application.
Wrapping my application in an executable that requires a password to the user, my real application and my wrapper are double-linked and if my wrapper does not gives a green light my application will not run.
Web based distribution like the popular "Steam" service with a customized compilation for every user based on some login/ID verification.
What are the other options? I know that this will not end up with a definitive solution but at least i want to avoid the user to just redistribute my application with a simple copy and paste and i want to have at least a small edge over the software distribution system.
The usual way of doing this is to encrypt the data using some piece of information that is already on the user's system as the key; the data is then keyed to that system. For instance, on Mac OS X you can get the system serial serial number with a library call. Sun systems have a gethostid() library call that makes this trivial. An alternative that works on dumb systems cough Winders cough is to use the MAC address of an ethernet interface, or something like that.
It can be tricky, you typically have to write a little program that will grovel around in the system and generate a key, and then have the customer email this key to you, or at least OK the program to email the key to you. You can then encrypt the protected data using the key information you got back, and have the customer download it. It is possible to add this entire transaction to your application installer, if the size of the data blob is reasonable.

Obtain a list of partitions on Windows

Goal
I'm porting a filesystem to Windows, and am writing a more Windows-like interface for the mounter executable. Part of this process is letting the user locate a partition and pick a drive letter. Ultimately the choice of partition has to result in something I can open using CreateFile(), open(), fopen() or similar.
Leads
Windows seems to revolve around the concept of volumes, which don't seem quite analogous to disks, and only occur for already mounted filesystems.
Promising leads I've had include:
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
Physical Disks and Volumes
Displaying Volume Paths
However these all end in volumes or offsets thereof, not the /dev/sda1 partition-specific-style handle I'm after.
This question is after a very similar thing, I considered a bounty until I observed the OP is after physical disk names, not partitions. This answer contains a method to brute force partition names, I'd like to avoid that (or see documentation containing bounds for the possible paths).
Question
I'd like:
Correct terminology and documentation for unmounted partitions in Windows.
An effective and documented method to reliably retrieve all available partitions.
The closest fit to the partition file abstraction as available in Linux, wherein all IO is bound to the appropriate area of the disk for the partition opened.
Update0
While the main goal is still opening raw partitions, it appears the solution may involve first acquiring a handle to each disk drive, and then using that in turn to acquire each partition. How to enumerate all the disk drives (even those without mounted volumes on them already) is required.
As you noted, you can use IOCTL_DISK_GET_DRIVE_LAYOUT_EX to get a list of partitions.
There's a good overview of the related concepts here. I wonder if the missing link for you is
Detecting the Type of Disk
There is no specific function to
programmatically detect the type of
disk a particular file or directory is
located on. There is an indirect
method.
First, call GetVolumePathName. Then,
call CreateFile to open the volume
using the path. Next, use
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
with the volume handle to obtain the
disk number and use the disk number to
construct the disk path, such as
"\?\PhysicalDriveX". Finally, use
IOCTL_DISK_GET_DRIVE_LAYOUT_EX to
obtain the partition list, and check
the PartitionType for each entry in
the partition list.
The full list of disk management control codes may have more that would be useful. To be honest I'm not sure how the Unix partition name maps onto Windows, maybe it just doesn't directly.
If you can imagine moving from safe haven of userspace and the Windows API (win32) to coding a device driver with NTTDK, you could try IoReadPartitionTableEx or some other low level disk function.
To be blunt, the best way to reliably get all mounted/unmounted disk partitions is to parse the mbr/gpt yourself.
First to clear a few things up: Disks contain partitions and partitions combine to create volumes. Therefore, you can have one volume which consists of two partitions from two different disks.
IOCTL_DISK_GET_DRIVE_LAYOUT_EX is the closest solution you're going to get without doing it manually. The problem with this is that it relies on windows which can incorrectly parse the MBR for god knows what reason. My current working theory is that if Windows was installed via EFI but is being booted via MBR, youll see this sort of issue. Windows manages to get away with this because most partition managers copy the important partition information to the MBR alongside the GPT. But this means that you wont get important information like the partition UUID (which is only stored in the GPT).
All of the other solutions involve getting the Volume information which is completely different from the partition information.
Side Note: a Volume id will usually be of the form \\.\Volume{PARTITION_UUID}. Cases where this would not hold: if the drive is partitioned with MBR and not GPT (MBR does not have a partition UUID, therefore windows makes one up), if you have a raid drive, or if you have a volume consisting of partitions from multiple disks (kinda the same thing as raid). Those are just the cases that come to my mind, dont hold me to them.
I think you're slightly mistaken in an earlier phase. For instance, you seem to assume that "mounting" works in Windows like it works in Unix. It's a bit different.
Let's start at the most familiar end. Paths like C:\ use drive letters. Those are essentially just a set of symbolic links nowadays (On Windows, they're more formally known as "junctions"). There's a base set for all users, and each user can add their own. Even if there is no drive letter for a volume, there will still be a volume name like \\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}\. You can use this volume name in calls to CreateFile() etc. I'm not sure if fopen() likes them, though.
The function QueryDosDevice will get you the Windows device name for a drive letter or a volume name. A device name looks like "\Device\HarddiskVolume1", but you can't pass it to CreateFile
Microsoft has example code to enumerate all partitions.
On Windows, like on Linux, you can open the partition itself as if it were a file. This is quite well documented under CreateFile.

Extracting MAC addresses from UUIDs

A program that I work on assumes that the UUID generated by the Windows RPC API call UuidCreateSequential() contains the MAC address of the primary ethernet adapter. Is this assumption correct or should I use a different method to get the MAC address?
I wouldn't rely on this - the only reason that UuidCreateSequential has the MAC address is it's trying to guarantee that the UUID is unique across the network. Plus, why would you use such a weird way to get a MAC address? Use WMI and actually ask for the MAC address instead of a side-effect of a UUID creation function.
This appears to be a valid assumption. The documentation on MSDN specifically says this will contain the address of the ethernet card on the machine. It doesn't mention anything about a mult-card scenario but picking the primary card appears to be a logical leap.
If you're writing managed code, I would use the NetworkInterface class and call GetAllNetworkInterfaces(). Or from C++ code, call GetAdaptersInfo, which is what the managed implementation uses.
Even if UuidCreateSequential does work for this, it's a pretty obscure way to get the info, and hides potential issues like a computer having more than one adapter.
Only a version 1 UUID contains a MAC address, and only if the original generator had access to the MAC address to begin with. If the original generator didn't have access to a MAC address, it would have used 6 random bytes sourced from a cryptographically secure random number generator, as per section 4.5 of RFC 4122. Because of this, there is no guarantee that the MAC address given in a UUID is actually a MAC address.
In most cases, the only reason anyone would ever need to parse out the MAC address from a UUID is for forensic purposes. See for example the UUIDs embedded in the Word document payload for the Melissa virus. Investigators extracted the MAC address from these IDs and matched it to the MAC address of the suspect's primary network adapter.
If you are trying to obtain the MAC address of your own computer, there are far better ways of going about this.