Серийный номер жесткого диска переворачивается каждые 2 байта в Windows XP, Vista и 7, но не в Windows 8.

Мне нужно получить серийный номер жесткого диска, чтобы использовать его в качестве ключа для лицензирования программного обеспечения. Я использовал код diskid32 в этом URL-адресе: http://www.winsim.com/diskid32/diskid32.html Он использовал DeviceIoControl Win32 API с кодом управления вводом-выводом IOCTL_STORAGE_QUERY_PROPERTY.

Это сработало. Однако, когда я дважды сверился с фактическим серийным номером, напечатанным на самом жестком диске, я обнаружил, что каждые 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 );

        ...
     }

person A.Danesh    schedule 31.01.2013    source источник
comment
Win8 вообще имеет множество исправлений для старых ошибок Windows, которые были оставлены на полке по причинам совместимости. Изолируйте себя от этого с помощью WMI, класса Win32_DiskDrive, свойства SerialNumber.   -  person Hans Passant    schedule 06.02.2013
comment
Хотя я согласен с @HansPassant, я бы настоятельно не рекомендовал использовать серийные номера жестких дисков в качестве уникального идентификатора для вашего программного обеспечения не потому, что его легко подделать, а потому, что серийный номер является индивидуальным для поставщика продукта, и поэтому вы можете получить дублировать ключи продукта в худшем случае. Насколько мне известно, единственным сертифицированным уникальным идентификатором на компьютере является MAC-адрес или адрес IPv6. Проблема со всеми этими решениями заключается в том, что они привязывают вас только к конкретному аппаратному компоненту, а не к конкретной коробке.   -  person    schedule 12.02.2013
comment
Если вам просто нужно, чтобы это было своего рода уникальным, чтобы остановить случайное пиратство, зачем вообще их переворачивать? Каждый раз, когда вы читаете его на одном и том же компьютере, он будет совпадать с первоначальным перевернутым чтением. Хотя это может вызвать проблему, если пользователь обновится до Windows 8 и выберет сохранить мои программы и данные.   -  person Luke    schedule 13.02.2013
comment
@Kris Сетевой адаптер может отсутствовать в некоторых системах или быть отключенным. Вероятность дублирования серийного номера жесткого диска в малом бизнесе, таком как мой случай, очень мала и может быть проигнорирована.   -  person A.Danesh    schedule 13.02.2013
comment
@Luke Моя основная проблема заключается в том, что некоторые пользователи обновляют свои системы с Windows 7 до Windows 8, и предыдущий код активации не работает в их системах. Если пользователь использует только Windows 7 или 8, проблем вообще нет.   -  person A.Danesh    schedule 13.02.2013
comment
Получайте удовольствие от настройки аппаратного RAID :)   -  person pistache    schedule 13.02.2013
comment
@A.Danesh, если ваша компания настолько мала, что это не будет проблемой, а на некоторых компьютерах даже нет сетевой карты, то зачем ее вообще использовать? Я так понимаю, вы хотите жестко закодировать идентификаторы в программном коде? Мое предложение вам по-прежнему будет заключаться в том, чтобы вместо этого создавать серийные ключи для вашего программного обеспечения, это будет формат, который вы контролируете, а не формат, который невероятно случайен по структуре. Затем все, что вам нужно сделать, это добавить свой собственный серийный ключ в реестр Windows, что невероятно просто.   -  person    schedule 13.02.2013


Ответы (5)


Я использую тот же подход (и тот же код) при лицензировании своего программного обеспечения. Да, Windows 8 по какой-то причине возвращает перевернутые значения для этого метода, я не могу сказать, почему (поэтому я не могу ответить на ваш вопрос).

Мое решение - то, на которое вы указали: снова переверните значения. Итак, после вызова «flipAndCodeBytes» вы можете проверить, является ли ОС Windows 8, и перевернуть значения.

В моем случае это работает сейчас (у меня одинаковые значения для Windows XP/Vista/7 и Windows 8).

Удачи!

person cunhaw    schedule 12.09.2013

Просто отключите флип, используя флаг «флип» функции flibAndCodeBytes, когда Windows 8 или выше.

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)

person zajac.m2    schedule 14.05.2014
comment
Или просто вызовите IsWindows8OrGreater. - person IInspectable; 25.02.2016
comment
и конечно же bool shouldFlipBytes = ! IsWindows8OrGreater() - person Sebastian; 31.10.2016

По сути, вы полагаетесь на данные, которые не являются строго надежными с самого начала. Диски могут меняться в течение всего срока службы компьютера; при этом получение точного серийного номера даже не важно для вашего продукта.

Один простой способ, который я могу придумать, - это нормализовать серийный номер, например. путем сортировки цифр; это сделает больше дисков похожими, но я сомневаюсь, что это станет проблемой.

Другой взгляд на проблему заключается в том, что приложение должно обеспечивать изменение серийного номера; пользователя могли проинформировать о проблеме с лицензией (по каким-либо причинам) и попросить связаться со службой поддержки с помощью сгенерированного кода (не обязательно самого серийного номера). С помощью этого кода служба поддержки может создать новую лицензию для клиента.

person Ja͢ck    schedule 15.02.2013
comment
Другой алгоритм: Проверить серийный номер. Если не совпадает, переверните байты и проверьте еще раз. - person Raymond Chen; 15.02.2013

Кажется, вам нужно проверить версию Windows через API и добавить ветку if() в свой код, если версия достаточно высока.

Мои разработчики обнаружили другую проблему с этим методом - такой код IOCtl зависит от того, что программа запускается с правами администратора на Win7\Win8+. Что касается нашего программного обеспечения, это служба, которая запускается с системными правами, и клиентское программное обеспечение, которое запускается строго с правами пользователя.

person Swift - Friday Pie    schedule 19.09.2014

Для целей проверки лицензии вам действительно все равно. Все, что вам нужно знать, это то, что некоторые конфигурации приводят к переключению, некоторые нет, и это может измениться в течение срока действия лицензии.

Так что принимайте оба варианта:

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

(Я вижу, что Раймонд предложил это в комментарии)

Нет проверки на хрупкость ОС, нет беспокойства о том, не перевернулось ли оно правильно, когда пользователь подал заявку на лицензию. Просто счастливые пользователи.

person Ben Voigt    schedule 16.02.2015