15

我需要获取HDD 序列号才能将其用作许可软件的密钥。我在这个 url 中使用了diskid32代码:http: //www.winsim.com/diskid32/diskid32.html 它使用了DeviceIoControl Win32 API 和IOCTL_STORAGE_QUERY_PROPERTY的 IO 控制代码。

有效。然而,当我仔细检查打印在硬盘本身上的实际序列号时,我发现每 2 个字节的数字被翻转。

一个简单的解决方案可能是简单地将字节翻转回来。它适用于 Windows XP、Vista 和 7,但在 Windows 8 中不需要翻转!

我想知道字节在 Windows XP、Vista 和 7 中翻转的确切原因,以及为什么在 Windows 8 中不翻转。下一个 Windows呢?

部分代码稍作改动:

  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 );

        ...
     }
4

5 回答 5

3

在 Windows 8 或更高版本时,只需使用 flibAndCodeBytes 函数的“翻转”标志关闭翻转即可。

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

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

您可以使用它来检查 Windows 版本:

#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));
}

根据http://msdn.microsoft.com/en-us/library/ms724832%28VS.85%29.aspx (感谢 ChrisV确定操作系统是否为 Windows 7

于 2014-05-14T09:47:24.780 回答
3

我在我的软件许可中使用相同的方法(和相同的代码)。是的,Windows 8 出于某种原因返回了此方法的翻转值,我无法说明原因(所以我无法回答您的问题)。

我的解决方案是您指出的那个:再次翻转值。因此,在调用“flipAndCodeBytes”之后,您可以测试是否是 Windows 8 操作系统,并翻转这些值。

就我而言,它现在可以工作了(我在 Windows XP/Vista/7 和 Windows 8 上得到了相同的值)。

祝你好运!

于 2013-09-12T00:34:19.300 回答
1

基本上,您所依赖的数据一开始并不严格可靠。驱动器可能会在计算机的整个生命周期内发生变化;始终获得正确的序列号对您的产品甚至都不重要。

我能想到的一个简单的技巧是规范化序列号,例如通过对数字进行排序;这将使更多驱动器看起来相似,但我怀疑它会成为一个问题。

另一种看待问题的方式是,应用程序应该提供序列号更改;用户可能会被告知许可问题(无论出于何种原因),并被要求使用生成的代码(不一定是序列号本身)联系支持部门。有了这个代码,支持人员就可以为客户创建一个新的许可证。

于 2013-02-15T02:22:42.517 回答
0

似乎您必须通过 API 检查 Windows 版本,如果版本足够高,则将 if() 分支添加到您的代码中

我的开发人员发现此方法存在其他问题 - 依赖于程序的 IOCtl 代码在 Win7\Win8+ 上以管理员权限运行。由于我们的软件,它是使用系统权限运行的服务和严格使用用户权限运行的客户端软件

于 2014-09-19T21:55:28.797 回答
0

出于许可检查的目的,您真的不在乎。您需要知道的是,某些配置会导致翻转,而有些则不会,并且它可以在许可证的生命周期内更改。

所以接受这两种变体:

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

(我看到雷蒙德在评论中提出了这个建议)

没有脆弱的操作系统检查,不用担心用户申请许可证时是否无法正确翻转。只是快乐的用户。

于 2015-02-16T17:37:28.110 回答