Что за бред, подумает читатель, прочитав название этой статьи. Как можно сгенерировать ключ, если алгоритм генерации полностью не известен? Но я гарантирую, что, прочитав эту статью, вы убедитесь, что и такое возможно... Итак приступим.

Мне понадобилось перевести несколько видеороликов в стандарт MPEG, а для сего я скачал с www.download.com XingMPEG Encoder 2.20 – во всех отношениях просто замечательную программу, кроме одного: это trial-версия (т.е. она работает только 30 дней), но главное – trial позволяет делать файлы не более 30 секунд. А поскольку большинство роликов заметно больше 30 секунд, мы займемся исправлением этого недоразумения.

Для начала с помощью SoftICE. При запуске программы появится окошко с логотипом фирмы и сообщением, что это не полная версия. Внизу окошка – бегунок, показывающий количество дней до конца халявы, а так же 3 кнопки: "Buy Now", "Try First" и "Cancel".

Нажимаем кнопку "Buy Now" и попадаем в окно регистрации, где заполним больше десятка полей всяческой ерундой. Пару раз щелкаем "Дальше". Попали в окошко, где надо вводить данные о кредитной карточке. Я заполнил поля так:

  Тип карточки	– American Express 

  Card Number	– 1234 1234 1234 1234 

  Expiration	– 11/11 

  Name on card	– You!

Трижды щелкаем "Дальше", и попадем в окно с выбором платежа. Выберем "ORDER BY MAIL/FAX", т.к. все остальные отпадают по понятным причинам. Теперь, когда мы снова запустим программу и нажмем "Buy Now", мы попадем в само окно регистрации, где и необходимо ввести код, якобы присланный нам по почте после оплаты.

Теперь поставим в SoftICE контрольную точку на выполнение MessageBoxA(). Вводим в окно для кода любое число, но меньше 10 знаков (можно и 10, но тогда придется прокручивать страниц пять текста, чтобы найти команду перехода). Щелкаем "ОК" и попадаем в SoftICE. Жмем F12, "ОК" в окошке с сообщением о неверном коде, и попадаем обратно в SoftICE. Наблюдаем такую картину:

:10005635  call [user32!MessageBoxA] 

:1000563B  mov ecx, [10031774] <--- Мы здесь. 

:10005641  or eax, -01

Прокрутим код немного вверх, пока не натолкнемся на строчки:

:1000560C  repnz scasb 

:1000560E  not ecx 

:10005610  dec ecx 

:10005611  cmp ecx, 0A <---- Проверка длины. 

:10005614  jz 10005655 <---- Сюда bpx. 

:10005616  lea edx, [esp+10]

Отключим предыдущие контрольные точки, и поставим новую на выполнение команды jz 10005655 (просто двойным щелчком по этой строке), вернемся в программу и введем теперь точно 10 цифр в окно для кода (а можно просто поменять значение регистра флагов Z) и снова попытаемся зарегистрироваться. Произойдет остановка на jz 10005655 (JUMP), протрассируем (F10) немного программу, пока не дойдем до места:

:10005698  push ecx 

:10005699  push edx 

:1000569A  push eax 

:1000569B  call 1000B950 <---- Остановимся тут. 

:100056A0  add esp, 0C

Не выполняя команду call, посмотрим что ей передается:

  d ecx – пусто 

  d edx – крупненькая константа = Er5286RteWa2314HmN 

  d eax – номер, у меня – 4872151134

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

Проверим это, выполнив call. Посмотрим, что теперь находится в ранее пустом ecx:

  d ecx – регистрационный код, у меня – QLRHMLIRYR

На этом первая часть заканчивается. Теперь можно ввести код в окне регистрации – и полностью рабочий XingMPEG Encoder 2.20 у нас в руках.

Убрать регистрацию можно так:

  1. Uninstall.
  2. Удалить из реестра ключ HKEY_CLASES_ROOT\ultxfile\Format\MSHVVEN2 (или типа такого).
  3. Переустановить программу.

А теперь о главном: как сделать генератор РН, не зная алгоритма его вычисления?

Для примера возьмём все тот же XingMPEG Encoder v2.20 (как найти правильный РН с помощью SoftICE я объяснять здесь не буду, об этом мы уже говорили в первой части, да и о нахождении большинства необходимых данных можно прочитать там же).

Поставив нужную контрольную точку, мы наткнёмся на процедуру генерации РН:

:10005698  51           push ecx 

:10005699  52           push edx 

:1000569A  50           push eax 

:1000569B  E8B0620000   call 1000B950 

:100056A0  83C40C       add esp, 0C

Обращаем внимание на то, что процедура эта находится в rsagnt32.dll. Также уделяем внимание EIP, из которого можно сделать вывод, что rsagnt32.dll грузилась по стандартному адресу 10000000. Так что несложно будет вычислить адрес и самой функции: 1000В950h – 10000000h = В950h. Самое время посмотреть, какие функции являются в rsagnt32.dll экспортируемыми (для этой цели я использовал DumpBin).

Вот собственно и есть эти функции:

Ordinal  Hint     RVA             Name 



   1      0     00002A40     SAAddProductItem 

   2      1     00011590     SAChargeTax 

   3      2     00011580     SACheckEnable 

   4      3     00002B70     SACleanup 

   5      4     00002930     SAInitialize 

   6      5     0000E350     SAPurchaseOrderEnable 

   7      6     000085B0     SAPurchaseOrderSetFaxNumber 

   8      7     0000E360     SAPurchaseOrderSetInstParagraph 

   9      8     0000E3C0     SAPurchaseOrderSetOrderInfoParagraph 

  10      9     00010660     SAReceiptSetNoSerialNumber 

  11      A     00010600     SAReceiptSetParagraph 

  12      B     000115A0     SASelectTransMethod 

  13      C     000029E0     SASetHelpDir 

  14      D     000088E0     SASetMailInstruction 

  15      E     00008930     SASetNoWaitMail 

  16      F     00002980     SASetScreenText 

  17     10     00008580     SASetVendorName 

  18     11     000012E0     startSalesAgent

И что же мы видим? А ничего. Экспортируемой функции с RVA=0000В950 просто нет!

Вот теперь мы перейдём к самому интересному. А что если нам написать программку (я использовал С++), которая будет делать следующее:

 

  1. Загружать rsagnt32.dll. Можно использовать HINSTANCE hInst=LoadLibrary(rsagnt32), при этом hInst - не что иное, как RVA самой DLL (как 10000000, см.выше).
  2. Вычислять адрес этой функции. Чтобы получить адрес функции, нам нужно к hInst прибавить В950h. Теперь у нас есть адрес функции (далее KeyMaker()), которую мы будем вызывать, осталось только найти нужные параметры.
  3. Вызывать эту функцию, передав ей нужные параметры. Для этого вернемся ещё раз к самой функции из SoftICE:
    :10005698  51          push ecx         <----- Buffer 
    
    :10005699  52          push edx         <----- Const 
    
    :1000569A  50          push eax         <----- PersonalCode 
    
    :1000569B  E8B0620000  call 1000B950    <----- Вызов ф-ции 
    
    :100056A0  83C40C      add esp, 0C      <----- Правка стека
  4. Мы видим, что функции передаются три параметра: Buffer, Const и PersonalCode. Buffer - то место, куда запишется правильный код, Const имеет вид Er5286RteWa2314HmN, а PersonalCode берётся из rsagent.ini. (или из окошка в программе регистрации).

Теперь к самой программе:

char* Const="Er5286RteWa2314HmN"; 

char Buffer[10]; 

char* PersonalCode="4872151134" //PersonalCode можно читать из rsagent.ini

                               // используя GetPrivateProfileString()

Саму же функцию нам придётся вызывать с помощью Ассемблера, т.к она не является экпортируемой, после вызова будет неправильно выставлен стек, что приведёт непосредственно к сбою системы.

_asm 



{ 

push offset Buffer 

mov eax, [Const] 

push eax 

mov eax, [PersonalCode] 

push eax 

call dword ptr [KeyMaker] // KeyMaker это и есть адрес функции, который мы вычислили 

add esp, 0x0C 

}

После всего этого в Buffer стоит правильный РН. Ну что, смог я вас убедить?

Дальше


Образование на Куличках