КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"
Улучшенная защита программ с зашифрованием сообщений
Файлы к статье: CrakMe-3.
Как мы видели, защитить программу бывает довольно непросто, однако даже простые mетоды усложняют крекеру жизнь. К сожалению (или к счастью, это кому как), программисты не хотят тратить времени даже на простую, элементарную защиту своих программ. А ведь это не так сложно, как кажемся на первый взгляд. Я покажу на примере, как выростут затраты труда и времени, если сделагь простейшую защиту.
Давайте посмотрим, что же изменится, если применить правила, о которых я говорил, а именно:
Будем исследовать программу CRAKME-3.EXE. Запускаем ее и смотрим на окно программы.
Мы опять видим практически то же самое окно с полем для ввода пароля. Попробуем ввести любые символы и посмотреть на результат. Вводим "12345", нажимаем кнопку ОК. Сначала ничего не происходит; немного погодя получаем сообщение о неверном пароле.
Что же мы имеем на этот раз? Па первый взгляд, ничего нового. Однако если хорошо подумать, то получается, что программа запрашивает у нас пароль, что-то с ним делает (или ждет какое-то время) и выдает нам результат (мы уже занимаемся анализом!). Давайте запустим PEiD и посмотрим, что он нам скажет.
Так. Значит, программа не запакована и не зашифрована. Это уже хорошо. Запускаем OlyDbg и загружаем в него нашу программу.
Теперь пробуем найти все текстовые строки программы. Вдруг нам повезло, и программист не стал шифровать свои данные, как это было в программе CRAKME-1.EXE.
Мы видим, что не все строки зашифрованы, но вот самих сообщений, которые выводятся в случае правильности (или неправильности) пароля нет. Значит, программист все-таки зашифровал свои сообщения.
Откроем CrackMe-3.exe в IDA. Создадим MAP файл. Далее открываем крэкми в OllyDbg и при помощи плагина GODUP подкючаем MAP файл. Как это делать - смотри в уроке 2.
Что же нам делать? Попробуем поставить BPX на функцию MessageBoxA. Запускаем программу в отладчике, вводим в окне пароль "12345" и нажимаем кнопку ОК. Теперь мы в отладчике. Что же мы видим? Вывод сообщения о неверном пароле. Если посмотреть чуть выше, то мы увидим, что там находится сообщение о верном пароле.
Причем все сообщения уже расшифрованы. Это значит, что где-то в программе сообщения расшифровываются. А раз так, то расшифровывается и пароль (хотя формально это вовсе не обязательно, поскольку сравниваться могут не пароли, а хеш-функции). Что же делать? Можно, конечно, попытаться проследить, откуда эта функция вызывается, но нет гарантии, что мы найдем нужное место достаточно быстро (хотя этот метод довольно часто срабатывает). В данном случае этот способ нам не подходит. Давайте подумаем. Есть программа, в которую вводится пароль, он сравнивается с паролем, который есть в самой программе. Стоп! Раз он "сравнивается", значит можно попробовать "отловить" функцию сравнения. Какие же функции нам нужны? А вот для этого мы и пытались определить язык, на котором написана программа. Поскольку она написана на Borland C++, берем справочник по этому компилятору. Там есть несколько функций сравнения:
extern PACKAGE int __fastcall CompareStr(const AnsiString S1,
const AnsiString S2);
extern PACKAGE int __fastcall CompareText(const AnsiString S1,
const AnsiString S2);
int strcmp(const char *s1, const char *s2);
Эти функции предназначены для сравнения строк. И не забудьте, что еще есть простой оператор сравнения:
(const1*) == (const2*)
Его применяют, когда надо сравнить, например, так, как показано в листинге ниже.
AnsiString pas1 = "Pas1234";
AnsiString pas2 = "456Pas3";
if(pas1 == pas2)
ShowMessage("Password is TRUE");
else
ShowMessage("Password is FALSE");
Эту комбинацию довольно часто применяют в программах на языке С++, поэтому о ней ни в коем случае не стоит забывать.
Теперь давайте поставим брекпойнт на функцию CompareStr. Поставили, запускаем программу, вводим в нее любые значения, нажимаем кнопку ОК и... Ничего не происходит. Значит, как я уже говорил, эта функция не используется. Попробуем поставить брекпойнты на функции CompareText и strcmp. Поставили, запускаем программу. И опять ничего. Значит и эти функции не используются для сравнения.
Посмотрим какие функции используются (вызываются) в программе - для этого в окне OllyDbg надо нажать комбинацию клавиш Ctrl + N.
В столбце Name отображается имя функции. Конечно их тут много, но ведь нам не нужны все. Самые интересные — системные функции. Если просто набрать "system", то быстрый поиск перенесет нас к ним.
Мы видим очень интересные системные функции, в том числе:
System::AnsiString::operator==(System::AnsiString &)
Давайте поставим на нее брекпойнт. Для этого выделим ее строку и нажмем клавишу F2.
Запускаем программу, вводим любые символы (я ввел "12345") и попадаем вот сюда.
Начинаем трассировать программу при помощи F8. Выполняем функцию LStrCmp.
При этом вызове функции ничего не происходит. Нажимаем клавишу F8 еще раз и попадаем сюда же.
А вот тут при вызове функции в регистрах ЕАХ, EDX есть интересные значения!
Мы нашли пароль! Вот так использование программистом правил помогает защитить программу. Конечно, защита не будет полной, если использовать только эти два правила, но начинающего крекера уже сможет остановить. А для еще большего осложнения жизни крекеров рекомендуется использовать в программе две строки — одну зашифрованную, а другую нет. С зашифрованной работают, а незашифрованную оставляют для ловушки (или просто ничего с ней не делают). Крекеру придется поломать голову, каким образом вы добираетесь до этой строки (про ловушки мы поговорим позднее).