Blog. Just Blog

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

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

Программа KeyboardTest предназначена для тестирования практически всех типов проводных и беспроводных клавиатур: WiFi, PS/2 и USB. Показывает скан-коды нажатых клавиш, тестирует световые индикаторы, кнопки расширенной клавиатуры, комбинации клавиатуры и мыши, макро-клавиши и т.п. Хороший инструмент, когда надо проверить что не так с клавиатурой или если вам надо держать под рукой справочник по кодам клавиш при разработке программ. Несмотря на всю пользу, выкладывать тридцатку зелени за софт - это не в моих правилах.

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

Окно регистрации
Окно регистрации

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

Окно "О программе"
Окно "О программе"

Поиском по этим строчкам в файле обнаружится следующее совпадение:

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

Посмотрим, где и как это используется.
  1. .text:00401387                 lea     eax, [ebp+String]
  2. ; Проверить переменную, если ее значение 1, то программа не зарегистрирована
  3. .text:0040138D                 cmp     dword_4334B0, 1
  4. .text:00401394                 jnz     short loc_4013AC
  5. .text:00401396                 push    dword_4337DC
  6. .text:0040139C                 push    offset aIDaysLeftInEva
  7. ; "%i Days left in evaluation"
  8. .text:004013A1                 push    eax
  9. .text:004013A2                 call    sub_40E5C8
  10. .text:004013A7                 add     esp, 0Ch
  11. .text:004013AA                 jmp     short loc_4013BA
  12. .text:004013AC ; ---------------------------------------
  13. .text:004013AC loc_4013AC:
  14. .text:004013AC                 push    offset aRegisteredVers
  15. ; "Registered Version"
  16. .text:004013B1                 push    eax
  17. .text:004013B2                 call    sub_40E5C8
  18. .text:004013B7                 add     esp, 8
Ага, значит переменная dword_4334B0 отвечает за состояние регистрации программы. Если она имеет значение 1, то регистрации нет, если любое другое значение, то программа считается зарегистрированной. Значит надо найти все места, где эта переменная может инициализироваться и откорректировать их таким образом, чтобы полученное значение всегда было правильным. Для этого пройдемся по перекрестным ссылкам:

Перекрестные ссылки на переменную
Перекрестные ссылки на переменную

Первый фрагмент, отвечающий за инициализацию:
  1. .text:004093E8                 cmp     [ebp+var_19C], 0
  2. ; По умолчанию программа не зарегистрирована
  3. .text:004093EF                 mov     dword_4334B0, 1
  4. ; Условный переход на основании предыдущего сравнения
  5. .text:004093F9                 jz      short loc_409424
  6. ; Программа зарегистрирована
  7. .text:004093FB                 mov     dword_4334B0, 0
  8. .text:00409405                 xor     eax, eax
  9. .text:00409407                 jmp     short loc_409410
Тут правильнее будет нейтрализовать условный переход, так как в "зарегистрированной" ветке алгоритма выполняются еще какие-то действия с регистрами. Смотрим дальше.
  1. .text:0040D1E8                 call    sub_407DF0
  2. .text:0040D1ED                 mov     eax, hInstance
  3. .text:0040D1F2                 add     esp, 4
  4. .text:0040D1F5                 mov     esi, ds:LoadIconA
  5. ; Инициализация переменных при запуске программы
  6. .text:0040D1FB                 mov     dword_4334B0, 1
  7. .text:0040D205                 mov     dword_4337DC, 0
  8. .text:0040D20F                 push    offset IconName ; "KeyboardTest"
  9. .text:0040D214                 push    eax             ; hInstance
  10. .text:0040D215                 mov     [ebp+var_540.cbSize], 30h
  11. .text:0040D21F                 mov     [ebp+var_540.style], 3
Тут выполняется первоначальная инициализация переменной до всех проверок наличия и корректности серийника. В принципе, можно и пропатчить этот код, заменив 1 на 0, так как "неправильных" значений переменной больше нигде не присваивается. Сохраняем изменения, запускаем. Никаких окон с предложениями о регистрации больше не появляется. Перевод системного времени на пару месяцев вперед на работоспособность программы также не повлиял. Цель почти достигнута. Почему "почти"? Если сейчас заглянуть в окно "О программе", то кроме надписи "Registered Version" там красуется одинокая надпись "User:" без указания имени, на которое программа зарегистрирована. Для домашнего использования можно оставить и так, а вот для публичного релиза лучше сделать все красиво.

По строчке "User:" находим код, где формируется итоговая строка. Кто знаком с программированием, наверняка узнает функцию printf.
  1. ; Указатель на строку регистрационного имени
  2. .text:0040140E                 push    offset DstBuf
  3. .text:00401413                 lea     eax, [ebp+String]
  4. .text:00401419                 push    offset aUserS   ; "User: %s"
  5. .text:0040141E                 push    eax
  6. .text:0040141F                 call    sub_40E5C8
На стек кладутся параметры, в нашем случае это адрес строки с именем, маска с шаблоном и адрес итоговой строки. По понятным причинам строки с именем у нас нет, поэтому надо заменить адрес этой несуществующей строки на адрес другой строки, которая гарантированно есть. Например, это строка "Unregistered User". Заменяем адрес в первой команде PUSH на виртуальный адрес строки, а в строку вписываем нужный ник или другую информацию. Сохраняем изменения, запускаем.

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

Красота! Вот теперь все недостатки программы KeyboardTest окончательно устранены, ей можно пользоваться без ограничений.

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

Комментарии

Отзывы посетителей сайта о статье
Eka (12.03.2019 в 12:02):
Спасибо ! Возьму как "Get Started" для IDA Pro. Очень хороший пример, т.к. нет обфускации, чисто работа с дизассемблером.
ManHunter (07.03.2019 в 14:58):
Да, там еще есть отсылки к Armaccess.dll и несколько типичных переменных армудилы. Хотя фактически они нигде не используются.
voffka (07.03.2019 в 00:52):
Видать на прошлых версиях проги висела арма со stolen code, видно по огромным кускам nop'oв средь кода.
user (28.02.2019 в 01:41):
Достойный пример спасибо за основу
Ellephant (27.02.2019 в 16:46):
ManHunter, печатной машинки! )))
ManHunter (27.02.2019 в 14:54):
Ellephant, а цифры, а знаки препинания, а всякие F1-F12? Так шрифты можно проверять, но точно не клавиатуру.
Ellephant (27.02.2019 в 14:47):
А в древние времена, для проверки клавиатуры достаточно было ввести текст "В чащах юга жил бы цитрус? Да, но фальшивый экземпляр."  В этом тексте все клавиши печатной машинки ;)

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

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

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