Исследование защиты программы Photos for Grandma


Скриншот программы Photos for Grandma

Photos for Grandma - простенькая программа для пакетного изменения размера фотографий и последующей отправки их на указанный почтовый адрес. Как следует из названия, программа предназначена для отправки ваших семейных фото на деревню бабушке, которая до сих пор серфит на диалапе или жопорезе и не может сливать себе на хард тяжелые аттачи к мылу.

Скачиваем дистрибутив, устанавливаем, запускаем, смотрим. С регистрацией промахнуться невозможно, для нее выделена специальная большая кнопка "Registration". А вот на ввод неправильного серийного номера программа реагирует таким сообщением:


Сообщение о неправильной регистрации

Разработчики позаботились, чтобы мы еще до отладчиков и дизассемблеров узнали формат правильного серийного номера. Спасибо, чо. Но в дизассемблер исполняемый файл все-таки отправим, благо, что он ничем не защищен и даже не упакован. Пока файл приводится в удобочитаемый вид, поищем окно сообщения о неправильной регистрации.


Диалоговое окно в ресурсах

Окно найдено в ресурсах под номером 151, или 97h в шестнадцатеричной системе счисления. Поищем это значение в листинге дизассемблера. Будет найдено несколько участков кода, где используется это значение, поэтому точное место срабатывания отлавливается под отладчиком. Устанавливаем брейкпоинты на найденные по очереди куски кода, и после недолгой трассировки будет найдено точное место появления окна с сообщением об ошибочной регистрации:
.text:00427FA4                 push    0
; Индекс диалогового окна в ресурсах
.text:00427FA6                 push    97h
.text:00427FAB                 lea     ecx, [esp+54h]
; Вывести диалоговое окно
.text:00427FAF                 call    sub_440310
Теперь посмотрим место, откуда выполняется переход на этот код:
Code (Assembler) : Убрать нумерацию
; Вызвать какую-то функцию проверки
.text:00427DD5                 call    sub_4265E0
; Если она вернула AL=0, то введенный код неправильный
.text:00427DDA                 test    al, al
.text:00427DDC                 jz      loc_427FA4

Тоже все понятно. Вызывается функция проверки, по ее результату принимается решение о зарегистрированности программы. Минутное решение - патч MOV AL,1; RET 4 по адресу 004265E0. Обратите внимание на выравнивание стека. После патча программа с радостью примет любой серийник и будет считать его правильным.


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

Быстро, надежно, но опять же неспортивно. Попробуем разобрать алгоритм генерации серийного номера, тем более, что его формат мы уже знаем. Запускаем программу под отладчиком, ставим точку останова на начало функции проверки 004265E0, регистрируем программу с каким-нибудь левым ключом, но с соблюдением формата - три группы по 5 символов.
.text:004265E0                 push    0FFFFFFFFh
.text:004265E2                 push    offset loc_6262F8
.text:004265E7                 mov     eax, large fs:0
.text:004265ED                 push    eax
.text:004265EE                 sub     esp, 8
.text:004265F1                 push    ebx
.text:004265F2                 push    ebp
.text:004265F3                 push    esi
.text:004265F4                 push    edi
; Здесь начинается проверка соответствия серийника нужному формату
; Ее можно пропустить, ведь его длину и формат мы уже знаем
.text:004265F5                 mov     eax, dword_749D2C
...
...
...
.text:00426700                 jnz     loc_426820
...
; Пропускаем аж до этого места
...
.text:00426726                 mov     eax, [esp+28h+EndPtr]
.text:0042672A                 add     eax, 6
.text:0042672D                 mov     edx, eax
.text:0042672F                 nop
.text:00426730 loc_426730:
.text:00426730                 mov     cx, [eax]
.text:00426733                 add     eax, 2
.text:00426736                 test    cx, cx
.text:00426739                 jnz     short loc_426730
.text:0042673B                 mov     edi, ebx
.text:0042673D                 sub     eax, edx
.text:0042673F                 add     edi, 0FFFFFFFEh
.text:00426742 loc_426742:
.text:00426742                 mov     cx, [edi+2]
.text:00426746                 add     edi, 2
.text:00426749                 test    cx, cx
.text:0042674C                 jnz     short loc_426742
.text:0042674E                 mov     ecx, eax
.text:00426750                 shr     ecx, 2
.text:00426753                 mov     esi, edx
.text:00426755                 rep movsd
.text:00426757                 push    10h             ; Radix
.text:00426759                 lea     edx, [esp+2Ch+EndPtr]
.text:0042675D                 mov     ecx, eax
.text:0042675F                 push    edx             ; EndPtr
.text:00426760                 and     ecx, 3
.text:00426763                 add     ebp, 2
.text:00426766                 push    ebp             ; Str
.text:00426767                 rep movsb
; Вторая группа символов серийника преобразуется в шестнадцатеричное число
.text:00426769                 call    _wcstoul
.text:0042676E                 mov     edi, [esp+34h+var_10]
.text:00426772                 push    10h             ; Radix
.text:00426774                 mov     esi, eax
; Полученное число умножается на константу 64h
.text:00426776                 imul    esi, [edi+74h]
.text:0042677A                 push    0               ; EndPtr
.text:0042677C                 push    ebx             ; Str
; В число преобразуется строка, состоящая из первой группы символов и
; последних трех символов третьей группы серийного номера
.text:0042677D                 call    _wcstoul
; Полученное число складывается с константой 25B431EEh
.text:00426782                 add     eax, [edi+7Ch]
.text:00426785                 xor     ecx, ecx
; Затем результат сложения умножается на константу 28h
.text:00426787                 imul    eax, [edi+78h]
.text:0042678B                 add     esp, 18h
; Результат сравнивается с результатом умножения первой группы символов
.text:0042678E                 cmp     esi, eax
.text:00426790                 mov     eax, [esp+28h+Str]
.text:00426794                 setz    cl
; Дальше уже не интересно, можно пропустить
.text:00426797                 test    eax, eax
...

Итого, что мы имеем. Серийный номер имеет три группы по 5 символов, разделенных черточкой. Например, "12345-67890-ABCDE". Первая группа символов преобразуется в шестнадцатеричное число и умножается на число 64h, получаем первое контрольное число. Затем из второй группы символов и трех последних символов третьей группы составляется строка, в этом примере получится "67890CDE". Полученная строка также преобразуется в шестнадцатеричное число, складывается с числом 25B431EEh и умножается на число 28h. Если полученный результат равен первому контрольному числу, то серийный номер правильный. Оставшиеся два символа третьей группы могут быть произвольными. Валидный серийник можно без труда подобрать простейшим брутфорсом, например, вот такой: DA54E-3A41A-1B853. Проверим его. Первое контрольное число: 3A41Ah * 64h = 016C1A28h. Вторая проверка: (DA54E853h + 25B431EEh) * 28h = 016C1A28h. Все совпало, серийный номер правильный. Регистрационное имя нигде не проверяется и может быть любым. Попробуем зарегистрировать программу с найденным серийником:


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

Вот теперь программа зарегистрирована по-настоящему. Таким нехитрым способом вы сэкономили немного денег на установку любимой бабушке нормального спутникового интернета
Теги:
защита, взлом
Добавлено: 15 Сентября 2013 02:16:46 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...