Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #66, МАЙ 2006 г.

копаемся в броне

КРИС КАСПЕРСКИ АКА МЫЩЪХ

Спецвыпуск: Хакер, номер #066, стр. 066-062-6


Конечно же, не стоит использовать для этой цели саму библиотечную функцию rand(), иначе перекрестные ссылки выдадут все ветвления на блюдечке с голубой каемочкой. Или же взломщик пропатчит функцию rand() так, чтобы она всегда выдавала один и тот же результат, заставляющий программу ходить одним маршрутом. Лучше исследовать исходный код rand() и переписать его самостоятельно, непосредственно вживив в тело программы, — тогда ломать программу будет очень и очень сложно.

Допустим, мы имеем десять разных, никак не зависимых друг от друга защитных функций. Часть из них вызывается при каждом запуске программы, часть — через раз, а часть — с вероятностью раз в несколько недель. Если защитные функции не выявляются ни по каким косвенным признакам, то взломщику придется полностью проанализировать весь код программы, что нереально.

присутствие регистрационных данных в памяти

Классический способ взлома, уходящий своими корнями в эпоху времен ZX-SPECTRUM, — прямой поиск регистрационных данных в памяти. Хакер вводит серийный номер от балды (подсовывает программе «левый» ключевой файл), затем ищет его в памяти и, если защита не прикладывает никаких дополнительных усилий, действительного находит его. Остается установить точку останова на эти данные и терпеливо ждать, пока защитный код, обращающийся к ним, не угодит в капкан. Процедура, ответственная за сравнение данных (введенных пользователем) с «эталоном», будет локализована и… безжалостно взломана.

Хитрые программисты поступают так: посимвольно считывают клавиатурный ввод и тут же шифруют его. Таким образом, в памяти уже не оказывается данных, введенных пользователем, и контекстный поиск теперь не срабатывает, обламывая взломщика по полной программе.

защита в ассемблерных вставках

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

Проведем простой эксперимент. Возьмем программу и откомпилируем ее компилятором Microsoft Visual C++ с максимальным режимом оптимизации (ключ /Ox).

исходный код функции без ассемблерных вставок

main()

{

int a,b=0;

for (a=0;a<10;a++) b+=a*2;

printf("%x\n",b);

}

дизассемблерный листинг функции без ассемблерных вставок (стандартный пролог выброшен компилятором)

.text:00000000 _main proc near

Назад на стр. 066-062-5  Содержание  Вперед на стр. 066-062-7