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

Программа успешно зарегистрирована
Вот теперь программа зарегистрирована по-настоящему. Таким нехитрым способом вы сэкономили немного денег на установку любимой бабушке нормального спутникового интернета