Исследование защиты программы RecoveryRobot
Скриншот программы RecoveryRobot
Программа RecoveryRobot предназначена для восстановления информации с поврежденных дисков, а также восстановления удаленных файлов с различных носителей. От аналогичных программ не отличается практически ничем, никакого запредельного функционала на борту нет. В бесплатном режиме восстанавливает небольшой объем данных, за снятие лимитов требует сумму до нескольких сотен вечнозеленых. Ну что ж, добро пожаловать на разделочный стол.
Забираем с офсайта дистрибутив, устанавливаем. Исполняемый файл ничем не упакован, отправляем его в дизассемблер. Ну а параллельно посмотрим, за что можно уцепиться при начальном анализе. Самое приметное - это строка "Unregistered" вы заголовке главного окна программы.
Строка сообщения в ресурсах
Строка из заголовка обнаруживается в ресурсах. Ее индекс равняется 367 или 16Fh, если в шестнадцатеричной системе счисления. В листинге находится вот такой код, где этот индекс используется:
Code (Assembler) : Убрать нумерацию
- .text:0041139C mov edx, [esi]
- .text:0041139E mov eax, [edx+48h]
- .text:004113A1 mov ecx, esi
- ; Функция проверки
- .text:004113A3 call eax
- .text:004113A5 cmp eax, 64h ; switch 101 cases
- .text:004113A8 ja loc_4116A3
- .text:004113AE movzx ecx, ds:byte_411748[eax]
- .text:004113B5 jmp ds:off_411734[ecx*4]
- .text:004113BC loc_4113BC:
- ; jumptable 004113B5 case 100
- .text:004113BC lea edx, [esp+54h+var_34]
- .text:004113C0 push edx
- ; Загрузить строку из ресурсов
- .text:004113C1 mov edi, 16Fh
- .text:004113C6 call sub_41DC60
- .text:004113CB add esp, 4
- .text:004113CE mov edi, eax
Обратите внимание, что при обычном старте программа запускает свою вторую копию с параметром в командной строке " -run" и таким образом убегает из отладчика. Надо в меню Debug - Arguments добавить строку запуска, причем обязательно с первым пробелом. Тогда все нормально запустится под отладчиком.
Ставим точку останова на адрес 004113A3, запускаем программу, в момент срабатывания брейкпоинта получаем, что проверка выполняется по адресу 00469DC0.
Code (Assembler) : Убрать нумерацию
- .text:00469DC0 push ebp
- .text:00469DC1 mov ebp, esp
- .text:00469DC3 and esp, 0FFFFFFF8h
- .text:00469DC6 push 0FFFFFFFFh
- .text:00469DC8 push offset sub_657284
- .text:00469DCD mov eax, large fs:0
- .text:00469DD3 push eax
- .text:00469DD4 sub esp, 0D0h
- .text:00469DDA mov eax, ___security_cookie
- .text:00469DDF xor eax, esp
- .text:00469DE1 mov [esp+0DCh+var_14], eax
- .text:00469DE8 push ebx
- .text:00469DE9 push esi
- .text:00469DEA push edi
- .text:00469DEB mov eax, ___security_cookie
- .text:00469DF0 xor eax, esp
- .text:00469DF2 push eax
- .text:00469DF3 lea eax, [esp+0ECh+var_C]
- .text:00469DFA mov large fs:0, eax
- .text:00469E00 mov ebx, [ebp+arg_0]
- .text:00469E03 mov edx, ebx
- .text:00469E05 lea eax, [esp+0ECh+var_94]
- .text:00469E09 mov [esp+0ECh+var_DC], ecx
- .text:00469E0D call sub_469CA0
- .text:00469E12 push 0FFFFFFFFh
- .text:00469E14 mov ecx, 19h
- .text:00469E19 lea esi, [esp+0F0h+var_B0]
- .text:00469E1D mov edx, ebx
- .text:00469E1F mov [esp+0F0h+var_4], 0
- .text:00469E2A call sub_46A230
- .text:00469E2F push offset aKey ; "KEY"
- .text:00469E34 push 0AFh ; lpName
- .text:00469E39 push 0 ; hModule
- .text:00469E3B mov byte ptr [esp+0F8h+var_4], 1
- .text:00469E43 call ds:FindResourceW
- .text:00469E49 mov esi, eax
- .text:00469E4B push esi ; hResInfo
- .text:00469E4C push 0 ; hModule
- .text:00469E4E call ds:LoadResource
- .text:00469E54 push eax ; hResData
- .text:00469E55 call ds:LockResource
- .text:00469E5B push esi ; hResInfo
- .text:00469E5C push 0 ; hModule
- .text:00469E5E mov edi, eax
- .text:00469E60 call ds:SizeofResource
- .text:00469E66 mov esi, eax
- .text:00469E68 lea eax, [esp+0ECh+var_B0]
- .text:00469E6C push eax
- ...
- ...
Давайте попробуем разобрать проверку серийного номера. При попытке ввести левые данные в качестве серийника программа выдает сообщение "Register Code is wrong". Соответствующая строка с индексом 356 (она же 164h) находится там же в ресурсах:
Строка сообщения в ресурсах
Возвращаемся в дизассемблер и ищем в листинге индекс строки из ресурсов, а заодно смотрим, какие ветки алгоритма туда приводят.
Code (Assembler) : Убрать нумерацию
- ; Проверка длины введенного серийника
- .text:00435CF6 mov eax, [esi-0Ch]
- .text:00435CF9 test eax, eax
- ; Пустой?
- .text:00435CFB jz loc_435ED8
- ; Больше или равно 95 символов?
- .text:00435D01 cmp eax, 5Fh
- .text:00435D04 jge loc_435ED8
- ; Меньше 89 символов?
- .text:00435D0A cmp eax, 59h
- .text:00435D0D jl loc_435ED8
- ...
- ...
- ...
- .text:00435ED8 loc_435ED8:
- .text:00435ED8 lea ecx, [esp+448h+var_430]
- .text:00435EDC push ecx
- ; Загрузить строку сообщения из ресурсов
- .text:00435EDD mov edi, 164h
- .text:00435EE2 call sub_41DC60
- .text:00435EE7 add esp, 4
- .text:00435EEA push 0 ; unsigned int
- .text:00435EEC mov [esp+44Ch+var_4], 0
- .text:00435EF7 mov eax, [eax]
- .text:00435EF9 push 0 ; lpCaption
- .text:00435EFB push eax ; lpText
- .text:00435EFC mov ecx, ebp ; this
- ; Вывести сообщение
- .text:00435EFE call ?MessageBoxW@CWnd@@QAEHPB_W0I@Z
- ; CWnd::MessageBoxW(wchar_t const *,wchar_t const *,uint)
- .text:00435F03 mov [esp+448h+var_4], 0FFFFFFFFh
- .text:00435F0E mov eax, [esp+448h+var_430]
А дальше следуют еще две проверки, по результатам которых могут появиться сообщения, что код неправильный или же что у серийника истек срок действия. Коды строчек находятся в ресурсах, вывод сообщений отслеживается на адресах двух условных переходов:
Строки сообщений в ресурсах
Code (Assembler) : Убрать нумерацию
- .text:00435D50 mov edx, [edx+10h]
- .text:00435D53 mov ecx, esi
- .text:00435D55 push ecx
- .text:00435D56 mov ecx, eax
- ; Функция проверки корректности серийного номера
- .text:00435D58 call edx
- .text:00435D5A test eax, eax
- .text:00435D5C jz loc_435E88
- .text:00435D62 call ?AfxGetModuleState
- .text:00435D67 mov eax, [eax+4]
- .text:00435D6A mov edx, [eax]
- .text:00435D6C mov ecx, eax
- .text:00435D6E mov eax, [edx+0C0h]
- .text:00435D74 call eax
- .text:00435D76 mov edx, [eax]
- .text:00435D78 mov edx, [edx+4]
- .text:00435D7B mov ecx, esi
- .text:00435D7D push ecx
- .text:00435D7E mov ecx, eax
- ; Функция проверки срока действия серийного номера
- .text:00435D80 call edx
- .text:00435D82 test al, al
- .text:00435D84 jnz short loc_435DC3
- .text:00435D86 lea eax, [esp+448h+var_434]
- .text:00435D8A push eax
Code (Assembler) : Убрать нумерацию
- .text:00469C20 sub_469C20 proc near
- .text:00469C20 push ebp
- .text:00469C21 mov ebp, esp
- .text:00469C23 and esp, 0FFFFFFF8h
- .text:00469C26 sub esp, 0Ch
- .text:00469C29 push ebx
- .text:00469C2A push esi
- .text:00469C2B mov esi, [ebp+arg_0]
- .text:00469C2E push edi
- .text:00469C2F push esi
- .text:00469C30 call sub_469CC0
- .text:00469C35 mov edx, esi
- .text:00469C37 lea edi, [esp+18h+var_8]
- .text:00469C3B call sub_469AF0
- .text:00469C40 push 0 ; Time
- .text:00469C42 call __time64
- .text:00469C47 mov ebx, [esp+1Ch+var_8]
- .text:00469C4B mov edi, [esp+1Ch+var_4]
- .text:00469C4F add esp, 4
- .text:00469C52 mov esi, eax
- .text:00469C54 sub esi, ebx
- .text:00469C56 mov ecx, edx
- ...
Code (Assembler) : Убрать нумерацию
- .text:00469CC0 sub_469CC0 proc near
- .text:00469CC0 push 0FFFFFFFFh
- .text:00469CC2 push offset sub_64ED28
- .text:00469CC7 mov eax, large fs:0
- .text:00469CCD push eax
- .text:00469CCE sub esp, 24h
- .text:00469CD1 mov eax, ___security_cookie
- .text:00469CD6 xor eax, esp
- .text:00469CD8 mov [esp+30h+var_10], eax
- .text:00469CDC push esi
- .text:00469CDD mov eax, ___security_cookie
- .text:00469CE2 xor eax, esp
- .text:00469CE4 push eax
- .text:00469CE5 lea eax, [esp+38h+var_C]
- .text:00469CE9 mov large fs:0, eax
- .text:00469CEF mov edx, [esp+38h+arg_0]
- .text:00469CF3 lea eax, [esp+38h+var_2C]
- .text:00469CF7 call sub_469CA0
- .text:00469CFC mov [esp+38h+var_4], 0
- .text:00469D04 cmp [esp+38h+var_18], 19h
- .text:00469D09 jz short loc_469D1D
- .text:00469D0B cmp [esp+38h+var_14], 10h
- .text:00469D10 jb loc_469D99
- ...
Убираем релоки из файла
Делается это модификацией PE-заголовка через взведение флага "Relocations stripped". Удобнее всего подобную операцию выполнять в PE Tools. На мой взгляд, удалять релоки надо независимо от того, попадают они на место патча или нет.
Программа успешно "зарегистрирована"
Вот и все, на попытку повторной регистрации программа пишет, что она уже зарегистрирована. В заголовке красуется лицензия уровня "Expert". Ограничений на объем восстанавливаемых данных тоже нет, так же как и нет никаких стремных уведомлений при попытке эти данные восстановить. Цель достигнута.
Просмотров: 1534 | Комментариев: 10
Метки: исследование защиты, HDD
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Илья
(01.01.2024 в 13:05):
Спасибо, статья помогла разобраться с причиной, почему не выполняется код с самописной тестовой dll-кой. Причем на Win7 выполняется, а на десятке и 11 - нет. Пишет "Программа "путь.dll" не предназначена для выполнения в Windows...". Удалил релоки из заголовка - заработало. Оказалось, дело было в том, что не указал флаг readable в секции .reloc.
ManHunter
(08.08.2019 в 09:16):
Релоки попадают на этот адрес. Надо в PE-заголовке в флагах поставить "relocation stripped". Вроде трезвый писал статью, чо столько пропустил...
Дополнил, спасибо!
Дополнил, спасибо!
Михаил
(08.08.2019 в 08:56):
Нашел проблемку, почему то по адресу 00469DC0 не хочет корректно пропатчивать рет4 при повторном открытии дебаггера (пробовал Олю и х32дбг) вижу испорченный код
https://i87.fastpic.ru/big/201...385abe33.jpg
хотя если хекс редактором открыть то там есть рет4, но при запуске программа крошится в этом месте
https://i87.fastpic.ru/big/201...385abe33.jpg
хотя если хекс редактором открыть то там есть рет4, но при запуске программа крошится в этом месте
Михаил
(07.08.2019 в 20:17):
Ясно, спасибо, буду смотреть значит где я ошибся
ManHunter
(07.08.2019 в 20:15):
Это не отличие, это я уже потом экспериментировал с типом лицензии, хотел повысить до бизнеса. Изначально там тоже 1.
Михаил
(07.08.2019 в 20:05):
Вот и отличие от текста:
000691C0: 55 B8
000691C1: 8B 04
По тексту кругом mov eax,1
000691C0: 55 B8
000691C1: 8B 04
По тексту кругом mov eax,1
ManHunter
(07.08.2019 в 16:43):
Сравнение файлов RecoveryRobotPro.! и RECOVERYROBOTPRO.EXE
000350FB: 0F 90
000350FC: 84 90
000350FD: D7 90
000350FE: 01 90
000350FF: 00 90
00035100: 00 90
00035104: 0F 90
00035105: 8D 90
00035106: CE 90
00035107: 01 90
00035108: 00 90
00035109: 00 90
0003510D: 0F 90
0003510E: 8C 90
0003510F: C5 90
00035110: 01 90
00035111: 00 90
00035112: 00 90
00069020: 55 B8
00069021: 8B 01
00069022: EC 00
00069023: 83 00
00069024: E4 00
00069025: F8 C2
00069026: 83 04
00069027: EC 00
000690C0: 6A B8
000690C1: FF 01
000690C2: 68 00
000690C3: 28 00
000690C4: ED 00
000690C5: 64 C2
000690C6: 00 04
000690C7: 64 00
000691C0: 55 B8
000691C1: 8B 04
000691C2: EC 00
000691C3: 83 00
000691C4: E4 00
000691C5: F8 C2
000691C6: 6A 04
000691C7: FF 00
Патч из статьи, все работает. И во всех трех случаях в оригинале выход из функций через RETN 4.
000350FB: 0F 90
000350FC: 84 90
000350FD: D7 90
000350FE: 01 90
000350FF: 00 90
00035100: 00 90
00035104: 0F 90
00035105: 8D 90
00035106: CE 90
00035107: 01 90
00035108: 00 90
00035109: 00 90
0003510D: 0F 90
0003510E: 8C 90
0003510F: C5 90
00035110: 01 90
00035111: 00 90
00035112: 00 90
00069020: 55 B8
00069021: 8B 01
00069022: EC 00
00069023: 83 00
00069024: E4 00
00069025: F8 C2
00069026: 83 04
00069027: EC 00
000690C0: 6A B8
000690C1: FF 01
000690C2: 68 00
000690C3: 28 00
000690C4: ED 00
000690C5: 64 C2
000690C6: 00 04
000690C7: 64 00
000691C0: 55 B8
000691C1: 8B 04
000691C2: EC 00
000691C3: 83 00
000691C4: E4 00
000691C5: F8 C2
000691C6: 6A 04
000691C7: FF 00
Патч из статьи, все работает. И во всех трех случаях в оригинале выход из функций через RETN 4.
Михаил
(07.08.2019 в 16:38):
Все равно какая то ерунда, после всех манипуляций при попытке запустить программу она создает у себя в каталоге файл edrdump0.dmp и выкидует окно ошибки с предложением отправить разрабам. И второй момент по 367 индексу там точно RET4 так как там при входе в Call заканчивается все простым RET
ManHunter
(06.08.2019 в 14:33):
Это я забыл указать в статье, что программа запускает свою вторую копию с параметром в командной строке " -run" и таким образом убегает из отладчика. Надо в меню Debug - Arguments добавить строку запуска, причем обязательно с первым пробелом. Тогда все нормально запустится под отладчиком.
Добавил в статью, спасибо за уточнение.
Добавил в статью, спасибо за уточнение.
Михаил
(06.08.2019 в 14:29):
Подскажите как быть, если в Олли и х32dbg программа не реагирует на брекпоинты. Запускается, затем после остановки и даже закрытия дебаггера программа остается быть запущенной
Добавить комментарий
Заполните форму для добавления комментария