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

Пиши безопасно

Крис Касперски ака мыщъх

Спецвыпуск: Хакер, номер #057, стр. 057-070-1


Шесть советов по защите кода на этапе программирования

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

Использование ненадежных приемов программирования и навесных протекторов вроде Extreme Protector или Armadillo иногда создает проблем гораздо больше, чем решает. Порой защищенная программа становится неуклюжей, тормозной, конфликтной и вообще всячески нестабильной. В ней появляются многочисленные критические ошибки, вылезают голубые экраны смерти, в результате чего программист получает весьма подмоченную репутацию. Ну и кому это надо? Никаких недокументированных возможностей! Никакой привязки к операционной системе! Никаких приемов нетрадиционного программирования! Защита должна быть простой и надежной, как индуистский слон! Минимум усилий, максимум эффективности!

Совет №1: шифруйся!

Шифровка - простой, но весьма эффективный способ борьбы с дизассемблером. Естественно, она обязана быть динамической: крохотные порции кода/данных должны расшифровываться по мере необходимости, а после употребления зашифровываться обратно. Статические шифровальщики, расшифровывающие все тело программы за один раз, уже неактуальны. Достаточно снять дамп с работающей программы и - вуаля! Многие протекторы гробят таблицу импорта, корежат атрибуты секций, в общем, пакостят по всему мясокомбинату, в результате чего снятый дамп оказывается неработоспособен, но для дизассемблирования он подходит вполне, и такие меры защиты ни от чего не спасают!

В реализации динамического шифровщика есть множество тонкостей. Если реализовать его в виде автономной процедуры типа crypt(void *p, int N), хакер сможет расшифровать любой желанный для него фрагмент простым вызовом crypt с соответствующими аргументами. Чтобы воспрепятствовать этому, различные части программы должны расшифровываться различными функциями. Некоторые "эксперты по безопасности" предлагают использовать асимметричную криптографию, полагая, что это убережет программу от модификации (то есть от взлома). Действительно, зашифровать модифицированную программу назад уже не получится - для этого нужно знать ключ, который хранится у разработчика и отсутствует в самой программе. Однако ничего не стоит дописать к концу распаковщика несколько машинных команд, ломающих программу налету прямо в памяти.

Шифровать можно как код, так и данные, причем с кодом все намного сложнее. Во-первых, приходится предварительно манипулировать атрибутами страниц, выдавая разрешение на запись, а во-вторых, учитывать такую штуку, как перемещаемые элементы - специальные ячейки памяти, в которые в процессе загрузки файла операционная система прописывает фактические адреса. Впрочем, в большинстве случаев шифровки данных оказывается вполне достаточно. Главное - не дать хакеру обнаружить в дампе текстовые строки с ругательными сообщениями (типа "trial expired"), на которые легко поставить точку останова или подсмотреть перекрестную ссылку.

Содержание  Вперед на стр. 057-070-2