
Скриншот программы Actual Search & Replace
Программа
Actual Search & Replace - мощная программа для поиска и замены фрагментов текста в файлах. Поиск можно осуществлять как по отдельным словам, так и по целым фразам или регулярным выражениям. В общем, полезный инструмент для тех, кому приходится часто что-то искать в куче текстовых или HTML-файлов. Программа действительно хорошая, что подтверждают многочисленные награды от различных интернет-изданий, если бы не одно "но". Бесплатно программа будет работать только в течение 30 дней, после чего потребует оплату.
Скачиваем
дистрибутив, распаковываем, устанавливаем, запускаем. Сразу же получаем окно с предложением купить или ввести серийный номер:

Окно регистрации программы
Попробуем ввести какие-нибудь левые данные. Получим сообщение об ошибке "Incorrect key". Исполняемый файл ничем не упакован, поищем в нем эту строку. Никаких проблем, строка находится с первого раза:

Нехорошая строка найдена
Переходим к дизассемблеру. Вот так выглядит кусок кода, отвечающий за вывод сообщения о неправильном ключе регистрации:
...
CODE:004E746A push ebp
CODE:004E746B push offset loc_4E74A3
CODE:004E7470 push dword ptr fs:[eax]
CODE:004E7473 mov fs:[eax], esp
CODE:004E7476 mov eax, ds:off_4E9578
CODE:004E747B mov eax, [eax]
CODE:004E747D mov edx, [eax+2164h]
CODE:004E7483 mov eax, [ebp+var_10]
CODE:004E7486 call sub_48D3C4
CODE:004E748B lea ecx, [ebp+var_8]
CODE:004E748E mov edx, [ebp+var_C]
CODE:004E7491 mov eax, [ebp+var_10]
CODE:004E7494 call sub_48CBC8
CODE:004E7499 xor eax, eax
CODE:004E749B pop edx
CODE:004E749C pop ecx
CODE:004E749D pop ecx
CODE:004E749E mov fs:[eax], edx
CODE:004E74A1 jmp short loc_4E74EA
CODE:004E74A3 ; --------------------------------------------
CODE:004E74A3 loc_4E74A3:
CODE:004E74A3 jmp sub_403468
CODE:004E74A8 ; --------------------------------------------
; Первое сообщение о неправильном серийном номере
CODE:004E74A8 push 0
CODE:004E74AA mov cx, word_4E7638
CODE:004E74B1 mov dl, 1
CODE:004E74B3 mov eax, offset aIncorrectKey
; "Incorrect key"
CODE:004E74B8 call sub_45AA54
CODE:004E74BD mov eax, [ebp+var_10]
CODE:004E74C0 call sub_48CB60
CODE:004E74C5 mov eax, [ebp+var_10]
CODE:004E74C8 call sub_402FBC
CODE:004E74CD mov eax, ds:off_4E9578
CODE:004E74D2 mov eax, [eax]
CODE:004E74D4 mov byte ptr [eax+2170h], 0
CODE:004E74DB call sub_4037C4
CODE:004E74E0 jmp loc_4E7600
CODE:004E74E5 ; ----------------------------------------------
CODE:004E74E5 call sub_4037C4
CODE:004E74EA loc_4E74EA:
CODE:004E74EA mov eax, [ebp+var_10]
CODE:004E74ED call sub_48CB60
CODE:004E74F2 mov eax, [ebp+var_10]
CODE:004E74F5 call sub_402FBC
CODE:004E74FA mov edx, [ebp+var_8]
CODE:004E74FD mov eax, offset aAcsearchRepl_0
; "AcSearch&Replace;"
CODE:004E7502 call sub_40420C
CODE:004E7507 mov ebx, eax
CODE:004E7509 test ebx, ebx
CODE:004E750B jz short loc_4E751C
; Сравнить введенный серийный номер со строкой
CODE:004E750D mov eax, [ebp+var_C]
CODE:004E7510 mov edx, offset aIkizhzl170uu_0
; "IKiZhZL170UUvtoyVN5ginTgPygyaoVTh1+lRil"...
CODE:004E7515 call sub_404030
; Если они не равны, то все в порядке
CODE:004E751A jnz short loc_4E7574
CODE:004E751C loc_4E751C:
; Второе сообщение о неправильном серийном номере
CODE:004E751C xor eax, eax
CODE:004E751E push ebp
CODE:004E751F push offset loc_4E7549
CODE:004E7524 push dword ptr fs:[eax]
CODE:004E7527 mov fs:[eax], esp
CODE:004E752A push 0
CODE:004E752C mov eax, offset aIncorrectKey
; "Incorrect key"
CODE:004E7531 mov cx, word_4E7638
CODE:004E7538 mov dl, 1
CODE:004E753A call sub_45AA54
CODE:004E753F xor eax, eax
CODE:004E7541 pop edx
CODE:004E7542 pop ecx
...
Обратите внимание, что здесь два блока кода, в которых выводятся сообщения "Incorrect key". В первом случае проверяется ключ на корректность, и, если ключ неправильный, то взводится исключение и управление передается на адрес 004E74A8. Команды условных переходов не используются, что несколько затрудняет анализ. Посмотрим дальше. А дальше выполняется сравнение введенного серийного номера с какой-то хитрой строкой, причем, если они совпадают, то снова выдается сообщение о неправильном серийном номере. К чему бы это? Забегая вперед, скажу, что здесь используется "черный список" ключей. То есть разработчики блокируют ключи к своим программам, которые были получены незаконным путем, например, куплены по левым кредитным картам или выложены в свободный доступ.

Заблокированный регистрационный ключ
Такая технология блокировки очень часто встречается в навесных протекторах, а тут же аффтар решил бороться с варезом самостоятельно. Но вроде бы правильная задумка оборачивается совершенно противоположной стороной. Ведь теперь мы знаем как минимум один валидный регистрационный ключ. Сохраним ключ в сухом прохладном месте, а затем изменим в файле несколько символов в строке ключа, чтобы при сравнении строки не совпали. Запишем изменения в исполняемый файл и попробуем снова зарегистрировать программу, но с уже известным нам ключом:

Программа успешно зарегистрирована
Догадка подтвердилась. Это действительно правильный серийный номер. В программе пропали все внешние признаки триальности, в окне About написано, что она зарегистрирована. Выходим из программы, запускаем снова. Оп-па! Триальное окно снова на месте. Можно повторять регистрацию сколько угодно раз, она будет сохраняться только на текущий сеанс работы с программой. Значит где-то выполняется дополнительная проверка на заблокированный ключ. Сперва поищем строку заблокированного ключа. Найдется еще одно совпадение. С ней выполняем те же самые манипуляции по замене символов, что и с первой строкой.

Изменяем заблокированный ключ в файле
Повторяем регистрацию - то же самое, то есть все плохо. Попробуем поискать какие-нибудь другие зацепки, например, по строке из заголовка программы "Unregistered". Найдется такой код:
...
CODE:004C0444 mov eax, ds:off_4E9578
CODE:004C0449 mov eax, [eax]
CODE:004C044B mov eax, [eax+216Ch]
CODE:004C0451 mov edx, offset aDavidLeeSingle
; "David Lee - single user license"
CODE:004C0456 call sub_404030
CODE:004C045B jnz loc_4C04F7
CODE:004C0461 lea edx, [ebp+var_34]
CODE:004C0464 mov eax, ds:off_4E9578
CODE:004C0469 mov eax, [eax]
CODE:004C046B call sub_434894
CODE:004C0470 mov eax, [ebp+var_34]
CODE:004C0473 mov edx, offset aActualSearch_1
; "Actual Search & Replace (Unregistered)"
CODE:004C0478 call sub_404030
CODE:004C047D jz short loc_4C04F7
CODE:004C047F lea eax, [ebp+var_2C]
CODE:004C0482 mov edx, offset aUnregistered
; "Unregistered"
CODE:004C0487 call sub_403D38
CODE:004C048C mov eax, [ebp+var_2C]
...
Ага, знакомая нам строчка "David Lee - single user license". Ее мы видели после регистрации. Значит на "черный список" проверяется не только ключ при вводе, но и регистрационное имя в уже работающей программе. Логично, ведь ключ можно записать через реестр, или же подобная незаконная регистрация могла сохраниться от предыдущей установки, где она еще не была заблокирована. Поищем в исполняемом файле все упоминания несчастного Дэвида и также затрем в каждом из них по несколько символов. Таких проверок будет как минимум три. Зато теперь, после стирания из файла всех упоминаний имени Дэвида Ли и его регистрационного ключа, программа спокойно регистрируется заблокированным ранее ключом и работает как ни в чем не бывало.
Вот так жадность в очередной раз была наказана, а мы познакомились с новым способом обхода защиты программ через разблокировку ключей.