Blog. Just Blog

Исследование защиты программы Process Master

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Темная сторона Силы | Автор: ManHunter
Скриншот программы Process Master
Скриншот программы Process Master

Программа Process Master - менеджер процессов с возможностью принудительного завершения выбранных процессов и якобы даже способный обнаруживать руткиты. Ну и все, вроде как. И за все это грандиозное разнообразие функций, которое студенты-первокурсники пишут в качестве лабораторных работ, аффтар требовал быренько метнуться в кассу на предмет выкладывания своих кровных. К счастью, проект прекратил свое развитие практически сразу после начала, оффсайт сдох, так что нам остается только попрактиковаться в реверсивной некромантии. Ну а что, почему бы и нет?

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

Триальный счетчик
Триальный счетчик

Исполняемый файл ничем не упакован, просто отправляем его в дизассемблер. Теперь надо выяснить, как программа будет реагировать на попытку ее зарегистрировать какой-нибудь левотой.

Сообщение после активации программы
Сообщение после активации программы

Это уже интереснее. Никаких сообщений о правильной или неправильной регистрации, просто предложение перезапустить программу. Значит проверка регистрационных данных выполняется при запуске. Подобная схема - это очень правильный подход к реализации защиты. Логично предположить, что когда при запуске программа определяет свой статус, на его основании она обозначает триальный срок. Поищем какие-нибудь строки, связанные с триальным временем.

Строка сообщения в файле
Строка сообщения в файле

Код, где используются эти строки достаточно объемный, целиком я его приводить не буду. Главное, что ему предшествует проверка и условный переход, который перепрыгивает все, что связано с проверкой окончания триального срока:
  1. ; Проверить значение переменной
  2. .text:00405824                 mov     eax, [esi+2E0h]
  3. .text:0040582A                 test    eax, eax
  4. ; Если оно не равно нулю, то перепрыгнуть все триальные активности
  5. .text:0040582C                 jnz     loc_405A42
  6. .text:00405832                 cmp     [esi+2F0h], eax
  7. .text:00405838                 jz      short loc_4058B8
  8. .text:0040583A                 mov     ecx, 1Eh
  9. .text:0040583F                 sub     ecx, [esi+2F4h]
Надо выяснить, откуда берется проверяемое значение переменной. Пролистываем чуть выше и обнаруживаем вот что:
  1. .text:004057BF                 lea     ecx, [esi+29Eh]
  2. ; Вызвать функцию проверки
  3. .text:004057C5                 call    sub_406A60
  4. .text:004057CA                 mov     edi, [esi+2E8h]
  5. .text:004057D0                 mov     ebx, [esi+2ECh]
  6. .text:004057D6                 push    0
  7. ; Сохранить результаты проверки
  8. .text:004057D8                 mov     [esi+2E0h], eax
Именно тут инициализируется значение [esi+2E0h] результатами выполнения функции проверки. Сама функция проверки серийного номера выглядит следующим образом:
  1. .text:00406A60 sub_406A60
  2. .text:00406A60                 sub     esp, 50h
  3. .text:00406A63                 mov     eax, ___security_cookie
  4. .text:00406A68                 xor     eax, esp
  5. .text:00406A6A                 mov     [esp+50h+var_4], eax
  6. .text:00406A6E                 push    ebx
  7. .text:00406A6F                 push    esi
  8. .text:00406A70                 push    edi
  9. .text:00406A71                 lea     eax, [esp+5Ch+String1]
  10. .text:00406A75                 mov     ebx, ecx
  11. .text:00406A77                 push    eax
  12. .text:00406A78                 push    ebx             ; lpString
  13. .text:00406A79                 call    ds:lstrlenA
  14. .text:00406A7F                 push    eax
  15. .text:00406A80                 call    sub_40A120
  16. .text:00406A85                 mov     ebx, ds:lstrcmpA
  17. .text:00406A8B                 add     esp, 8
  18. .text:00406A8E                 xor     edi, edi
  19. ; Указатель на массив сравниваемых хэшей
  20. .text:00406A90                 mov     esi, offset String2
  21. ; "ed4080635961cbc29753aebbb21b0af277ddfda"...
  22. .text:00406A95 loc_406A95:
  23. .text:00406A95                 push    esi             ; lpString2
  24. .text:00406A96                 lea     ecx, [esp+60h+String1]
  25. .text:00406A9A                 push    ecx             ; lpString1
  26. .text:00406A9B                 call    ebx ; lstrcmpA
  27. .text:00406A9D                 test    eax, eax
  28. .text:00406A9F                 jz      short loc_406AAF
  29. .text:00406AA1                 add     esi, 41h
  30. .text:00406AA4                 add     edi, 1
  31. .text:00406AA7                 cmp     esi, offset Blowfish_p_init
  32. .text:00406AAD                 jl      short loc_406A95
  33. .text:00406AAF loc_406AAF:
  34. .text:00406AAF                 mov     ecx, [esp+5Ch+var_4]
  35. .text:00406AB3                 xor     eax, eax
  36. ; Все 1000 сравнений выполнены?
  37. .text:00406AB5                 cmp     edi, 3E8h
  38. .text:00406ABB                 pop     edi
  39. .text:00406ABC                 pop     esi
  40. ; AL = 1 - совпадение найдено, программа зарегистрирована
  41. .text:00406ABD                 setnz   al
  42. .text:00406AC0                 pop     ebx
  43. .text:00406AC1                 xor     ecx, esp
  44. .text:00406AC3                 call    @__security_check_cookie@4
  45. .text:00406AC8                 add     esp, 50h
  46. .text:00406ACB                 retn
  47. .text:00406ACB sub_406A60      endp
Хэш от сохраненного серийного номера сравнивается поочередно со строками из большого массива предустановленных хэшей (1000 штук, если быть точным). Если совпадение найдено, то программа считается зарегистрированной. Со стороны автора было очень оптимистично предположить, что целая тыщща человек загорятся желанием приобрести его поделие. Пытаться обратить хэши бесполезно, если не обманывают программы-криптоанализаторы, то тут и Blowfish, и HAVAL, и много других страшных слов. Так что приступим к патчу. Достаточно сделать так, чтобы функция проверки всегда возвращала AL=1. Для разнообразия заменим команду SETNZ AL по адресу 00406ABD на команду MOV AL,1 и NOP, чтобы выровнять патч на последний байт изменяемой команды. Сохраняем изменения, запускаем.

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

В окне "О программе" красуются введенные ранее левые регистрационные данные. Переводим системные часы на пару месяцев вперед. Никаких сообщений об окончании пробного периода не появляется. Цель достигнута. В качестве второго варианта для патча можно было в отладчике подсмотреть хэш левых регистрационных данных и заменить им одно из значений в массиве предустановленных хэшей. В этом случае программа принимала бы эти данные как корректные.

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 716 | Комментариев: 3

Комментарии

Отзывы посетителей сайта о статье
ManHunter (15.12.2018 в 22:36):
voffka, прочитай последний абзац.
voffka (15.12.2018 в 21:18):
А почему бы хэш не подменить? там sha-256 от ключа.
X-Wing Top Ace (15.12.2018 в 10:38):
Цитатаразнообразие функций, которое студенты-первокурсники пишут в качестве лабораторных работ

Ну, это уж вы загнули. Сильный студент, конечно, и на первом курсе может такое написАть, но не за одну лабораторку - даже в RAD-среде и на языке высокого уровня просто времени не хватит. Или хватит, чтобы кое-как слепить (без копирастического кода), но потом придется минимум несколько дней фиксить баги и дорабатывать функционал.

Другое дело, что студента можно озадачить написанием такой проги ВМЕСТО примитивных лабораторных заданий. Написал, отнес преподу вместе с исходниками, и получил зачет по всем лабораторным без примитивных задач типа "дан массив, обнулить нулевые элементы, проотрицать отрицательные". Я сам, когда учился, вместо такого примитива писАл на зачет по асму один досный резидент.

Цитатаякобы даже способный обнаруживать руткиты

Даже интересно стало - якобы или способный? Проверить наличие команд JMP или CALL вместо "PUSH EBP;MOV EBP, ESP" в начале кода перехватываемых руткитами функций, конечно, можно, но таким перехватом не одни руткиты занимаются.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2019
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0055 сек.) / Память: 4.75 Mb
Наверх