PID и программный модуль pidgen.dll

04.06.2008

В этой динамически подключаемой библиотеке находятся функции, с помощью которых Windows XP проверяет установочный ключ (ProductKey).

Экспортируемые функции5.1.2600.05.1.2600.11065.1.2600.12105.1.2600.12805.1.2600.3180*5.1.2600.3244*5.1.2600.5512*
PIDGenA+++++++
PIDGenW+++++++
PIDGenSimpA+++++++
PIDGenSimpW+++++++
SetupPIDGenA+++++++
SetupPIDGenW+++++++
VerifyPIDSequenceW-++++++

Все функции (за исключением VerifyPIDSequenceW) предназначены для генерации номера продукта (ProductID) из ProductKey. ProductKey имеет вид: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX - пять полей по пять символов, разделённые дефисом. Где X - это один символ из специального набора "BCDFGHJKMPQRTVWXY2346789". ProductID имеет вид: xxxxx-xxx-xxxxxxx-xxxxx или xxxxx-OEM-xxxxxxx-xxxxx для Retail лицензии и OEM лицензии соответственно. Где x - это одна цифра. Ключ - это зашифрованный специальным образом номер. Эта бинарная информация имеет специфическое символьно-цифровое представление. Как некое число в 24-ричной системы исчисления, в качестве цифр используются символы из вышеуказанного набора. Назначение функций - расшифровать номер и сформировать его текстовое представление.

То, то функций несколько, это не значит, что каждая занимается расшифровкой по-своему. Реальной расшифровкой занимается одна функция PIDGenA, а все остальные занимаются предварительным преобразованием (подготовкой) параметров и последующим вызовом функции PIDGenA. Например, функции, имеющие суффикс W, принимают строковые параметры как двухбайтные символы WCHAR, конвертируют их в однобайтовые символы CHAR, и вызывают соответствующую функцию с суффиксом A. Другие функции имеет меньшее число параметров, чем PIDGenA, они вызывают PIDGenA, заменяя недостающие параметры нулями. Зачем нужно столько параметров неизвестно, используется только их небольшая часть. На С++ это выглядит примерно так:

BOOL WINAPI PIDGenA( LPCSTR, // [IN] szSetupKey LPCSTR, // [IN] szProductType LPCSTR, // [IN] szA22-00001 LPVOID, // NULL LPVOID, // NULL LPVOID, // NULL LPVOID, // NULL LPVOID, // NULL BOOL, // [IN] bOEM, FALSE - Retail, TRUE - OEM LPSTR, // [OUT] szProductID PDIGITAL_PID, // [OUT] pDigitalProductID LPVOID, // NULL LPVOID*, // NOT USED LPVOID); // NULL

При неудачной попытке сгенерировать ProductID сообщает FALSE, при удачной - TRUE. В буфер szProductID будет скопирован ProductID, а буфер pDigitalProductID будет заполнен информацией, которая храниться в реестре.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion] "DigitalProductId"=hex:a4,00,00,00,...
  • szSetupKey - это тестируемый ключ.
  • szProductType - это тип продукта. Находится в settupp.ini (первые пять цифр)
    [Pid] Pid=55683270
  • szA22-00001 - это некий параметр, происхождение и назначение неизвестно. Принимает значение "A22-00001" в разных версиях XP.
  • bOEM - определяет, какой тип лицензии, OEM или Retail, определяется в settupp.ini (последние символы) [Pid] Pid=55683270 ; цифры - Retail Pid=55683OEM ; OEM
  • szProductID - буфер, достаточного размера для результата
  • pDigitalProductID - буфер, достаточного размера для результата. Перед применинием нужно заполнить поле dwSize, определяющее размер буфера в байтах.
typedef struct _DIGITAL_PID { DWORD dwSize; // размер этой структуры в байтах (A4h, 164d) DWORD dwReserved1; // неизвестно CHAR szPID[24]; // ProductID DWORD dwBinkID; // BINK_ID CHAR szA22-00001[16]; // неизвестно, сюда копируется параметр szA22-00001 PIDGenA BYTE btKey[112]; // Зашифрованный установочный ключ + ещё что то } DIGITAL_PID, *PDIGITAL_PID;

Когда PIDGenA начинает расшифровывать ключ, то первым делом проверяет формат ключа (наличие полей, соответствие символов набору допустимых символов), затем конвертирует символьное представление в бинарное, и приступает к расшифровке номера продукта. А здесь начинается самое интересное. Дело в том, что кроме экспортируемых функций, pidgen.dll содержит криптографические ресурсы для расшифровки ключа. Они именованы как "BINK", и их - два.

Если параметр bOEM равен FALSE, то для расшифровки используется BINK 1, в противном случае - BINK 2. Экспериментально было установлено, что BINK 1 предназначен для Retail, а BINK 2 - для OEM ключей.

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

Установочный ключ может быть расшифрован только тем криптографическим ключом, которым он был зашифрован. Для разных версий XP (home, pro, VLK, + OEM/Retail) эти криптографические ключи разные, что видно из таблицы. Поэтому они не подходят друг к другу. В конечном итоге должен получиться ProductID.

  • xxxxx-xxx-xxxxxxx-xxxxx

Идентификаторы ключей для разных версий Windows представлены в таблице

 BINK_ID 1BINK_ID 2
home-retail-en-5.1.2600.02Ah2Bh
home-retail-ru-5.1.2600.02Ah2Bh
home-retail-en-5.1.2600.11062Ah2Bh
home-retail-ru-5.1.2600.11062Ah2Bh
home-retail-en-5.1.2600.21802Ah2Bh
home-retail-ru-5.1.2600.21802Ah2Bh
pro-retail-en-5.1.2600.02Ch2Dh
pro-retail-ru-5.1.2600.02Ch2Dh
pro-retail-en-5.1.2600.11062Ch2Dh
pro-retail-ru-5.1.2600.11062Ch2Dh
pro-retail-en-5.1.2600.12102Ch2Dh
pro-retail-ru-5.1.2600.12102Ch2Dh
pro-retail-en-5.1.2600.21802Ch2Dh
pro-retail-ru-5.1.2600.21802Ch2Dh
pro-VLK-ru-5.1.2600.3180*2Eh2Fh
pro-VLK-ru-5.1.2600.3244*2Eh2Fh
pro-VLK-ru-5.1.2600.5512*2Eh2Fh

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

Так же для проверки ключей можно использовать утилиту pidgen.exe. Это консольное приложение. Для работы ей требуется три параметра

/i path1 - путь к папке (I386), в которой находятся setupp.ini и pidgen.dll

/s path2 или /k XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Либо папка c файлом WinNT.sif, в котором прописан ключ, либо непосредственное значение ключа.

/o path3 - папка для результата. В ней будет создан change.reg, в котором будут прописаны Pid, PruductID, и DigitalProductID, соответствующие ключу.

Пример использования:

C:> pidgen /i path1 /s path2 /o path3