Принесли мне компакт от какой-то книги издательства Питер, кажется книга про Web. Там валялись всякие проги для работы с графикой и html, не долго думая, я решил скопировать все это на свой хард, чтобы потом поразобраться...
Спустя неделю ко мне в руки попал компакт с огромным количеством картинок в формате jpg. При не очень большом разрешении их размер достигал 500 кило, и это меня не обрадовало. Их было так много, что я сразу отбросил мысль об использовании IrfanView"а (очень рулезная прога, всем рекомендую www.irfanview.com). Тут я вспомнил о компакте, где были проги для работы с графикой, а точнее оптимизаторы. Так я вышел на эту прогу. К моему сожалению, она просила за регистрацию $29 и это была ее главная ошибка. Приступаем
Что за прога:
Очень хорошая прога для сжатия графики, позволяет обрабатывать файлы в автоматическом режиме. Короче мне понравилась, я ее себе даже русифицировал, если кому интересно, то напишите на мыло. Размер в архиве примерно 400Kb. Единственный недостаток - регистрация, который мы сейчас исправим.
Начало
Взглянув на ресурсы, я понял, что программа написана на Delphi и это хорошо (присутствуют bmp файлы всегда вставляющиеся Delphi). Запускаем ее, заходим в раздел Register и вводим произвольный пароль. На это нам выплевывается надпись Incorrect Registration Code. Это будет главная зацепка.
Кидаем программу в Win32Dasm. И в секции строк ищем нашу. Нашли. Нажимаем на нее два раза и оказываемся тут
:00427F8E 50 push eax
:00427F8F FF4E1C dec [esi+1C]
:00427F92 8D45F8 lea eax, dword ptr [ebp-08]
:00427F95 BA02000000 mov edx, 00000002
:00427F9A E891D10100 call 00445130
:00427F9F 59 pop ecx
:00427FA0 84C9 test cl, cl
:00427FA2 0F84B7000000 je 0042805F
:00427FA8 66C746102C00 mov [esi+10], 002C
* Possible StringData Ref from Data Obj ->"JPEG Optimizer"
|
:00427FAE BA6D9B4700 mov edx, 00479B6D
(всякий мусор выкинут)
:00427FF0 8D4DEC lea ecx, dword ptr [ebp-14]
* Possible StringData Ref from Data Obj ->"Code"
|
:00427FF3 BA7C9B4700 mov edx, 00479B7C
(здесь выкинут код отвечающий за запись правильного кода в реестр)
:00428040 8BC3 mov eax, ebx
:00428042 E8054A0200 call 0044CA4C
:00428047 6A40 push 00000040
* Possible StringData Ref from Data Obj ->"Message"
|
:00428049 B9AA9B4700 mov ecx, 00479BAA <- Выводится сообщение о правильной регистрации.
* Possible StringData Ref from Data Obj ->"Thank you for registering JPEG "
->"Optimizer"
|
:0042804E BA819B4700 mov edx, 00479B81
:00428053 A104F54700 mov eax, dword ptr [0047F504]
:00428058 E843A80300 call 004628A0
:0042805D EB16 jmp 00428075
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427FA2(C) <- Вот оттуда переход на првильный или неправильный
|
:0042805F 6A30 push 00000030
* Possible StringData Ref from Data Obj ->"Error"
|
:00428061 B9CE9B4700 mov ecx, 00479BCE
* Possible StringData Ref from Data Obj ->"Incorrect Registration Code"
|
:00428066 BAB29B4700 mov edx, 00479BB2
:0042806B A104F54700 mov eax, dword ptr [0047F504]
:00428070 E82BA80300 call 004628A0
Вроде бы проверка в процедуре call 445130. Но меня смутила строка 427F9F (она выделена). А потом я просек в чем дело, взглянув чуть выше, строка 427F8E. Я уж не знаю, сами ли программеры решили так нас обмануть, а может компилятор. Скорее всего второе. Теперь смотрим повыше
:00427F75 BA6C9B4700 mov edx, 00479B6C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427F73(U)
|
:00427F7A 52 push edx
:00427F7B E8380A0000 call 004289B8
:00427F80 59 pop ecx
:00427F81 84C0 test al, al <- Проверяем
:00427F83 7504 jne 00427F89 <- Если все тип-топ (al<>0), то переход
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427F68(C)
|
:00427F85 33C0 xor eax, eax
:00427F87 EB05 jmp 00427F8E
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427F83(C)
|
:00427F89 B801000000 mov eax, 00000001
Что ж идем в процедуру и попробуем разобраться в коде.
:004289B8 55 push ebp
:004289B9 8BEC mov ebp, esp
:004289BB 83C4F8 add esp, FFFFFFF8
:004289BE 53 push ebx
:004289BF 8B4508 mov eax, dword ptr [ebp+08]
:004289C2 8D5DF8 lea ebx, dword ptr [ebp-08]
:004289C5 8A10 mov dl, byte ptr [eax] <-
:004289C7 8813 mov byte ptr [ebx], dl <-
:004289C9 8A4801 mov cl, byte ptr [eax+01] <-
:004289CC 884B01 mov byte ptr [ebx+01], cl <-
:004289CF 8A5002 mov dl, byte ptr [eax+02] <-
:004289D2 885302 mov byte ptr [ebx+02], dl <- Копируем 6 байт регистрационного кода
:004289D5 8A4803 mov cl, byte ptr [eax+03] <- в другое местов оперативной памяти
:004289D8 884B03 mov byte ptr [ebx+03], cl <-
:004289DB 8A5004 mov dl, byte ptr [eax+04] <-
:004289DE 885304 mov byte ptr [ebx+04], dl <-
:004289E1 8A4005 mov al, byte ptr [eax+05] <-
:004289E4 884305 mov byte ptr [ebx+05], al <-
:004289E7 0FBE0B movsx ecx, byte ptr [ebx] <-
:004289EA 51 push ecx
:004289EB E8AC240400 call 0046AE9C
:004289F0 59 pop ecx
:004289F1 83F851 cmp eax, 00000051 <- Проверка кода 1 символа пароля с кодом буквы Q
:004289F4 7544 jne 00428A3A <- Если не правильно, то переход
:004289F6 0FBE4301 movsx eax, byte ptr [ebx+01]
:004289FA 50 push eax
:004289FB E89C240400 call 0046AE9C
:00428A00 59 pop ecx
:00428A01 83F84F cmp eax, 0000004F <- Проверка кода 2 символа пароля с кодом буквы O
:00428A04 7534 jne 00428A3A <- Если не правильно, то переход
:00428A06 0FBE5302 movsx edx, byte ptr [ebx+02]
:00428A0A 83FA37 cmp edx, 00000037 <- Проверка кода 3 символа пароля с кодом символа 7
:00428A0D 752B jne 00428A3A <- Если не правильно, то переход
:00428A0F 0FBE4B03 movsx ecx, byte ptr [ebx+03]
:00428A13 83F930 cmp ecx, 00000030 <- Проверка кода 4 символа пароля с кодом символа 0
:00428A16 7522 jne 00428A3A <- Если не правильно, то переход
:00428A18 0FBE4304 movsx eax, byte ptr [ebx+04]
:00428A1C 83F831 cmp eax, 00000031 <- Проверка кода 5 символа пароля с кодом символа 1
:00428A1F 7519 jne 00428A3A <- Если не правильно, то переход
:00428A21 0FBE5305 movsx edx, byte ptr [ebx+05]
:00428A25 83FA32 cmp edx, 00000032 <- Проверка кода 6 символа пароля с кодом символа 2
:00428A28 7510 jne 00428A3A <- Если не правильно, то переход
:00428A2A C605F0EC470001 mov byte ptr [0047ECF0], 01
:00428A31 E85AAEFDFF call 00403890
:00428A36 B001 mov al, 01 <- Вроде как код введен правильно
{В итоге для того, чтобы пройти эту проверку нужно написать код QO7012}
:00428A38 EB18 jmp 00428A52
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004289F4(C), :00428A04(C), :00428A0D(C), :00428A16(C), :00428A1F(C)
|:00428A28(C)
|
:00428A3A 53 push ebx
:00428A3B E8501A0000 call 0042A490
:00428A40 59 pop ecx
:00428A41 84C0 test al, al
:00428A43 7404 je 00428A49
:00428A45 B001 mov al, 01
:00428A47 EB09 jmp 00428A52
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00428A43(C)
|
:00428A49 C605F0EC470000 mov byte ptr [0047ECF0], 00
:00428A50 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00428A38(U), :00428A47(U)
|
:00428A52 5B pop ebx
:00428A53 59 pop ecx
:00428A54 59 pop ecx
:00428A55 5D pop ebp
:00428A56 C3 ret
И вроде бы, код найден, но меня заинтересовала процедура call 0042A490 (она выделена). После нее AL тоже устанавливается в единицу. И я решил проверить.
:0042A490 55 push ebp
:0042A491 8BEC mov ebp, esp
:0042A493 53 push ebx
:0042A494 8B5D08 mov ebx, dword ptr [ebp+08] <- В ebx адрес памяти с введенным кодом
(какой-то мутный код)
:0042A4B1 33D2 xor edx, edx <- Обнуляем edx
:0042A4B3 8BC3 mov eax, ebx <- В eax указатель на введенный код
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0042A4BD(C)
|
:0042A4B5 803093 xor byte ptr [eax], 93 <- Ксорим все символы введеного кода с 93h
:0042A4B8 42 inc edx <- Увеличиваем счетчик
:0042A4B9 40 inc eax <- Увеличиваем указатель
:0042A4BA 83FA06 cmp edx, 00000006 <- Сравниваем счетчик с 6
:0042A4BD 7CF6 jl 0042A4B5 <- Если меньше, то повторяем цикл
:0042A4BF 0FBE0B movsx ecx, byte ptr [ebx] <- Берем 1 символ отxorенного кода
:0042A4C2 83F9D8 cmp ecx, FFFFFFD8 <- Сравниваем с
:0042A4C5 7545 jne 0042A50C <- Если не равно, то в пролете
{Значит надо, чтобы было равно этим мы вычислим символ, который надо написать в коде,
можно, конечно, попробовать угадать в дебаггере или написать программу, но мы попробуем
посчитать все в ручную. Как, надеюсь, вам известно, что функция xor обратима, поэтому
ее часто используют для шифрования. Функция устанавливаем бит в единицу, если один
операнд единица, а второй ноль, иначе будет ноль. Переводим 93h в двоичную систему,
это можно сделать с помощью простого виндового калькулятора, можно тетрадами, а можно
в ручную.
93h - 10010011 93h - 10010011 93h - 10010011
D8h - 11011000 D9h - 11011001 A4h - 10100100
-------------- -------------- --------------
01001011 -> 4Bh(K) 01001010 -> 4Ah(J) 00110111 - 37h(7)
и так далее. В итоге получаем KJ7246}
:0042A4C7 0FBE4301 movsx eax, byte ptr [ebx+01]
:0042A4CB 83F8D9 cmp eax, FFFFFFD9
:0042A4CE 753C jne 0042A50C
:0042A4D0 0FBE5302 movsx edx, byte ptr [ebx+02]
:0042A4D4 83FAA4 cmp edx, FFFFFFA4
:0042A4D7 7533 jne 0042A50C
:0042A4D9 0FBE4B03 movsx ecx, byte ptr [ebx+03]
:0042A4DD 83F9A1 cmp ecx, FFFFFFA1
:0042A4E0 752A jne 0042A50C
:0042A4E2 0FBE4304 movsx eax, byte ptr [ebx+04]
:0042A4E6 83F8A7 cmp eax, FFFFFFA7
:0042A4E9 7521 jne 0042A50C
:0042A4EB 0FBE5305 movsx edx, byte ptr [ebx+05]
:0042A4EF 83FAA5 cmp edx, FFFFFFA5
:0042A4F2 7518 jne 0042A50C
:0042A4F4 C605F0EC470001 mov byte ptr [0047ECF0], 01
:0042A4FB C60500F4470001 mov byte ptr [0047F400], 01
:0042A502 E88993FDFF call 00403890
:0042A507 B001 mov al, 01 <- Если все хорошо
:0042A509 5B pop ebx
:0042A50A 5D pop ebp
:0042A50B C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0042A4C5(C), :0042A4CE(C), :0042A4D7(C), :0042A4E0(C), :0042A4E9(C)
|:0042A4F2(C)
|
:0042A50C 33C0 xor eax, eax <- здесь не есть хорошо
:0042A50E 5B pop ebx
:0042A50F 5D pop ebp
:0042A510 C3 ret
Ну вот и все, найдены два кода QO7012 и KJ7246. Чем они отличаются, честно говоря не знаю. Но все-таки думаю, что второй код приоритетней, т.к. он был замудрован посильнее первого (хотя и не очень сильно).
Спасибо за интерес к моему творчеству!
Удачи в Reversing Engeneering!
Послесловие
Спасибо авторам за предоставленный для исследования продукт. Он мне очень помог при переделывании картинок.
Господа Авторы: "Худшая защита месяца" только так можно охарактеризовать то, что я увидел в этой программе. Перед тем, как делать защиту можно было и почитать мануалы, написанные в этом направлении. Извините меня, но $29 для России это не дела. Крэкеров в Росии много. Россия рулез!
Братья Крэкеры: Не стоит сильно ругать авторов, они там за бугром не ведают, что творят.
Если Вас заинтересовала или понравилась информация по разработке на Delph - "Нахождение ключей для JPEG Optimizer v2.02 (взлом без Soft-Ice)", Вы можете поставить закладку в социальной сети или в своём блоге на данную страницу: Так же Вы можете задать вопрос по работе этого модуля или примера через форму обратной связи, в сообщение обязательно указывайте название или ссылку на статью!