Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Keygenning and patching MetaProducts Offline Explorer Enterprise 4.9

Обсудить статью на форуме

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: ev1l^4 [tPORt] <ev1l4@mail.ru>

:: Цель ::

MetaProducts Offline Explorer Enterprise
(http://cracklab.ru/art/ev1l4/Offline_Explorer_Enterprise_4.9_Build_2670.zip)

:: Инструменты ::

OllyDbg
IdaPro
RSA-Tool
WinAsm
MASM32

:: Вступление ::

Эта статья про взлом программы MetaProducts Offline Explorer Enterprise 4.9. Регистрация основана на вводе регистрационного кода (далее рег. код), который будет расшифровываться алгоритмом base64 и полученные данные будут закриптованы с помощью RSA, ключ которого будет составлять 470 бит. Для того, чтобы написать генератор ключей нам потребуется заменить экспоненту D(Private) на свою, т.к. ключ размером 470 бит я не имею возможности факторизировать.

:: Исследование ::

Прежде чем исследовать код, рекомендую распаковать программу, думаю проблем у Вас с этим не возникнет, т.к. там пакер ASPack, я воспользовался распаковщиком от PE_Kill'а. Распаковав программу, мы узнаём, что она написана на Borland Delphi. Находим имена функций RSA с помощью сигнатур FGIntRSA от bLaCk-eye. Присутствие Base64 можно узнать плагином kanal для PEiD'а. Далее поступаем как обычно - идём в меню "Справка", открываем окно регистрации, вводим любую строку, например "123", кликаем на кнопку "OK" - открылось сообщение, с помощью которого мы найдём начало процедуры кнопки "OK". Ставим breakpoint в конце API функции "MessageBoxA", в сообщении кликаем на кнопку "OK", два раза выходим из процедур.

Попадаем примерно в такое место:

CODE:007DEA18           test  esi, esi
CODE:007DEA1A           jnz   short loc_7DEA2D
CODE:007DEA1C           mov   eax, [ebx+324h]
CODE:007DEA22           mov   eax, [eax+220h]
CODE:007DEA28           mov   edx, [eax]
CODE:007DEA2A           call  dword ptr [edx+44h]


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

CODE:007DE5E4           push  ebp
CODE:007DE5E5           mov   ebp, esp
CODE:007DE5E7           mov   ecx, 7
CODE:007DE5EC loc_7DE5EC:                             ; CODE XREF: sub_7DE5E4+Dj
CODE:007DE5EC           push  0
CODE:007DE5EE           push  0
CODE:007DE5F0           dec   ecx
CODE:007DE5F1           jnz   short loc_7DE5EC


Это начало процедуры кнопки "OK" окна регистрации.

После выполнения этого кода возвращается результат обработки рег. кода:

CODE:007DE624           lea   eax, [ebp+var_C]
CODE:007DE627           push  eax
CODE:007DE628           lea   ecx, [ebp+var_8]
CODE:007DE62B           lea   edx, [ebp+var_4]
CODE:007DE62E           mov   eax, ds:off_8D343C
CODE:007DE633           mov   eax, [eax]
CODE:007DE635           call  sub_844414


Сравнение первых 4 символов рег. кода со строкой "dqma":

CODE:00843509           mov   edx, [esi]
CODE:0084350B           mov   eax, offset aDqma_0     ; "dqma"
CODE:00843510           call  sub_405CB0


Парсируется строка "amqd" для того, чтобы обрезать середину рег. кода между "dqma" и "amqd":

CODE:00843582 loc_843582:                             ; CODE XREF: sub_8432A0+31Aj
CODE:00843582           mov   eax, [esi]
CODE:00843584           cmp   byte ptr [eax+edi-1], 'a'
CODE:00843589           jnz   short loc_8435B7
CODE:0084358B           mov   eax, [esi]
CODE:0084358D           cmp   byte ptr [eax+edi], 'm'
CODE:00843591           jnz   short loc_8435B7
CODE:00843593           mov   eax, [esi]
CODE:00843595           cmp   byte ptr [eax+edi+1], 'q'
CODE:0084359A           jnz   short loc_8435B7
CODE:0084359C           mov   eax, [esi]
CODE:0084359E           cmp   byte ptr [eax+edi+2], 'd'
CODE:008435A3           jnz   short loc_8435B7
CODE:008435A5           push  esi
CODE:008435A6           lea   ecx, [edi+3]
CODE:008435A9           mov   eax, [esi]
CODE:008435AB           mov   edx, 1
CODE:008435B0           call  sub_405BCC
CODE:008435B5           jmp   short loc_8435BC
CODE:008435B7 ; ---------------------------------------------------------------------------
CODE:008435B7
CODE:008435B7 loc_8435B7:                             ; CODE XREF: sub_8432A0+2E9j
CODE:008435B7                                         ; sub_8432A0+2F1j ...
CODE:008435B7           dec   edi
CODE:008435B8           test  edi, edi
CODE:008435BA           jnz   short loc_843582


На данный момент можно сказать, что рег. код имеет вид: "dqma","Строка для декодирования алгоритмом Base64","amqd". Например: "dqmaMTIzamqd".

Экспонента E в виде десятичной строки конвертируется в шестнадцатеричное число:

CODE:008435D5           lea   edx, [ebp+var_24]
CODE:008435D8           mov   eax, ds:dword_8D9CEC
CODE:008435DD           call  sub_82DAB8


Экспонента D в виде десятичной строки конвертируется в шестнадцатеричное число:

CODE:008435E2           lea   edx, [ebp+var_1C]
CODE:008435E5           mov   eax, ds:dword_8D9CF8
CODE:008435EA           call  sub_82DAB8


Вырезанная строка декодируется с помощью Base64:

CODE:008435EF           lea   edx, [ebp+var_10]
CODE:008435F2           mov   eax, [esi]
CODE:008435F4           call  sub_4B7EF8


RSA, криптовка:

CODE:00843601           lea   eax, [ebp+var_2C]
CODE:00843604           push  eax
CODE:00843605           lea   eax, [ebp+var_2C]
CODE:00843608           push  eax
CODE:00843609           lea   eax, [ebp+var_2C]
CODE:0084360C           push  eax
CODE:0084360D           lea   eax, [ebp+var_2C]
CODE:00843610           push  eax
CODE:00843611           lea   eax, [ebp+var_14] <<< Буфер для блока криптованных данных
CODE:00843614           push  eax
CODE:00843615           lea   ecx, [ebp+var_1C] <<< Экспонента D в виде числа
CODE:00843618           lea   edx, [ebp+var_24] <<< Экспонента E в виде числа
CODE:0084361B           mov   eax, [ebp+var_10] <<< Криптуемое сообщение
CODE:0084361E           call  @RSADecrypt$qqr10AnsiStringr6TFGIntt2t2t2t2t2r10AnsiString ;
RSADecrypt(AnsiString,TFGInt &,TFGInt &,TFGInt &,TFGInt &,TFGInt &,TFGInt &,AnsiString &)


Процедура RSADecrypt на Delphi работает с данными примерно так - сначала она их переводит в двоичную систему счисления в виде строки, затем выполняется основной алгоритм RSA, после этого в блоке закриптованных данных парсируется 3 бита выставленных в 1, строка "111", данные после "111" будут считаться началом закриптованных данных. Я хочу обратить Ваше внимание на то, что вначале декриптуемых данных должен стоять байт 07h, что в двоичной системе будет 111b, в противном случае данные возвращённые функцией RSA Encrypt будут (если будут) не всегда идентичны декриптованным.

Ниже идёт две процедуры криптовки RSA, но мы их пропустим, т.к. нет необходимости их исследовать, потому что дальнейшая задача узнать какие данные нужно декриптовать.

Сравниваются первые 2 криптованных байта со строкой "OE":

CODE:00843633           mov   edx, offset byte_844040
CODE:00843638           mov   eax, [ebp+var_14]
CODE:0084363B           call  sub_4B4C78
CODE:00843640           test  al, al
CODE:00843642           jnz   loc_8436EB <<< Переход, если равно.


Сравниваются первые 2 криптованных байта со строкой "OE":

CODE:008436EB           mov   edx, offset byte_844040
CODE:008436F0           mov   eax, [ebp+var_14]
CODE:008436F3           call  sub_4B4C78
CODE:008436F8           test  al, al
CODE:008436FA           jnz   loc_8437A3 <<< Переход, если равно.


Находится байт 01h в криптованных данных, для обрезки байт до 01h:

CODE:008437AB           mov   edx, [ebp+var_14]
CODE:008437AE           mov   eax, offset unk_844070
CODE:008437B3           call  sub_405CB0


Сравниваются первые 3 криптованных байта со строкой "OEE":

CODE:00843839           mov   eax, [ebp+var_30]
CODE:0084383C           mov   edx, offset off_84407C
CODE:00843841           call  sub_405AB8


Находится байт 01h в криптованных данных, для обрезки байт 2-ой строки до 01h:

CODE:0084387A           mov   edx, [ebp+var_14]
CODE:0084387D           mov   eax, offset unk_844070
CODE:00843882           call  sub_405CB0


Судя по тому, что вторая строка сравнивается со строками похожими на баны, то можно считать следущую строку именем пользователя программы, например:

CODE:008438A5           mov   edx, [ebp+var_4]
CODE:008438A8           mov   edx, [edx]
CODE:008438AA           mov   eax, offset aTsrh       ; "TSRh"
CODE:008438AF           call  sub_405CB0


Находится байт 01h в криптованных данных, для обрезки строки типа лицензии:

CODE:00843BCD           mov   edx, [ebp+var_14]
CODE:00843BD0           mov   eax, offset unk_844070
CODE:00843BD5           call  sub_405CB0


Обрезается строка типа лицензии и переводится в число:

CODE:00843BE4           lea   eax, [ebp+var_30]
CODE:00843BE7           push  eax
CODE:00843BE8           mov   ecx, edi
CODE:00843BEA           dec   ecx
CODE:00843BEB           mov   edx, 1
CODE:00843BF0           mov   eax, [ebp+var_14]
CODE:00843BF3           call  sub_405BCC
CODE:00843BF8           or    edx, 0FFFFFFFFh
CODE:00843BFB           mov   eax, [ebp+var_30]
CODE:00843BFE           call  sub_40C13C
CODE:00843C03           mov   edx, ds:dword_8D9CA8
CODE:00843C09           mov   [edx+0C1Ch], eax


Сравнивается тип лицензии:

CODE:00843C2F           mov   eax, ds:dword_8D9CA8
CODE:00843C34           mov   eax, [eax+0C1Ch]
CODE:00843C3A           cmp   eax, 1
CODE:00843C3D           jnz   short loc_843C96
; ---------------------------------------------------------------------------
CODE:00843C96           cmp   eax, 2710h <<< Мы выберем эту, используя строку "10000"
CODE:00843C9B           jl    short loc_843CF4
; ---------------------------------------------------------------------------
CODE:00843CF4           cmp   eax, 3E8h
CODE:00843CF9           jl    short loc_843D4F
; ---------------------------------------------------------------------------
CODE:00843D4F           dec   eax
CODE:00843D50           jle   loc_843FAF


Проверяется на присутствие строка "date=":

CODE:00843DB0           mov   eax, ds:dword_8D9CA8
CODE:00843DB5           mov   eax, [eax+0C18h]
CODE:00843DBB           mov   edx, offset aDate_2     ; "date="
CODE:00843DC0           call  sub_4B4D18


Если таковой нет, то следующая строка будет использоваться в качестве строки электронного ящика:

CODE:00843F83           mov   eax, ds:dword_8D9CA8
CODE:00843F88           add   eax, 0AB4h
CODE:00843F8D           mov   ecx, [ebp+var_14]
CODE:00843F90           mov   edx, offset aCustomerEMail ; "Customer E-mail: "
CODE:00843F95           call  sub_4059B8


Устанавливается результат регистрации TRUE:

CODE:00843FAB           mov   [ebp+var_9], 1


Необходимая информация для создания генератора ключей известна. Пример данных, которые нужно декриптовать:
"OEE",01h,"NameOfUser",01h,"10000",01h,"date=12.31.2100",0

Осталось подменить экспоненту.
Посмотрим на код, где экспонента D берётся для перевода в шестнадцатеричное число:

CODE:008435E2           lea   edx, [ebp+var_1C]
CODE:008435E5           mov   eax, ds:dword_8D9CF8
CODE:008435EA           call  sub_82DAB8


Поищем место где ещё используется адрес 8D9CF8, вот что мне попалось:

CODE:0087A79D           lea   edx, [ebp+var_10]
CODE:0087A7A0           mov   eax, offset 87A9FC ; "MjU0MjIxODQ2MTQ0OTA1MTExNjc0Mzc0MTY5Mjc"...
CODE:0087A7A5           call  sub_4B7E90
CODE:0087A7AA           mov   edx, [ebp+var_10]
CODE:0087A7AD           mov   eax, offset dword_8D9CF8
CODE:0087A7B2           call  sub_4056F0


По адресу 87A9FC хранится строка закодированная алгоритмом Base64, после декодирования будет экспонента в виде строки в десятичной системе счисления:
25422184614490511167437416927987016597758901965279751221871555872069753
03830212504351697049643415317998648177930553115825240387100833950106213


Инициализируется экспонента E:

CODE:0087A74F           lea   edx, [ebp+var_4]
CODE:0087A752           mov   eax, offset dword_87A854     ; "NjU1Mzc="
CODE:0087A757           call  sub_4B7E90
CODE:0087A75C           mov   edx, [ebp+var_4]
CODE:0087A75F           mov   eax, offset dword_8D9CEC
CODE:0087A764           call  sub_4056F0


Base64: NjU1Mzc=
Decimal value: 65537
Hexadecimal value: 10001

Остаётся только заменить экспоненту N, для этого мы генерируем пару экспонент размером 470 бит:
N: 21522360450033028507540100165610588197382555173010143598675537539231924
80943739822482453230883084884937164795959820209034151836380066983902033

D: 14912322286274162557011892647210143879868539113038705016589979463798807
26104568553381045114249181404409861144880912205395172309853297053339189


Экспоненту N кодируем алгоритмом Base64:
MjE1MjIzNjA0NTAwMzMwMjg1MDc1NDAxMDAxNjU2MTA1ODgxOTczODI1NTUxNzMwMTAxNDM1OTg2NzU1Mzc1MzkyMzE5MjQ4
MDk0MzczOTgyMjQ4MjQ1MzIzMDg4MzA4NDg4NDkzNzE2NDc5NTk1OTgyMDIwOTAzNDE1MTgzNjM4MDA2Njk4MzkwMjAzMw==


И заменяем по адресу 87A9FC строку строкой указанной выше.

:: Алгоритм генерации рег. кода ::

• Формируем строку для декриптования.
• Декриптуем строку, RSA M=C^D mod N.
• Кодируем полученный блок сообщения алгоритмом Base64.
• В начале строки присоединяем строку "dqma", а в конце "amqd".

:: Исходный код генератора ::


GenerateProc	PROTO	:DWORD,:DWORD

.data
LabelOfProgram		db	"OEE",0
TypeOfLicense		db	"10000",0
DateEndOfUse		db	"date=12.31.2100",0
Byte_01h		db	01h,0
szExponentD		db	"14912322286274162557011892647210143879868539113038705016589979463798807"
			db	"26104568553381045114249181404409861144880912205395172309853297053339189",0
szExponentN		db	"21522360450033028507540100165610588197382555173010143598675537539231924"
			db	"80943739822482453230883084884937164795959820209034151836380066983902033",0

.data?
pExponentD		dd	?
pExponentN		dd	?
pChiperText		dd	?
LengthMessageBlock	dd	?
ChiperMessageBlock	db	64	dup(?)
NameOfUser		db	32	dup(?)
Buffer4Serial		db	100	dup(?)

.code
;init bigs
invoke	_BigCreate,0
mov		pExponentD,eax
invoke	_BigCreate,0
mov		pExponentN,eax
invoke	_BigCreate,0
mov		pChiperText,eax
invoke	_BigIn,addr szExponentD,10,pExponentD
invoke	_BigIn,addr szExponentN,10,pExponentN

;generate
invoke	GenerateProc, addr NameOfUser,addr Buffer4Serial

;generate function
GenerateProc	proc lpName:DWORD, lpBuffer4Serial:DWORD
; Формирование сообщения для декриптования.
mov	byte ptr [ChiperMessageBlock],07h
invoke	lstrcat,addr ChiperMessageBlock,addr LabelOfProgram
invoke	lstrcat,addr ChiperMessageBlock,addr Byte_01h
invoke	lstrcat,addr ChiperMessageBlock,lpName
invoke	lstrcat,addr ChiperMessageBlock,addr Byte_01h
invoke	lstrcat,addr ChiperMessageBlock,addr TypeOfLicense
invoke	lstrcat,addr ChiperMessageBlock,addr Byte_01h
invoke	lstrcat,addr ChiperMessageBlock,addr DateEndOfUse
invoke	GetTickCount
push	eax
invoke	lstrlen,addr ChiperMessageBlock
pop	ecx
mov	byte ptr [ChiperMessageBlock+eax], 0
mov	byte ptr [ChiperMessageBlock+eax+1], cl
add 	eax, 2
mov	LengthMessageBlock,eax
; Декриптование сообщения.
invoke	_BigInB256,addr ChiperMessageBlock,LengthMessageBlock,pChiperText
invoke	_BigPowMod,pChiperText,pExponentD,pExponentN,pChiperText
invoke	_BigOutB256,pChiperText,addr ChiperMessageBlock
; Присоединение к рег. коду строки "dqma".
mov	eax, lpBuffer4Serial
mov	dword ptr [eax], "amqd"
add	eax, 4
; Кодирование декриптованного сообщения.
invoke	Base64Encode,addr ChiperMessageBlock,63,eax
; Присоединение в конце рег. кода строки "amqd".
invoke	lstrlen,lpBuffer4Serial
add	eax, lpBuffer4Serial
mov	dword ptr [eax], "dqma"
invoke	RtlZeroMemory,addr ChiperMessageBlock,sizeof ChiperMessageBlock
ret
GenerateProc EndP

;destroy bigs
invoke	_BigDestroy, pExponentD
invoke	_BigDestroy, pExponentN
invoke	_BigDestroy, pChiperText


:: Заключение ::

В этой статье Вы прочитали, как я исследовал и писал генератор ключей к очередной программе использующей RSA. Надеюсь, статья Вам понравилась. Хочу также пояснить одну мелочь - сигнатуры распознали функцию powmod как RSADecrypt, а я всё время называл это действие криптованием, потому что экспонента 10001h или 65537d является маленькой и выставлена по умолчанию в RSA Tool как E, что и следует принимать как E(Encrypt), т.е. криптование.

Source keygen and signatures: http://cracklab.ru/art/ev1l4/files.rsa.470.zip

Приветы летят всем true-участникам команды tPORt и моим друзьям.
Also greet to Witch (girl of void). (:
Thanks to Bat, Guru.eXe, void for preview. (:
Join to tPORt and compile in place with us. :)



Обсуждение статьи: Keygenning and patching MetaProducts Offline Explorer Enterprise 4.9 >>>


Комментарии к статье: Keygenning and patching MetaProducts Offline Explorer Enterprise 4.9

-= XjekaCR =- 17.03.2008 01:26:56
Лучшая статья! Автору респект!
---
AVE 18.03.2008 20:34:53
Действительно респект
---
fire4x 02.05.2008 00:21:51
Нет ли в планах сварганить кейген под 5-ю версию ?
---
MAXakaWIZARD 01.03.2009 00:10:39
Странно, но на вызовах:
invoke _BigInB256, addr ChiperMessageBlock, LengthMessageBlock, pChiperText
invoke _BigPowMod, pChiperText,pExponentD, pExponentN, pChiperText
invoke _BigOutB256, pChiperText, addr ChiperMessageBlock

получаем ошибку нарушения доступа ( AccessViolation )
---
MAXakaWIZARD 01.03.2009 00:12:08
Странно, но на вызовах:
invoke _BigInB256, addr ChiperMessageBlock, LengthMessageBlock, pChiperText
invoke _BigPowMod, pChiperText,pExponentD, pExponentN, pChiperText
invoke _BigOutB256, pChiperText, addr ChiperMessageBlock

получаем ошибку нарушения доступа ( AccessViolation )
---
ThugboyZ 15.03.2010 23:12:39
tPORt лучшие жаль что ev1|^4 куда-то свалил :(
---

Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS