
Исследование защиты скринсейвера Incredible Mars 3D

Скриншот скринсейвера Incredible Mars 3D
Под сегодняшнюю принудительную раздачу халявы у нас попадает скринсейвер Incredible Mars 3D. На экране крутится планета Марс, причем как в ее нынешнем высушенном состоянии, так и ее гипотетическая версия, когда планета была покрыта водой и всякой зеленью. Не самый великий шедевр скринсейверостроения, конечно, но в качестве подопытного вполне сгодится.
Скачиваем дистрибутив, устанавливаем. Основной файл скринсейвера Incredible Mars 3D.scr устанавливается в папку с Windows, поэтому искать его надо именно там. Файл ничем не упакован, поэтому сразу отправляем его в дизассемблер. Дальше открываем системные настройки скринсейверов, выбираем Incredible Mars 3D и открываем его свойства.

Настройки скринсейвера и окно регистрации
На ввод неправильного серийного номера программа реагирует сообщением "The key is incorrect", значит надо поискать его в файле:

Нехорошая строка найдена
Строчка найдена, и там же рядом, по всей видимости, строка сообщения об успешной регистрации. Теперь поищем в дизассемблере ссылки на эти строчки и условия, при которых они появляются.
Code (Assembler) : Убрать нумерацию
- ...
- .text:00422E48 mov eax, ds:dword_44788C
- .text:00422E4D mov [esp+1ECh+var_1DC], 0
- .text:00422E55 mov [esp+1ECh+var_1E0], offset sub_422110
- .text:00422E5D mov [esp+1ECh+var_1E4], ebp
- .text:00422E61 mov [esp+1ECh+var_1E8], 68h
- .text:00422E69 mov [esp+1ECh+var_1EC], eax
- .text:00422E6C mov ebx, 1
- .text:00422E71 call DialogBoxParamA
- .text:00422E76 sub esp, 14h
- .text:00422E79 test eax, eax
- .text:00422E7B jz loc_422248
- ; Если байт по адресу 430158 равен нулю, то введенный серийник правильный
- .text:00422E81 cmp byte_430158, 0
- .text:00422E88 jz loc_422FE2
- ; Иначе вывести сообщение о неправильном серийном номере
- .text:00422E8E mov [esp+1ECh+var_1E0], 10h
- .text:00422E96 mov [esp+1ECh+var_1E4], offset aError
- ; "Error"
- .text:00422E9E mov [esp+1ECh+var_1E8], offset aTheKeyIsIncorr
- ; "The key is incorrect."
- .text:00422EA6 mov [esp+1ECh+var_1EC], ebp
- .text:00422EA9 call MessageBoxA
- ; ---------------
- ; часть кода пропущена
- ; ---------------
- .text:00422FE2 loc_422FE2:
- ; Сообщение об успешной регистрации
- .text:00422FE2 call sub_401B40
- .text:00422FE7 lea esi, [esp+1ECh+hWnd]
- .text:00422FEB mov eax, ds:dword_44788C
- .text:00422FF0 mov [esp+1ECh+var_1E4], esi
- .text:00422FF4 mov [esp+1ECh+var_1E0], 104h
- .text:00422FFC mov [esp+1ECh+var_1E8], 9C41h
- .text:00423004 mov [esp+1ECh+var_1EC], eax
- .text:00423007 call LoadStringA
- .text:0042300C sub esp, 10h
- .text:0042300F mov [esp+1ECh+var_1EC], ebp
- .text:00423012 mov [esp+1ECh+var_1E0], 40h
- .text:0042301A mov [esp+1ECh+var_1E4], offset aSuccess
- ; "Success"
- .text:00423022 mov [esp+1ECh+var_1E8], offset aRegistrationCo
- ; "Registration completed."
- .text:0042302A call MessageBoxA
- ...
Code (Assembler) : Убрать нумерацию
- .data:00430158 byte_430158 db 1

Перекрестные ссылки на байт
Все очевидно. Первые две ссылки - инициализация флажка в режим триальности и в режим зарегистрированной программы, а дальше только куча проверок. Нас интересует вторая ссылка, там флажок сбрасывается и программа переходит в зарегистрированный режим. Надо посмотреть, где и как это делается. Вся инициализация и проверка оформлены в виде отдельной процедуры. Для наглядности лучше ее пройти под отладчиком.
Code (Assembler) : Убрать нумерацию
- .text:00401920 push ebp
- .text:00401921 push edi
- .text:00401922 push esi
- .text:00401923 push ebx
- .text:00401924 sub esp, 8Ch
- ; Начальная инициализация - программа по умолчанию не зарегистрирована
- .text:0040192A mov byte_430158, 1
- ; Если вообще никакого серийного номера нет, то сразу на выход
- .text:00401931 cmp ds:byte_4476E0, 0
- .text:00401938 jz loc_401B2E
- ; Перевести серийник в верхний регистр
- .text:0040193E lea edi, [esp+9Ch+var_3C]
- .text:00401942 mov ecx, 8
- .text:00401947 xor eax, eax
- .text:00401949 xor esi, esi
- .text:0040194B rep stosd
- .text:0040194D xor ebx, ebx
- .text:0040194F mov edi, ds:__mb_cur_max
- .text:00401955 mov ebp, ds:_pctype
- .text:0040195B jmp short loc_401982
- .text:0040195B ; -----------------------------------
- .text:0040195D align 10h
- .text:00401960 loc_401960:
- .text:00401960 mov edx, [ebp+0]
- .text:00401963 movzx eax, word ptr [edx+eax*2]
- .text:00401967 and eax, 80h
- .text:0040196C loc_40196C:
- .text:0040196C test eax, eax
- .text:0040196E jz short loc_40197C
- .text:00401970 movzx eax, ds:byte_4476E0[ebx]
- .text:00401977 mov [esp+esi+9Ch+var_3C], al
- .text:0040197B inc esi
- .text:0040197C loc_40197C:
- .text:0040197C inc ebx
- .text:0040197D cmp ebx, 20h
- .text:00401980 jz short loc_4019A0
- .text:00401982 loc_401982:
- .text:00401982 movsx eax, ds:byte_4476E0[ebx]
- .text:00401989 cmp dword ptr [edi], 1
- .text:0040198C jz short loc_401960
- .text:0040198E mov [esp+9Ch+var_98], 80h
- .text:00401996 mov [esp+9Ch+var_9C], eax
- .text:00401999 call _isctype
- .text:0040199E jmp short loc_40196C
- .text:004019A0 ; --------------------------------------------
- .text:004019A0 loc_4019A0:
- ; А вот тут начинаются манипуляции с серийным номером
- .text:004019A0 lea esi, [esp+9Ch+var_7C]
- .text:004019A4 xor eax, eax
- .text:004019A6 movzx edx, [esp+9Ch+var_3C]
- .text:004019AB lea edi, [esp+9Ch+var_5C]
- .text:004019AF mov ecx, 8
- .text:004019B4 rep stosd
- .text:004019B6 mov [esp+9Ch+var_54], dl
- .text:004019BA lea edi, [esp+9Ch+var_7C]
- .text:004019BE movzx edx, [esp+9Ch+var_3B]
- .text:004019C3 mov cl, 8
- .text:004019C5 mov [esp+9Ch+var_55], dl
- .text:004019C9 movzx edx, [esp+9Ch+var_3A]
- .text:004019CE mov [esp+9Ch+var_53], dl
- .text:004019D2 movzx edx, [esp+9Ch+var_39]
- .text:004019D7 mov [esp+9Ch+var_56], dl
- .text:004019DB movzx edx, [esp+9Ch+var_38]
- .text:004019E0 mov [esp+9Ch+var_52], dl
- .text:004019E4 movzx edx, [esp+9Ch+var_37]
- .text:004019E9 mov [esp+9Ch+var_57], dl
- .text:004019ED movzx edx, [esp+9Ch+var_36]
- .text:004019F2 mov [esp+9Ch+var_51], dl
- .text:004019F6 movzx edx, [esp+9Ch+var_35]
- .text:004019FB mov [esp+9Ch+var_58], dl
- .text:004019FF movzx edx, [esp+9Ch+var_34]
- .text:00401A04 mov [esp+9Ch+var_50], dl
- .text:00401A08 movzx edx, [esp+9Ch+var_33]
- .text:00401A0D mov [esp+9Ch+var_59], dl
- .text:00401A11 movzx edx, [esp+9Ch+var_32]
- .text:00401A16 mov [esp+9Ch+var_4F], dl
- .text:00401A1A movzx edx, [esp+9Ch+var_31]
- .text:00401A1F mov [esp+9Ch+var_5A], dl
- .text:00401A23 movzx edx, [esp+9Ch+var_30]
- .text:00401A28 mov [esp+9Ch+var_4E], dl
- .text:00401A2C movzx edx, [esp+9Ch+var_2F]
- .text:00401A31 mov [esp+9Ch+var_5B], dl
- .text:00401A35 movzx edx, [esp+9Ch+var_2E]
- .text:00401A3A mov [esp+9Ch+var_4D], dl
- .text:00401A3E movzx edx, [esp+9Ch+var_2D]
- .text:00401A43 mov [esp+9Ch+var_5C], dl
- .text:00401A47 rep stosd
- .text:00401A49 lea eax, [esp+9Ch+var_5C]
- .text:00401A4D mov [esp+9Ch+var_9C], esi
- .text:00401A50 mov edi, 0A3F3h
- .text:00401A55 mov [esp+9Ch+var_94], 8
- .text:00401A5D mov [esp+9Ch+var_98], eax
- .text:00401A61 call strncpy
- .text:00401A66 mov [esp+9Ch+var_9C], esi
- .text:00401A69 mov [esp+9Ch+var_94], 10h
- .text:00401A71 mov [esp+9Ch+var_98], 0
- .text:00401A79 call strtoul
- .text:00401A7E mov [esp+9Ch+var_9C], esi
- .text:00401A81 mov ebx, eax
- .text:00401A83 mov [esp+9Ch+var_94], 8
- ; Собрать 8 нечетных символов серийника в обратном порядке, преобразовать
- ; их в HEX-число и поXORить результат с 05AEB7C3h
- .text:00401A8B xor ebx, 5AEB7C3h
- .text:00401A91 lea eax, [esp+9Ch+var_54]
- .text:00401A95 mov [esp+9Ch+var_98], eax
- .text:00401A99 call strncpy
- .text:00401A9E mov [esp+9Ch+var_9C], esi
- .text:00401AA1 mov [esp+9Ch+var_94], 10h
- .text:00401AA9 mov [esp+9Ch+var_98], 0
- .text:00401AB1 call strtoul
- .text:00401AB6 mov [esp+9Ch+var_94], 0A3F3h
- .text:00401ABE mov esi, eax
- .text:00401AC0 mov [esp+9Ch+var_90], 0
- ; Собрать 8 четных символов серийника в HEX-число и поXORить полученный
- ; результат с 14AB7B4Ah
- .text:00401AC8 xor esi, 14AB7B4Ah
- ; Теперь в ESI проверочное значение
- .text:00401ACE mov [esp+9Ch+var_9C], ebx
- .text:00401AD1 mov [esp+9Ch+var_98], 0
- .text:00401AD9 call sub_42EB10
- .text:00401ADE mov [esp+9Ch+var_94], 0A3F3h
- .text:00401AE6 imul ecx, edx, 0A3F3h
- .text:00401AEC mov [esp+9Ch+var_90], 0
- .text:00401AF4 mul edi
- .text:00401AF6 mov [esp+9Ch+var_9C], ebx
- .text:00401AF9 add edx, ecx
- .text:00401AFB mov [esp+9Ch+var_84], eax
- .text:00401AFF mov [esp+9Ch+var_80], edx
- .text:00401B03 mov [esp+9Ch+var_98], 0
- .text:00401B0B call sub_42EC34
- .text:00401B10 add eax, [esp+9Ch+var_84]
- .text:00401B14 mov edi, eax
- .text:00401B16 add edi, 7B1h
- .text:00401B1C mul edi
- .text:00401B1E add eax, 7CBh
- ; Сравнить вычисленное значение EAX с сохраненным ESI
- .text:00401B23 cmp esi, eax
- .text:00401B25 jnz short loc_401B2E
- ; Регистрационный номер правильный
- .text:00401B27 mov byte_430158, 0
- .text:00401B2E loc_401B2E:
- ...
Первый вариант решения проблемы регистрации - патч. Достаточно заменить команду инициализации mov byte_430158, 1 на mov byte_430158, 0, а затем поменять с 1 на 0 начальное значение байта в файле. После этого скринсейвер переходит в полноценный режим работы. Это быстро, эффективно, но неспортивно.

Программа успешно "зарегистрирована"
Второй вариант - серийный номер. Разбирать все алгоритмы преобразований мне лениво, а вот подобрать какой-нибудь правильный серийный номер вполне реально. Вспомним алгоритм проверки. На последнем этапе у нас есть тестовое число, которое должно быть равно проверочному.
Тестовое число = (четные символы) XOR 14AB7B4Ah
Уравнение младших классов. Тестовое число мы узнаем при проверке, команда XOR обратимая и при ее применении с тем же параметром 14AB7B4Ah мы получим некое число, которое является четными символами серийного номера. То есть подбор сводится к тому, чтобы на основании введенных нечетных символов в конце проверки узнать правильные четные символы. Берем серийник "192A3B4C5D6E7F80", под отладчиком пытаемся зарегистрировать им программу. Тестовое число в регистре EAX получается "8BDBD25D":

Сравнение тестового и контрольного чисел
Осталась простейшая двоичная математика: 8BDBD25D xor 14AB7B4A = 9F70A917, это и есть искомые символы серийного номера, которые должны быть на четных позициях. Записываем их в серийный номер, получается строка "99FA7B0CAD9E1F70". Попробуем зарегистрировать скринсейвер с его помощью.

Программа успешно зарегистрирована
Вот теперь все красиво. Серийный номер принят, скринсейвер работает в полном режиме. Можете бесплатно приобщаться к красотам космоса.
Просмотров: 4883 | Комментариев: 6
Метки: исследование защиты

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Petya
(03.11.2020 в 16:02):
Благодарствую.

ManHunter
(03.11.2020 в 15:55):

Petya
(03.11.2020 в 15:27):
Дистрибутива не сохранилось? Офсайт мёртв.

DimitarSerg
(10.10.2012 в 00:08):
Насчет зашифрованных строк и нестандартных путей поиска:
Вот это интересно было когда-то (настоятельно рекоммендую), те, что без надписи FREE:
http://www.mcrenox.com.ar/downloads/
своеобразно, но не сложно, а если повезет, то ваяется скрипт и достаются валидные серийники, кейген я чёт так и не осилил в свое время (может обленился).
Вот это интересно было когда-то (настоятельно рекоммендую), те, что без надписи FREE:
http://www.mcrenox.com.ar/downloads/
своеобразно, но не сложно, а если повезет, то ваяется скрипт и достаются валидные серийники, кейген я чёт так и не осилил в свое время (может обленился).

ManHunter
(09.10.2012 в 19:15):
Только если вспомню или найду такую программу. На ум приходит только BWMeter, но я его тут уже разбирал.

Балбес
(09.10.2012 в 19:14):
Не могли бы вы показать пример взлома программы, в котором бы демонстрировались нестандартные пути поиска регистрации, к примеру, когда строки зашифрованы?

Добавить комментарий
Заполните форму для добавления комментария
