
Скриншот программы FinalRecovery
FinalRecovery от MeetSoft - хорошая программа для восстановления удаленных файлов. Авторы старательно борются со всеми появляющимися варезными решениями, изменяя алгоритмы генерации серийных номеров. Новые кейгены быстро перестают работать, поэтому я расскажу как подбирать серийники к программе фишингом. Кроме того, в FinalRecovery используется интересная система проверки регистрации, на которой могут срезаться начинающие крякеры. Для исследования потребуется дистрибутив FinalRecovery и отладчик. Устанавливаем программу, смотрим. Исполняемый файл упакован UPX, он распаковывается самим же UPX с ключом "-d", тут никаких сюрпризов нет.
Запускаем распакованную программу под отладчиком, пробуем зарегистрировать какими-нибудь левыми данными. Получаем сообщение "Invalid license code", поищем эту строчку в файле.

Строка найдена
Теперь посмотрим в пошаговом режиме под отладчиком код, который ссылается на "нехорошую" строчку. Он небольшой и достаточно понятный.
CODE:004A6274 push ebp
CODE:004A6275 mov ebp, esp
CODE:004A6277 mov ecx, 6
CODE:004A627C loc_4A627C:
CODE:004A627C push 0
CODE:004A627E push 0
CODE:004A6280 dec ecx
CODE:004A6281 jnz short loc_4A627C
CODE:004A6283 push ebx
CODE:004A6284 push esi
CODE:004A6285 mov ebx, eax
CODE:004A6287 xor eax, eax
CODE:004A6289 push ebp
CODE:004A628A push offset unk_4A64A7
CODE:004A628F push dword ptr fs:[eax]
CODE:004A6292 mov fs:[eax], esp
CODE:004A6295 lea edx, [ebp+var_C]
CODE:004A6298 mov eax, [ebx+2D8h]
CODE:004A629E call sub_42FCA8
CODE:004A62A3 mov eax, [ebp+var_C]
CODE:004A62A6 lea edx, [ebp+var_4]
CODE:004A62A9 call sub_4085A8
; Непонятная пауза. С понтом имитация напряженых вычислений :)
CODE:004A62AE push 32h ; dwMilliseconds
CODE:004A62B0 call Sleep
CODE:004A62B5 mov eax, [ebp+var_4]
CODE:004A62B8 call sub_403DB8
CODE:004A62BD cmp eax, 6
; Проверка длины регистрационного имени, должно быть не менее 6 символов,
; иначе вывести сообщение об ошибке
CODE:004A62C0 jge short loc_4A62DC
CODE:004A62C2 push 0
CODE:004A62C4 mov cx, word_4A64B4
CODE:004A62CB mov dl, 1
; "Invalid license code."
CODE:004A62CD mov eax, offset aInvalidLicense
CODE:004A62D2 call sub_4569F8
CODE:004A62D7 jmp loc_4A644A
CODE:004A62DC ; -----------------------------------------------------
CODE:004A62DC loc_4A62DC:
CODE:004A62DC lea eax, [ebp+var_4]
CODE:004A62DF push eax
CODE:004A62E0 mov eax, [ebp+var_4]
CODE:004A62E3 call sub_403DB8
CODE:004A62E8 mov ecx, eax
CODE:004A62EA sar ecx, 1
CODE:004A62EC jns short loc_4A62F1
CODE:004A62EE adc ecx, 0
CODE:004A62F1 loc_4A62F1:
CODE:004A62F1 mov edx, 1
CODE:004A62F6 mov eax, [ebp+var_4]
CODE:004A62F9 call sub_403FC0
; Опять какая-то непонятная пауза. Хороший понт дороже денег :)
CODE:004A62FE push 32h ; dwMilliseconds
CODE:004A6300 call Sleep
CODE:004A6305 lea ecx, [ebp+var_8]
CODE:004A6308 mov edx, offset unk_4A64E0
CODE:004A630D mov eax, [ebp+var_4]
CODE:004A6310 call sub_4753D8
CODE:004A6315 lea ecx, [ebp+var_10]
CODE:004A6318 mov edx, [ebp+var_8]
CODE:004A631B mov eax, [ebp+var_4]
CODE:004A631E call sub_4753D8
CODE:004A6323 mov edx, [ebp+var_10]
CODE:004A6326 lea eax, [ebp+var_8]
CODE:004A6329 call sub_403BD0
; И еще немного имитируем напряженные вычисления...
CODE:004A632E push 32h ; dwMilliseconds
CODE:004A6330 call Sleep
CODE:004A6335 lea edx, [ebp+var_18]
CODE:004A6338 mov eax, [ebx+2E0h]
CODE:004A633E call sub_42FCA8
CODE:004A6343 mov eax, [ebp+var_18]
CODE:004A6346 lea edx, [ebp+var_14]
CODE:004A6349 call sub_4085A8
; В регистре EAX указатель на вычисленный серийник, в регистре EDX
; наши введенные "левые" данные. Далее выполняется проверка их совпадения
CODE:004A634E mov edx, [ebp+var_14]
CODE:004A6351 mov eax, [ebp+var_8]
CODE:004A6354 call sub_4040A4
CODE:004A6359 dec eax
CODE:004A635A jnz loc_4A6435
; Проверка успешно пройдена, записать в реестр регистрационные данные
CODE:004A6360 mov dl, 1
CODE:004A6362 mov eax, off_44FFC0
CODE:004A6367 call sub_4500C0
CODE:004A636C mov esi, eax
CODE:004A636E mov edx, 80000002h
CODE:004A6373 mov eax, esi
CODE:004A6375 call sub_450160
CODE:004A637A mov cl, 1
.......
Из алгоритма видно, что берется половина регистрационного имени, над ним выполняются какие-то действия и в результате получается 16-символьный код, который и сравнивается с введенным серийным номером.

Проверка серийного номера
Сохраним его и попробуем зарегистрировать программу с тем же именем, но с уже пойманным серийником. Ура! Программа сообщает, что успешно зарегистрирована, триальная надпись в заголовке пропадает, окно About показывает ваше имя. Вроде бы все хорошо и можно выкладывать релиз, но вот тут и начинается самое интересное. Попробуем восстановить какой-нибудь удаленный файл нашей свежезарегистрированной программой, например в режиме "Standard Recovery". Что мы видим в логе?

Программа не зарегистрирована и работает с ограничениями
Значит где-то выполняется дополнительная проверка регистрационных данных. Попробуем найти вторую "нехорошую" строчку.

Строка найдена
Смотрим ссылающийся код и условия появления сообщения об ограничении функционала незарегистрированной версии.
.......
CODE:00479517 mov eax, [ebp+var_8]
CODE:0047951A mov [ebp+var_14], eax
; Проверка, если вообще никаких регистрационных данных не вводилось
CODE:0047951D cmp ds:byte_4B49E0, 0
CODE:00479524 jz short loc_479533
; Вот она, вторая проверка. Сраваниваются две строки. В регистре EAX строка
; из серийного номера, в регистре EDX - вычисленное значение
CODE:00479526 mov eax, [ebp+var_74]
CODE:00479529 mov edx, [ebp+var_78]
CODE:0047952C call sub_403EC8
; В случае совпадения файл восстанавливается в обычном режиме
CODE:00479531 jz short loc_47956F
CODE:00479533 loc_479533:
CODE:00479533 mov eax, [ebp+var_14]
; Размер файла меньше 64 килобайт? Если да, то восстановить в любом случае
CODE:00479536 cmp dword ptr [eax+1Ch], 0FA00h
CODE:0047953D jle short loc_47956F
CODE:0047953F lea eax, [ebp+var_EC]
; Иначе вывести "нехорошую" надпись
; ": Unregistered version can recover file"...
CODE:00479545 mov ecx, offset aUnregisteredVe
CODE:0047954A mov edx, [ebp+var_C]
CODE:0047954D call sub_403E04
CODE:00479552 mov edx, [ebp+var_EC]
CODE:00479558 mov cl, 2
CODE:0047955A mov eax, [ebp+arg_0]
.......
Таких участков кода в программе всего три, расставим под отладчиком точки останова на все три вызова функции сравнения. Пробуем снова восстановить файл, отладчик остановится на втором вхождении:

Дополнительная проверка серийника
Кажется странно, потому что фактически вторая строка серийника сравнивается с первой, а такого быть не может. Значит это только часть серийного номера. Попробуем дописать вторую строчку к уже найденному серийному номеру и повторить все проверки. Первая проверка при вводе регистрационного имени и уже 32-символьного серийника проходится успешно. Во второй проверке при восстановлении файла в регистре EAX уже будет правильное значение, значит все сделано правильно. Пойманный серийный номер "2FA02A1773CC30C097AD622D9893F5FA".

Программа успешно зарегистрирована
Вот и очередная рыбалка закончилась успешно, больше не придется ждать посторонних кряков в случае выхода новой версии с новой регистрацией.