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