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


Скриншот скринсейвера Incredible Mars 3D

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

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


Настройки скринсейвера и окно регистрации

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


Нехорошая строка найдена

Строчка найдена, и там же рядом, по всей видимости, строка сообщения об успешной регистрации. Теперь поищем в дизассемблере ссылки на эти строчки и условия, при которых они появляются.
...
.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
...

Значит флажок условия триальности хранится в байте по адресу 0430158h. Если он равен нулю, то программа зарегистрирована, и если равен 1, то программа работает в триальном режиме. Все не как у людей, все нормальные разработчики взводят флажок зарегистрированности, а тут сбрасывают флажок триальности. Ладно, космические фантазии аффтаров нам не очень интересны, нас больше интересует где же этот флажок инициализируется и изменяется. Посмотрим в сегменте данных:
Code (Assembler) : Убрать нумерацию
.data:00430158 byte_430158 db 1
Еще более странно. Значение флажка триальности вбито прямо в данные и по умолчанию сразу же равно "незарегистрировано". Смоторим перекрестные ссылки на этот несчастный байт:


Перекрестные ссылки на байт

Все очевидно. Первые две ссылки - инициализация флажка в режим триальности и в режим зарегистрированной программы, а дальше только куча проверок. Нас интересует вторая ссылка, там флажок сбрасывается и программа переходит в зарегистрированный режим. Надо посмотреть, где и как это делается. Вся инициализация и проверка оформлены в виде отдельной процедуры. Для наглядности лучше ее пройти под отладчиком.
.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:
...

В коде я прокомментировал ключевые моменты, но повторю их словами. Из серийного номера выбираются нечетные символы в обратном порядке, начиная с 15-го. То есть длина серийника должна быть 16 символов. Затем из него же выбираются все четные символы по порядку, начиная с нулевого. Для наглядности из введенного серийника 192A3B4C5D6E7F80 получится две строки "0FEDCBA" и "12345678". Дальше эти строки переводятся в шестнадцатеричные числа, первое XORится с константой 05AEB7C3h, а второе с константой 14AB7B4Ah. Полученный из второго преобразования результат является проверочным значением для серийника. А на основании первого числа, путем различных преобразований, получается тестовое число. Если оно равно проверочному, то серийный номер правильный и в байт 0430158h заносится ноль.

Первый вариант решения проблемы регистрации - патч. Достаточно заменить команду инициализации mov byte_430158, 1 на mov byte_430158, 0, а затем поменять с 1 на 0 начальное значение байта в файле. После этого скринсейвер переходит в полноценный режим работы. Это быстро, эффективно, но неспортивно.


Программа успешно "зарегистрирована"

Второй вариант - серийный номер. Разбирать все алгоритмы преобразований мне лениво, а вот подобрать какой-нибудь правильный серийный номер вполне реально. Вспомним алгоритм проверки. На последнем этапе у нас есть тестовое число, которое должно быть равно проверочному.

Тестовое число = (четные символы) XOR 14AB7B4Ah

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


Сравнение тестового и контрольного чисел

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


Программа успешно зарегистрирована

Вот теперь все красиво. Серийный номер принят, скринсейвер работает в полном режиме. Можете бесплатно приобщаться к красотам космоса.
Теги:
защита, взлом
Добавлено: 15 Сентября 2013 02:28:22 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...