Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Как сделать генератор PH, не зная алгоритма его вычисления
Едет программер с девушкой в троллейбусе. Девушка:
- Мечтаю съездить на могилку к Янке... Программер (немного подумав):
- А я мечтаю съездить на могилку к Биллу Гейтсу.

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

Мне понадобилось перевести несколько видеороликов в стандарт 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 у нас в руках.

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

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

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

Для примера возьмём все тот же 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 просто нет!

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

  • Загружать rsagnt32.dll. Можно использовать HINSTANCE hInst=LoadLibrary(rsagnt32), при этом hInst - не что иное, как RVA самой DLL (как 10000000, см.выше).
  • Вычислять адрес этой функции. Чтобы получить адрес функции, нам нужно к hInst прибавить В950h. Теперь у нас есть адрес функции (далее KeyMaker()), которую мы будем вызывать, осталось только найти нужные параметры.
  • Вызывать эту функцию, передав ей нужные параметры. Для этого вернемся ещё раз к самой функции из 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      <----- Правка стека

  • Мы видим, что функции передаются три параметра: 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 стоит правильный РН. Ну что, смог я вас убедить?

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay