Защитить свой продукт
Мы с вами медленно, но верно приближаемся к победному завершению серии статей о защите программных продуктов от несанкционированного использования. Сегодня продолжим разговор о продвинутых приёмах, начатый в прошлый раз.
Как я уже говорил, действительно эффективные против злоумышленников приёмы защиты - это всегда палка о двух концах, которая, к сожалению, может ударить и разработчика. И самый эффективный из защитных приёмов, к сожалению, часто неоднозначно трактуется антивирусами, которые начинают подозревать ни в чем не повинного автора программы в желании подсунуть пользователю что-либо вредоносное. Именно из-за этого приема авторы программ, распространяемых по принципу shareware, имеют массу неприятностей с так называемыми false positives у антивирусов. Впрочем, давайте обо всём по порядку.
В прошлый раз мы закончили разговор о защите на детектировании запуска программы под отладчиком. И тогда я отметил, что отладчик, являясь, в общем-то, важным и удобным для взломщика инструментом, тем не менее, не всегда необходим, потому что основную информацию для взлома программного продукта можно получить из дизассемблированного кода программы. Соответственно, защита от отладчика должна быть дополнением к самой главной защите - защите от дизассемблирования.
Задача, в общем-то, ясна, однако встаёт вопрос о том, каким именно образом её выполнить? Понятно, что нужно сделать так, чтобы код был доступен операционной системе для выполнения, но при этом дизассемблеру он всё равно оставался "не по зубам". Очевидное и, пожалуй, единственное решение этой задачи состоит в том, чтобы хранить код в исполняемом файле не в том непосредственном виде, в котором его считывает и передаёт на исполнение процессору операционная система (и в котором, собственно говоря, и ищет его дизассемблер), а в каком-то другом, и преобразовывать в нужный системе вид прямо во время работы программы - "на лету".
Вариантов реализации этой концепции может быть два. Первый - хранение зашифрованного кода, который будет дешифроваться программой перед его исполнением операционной системой; второй - использование специального байт-кода и специальной виртуальной машины, под управлением которой будет исполняться этот байт-код. В общем-то, с некоторыми вариациями, практически во всех видах защиты приложений от дизассемблирования и анализа. Конечно, лучше всего будет применить оба этих метода для разных частей вашей системы защиты, но при этом не нужно забывать о самом главном принципе защиты - целесообразности. То есть заниматься этим нужно только тогда, когда вы уже перепробовали всё то, что мы обсуждали на протяжении предыдущих восьми статей цикла "Защитить свой продукт", а результаты всё равно оставляют желать чего-то лучшего.
Что ж, давайте посмотрим на каждую из этих технологий защиты с более близкого расстояния.
Шифрование исполняемого кода
Поскольку все, что мы обсуждали раньше, касалось, в основном, операционной системы Windows, то не будем отступать от традиции, хотя, в принципе, техники для других операционных систем (так как речь идет о коммерческом ПО, то это, в основном, Mac OS X) могут быть достаточно схожими, но я за это, конечно, не поручусь.
Нам помогут API-функции ReadProcessMemory и WriteProcessMemory. Про первую из них в MSDN написано буквально следующее: "Reads data from an area of memory in a specified process" (кто не верит - можете зайти по адресу msdn.microsoft.com/en-us/library/ms680553%28v=vs.85%29.aspx и ознакомиться с подробным описанием функции самостоятельно), про вторую можно почитать по адресу msdn.microsoft.com/en-us/library/ms681674%28v=vs.85%29.aspx. Собственно, в основном, на последнюю функцию и обращают внимание антивирусы.
Идея, в общем-то, предельно простая: берем предварительно зашифрованный код, расшифровываем его и пишем обратно на то место, где у нас лежит шифровка - не в EXE-файл, понятное дело, а в память, занимаемую нашим запущенным процессом. Тут нам понадобится ещё одна знаковая по своей важности функция из мощного арсенала Windows API, она называется OpenProcess (msdn.microsoft.com/en-us/library/ms684320%28v=vs.85%29.aspx).
Обратите внимание, что при таком подходе нужно постараться, чтобы зашифрованный код имел те же самые размеры, что и незашифрованный. Проще всего этого добиться, конечно же, если в качестве алгоритма шифрования мы применяем обычный XOR, и, в общем-то, для множества сравнительно недорогих программ такое решение действительно имеет право на жизнь. Но если речь идёт о защите чего-то действительно серьезного и имеющего цену со многими нулями между первой значащей цифрой и запятой, то такой вариант, как говорится, "не покатит". Хотя, если будет очень нужно, то взломщик постарается "выдрать" из кода даже достаточно сложный алгоритм дешифровки, потому что на его стороне время и виртуально ничем не ограниченный арсенал отладочных инструментов, а на вашей - достаточно частый выпуск обновлений для вашей программы плюс фантазия для создания гибкой защиты, которая позволит "малой кровью" менять параметры, обеспечивая после каждой новой версии взломщиков достаточным количеством не самой лёгкой работы.
Здесь, кстати, нам самим пригодится отладчик. Потому что функциям ReadProcessMemory и WriteProcessMemory нужно передавать в качестве одного из параметров адрес того блока кода, который будет дешифроваться и перезаписываться. Найти его проще всего из-под отладчика, воспользовавшись уже упоминавшимся в прошлый раз OllyDbg - пусть он не только взломщику послужит, но и праведным труженикам на ниве софтостроения. Перезаписывать обычный код на зашифрованный внутри EXE-файла можно той утилитой, которую вам всё равно придётся написать для реализации шифрования, или с помощью любого удобного для вас лично HEX-редактора.
В Сети достаточно много статей по поводу шифрования исполняемого кода, начиная с простых примеров и заканчивая решениями по борьбе с разными антивирусами и специальными инструментами для взлома. Практическое освоение шифрования я бы порекомендовал начать с этой статьи: zetblog.ru/programming/200811/безопасность-защита-кода-шифрование.
Виртуальная машина
В последнее время этот способ приобретает всё большую популярность, во многом благодаря тому, что, как написали на CrackLab.ru, "на крэкера ложится большой объём трудной неоплачиваемой работы, большие объёмы автоматически сгенерированных структур кода, требующих либо глубокого ручного разбора алгоритма всей защиты, либо ручного разбора текущего машинного кода, сгенерированного данной ВМ. То есть, проще говоря, на крэкера ложится рутина и, учитывая, что крэкерство чаще всего это хобби, происходит ситуация, когда защита остается неповерженной в большинстве случаев". Можно, конечно, пожалеть бедных взломщиков, которым так трудно заниматься их тяжелой неоплачиваемой работой, но у нас с вами задача всё-таки немного другая - и виртуальная машина для нас будет очень интересным решением.
Но у всего есть свои минусы. Во-первых, здесь уже не ограничишься вызовом пары функций - нужно разрабатывать целый набор инструкций для байт-кода, заниматься их трансляцией в машинный код и попутно следить за тем, чтобы всё это было не слишком очевидным для отладчика. То есть, без хороших знаний ассемблера уже никуда, и работы очень много. Во-вторых, минусом виртуальной машины является снижение быстродействия программы. В общем-то, как бы и не сильно страшно, если, говоря об этом, иметь в виду исключительно код, непосредственно связанный с защитой. Но часто разработчики, стремясь сделать своё приложение максимально защищенным, "загоняют" под виртуальную машину и другой код, который должен был бы, по-хорошему, выполняться быстрее. Ну и, наконец, для виртуальной машины нужны дополнительные системные ресурсы, то есть в тех случаях, когда код должен быть "лёгким" и компактным, её уже тоже применить достаточно сложно.
В общем, реализация собственной виртуальной машины - дело сложное и кропотливое, и рассказ об этом выходит далеко за рамки данной статьи. Хотя, конечно, ничего невозможного нет, и если постараться, то по имеющимся в Сети источникам (их тоже немало) можно написать свою защиту на основе виртуальной машины. Но это имеет смысл только для дорогих B2B-продуктов, которые вряд ли кто-то будет создавать в одиночку. Поэтому реально сегодня используются не "самописные" виртуальные машины, а купленные у кого-либо из производителей профессиональных средств защиты. Давно тому назад в "КВ" рассказывалось об актуальном на то время раскладе на рынке этих средств, но с тех пор прошло уже много времени, так что в рамках нашей серии "Защитить свой продукт" мы поговорим и о таком варианте защиты.
Вадим СТАНКЕВИЧ,
dreamdrusch@tut.by