HDD serial number flipped every 2 bytes in Windows

2019-04-04 08:37发布

问题:

I need to get HDD serial number to use it as a key for licensing a software. I used diskid32 code in this url: http://www.winsim.com/diskid32/diskid32.html It used the DeviceIoControl Win32 API with the IO control code of IOCTL_STORAGE_QUERY_PROPERTY.

It worked. However, when I double check with the actual serial number printed on the HDD itself, I found that every 2 bytes of the number was flipped.

A simple solution could be to simply flip the bytes back. It worked in Windows XP, Vista and 7 but in windows 8 not need to be flipped!

I wish to know the exact reason why the bytes were flipped in Windows XP, Vista and 7, and why not flipped in Windows 8. What about next Windows?

Part of code with minor changes:

  int drive = 0;
  HANDLE hPhysicalDriveIOCTL = 0;
  char driveName [256];
  sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);
  //  Windows NT, Windows 2000, Windows XP - admin rights not required
  hPhysicalDriveIOCTL = CreateFile (driveName, 0,
                           FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                           OPEN_EXISTING, 0, NULL);
  if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
  {
     _STORAGE_PROPERTY_QUERY query;
     DWORD cbBytesReturned = 0;
     char buffer [10000];

     memset ((void *) & query, 0, sizeof (query));
     query.PropertyId = StorageDeviceProperty;
     query.QueryType = PropertyStandardQuery;

     memset (buffer, 0, sizeof (buffer));

     if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,
               & query,
               sizeof (query),
               & buffer,
               sizeof (buffer),
               & cbBytesReturned, NULL) )
     {
         _STORAGE_DEVICE_DESCRIPTOR * descrip = (_STORAGE_DEVICE_DESCRIPTOR *) & buffer;
         char serialNumber [1000];
         char modelNumber [1000];
         char vendorId [1000];
         char productRevision [1000];

         flipAndCodeBytes (buffer,
                           descrip -> SerialNumberOffset,
                           1, serialNumber );

        ...
     }

回答1:

I use the same approach (and same code) in my software licensing. Yes, Windows 8 for some reason is returning flipped values for this method, I can't say why (so I can't answer your question).

My solution is the one that you pointed out: Flip the values again. So, after calling the "flipAndCodeBytes", you could test if is a Windows 8 OS, and flip the values.

In my case, it's working now (I got the same values for Windows XP/Vista/7 and Windows 8).

Good luck!



回答2:

Just turn off the flip using the "flip" flag of the flibAndCodeBytes function when windows 8 or greater.

bool shoulFlipBytes = true;
if(IsWin8OrLater()) shouldFlipBytes = false;

flipAndCodeBytes(buffer,
                 descrip->SerialNumberOffset,
                 shouldFlipBytes,
                 serialNumber);

You can use this to check for windows version:

#include <windows.h>

bool IsWin8OrLater() {
    DWORD version = GetVersion();
    DWORD major = (DWORD) (LOBYTE(LOWORD(version)));
    DWORD minor = (DWORD) (HIBYTE(LOWORD(version)));

    return (major > 6) || ((major == 6) && (minor >= 2));
}

According to http://msdn.microsoft.com/en-us/library/ms724832%28VS.85%29.aspx (Thanks to ChrisV Determine if O/S is Windows 7)



回答3:

Basically you're relying on data that's not strictly reliable to begin with. Drives may change over the lifetime of a computer; all the while getting exactly the right serial number isn't even important to your product.

One easy hack I can think of is to normalize the serial number, e.g. by sorting the digits; this will make more drives look alike, but I doubt it will become an issue.

Another way of looking at the problem is that the application should provision for serial number changes; the user could be informed about the licensing issue (for whatever reasons) and asked to contact the support department with a generated code (not necessarily the serial number itself). Given this code, support can then create a new license for the customer.



回答4:

Seem you have to check for windows version through API and add if() branch to your code if version is high enough

My devs found other problem with this method - that kind of IOCtl code relies on program is being run with administrator rights on Win7\Win8+. In cause of our software, it's service that is run with system rights and clients software that is strictly run with user rights



回答5:

For licensing-checking purposes, you really don't care. All you need to know is that some configurations result in flipping, some don't, and it can change during the lifetime of a license.

So accept both variants:

string serial = get_serial();
if (license_check(serial)) {
    licensed = true;
    return;
}
serial = swap_bytes(serial);
if (license_check(serial)) {
    licensed = true;
    return;
}

(I see Raymond suggested this in a comment)

No fragile OS check, no worries about whether it failed to flip right when the user applied for the license. Just happy users.