Статья была опубликована в журнале "Мобильные Системы"
Проделав все эти операции, вы можете со спокойной совестью оставлять работающий ноутбук без присмотра, естественно нажав перед уходом "Alt-Ctrl-Del" и выбрав пункт "Блокировка системы". Система окажется заблокированной вплоть до ввода пароля, и злоумышленник, пускай он даже похитит ваш ноутбук, не сможет добраться до охраняемой информации. Правда вам придется отказаться от автоматического ввода пароля при старте системы, ибо это маленькое удобство сводит защищенность компьютера практически к нулю. Итак, "Панель управления" a
"Пользователи и пароли" a
"Требовать ввод имени пользователя и пароля".
Не лишним будет установить пароль и на включение компьютера (если, конечно, ваша BIOS это позволяет). Несмотря на то, что пароль снимается элементарным замыканием специальной перемычки на материнской плате, он все-таки представляет вполне надежную защиту, ведь далеко не во всех случаях злоумышленник имеет время, достаточное для вскрытия ноутбука. Правда, некоторые BIOS поддерживают, так называемый, мастер-пароль, наиболее известный из которых – AWARD_SW – в свое время наделал много шума. Не брезгуйте пройтись по хакерским сайтам, – очень много нового о своем кремниевом друге можете вычитать!
Также обязательно запретите BIOS'у грузиться с дискеты, иначе никакая Windows 2000 вам не поможет! Прочесть-то зашифрованную информацию злоумышленник не прочтет, но вот уничтожить сможет.
Кстати, о шифровании. В работе с зашифрованной папкой через "Проводника" есть одна тонкость. Файлы, "перетащенные" в зашифрованную папку, зашифрованы не будут! Microsoft честно об этом предупреждает и настоятельно рекомендует вместо "Drag & Drop" пользоваться командами "Вырезать/Копировать" и "Вставить". Неудобно, конечно, но…
Но было бы ошибкой считать систему шифрования Windows2000 кривой, как бумеранг. При более детальном знакомстве с ней негативное впечатление плавно перетекает, если уж не в щенячий восторг то, по крайней мере, в глубокое уважение.
Ах да, легально нам доступно лишь 56-битное шифрование, но контрафактные диски еще никто не отменял, и Windows 2000 с "крутым" шифрованием в России не редкость (невероятно, но Microsoft в файле помощи сама невольно подсказывает, как это сделать).
Как пользоваться шифрованием? Во-первых, поскольку в качестве ключа будет использоваться пароль, под которым вы входите в систему, со всем вниманием отнеситесь к его выбору. Пароль не должен представлять собой словарное слово, предсказуемую или слишком короткую последовательность.
Во-вторых, следует выбрать, какие папки вы будете шифровать. Не забывайте также про папку "TEMP"– очень многие приложения (тот же Word, например) не слишком-то аккуратно удаляют после себя временные файлы, а во временные файлы попадает все что угодно, – от рабочих данных до копий редактируемых файлов!
Папка с временными файлами может размещаться в различных каталогах, да к тому же она может быть и не одна. В "Командной строке" дайте команду "start %TEMP%", "start %TMP%", и указанные каталоги появятся на экране. (Обычно это что-то типа: "C:\Documents and Settings\Kris Kaspersky.KPNC\Local Settings\Temp"). Переходим на уровень вверх и, щелкнув правой клавишей мыша по папке, в контекстном меню выбираем "Свойства". Во вкладке "Общие" находим кнопочку "Дополнительно", которая открывает нам еще один диалог, содержащий помимо прочего пункт "Шифровать содержимое для защиты данных". Взводим галочку и дважды нажимаем "ОК". Система попросит уточнить: хотим ли мы шифровать вложенные папки или только эту папку? Конечно же, хотим шифровать вложенные! – "ОК". Если все сделано правильно, на экране появится "градусник", изображающий ход шифрования, и абстрактная анимационная картинка, с умным видом рисующая разноцветные крестики в нужных местах.
На первый взгляд может показаться, что ничего не произошло: работа с зашифрованными файлами происходит так же, как и раньше. Однако все изменится, если зайти в систему под другим именем. Будь вы хоть администратором, – в доступе вам будет отказано независимо от того, идентичен пароль или нет!
Теперь перейдем к "Корзине".
Вообще-то, от нее лучше сразу отказаться, указав в настройках "Удалять файлы сразу после удаления, не помещая их в корзину", но если уж очень хочется иметь возможность восстановления ранее удаленных файлов, найдите в корневых каталогах каждого из дисков скрытую папку "Recycle". Открыв ее, вы увидите несколько вложенных папок, каждая из которых хранит удаленные файлы "своего" пользователя. К сожалению, вместо имен здесь используются бессмысленные на первый взгляд идентификаторы. Впрочем, найти свою "Корзину" очень просто: лишь ее одну вы сможете открыть, а в остальные вас просто не пустят (если, конечно, вы не администратор системы, но постоянно заходить в систему с привилегиями администратора могут только самоубийцы). Шифруем "Корзину" и переходим к личной почте.
Почта – настоящий кладезь информации для злоумышленника, особенно, если вы бережно храните всю полученную и отправленную корреспонденцию. Не стоит пренебрегать возможностью ее зашифровать. В "Outlook Express" это делается так: щелкаем правой клавишей мыши по папке "Входящие" и выбираем "Свойства". В появившемся диалоговом окне находим пункт "Данная папка хранится в следующем файле". Переходим по указанному адресу и шифруем всю папку целиком.
В заключение шифруем папку "Мои документы", равно, как и все папки, где вы храните секретные документы, предварительно убедившись, что ничего ценного в других папках нет. В первую очередь "к другим" относится папка "WINNT\Repair", открыто хранящая копию реестра, в том числе и базу паролей. Либо удалите ее совсем, либо зашифруйте.
При установке системы обязательно выберите тип файловой системы NTFS и без колебаний откажитесь от FAT. Мотивация такова: NTFS, в отличие от FAT, действительно надежная отказоустойчива система, разрушить которую можно только динамитом (шутка, конечно, но весьма недалекая от истины).
К тому же, в состав NTFS входит EFS – Encryption File System (Шифрованная Файловая Система), обеспечивающая "прозрачное" шифрование файлов и папок. Конечно, эту возможность никак не назовешь уникальной – подобное сегодня реализуют все кому не лень. Сеть буквально кишит шифровальными программами. Как говорится, выбирай на вкус! Но помимо проблемы выбора (у буриданова осла было всего две кучки сена, и то он окочурился с голоду, так и не решив с какой из них начать трапезничать), пользователь сталкивается с невозможностью проверки соответствия заявленных характеристик действительным.
Разработчик может уверять вас, что использует 1024-битное шифрование, а на самом деле не выполнять никакого шифрования вообще или реализовать примитивнейшую "ксорку". И даже честные разработчики ничем не застрахованы от ошибок! "Благодаря" этому стойкость шифра может оказаться значительно ниже ожидаемой или, что еще хуже, зашифрованный файл в некоторых случаях необратимо искажается и его вообще не удается расшифровать!
Особенно щепетильным следует быть при выборе утилит, создающих виртуальные шифрованные диски (т.е. делающих приблизительно то же самое, что и EFS). Один неверный бит способен превратить десятки гигабайт ценнейшей информации в бесценный хлам. Положение усугубляется тем, что "дисковых докторов" для таких утилит нет, и даже самый ничтожный сбой восстанавливать нечем. Не поможет тут и ручная работа, поскольку разработчики практически никогда не описывают форматы шифрованных дисков.
Словом, несмотря на то, что EFS обеспечивает всего лишь 56-битное шифрование (что при мощностях современных компьютеров назвать "шифрованием" даже язык не поворачивается), она – хороший выбор!
Воздвигать крепость защиты мы начнем с закладки фундамента. Фундамент– это надежная, отказоустойчивая, пуленепробиваемая и максимально жизнеспособная операционная система. Народная Windows 98, равно как и ее старшая сестра Windows Millennium, построена на латанном-перелатанном ядре Windows 3.0, и потому на эту роль категорически не подходит. Какими бы изощренными защитами вы ни пользовались, профессиональный взломщик без особых трудов сумеет их обойти, поскольку Windows 9x не позволяет гарантированно предотвратить модификацию кода защиты (т.е., попросту говоря, ее убиение).
Поэтому имеет смысл установить на всех своих компьютерах, включая ноутбук, одну из систем, базирующихся на ядре NT. К таковым принадлежат (в порядке роста требований к аппаратным ресурсам): Windows NT, Windows 2000, Windows XP. Защищенность всех их в той или иной степени одинакова, а функциональность увеличивается явно медленнее, чем "аппетит", который в отношении Windows XP иначе, как "обжорливостью", просто не назовешь.
Теоретически можно оснастить ноутбук какой-нибудь UNIX-подобной системой, например, LINUX. Достаточно непритязательные к мощности аппаратуры, они, тем не менее, обладают не сильно уступающей Windows функциональностью и обеспечивают очень высокий уровень защиты. (Некоторые UNIX'ы сертифицированы по мандату B, что значительно выше мандата C2, выданного в свое время NT). Единственное, что останавливает: крайне убогая – да не запинают меня юниксоиды – поддержка форматов Microsoft Office, ставших сегодня стандартом де-факто (Star Office многие документы не открывает вообще или делает это не вполне корректно) и отсутствие драйверов под многие, в том числе, и не экзотические "железки". Очень может сложиться так, что LINUX на ваш компьютер просто не "встанет".
Поэтому давайте остановимся на компромиссном варианте – Windows 2000.
Остановимся на некоторых особенностях операционных систем, которые, несмотря на все свои положительные функции, подчас только мешают надежной защите конфиденциальной информации. Далее представлены наиболее распространенные системные механизмы, оставляющие для злоумышленника ряд «лазеек» и актуальные как для ноутбуков, так и для КПК.
Временные файлы. Многие программы (в том числе и операционная система) используют временные файлы для хранения промежуточных данных во время своей работы. Часто во временный файл заносится точная копия открытого программой файла, что позволяет обеспечить возможность полного восстановления данных в случае непредвиденных сбоев. Конечно, полезная нагрузка временных файлов велика, однако, будучи незашифрованными, такие файлы несут прямую угрозу корпоративным секретам.
Файлы подкачки (или swap-файлы). Очень популярной в современных операционных системах является технология swap-файлов, позволяющая предоставить любому приложению практически неограниченный объем оперативной памяти. Так, если операционной системе не хватает ресурсов памяти, она автоматически записывает данные из оперативной памяти на жесткий диск (в файл подкачки). Как только возникает потребность воспользоваться сохраненной информацией, операционная система извлекает данные из swap-файла и в случае необходимости помещает в это хранилище другую информацию. Точно так же, как и в предыдущем случае, в файл подкачки легко может попасть секретная информация в незашифрованном виде.
Выравнивание файлов. Файловая система Windows размещает данные в кластерах, которые могут занимать до 64 секторов. Даже если файл имеет длину в несколько байтов, он все равно займет целый кластер. Файл большого размера будет разбит на порции, каждая размером с кластер файловой системы. Остаток от разбиения (обычно последние несколько байтов) все равно будет занимать целый кластер. Таким образом, в последний сектор файла попадает случайная информация, которая находилась в оперативной памяти ПК в момент записи файла на диск.
Там могут оказаться пароли и ключи шифрования. Другими словами, последний кластер любого файла может содержать довольно чувствительную информацию, начиная от случайной информации из оперативной памяти и заканчивая данными из электронных сообщений и текстовых документов, которые раньше хранились на этом месте.
Корзина. Когда пользователь удаляет файл, Windows перемещает его в корзину. Пока корзина не очищена, файл можно легко восстановить. Тем не менее, даже если очистить корзину, данные все равно физически останутся на диске. Другими словами, удаленную информацию очень часто можно найти и восстановить (если поверх нее не было записано других данных). Для этого существует огромное количество прикладных программ, некоторые из них бесплатны и свободно распространяются через Интернет.
Реестр Windows. Сама система Windows, как и большое количество приложений, хранит свои определенные данные в системном реестре. Например, web-браузер сохраняет в реестре доменные имена тех страниц, которые посетил пользователь. Даже текстовый редактор Word сохраняет в реестре имя файла, открытого последним. При этом реестр используется ОС при загрузке. Соответственно, если какой-либо метод шифрования запускается после того, как загрузилась Windows, то результаты его работы могут быть скомпрометированы.
Файловая система Windows NT (NTFS). Считается, что файловая система со встроенным управлением доступом (как в Windows NT) является безопасной. Тот факт, что пользователь должен ввести пароль для получения доступа к своим персональным файлам, оставляет ложное ощущение, будто личные файлы и данные надежно защищены. Тем не менее даже файловая система со встроенными списками контроля доступа (Access Control List — ACL), например NTFS, не обеспечивает абсолютно никакой защиты против злоумышленника, имеющего физический доступ к жесткому диску или права администратора на данном компьютере. В обоих случаях преступник может получить доступ к секретным данным. Для этого ему понадобится недорогой (или вообще бесплатный) дисковый редактор, чтобы прочитать текстовую информацию на диске, к которому у него есть физический доступ.
Режим сна. Этот режим очень популярен на ноутбуках, так как позволяет сэкономить энергию батареи в тот момент, когда компьютер включен, но не используется. Когда лэптоп переходит в состояние сна, операционная система копирует на диск абсолютно все данные, находящиеся в оперативной памяти. Таким образом, когда компьютер «проснется», операционная система легко сможет восстановить свое прежнее состояние. Очевидно, что в этом случае на жесткий диск легко может попасть чувствительная информация.
Скрытые разделы жесткого диска. Скрытый раздел — это такой раздел, который операционная система вообще не показывает пользователю. Некоторые приложения (например, те, что занимаются энергосбережением на ноутбуках) используют скрытые разделы, чтобы хранить в них данные вместо файлов на обычных разделах. При таком подходе информация, размещаемая на скрытом разделе, вообще никак не защищается и легко может быть прочитана кем угодно с помощью дискового редактора.
Свободное место и пространство между разделами. Сектора в самом конце диска не относятся ни к одному разделу, иногда они отображаются как свободные. Другое незащищенное место — пространство между разделами. К сожалению, некоторые приложения, а также вирусы могут хранить там свои данные. Даже если отформатировать жесткий диск, эта информация останется нетронутой. Ее легко можно восстановить.
Таким образом, чтобы эффективно защитить данные, недостаточно их просто зашифровать. Необходимо позаботиться о том, чтобы копии секретной информации не «утекли» во временные и swap-файлы, а также в другие «потайные места» операционной системы, где они уязвимы для злоумышленника.
Рассмотрим, как различные подходы к шифрованию данных справляются с особенностями операционных систем.
Пофайловое шифрование (). Данный метод используется в основном для того, чтобы посылать зашифрованные файлы по e-mail или через Интернет. В этом случае пользователь шифрует конкретный файл, который необходимо защитить от третьих лиц, и отправляет его получателю. Такой подход страдает низкой скоростью работы, особенно когда дело касается больших объемов информации (ведь требуется шифровать каждый прикрепляемый к письму файл). Еще одной проблемой является то, что шифруется лишь файл-оригинал, а временные файлы и файл подкачки остаются полностью незащищенными, поэтому защита обеспечивается только от злоумышленника, пытающегося перехватить сообщение в Интернете, но не против преступника, укравшего ноутбук или КПК. Таким образом, можно сделать вывод: пофайловое шифрование не защищает временные файлы, его использование для защиты важной информации неприемлемо. Тем не менее данная концепция подходит для отправки небольших объемов информации через сеть от компьютера к компьютеру.
Шифрование папок. В отличие от пофайлового шифрования данный подход позволяет переносить файлы в папку, где они будут зашифрованы автоматически. Тем самым работать с защищенными данными намного удобнее. Поскольку в основе шифрования папок лежит пофайловое шифрование, оба метода не обеспечивают надежной защиты временных файлов, файлов подкачки, не удаляют физически данные с диска и т. д. Более того, шифрование каталогов очень неэкономично сказывается на ресурсах памяти и процессора. От процессора требуется время для постоянного зашифровывания/расшифровывания файлов, также для каждого защищенного файла на диске отводится дополнительное место (иногда более 2 кбайт). Все это делает шифрование каталогов очень ресурсоемким и медленным. Если подвести итог, то хотя данный метод довольно прозрачен, его нельзя рекомендовать для защиты важной информации. Особенно если злоумышленник может получить доступ к временным файлам или файлам подкачки.
Схема 3. Шифрование всего диска (включая загрузочные записи)
Для надежного сохранения данных требуются не только мощные и грамотно реализованные криптографические технологии, но и средства предоставления персонализированного доступа. В этой связи применение строгой двухфакторной аутентификации на основе аппаратных ключей или смарт-карт является самым эффективным способом хранения ключей шифрования, паролей, цифровых сертификатов и т. д. Чтобы успешно пройти процедуру сильной аутентификации, пользователю необходимо предъявить токен (USB-ключ или смарт-карту) операционной системе (например, вставить его в один из USB-портов компьютера или в устройство считывания смарт-карт), а потом доказать свое право владения этим электронным ключом (то есть ввести пароль). Таким образом, задача злоумышленника, пытающегося получить доступ к чувствительным данным, сильно осложняется: ему требуется не просто знать пароль, но и иметь физический носитель, которым обладают лишь легальные пользователи.
Внутреннее устройство электронного ключа предполагает наличие электронного чипа и небольшого объема энергонезависимой памяти. С помощью электронного чипа производится шифрование и расшифровывание данных на основе заложенных в устройстве криптографических алгоритмов. В энергонезависимой памяти хранятся пароли, электронные ключи, коды доступа и другие секретные сведения. Сам аппаратный ключ защищен от хищения ПИН-кодом, а специальные механизмы, встроенные внутрь ключа, защищают этот пароль от перебора.
Для того чтобы защитить информацию от несанкционированного доступа, применяются технологии шифрования. Однако у пользователей, не обладающих надлежащими знаниями о методах шифрования, может возникнуть ложное ощущение, будто все чувствительные данные надежно защищены. Рассмотрим основные технологии шифрования данных.
Пофайловое шифрование. Пользователь сам выбирает файлы, которые следует зашифровать. Такой подход не требует глубокой интеграции средства шифрования в систему, а следовательно, позволяет производителям криптографических средств реализовать мультиплатформенное решение для Windows, Linux, MAC OS X и т. д.
Шифрование каталогов. Пользователь создает папки, все данные в которых шифруются автоматически. В отличие от предыдущего подхода шифрование происходит на лету, а не по требованию пользователя. В целом шифрование каталогов довольно удобно и прозрачно, хотя в его основе лежит все то же пофайловое шифрование. Такой подход требует глубокого взаимодействия с операционной системой, поэтому зависит от используемой платформы.
Шифрование виртуальных дисков. Концепция виртуальных дисков реализована в некоторых утилитах компрессии, например Stacker или Microsoft DriveSpace. Шифрование виртуальных дисков подразумевает создание большого скрытого файла на жестком диске. Этот файл в дальнейшем доступен пользователю как отдельный диск (операционная система «видит» его как новый логический диск). Например, диск Х:\. Все сведения, хранящиеся на виртуальном диске, находятся в зашифрованном виде. Главное отличие от предыдущих подходов в том, что криптографическому программному обеспечению не требуется шифровать каждый файл по отдельности. Здесь данные шифруются автоматически только тогда, когда они записываются на виртуальный диск или считываются с него. При этом работа с данными ведется на уровне секторов (обычно размером 512 байт).
Шифрование всего диска. В этом случае шифруется абсолютно все: загрузочный сектор Windows, все системные файлы и любая другая информация на диске.
Защита процесса загрузки. Если зашифрован весь диск целиком, то операционная система не сможет запуститься, пока какой-либо механизм не расшифрует файлы загрузки. Поэтому шифрование всего диска обязательно подразумевает и защиту процесса загрузки. Обычно пользователю требуется ввести пароль, чтобы операционная система могла стартовать. Если пользователь введет пароль правильно, программа шифрования получит доступ к ключам шифрования, что позволит читать дальнейшие данные с диска.
Таким образом, существует несколько способов зашифровать данные. Некоторые из них менее надежные, некоторые более быстрые, а часть вообще не годится для защиты важной информации. Чтобы иметь возможность оценить пригодность тех или иных методов, рассмотрим проблемы, с которыми сталкивается криптографическое приложение при защите данных.
Алексей Доля
Проблема защиты конфиденциальной информации от несанкционированного доступа является одной из самых злободневных. В этой статье рассмотрены технологии, надежно защищающие чувствительные данные на ноутбуках и КПК с помощью шифрования и многофакторной аутентификации. Как показывает практика, это самый надежный, а порой и единственный способ, позволяющий обеспечить безопасность информации и одновременно удобство доступа к ней.
Одной из самых опасных угроз сегодня является несанкционированный доступ. Согласно исследованию Института компьютерной безопасности и ФБР (см. CSI/FBI Computer Crime and Security Survey 2005), в прошлом году 55% компаний зарегистрировали инциденты, связанные с неправомочным доступом к данным. Более того, вследствие неавторизованного доступа каждая фирма потеряла в 2005 году в среднем $303 тыс. Причем по сравнению с 2004 годом убытки увеличились в шесть раз. Таким образом, суммарные убытки, которые понесли свыше 600 опрошенных фирм, за год превысили $30 млн (см. ).
Проблема усугубляется тем, что за неавторизованным доступом к конфиденциальной информации часто следует ее кража. В результате такой комбинации двух чрезвычайно опасных угроз убытки компании могут возрасти в несколько раз (в зависимости от ценности похищенных данных). Кроме того, фирмы нередко сталкиваются и с физической кражей мобильных компьютеров, вследствие чего реализуются как угрозы несанкционированного доступа, так и кражи чувствительной информации. Кстати, стоимость самого портативного устройства зачастую несопоставима со стоимостью записанных на нем данных.
Проблемы, возникающие у предприятия в случае утечки информации, особенно показательны на примере кражи ноутбуков. Достаточно вспомнить недавние инциденты, когда у компании Ernst&Young в течение нескольких месяцев было похищено пять ноутбуков, содержащих приватные сведения клиентов фирмы: компаний Cisco, IBM, Sun Microsystems, BP, Nokia и т. д. Здесь в высшей мере проявился такой трудноизмеримый показатель нанесенного ущерба, как ухудшение имиджа и снижение доверия со стороны клиентов.
Между тем аналогичные трудности испытывает множество компаний.
Так, в марте 2006 года фирма Fidelity потеряла ноутбук с приватными данными 200 тыс. служащих HP, а в феврале аудиторская компания PricewaterhouseCoopers лишилась ноутбука с чувствительными сведениями 4 тыс. пациентов одного американского госпиталя. Если продолжать список, то в него попадут такие известные компании, как Bank of America, Kodak, Ameritrade, Ameriprise, Verizon, и другие.
Таким образом, помимо защиты конфиденциальной информации от несанкционированного доступа необходимо оберегать и сам физический носитель. При этом надо учитывать, что такая система безопасности должна быть абсолютно прозрачной и не доставлять пользователю трудностей при доступе к чувствительным данным ни в корпоративной среде, ни при удаленной работе (дома или в командировке).
До сих пор ничего более эффективного в области защиты информации от несанкционированного доступа, чем шифрование данных, не изобретено. При условии сохранности криптографических ключей шифрование гарантирует безопасность чувствительных данных.
Статья была опубликована в
В настоящей статье рассказывается о проблемах безопасности операционной системы Windows NT, в том числе и ее последней версии Windows 2000. Публикация рассчитана на системных администраторов и разработчиков прикладного программного обеспечения, предназначенного для работы на Windows NT.
Если первые кирпичи здания UNIX закладывались в ту далекую эпоху, когда никакой теории безопасности еще не существовало, то Windows NT изначально проектировалась как защищенная, отказоустойчивая система, стойкая ко всем антиамериканским настроениям.
Дейв Катлер, крестный отец Windows NT, ранее участвовавший в создании двух легенд семидесятых – RSX-11M и VMS, вложил в NT весь свой талант и опыт, но… похоже, потерпел неудачу. Да, Windows NT построена на передовых технологиях и основана на внутренне непротиворечивой модели безопасности, но теоретическую идиллию разрушают вездесущие ошибки реализации.
Кроме досадных багов – своеобразных программистских описок, исправляемых очередной заплаткой, – актуальны и проблемы стыковки различных компонентов операционной системы друг с другом. Несогласованная же работа способна значительно ослабить степень безопасности. Но ни один человек не в состоянии удержать в голове миллионы строк исходного кода операционной системы, а с ростом количества разработчиков, координировать их действия становится все сложнее и сложнее.
Неудивительно, что в Windows NT обнаруживаются серьезные бреши в защите и существуют способы несанкционированного повышения уровня своих привилегий с “гостя” до администратора. Часть ошибок устраняется правильным администрированием (читай – нечеловеческим ущемлением прав пользователей и отключением всего, что удается отключить), но в силу самой архитектуры Windows NT у злоумышленника всегда останется шанс проникнуть в систему.
Как и UNIX, операционная система Windows NT подвержена угрозе срыва стека, точно так же для нее актуальна возможность прорыва за пределы процесса, позволяющая пользователю получить доступ к данным и коду другого приложения (включая системные сервисы), наконец, реализация протоколов семейства TCP/IP оставляет желать лучшего и допускает возможность удаленной атаки.
/td> |
|
С защитой адресных пространств процессор связано огромное количество слухов, сплетен, легенд, да и простого непонимания самой философии защиты. Популярные руководства постоянно упускают из виду, что эта защита в первую очередь предназначается для непредумышленного доступа, то есть для того, чтобы процесс, пошедший "в разнос", не утащил бы на тот свет и все остальные процессы, исполняющиеся параллельно с ним.
Полноценной защиты от предумышленного доступа в чужое адресное пространство ни в UNIX, ни в NT на самом деле нет. Собственно, UNIX вообще не представляет никаких средств такого взаимодействия, кроме разве что разделяемых (т. е. совместно используемых) областей памяти, но это совсем не то. NT же обеспечивает весьма гибкий контроль доступа адресному пространству процессоров, но все-таки значительно проигрывает UNIX в отношении безопасности. И вот почему:
а) в NT доступ в чужое адресное пространство по умолчанию разрешен всем, даже гостю, и если какой-то процесс (точнее его владелец) не хочет, чтобы в него проникали, он должен заявить об этом явно;
б) в UNIX для отладки процессов необходимо, чтобы отлаживаемый процесс не только дал согласие на свою отладку, но и выполнил некоторые действия, причем, отладка уже запущенных процессов запрещена! NT же беспрепятственно позволяет отлаживать активные процессы и инициировать отладку новых, естественно, с наследованием всех привидений процесса-отладчика (то есть в общем случае, отладка более привилегированных процессов из менее привилегированных невозможна).
Короче говоря, - NT предоставляет весьма вольготные условия для существования Stealth-вирусов, клавиатурных и паролей шпионов и всех прочих тварей, нарушающих покой системы.
Существует мнение, что распространение электронно-вычислительных машин привнесло больше проблем, чем их решило. Человечество в своей массе ни морально, ни этически, ни психологически ко всему этому оказалось просто не готово и компьютерная техника попала в руки к людям, чей интеллект направлен лишь на разрушение. И, если до появления Интернета, вирусная угроза в основном сводилась к проблеме "грязных рук" и беспорядочного копирования ПО, то сейчас ситуация существенно изменилась.
.с другой стороны, степень опасности "дыры" зависит не сколько от ее "линейных размеров", столько от распространенности операционной системы, в которой она обнаружена. Огромное количество клонов UNIX ставит эту систему в весьма выигрышное (с точки зрения безопасности) положение. К тому же, постоянно переписываемые да и просто альтернативные ядра даже одну-единственную систему размножают до целого семейства, благодаря чему, уязвимость, найденная в одной версии ядра, зачастую недействительна для всех остальных.
В результате, могущество хакера, нашедшего дыру в UNIX, оказывается много ниже, чем если бы дыра аналогичных размеров была обнаружена в NT (в силу не многочисленности своих разновидностей, каждая, отдельно взятая версия NT, установлена на значительно большем количестве машин, нежели UNIX). Именно поэтому NT все-таки ломают или во всяком случае пытаются это сделать. Соблазн в самом деле настолько велик, что хакеров не останавливают ни отсутствие исходных текстов, ни трудоемкость анализа. К тому же, ядро NT не переписывается каждый день и практически все дыры, обнаруженные в NT 4.0 остаются актуальными и в Windows 2000, а то и в Windows XP. (Подробнее об этом рассказывается в книге Криса Касперски "Техника сетевых атак").
Напротив, если некоторая операционная система установлена на считанных компьютерах в мире, ломать ее сподобятся разве что мазохисты. Во всяком случае, хакеру потребуется весьма сильный стимул для изучения последней. Конечно, если эта операционная система защищает банковский компьютер, охраняющий миллиард электронных долларов, то за его сохранность ни один администратор не рискнет поручиться, что и неудивительно, ведь малораспространенные операционные системы практически полностью выпадают из внимания специалистов по информационной безопасности, вследствие чего частенько содержат большое количество тривиальных и легко обнаруживаемых ошибок, обнаруживаемых даже при поверхностном анализе.
Тем не менее, установка малораспространенной системы автоматически отсекает большую армию "хакеров", пользующихся для атак чужими эксплоитами. А, чтобы вас не атаковал профессионал, необходимо создать второй уровень защиты - узел с проверенной временем и тщательно проверенной специалистами операционной системой.
Неплохая идея: на передний план обороны водрузить какой-нибудь "редкоземельный" клон UNIX, а на второй - NT. Большинство хакеров, как показывает практика, в основном специализируются на одной операционной системе, и лишь в исключительных случаях - на двух сразу.
Комплект штатной поставки подавляющего большинства UNIX включает в себя огромное количество разнообразных программ от игрушек до компиляторов и интерпретаторов. А чем больше приложений установлено на машине, тем выше вероятность образования "дыр" в системе безопасности! К тому же, наличие компиляторов (интерпретаторов) на атакуемой машине значительно упрощает взлом, поскольку, во-первых, усиливает переносимость эксплоитов, во-вторых, позволяет автоматизировать атаку, и, в-третьих, предоставляет доступ к функциям и сервисам недоступным из командной оболочки.
Операционные системы семейства NT, укомплектованные более чем скромным набором утилит, в этом отношении выглядят более защищенными. Впрочем, это непринципиальное различие: грамотный администратор и так удалит из UNIX все лишнее.
Механизмы аутентификации пользователей (то есть, попросту говоря алгоритмы проверки правильности пароля) и в UNIX, и в NT построены на практически идентичных принципах. А именно: эталонный пароль вообще нигде не хранится, - вместо этого используется его хэш (грубо говоря: контрольная сумма). Пользователь вводит пароль, операционная система хэширует его по тому или иному алгоритму и сравнивает полученный результат с хэш-суммой эталонного пароля, хранящейся в специальной базе паролей. Если они совпадают, то все ОК и, соответственно, наоборот. Такая схема (при отсутствии ошибок реализации, конечно) гарантирует, что даже если злоумышленник и получит доступ к базе паролей, он все равно не сможет проникнуть в систему иначе, чем методом перебора. Впрочем, если спуститься с небес идеализированных математических концепций на грешную землю, можно обнаружить, что "нормальные герои всегда идут в обход". В частности, в большинстве UNIX'ов вводимый пароль открытым текстом передается по сети и при наличии хотя бы одного уязвимого узла в цепочке передачи, может быть перехвачен хакером. В NT же открытый пароль никогда не передается (ну, разве что администратор не настроит ее соответствующим образом) и используемая в ней схема аутентификации устойчива к перехвату трафика.
С другой стороны, NT крайне небрежно относится к охране парольной базы от посягательств хакеров. На первый взгляд кажется, что никакой проблемы вообще нет, т. к. доступ к базе имеется лишь у системы, администраторов и ограниченного количества специально назначенных администратором пользователей (например, операторов архива, периодически сохраняющих базу на резервных носителях). А вот в некоторых, правда, довольно немногочисленных UNIX'ах файл паролей свободно доступен всем пользователям системы и зачастую даже "виден" по сети! Ну и что с того? - спросите вы. - Ведь паролей в парольном файле все равно нет, а "обращение" хеша методом перебора занимает слишком много времени, пускай хакер перебирает, если ему это занятие так нравится. Хорошо, тогда такой вопрос: возможно ли в одном единственном переборе взломать все машины в сети? Не спешите отвечать "нет", ибо правильный ответ: "да"! Объем жестких дисков сегодня возрос настолько, что хакер может сохранить хеши всех перебираемых паролей. Неважно сколько это займет времени: месяц или даже несколько лет, - ведь теперь у взломщика появится возможность практически мгновенно восстановить пароль по его хешу - была бы только парольная база в руках! Мало того, что в NT резервные копии парольной базы по умолчанию хранятся в общедоступных каталогах, так алгоритм аутентификации не использует привязки (salt), в результате чего хеши одинаковых паролей в NT всегда будет совпадать, значительно упрощая тем самым взлом! Впрочем, от атак данного типа привязка все равно не спасает, разве что немного продляет "мучения" системы.
Процессы должны иметь возможность обмениваться данными, - это бесспорно, в противном случае такая система не будет никому нужна. С другой стороны, наличие каких бы то ни было средств межпроцессорного взаимодействия потенциально позволяет атакующему пагубно воздействовать на чужой процесс, причиняя его владельцу те или иные неприятности. Например, напрягать жертву посылкой больших объемов бессмысленных данных, которые та категорически не хочет принимать. Следовательно, каждый из взаимодействующих процессов должен иметь возможность:
а) самостоятельно решать с кем ему взаимодействовать, а с кем нет;
б) уметь определять подлинность процессов отправителей и процессов получателей;
в) контролировать целостность передаваемых/принимаемый данных;
г) создавать защищенный канал связи, устойчивый к перехвату трафика.
Многообразие средств межпроцессорного взаимодействия, поддерживаемых современными операционными системами, чрезвычайно затрудняет ответ на вопрос: а выполняются ли перечисленные выше требования на практике? Ограниченные объемом журнальной статьи мы рассмотрим лишь два наиболее популярных средства межпроцессорного взаимодействия: каналы,сокеты и сообщения.
Неименованные каналы позволяют связывать лишь родственные процессы и потому полностью отвечают условию пункта а). Даже если посторонний процесс каким-либо образом ухитриться получить дескриптор неименованного канала не родственного ему процесса, то он (дескриптор) вне контекста своего процесса потеряет всякий смыл и ничего пакостного с ним злоумышленник не сможет сделать. Если же злоумышленник проникнет в родственный процесс и попытается, скажем, облить своего соседа толстой струей информационного мусора, то. ничего не произойдет. Если процесс-читатель не будет успевать "заглатывать" посылаемые ему данные, система автоматически приостановит процесс передачи, не давая атакуемому процессу "захлебнуться". Причем, жертва вольна сама решать - выносить ли ей такие издевательства дальше или же просто закрыть канал и послать невоспитанного хакера куда подальше.
По определению, данному Ильей Медведовским атака на компьютерную систему - это действие, предпринимаемое злоумышленником, которое заключается в поиске и использовании той или иной уязвимости. Существует множество разнообразных методик поиска уязвимостей, но ведь мы договорились не останавливаться на конкретных реализациях, верно? Вот и давайте разделим все методики на две полярные категории слепого и целенаправленного поиска.
Слепые методики рассматривают защитный механизм как черный язык с входом и выходом. Методично перебирая всевозможные входные значения злоумышленник пытается выявить такие из них, которые бы нарушали нормальную работу защитного механизма или в той или иной степени ослабляли степень защиты. Эта чрезвычайно простая и интеллектуально непритязательная стратегия взлома весьма популярна в кругах начинающих хакеров, начитавшихся дешевой фантастики и свято уверовавших в свою исключительность. Впрочем, после .дцатой по счету попытки взлома терпение "хакера" кончается и вся эйфория внезапно проходит. Конечно, время от времени некоторым особо везучим счастливчикам все-таки удается проникнуть то в одну, то в другую защищенную систему, но особой опасности такие атаки не представляют в силу свой малочисленности.
Действительно, защитный механизм, принцип действия которого неизвестен, может быть взломан только грубой силой, то есть имеет вполне предсказуемую степень защищенности. Поэтому, любая мало-мальски серьезная акция начинается с изучения атакуемого объекта (целенаправленный взлом). Отсюда: при прочих равных условиях степень защищенности системы обратно пропорционально легкости анализа ее кода. А легкость самого анализа в первую очередь определяется доступностью исходных текстов защитного механизма!
Большинство UNIX'ов поставляются вместе с исходными текстами, в то время как исходные тексты NT недоступны, а анализ дизассемблерных листингов не только чрезвычайно трудоемок и утомителен сам по себе, но еще и требует изрядной профессиональной подготовки, которая есть далеко не у всех. К тому же подсистема защиты NT много сложнее аналогичной подсистемы большинства UNIX'ов и весьма поверхностно документирована, чем и отпугивает многих потенциальных злоумышленников.
Как следствие: количество дыр, обнаруженных в NT за все время ее существования, можно свободно пересчитать по пальцам одной руки (причем, большая часть из них была обнаружена практически случайно). В UNIX же, напротив, дыры обнаруживаются постоянно. С другой стороны..
Модель привилегий пользователей и механизмы контроля прав доступа, - ключевое и вместе с тем наиболее уязвимое (по статистике) звено подсистемы безопасности любой многопользовательской ОС. В общем случае к ней предъявляются следующие требования:
а) модель пользователей должна быть достаточно гибкой, удобной и интуитивно понятной, в противном же случае ошибки администрирования - неизбежны;
б) механизмы контроля прав доступа должны не только гарантировать невозможность не санкционирования повышения уровня своих привилегий, но и быть максимально устойчивыми к программистским ошибкам;
в) и сама система, и работающие в ней пользователи должны обходится минимально необходимым уровнем привилегий.
Анализ показывает, что перечисленные выше требования не выполняются ни в одной ОС массового назначения, а потому все они в той или иной степени заведомо уязвимы. Между тем, степень защищенности UNIX и NT различна.
Модель привилегий пользователей, применяемая в большинстве UNIX, является одноуровневой и допускает существование только двух типов пользователей: обычные пользователи и суперпользователь (он же root или администратор). В NT же, напротив, используется иерархическая схема, причем, помимо root'а в ней имеется еще один суперпользователь, - система. Что это означает? А то, что в NT, в отличии от UNIX, каждый пользователь получает минимум необходимых ему прав и никогда не повышает уровень своих привилегий без особой необходимости. Широко распространенное заблуждение гласит, что правильное администрирование UNIX позволяет добиться такого же точно распределения прав доступа, как и в NT, пускай и ценой большего времени и усилий. На самом же деле это не так.
Отсутствие системного пользователя в UNIX приводит к невозможности выполнения целого ряда действий иначе, чем временным повышением привилегий запущенной программы до root'a. Взять хотя бы классическую задачу смены пароля. Пользователи могут (и должны!) периодически менять свои пароли. Но ведь в UNIX (как впрочем и в NT) пароли всех пользователей хранятся в одном файле, причем, используемая модель привилегий не позволяет назначать различным частям файла различные права доступа.
Но ведь должен пользователь как- то изменять свой пароль, верно? В UNIX эта задача решается так: утилите, ответственной за смену пароля, присваивается специальный атрибут, позволяющий ей при необходимости получать права root'а, что она, собственно, и делает. Если бы этот механизм использовался только при операциях с паролями большой беды и не было бы. На самом же деле, такой атрибут необходим очень большому количеству приложений, в частности WEB и e-mail серверам. Задумайтесь, что произойдет, если в одной из программ, исполняющихся с наивысшими привилегиями, обнаружится ошибка, так или иначе приводящая к возможности передачи управления хакерскому коду? А ведь такие ошибки сыплются из UNIX'ых программ как из рога изобилия!
Совершенно иная ситуация складывается в среде NT. Непривилегированные пользователи только в исключительных случаях вынуждены повышать свои права до уровня администратора, а все остальное время они пользуются API-функциями операционной системы, выполняющими потенциально опасные действия "руками" самой ОС. Даже если в одном из таких приложений будет допущена ошибка и хакер захватит управление, - он унаследует минимум прав и причинит система минимум вреда.
Таким образом, NT устойчива к программистским ошибкам, а UNIX чрезвычайно чувствительна к ним.
Так какая же система надежнее? В идеале, конечно, следовало бы присвоить каждой характеристике свой "вес" и посчитать "очки" обоих систем. Поскольку, "весомость" понятие субъективное, нам ничего не стоит настроить измерительную шкалу так, чтобы более надежной оказалась наша любимая система, причем, такая подтасовка может происходить и подсознательно, а потому в свободной таблице, приведенной ниже, никакие весовые категории вообще не используются.
Не стоит так же забывать, что оценка безопасности системы весьма чувствительна к количеству и роду сравниваемых характеристик. Исключая одни или добавляя другие мы можем значительно изменить конечный результат. Так что не стоит считать наше сравнение истинной в последней инстанции.
Одно из концептуальных отличий философии NT от UNIX заключается в том, что UNIX не делает практически никаких различий между локальным и удаленным доступом к машине. В NT же, напротив, лишь некоторые действия могут быть выполнены удаленно, а для полноценного управления сервером администратор вынужден прибегать к физическому доступу.
Никто не спорит - удаленно управлять сервером очень удобно, но давайте задумаемся - насколько это безопасно? Увы, никакое удобство не проходит даром! Что комфортно администрировать, то комфортно и атаковать! Этому, кстати, будут способность и продвинутые командные интерпретаторы, поддерживающие полноценные языки программирования, разительно отличающие от того уродства, что переваривает примитивная оболочка NT. Вообще же, в NT удаленным доступом очень мало что можно сделать (правда, начиная с Windows 2000 в ней все-таки появилось более или менее совершенные механизмы удаленного управления).
Тем не менее не стоит впадать в крайности и полностью отказываться от возможности удаленного администрирования. Конечно, полностью запретив удаленный доступ вы в значительной степени усилите защищенность своего сервера, но. при этом будете вынуждены постоянно находится непосредственно рядом с сервером. Спрашиваете: зачем? А кто хакеров будет гонять?! Ведь проникнуть на атакуемую машину можно через любой, установленный на ней сервис (скажем, WEB) и потому крайне нежелательно лишать себя всех средств дистанционного мониторинга и управления сервером.
Словом, удаленное управление - палка о двух концах, одновременно и ослабляющая защищенность узла, но и усиливая оперативность выявления и нейтрализации злоумышленников. С другой стороны, в ответственных случаях, от удаленного управления все же лучше совсем отказаться, заменив его прикованным к серверу оператором.
Переполнение буфера - наиболее "популярная" и в то же время наиболее коварная ошибка, которой не избежало практически ни одно сколь ни будь сложное приложение. Коротко объясним ее суть: если размера выделенного программистом буфера вдруг окажется недостаточно для вмещения всех, копируемых в него данных, то содержимое памяти за концом буфера окажется разрушено (а точнее - замещено) не вместившимися в буфер данными. В зависимости от ситуации за концом буфера могут находится:
а) другие буфера и переменные программы;
б) служебные данные - в частности, адрес возврата из функции;
в) исполняемый код;
г) незанятая или д) отсутствующая страница памяти.
Наибольшую опасность представляют пункты б) и в) так как они чреваты возможностью полного захвата контроля над уязвимой программой. Пункт д) менее коварен и в худшем случае приводит к возможности реализации атаки отказа в обслуживании (при обращении к отсутствующей странице памяти процессор выбрасывает исключение, приводящее к аварийному завершению уязвимого приложения). Угроза от пункта а) в значительной степени зависит от рода и назначения переменных, находящихся за концом переполняющегося буфера и хотя теоретически уязвимое приложение способно на что угодно на практике угроза оказывается не столь уж и велика.
Есть еще одно обстоятельство, - для полноценного захвата управления хакер должен иметь возможность исполнять на удаленной машине собственный код, обычно передаваемый непосредственно через сам переполняющийся буфер. В зависимости от расположения уязвимого буфера и "характера" операционной системы, исполнение переданного хакером кода может быть как разрешено, так и нет.
Все системы: и UNIX, и NT потенциально допускают существование пунктов а), б), г) и д), исключая лишь единственный из них - пункт в). Следовательно, они в равной мере подвержены угрозе переполнения буфера. Кроме того, и UNIX, и NT имеют исполняемый стек (то есть разрешают выполнение кода в стеке) и запрещают его выполнение в сегменте данных. А это значит, что переполнение буферов, содержащихся в автоматических (т.е. стековых) переменных несет в себе угрозу полного захвата управления над уязвимой программой. Правда, для некоторых UNIX существуют заплаты, отнимающие у стека право выполнения, но сфера их применения весьма ограничена (исполняемый стек необходим множеству вполне легальных программ, в частности, компиляторов).
Самое забавное, что и UNIX, и NT написаны на Си - языке программирования, не поддерживающим автоматический контроль границ массива и потому подверженному ошибкам переполнения. Старожилы говорят, что в некоторых версиях UNIX ошибка переполнения присутствовала даже на вводе имени пользователя при регистрации в системе.
качество и полнота документирования |
документирована поверхностно |
документирована весьма обстоятельно |
доступность исходных текстов |
исходные тексты недоступны |
исходные тексты доступны |
сложность анализа |
высокая |
умеренная |
распространенность |
существует весьма ограниченное количество представителей NT, причем наблюдается ярко выраженная преемственность дыр от одних версий системы к другим |
существует огромное количество разнообразных клонов, причем ошибки одной версии системы зачастую отсутствуют в остальных |
сложность кода |
код излишне сложен |
код предельно прост |
поддержка удаленного администрирования |
частично поддерживает |
поддерживает |
комплектность штатной поставки |
содержит минимум необходимых приложений |
содержит огромное количество приложений, в том числе и не протестированных |
механизмы аутентификации |
устойчив к перехвату паролей |
передает открытый пароль |
использование привязки |
не использует |
использует |
выполнение привилегированных операций |
выполняется операционной системой |
выполняется самим приложением со временным повышением привилегий |
модель пользователей |
иерархическая |
одноуровневая |
защита от переполнения буфера |
отсутствует, причем сама ОС написана на языке провоцирующим такие ошибки |
отсутствует, причем сама ОС написана на языке провоцирующим такие ошибки |
возможность доступа в адресное пространство чужого процесса |
имеется, разрешена по умолчанию |
отсутствует |
возможность отладки процессов |
имеется, разрешена по умолчанию |
имеется, но связана с рядом ограничений |
возможность отладки активных процессов |
имеется, но требует наличия соответствующих привилегий |
отсутствует |
удаленный доступ к именованным каналам |
есть |
нет |
создание подложных именованных каналов |
есть, можно создать и канал, и даже подложный экземпляр уже открытого канала |
есть, можно создать лишь подложный канал |
защита именованных каналов от нежелательных подключений |
отсутствует |
отсутствует |
защита сокетов от нежелательных подключений |
отсутствует |
отсутствует |
возможность эмуляции ввода в более привилегированный процесс |
имеется |
отсутствует |
Сложность отладки и тестирования компьютерных программ стремительно растет с увеличением их сложности. И, начиная с некоторого уровня, затраты на тщательное "вылизывание" программы начинают перевешивать совокупный доход от ее продаж, вынуждая разработчиков ограничиться лишь поверхностным тестированием (если программа не зависла во время запуска - это уже хорошо).
Современные операционные системы давным-давно перешагнули через этот рубеж и никакая из них не застрахована от ошибок. С вероятностью близкой к единице можно утверждать, что критические ошибки присутствуют в любой ОС общего назначения, и потому любой узел в сети может быть гарантированно взломан, это всего лишь вопрос времени и усилий.
Между тем, ошибки крайне неоднородны по своей природе: одни лежат, что называется на поверхности, и обнаруживаются даже автоматизированными средствами контроля качества кода; другие же, напротив, зарыты так глубоко, что найти их можно только случайно. Фундаментальная проблема отладки заключается в том, что любая, даже самая незначительная модификация программного кода, чревата появлением каскада ошибок, возникающих в самых неожиданных местах. И потому, внесение каких бы то ни было изменений во внутренности операционной системы и/или сопутствующих ей приложений должно сопровождаться полным циклом повторного тестирования. Но ведь полное тестирование, как уже было показало выше, выполнить просто невозможно!
Чрезмерная сложность NT вкупе с огромным количеством изменений, вносимых в код каждой новой версии, собственно и объясняют скверное качество ее тестирования. Несмотря на все усилия, предпринимаемые Microsoft, уязвимость NT заложена уже в самой политике ее развития, а потому является принципиально неустранимой, т.е. фундаментальной.
Большинство UNIX'ов напротив, довольно компактны и содержат минимум необходимых для функционирования системы компонентов (или, во всяком случае, позволяют урезать себя до такого состояния). К тому же их медленное, эволюционное (а не революционное как у NT) развитие отнюдь не способствует появлению грубых, легко обнаруживаемых ошибок, которыми так славится NT.
Алгоритм обфускации в большинстве случаев рассматривается как алгоритм, которого должен придерживаться обфускатор (независимая программа, которая осуществляет процесс обфускации над переданным ей кодом).
На данный момент существуют различные алгоритмы осуществления процесса обфускации, начиная от общих (абстрактных) алгоритмов процесса обфускации и заканчивая более продвинутыми. Эти алгоритмы создавались в соответствии с возможностями того или иного языка программирования, и на сегодня большинство из них адаптировано непосредственно под языки программирования высокого уровня. Ниже представлено короткое описание некоторых из них.
Алгоритм Колберга ("Collberg`s algorithm").
Данный алгоритм оперирует следующими входными значениями:
программа "А" состоящая из исходных или объектных (двоичных) файлов "{С1,С2}". стандартные библиотеки, используемые программой "{L1,L2}". набор трансформирующих процессов "Т{Т1,Т2}". определенный фрагмент кода "S", который извлекается из программы "А", и который непосредственно будет подвержен трансформации. набор функций "Е{Е1,Е2}" которые будут определять эффективность применения определенных трансформирующих процессов "{Т1,Т2}" к фрагменту кода "S". набор функций "I{I1,I2}" которые будут определять важность фрагмента кода "S", и в зависимости от этого будут задавать определенное значение переменной "RequireObfuscation" (чем "S" важнее тем эта переменная будет хранить большее значение). две числовые переменные "AcceptCost" > 0, "RequireObfuscation" > 0, где первое хранит информацию о доступном максимальном увеличении системных ресурсов по требующихся программе "А" после того как она подвергнется обфускации, а вторая переменная будет хранить значение требуемого уровня осуществления обфускации (чем важнее фрагмент кода "S", тем это значение должно быть больше).
Быстрое развитие мультимедиа и Интернет технологий в последние годы вызывает потребность в защите такой интеллектуальной собственности, как программные продукты (ПП).
Разработка наиболее эффективного метода защиты для того или иного программного продукта, в нынешнее время, становиться одной из важных задач большинства программистов, которые занимаются разработкой специализированного, платного программного обеспечения (ПО), так как это позволяет им продавать свой интеллектуальный труд, и исключить возможности его нелегального использования среди потребителей, говоря иными словами, пользователь не сможет использовать оригинальную, лицензионную копию определенной программы предварительно не купив, не заплатив денег её разработчику.
Затраты производителей на создание эффективного метода защиты их программных продуктов окупаются и компенсируют потенциальный ущерб, наносимый нелегальным копированием и использованием программ.
Существуют два основных способа защиты интеллектуальной собственности, и следовательно, самих программных продуктов:
1) Юридический (законный). Данный способ защиты заключается в создании определенных актов, в соответствии с законом, которые будут охранять интеллектуальную собственность (в нашем случае программные продукты) от нелегального использования. Данный способ включает в себя такие методы как патентование, оформление авторских прав на интеллектуальную собственность и т.д. Также он предусматривает возможность лицензирования ПП, так, например большинство ПП поставляются вместе с лицензией, которая подтверждает право пользователя использовать этот ПП, то есть, покупая лицензионную копию программы, пользователь в некой мере производит покупку лицензии на право работы с ее копией. Можно выделить два основных вида лицензий на программные продукты:
Временная. Позволяет использовать ПП неограниченному числу пользователей в течение ограниченного периода времени. Оптимальная. Позволяет использовать ПП ограниченному числу пользователей в течение неограниченного периода времени.
2) Технический. Реализуется путем включения в ПП, какого либо из существующих методов защиты, который будет запрещать его нелегальное использование. По сравнению с юридическим способом защиты ПП, он является наиболее распространенным, так как он практичен, и сравнительно не дорогой в реализации (в дальнейшем, будет приводиться именно его описание).
Ниже приводится поверхностное описание наиболее распространенных на данный момент методов защиты ПП.
Наиболее простая, заключается в форматировании кода программы, изменении его структуры, таким образом, чтобы он стал нечитабельным, менее информативным, и трудным для изучения.
Обфускация такого вида включает в себя:
удаление всех комментариев в коде программы, или изменение их на дезинформирующие удаление различных пробелов, отступов которые обычно используют для лучшего визуального восприятия кода программы замену имен идентификаторов (имен переменных, массивов, структур, хешей, функций, процедур и т.д.), на произвольные длинные наборы символов, которые трудно воспринимать человеку добавление различных лишних (мусорных) операций изменение расположения блоков (функций, процедур) программы, таким образом, чтобы это не коим образом не повлияло на ее работоспособность.
Изменение глобальных имён идентификаторов следует производить в каждой единице трансляции (один файл исходного кода), так чтобы они имели одинаковые имена (в противном случае защищаемая программа может стать не функциональной). Также следует учитывать специфические идентификаторы, принятые в том языке программирования, на котором написана защищаемая программа, имена таких идентификаторов, лучше не изменять, например, в PERL-е к таким идентификаторам можно отнести "@ARGV", "$_", "$^O" и т.д.
Ниже представлен пример фрагмента исходного кода программы (написанной на Perl), до и после прохождения лексической обфускации.
До лексической обфускации:
my $filter;
if (@pod) { my ($buffd, $buffer) = File::Temp::tempfile(UNLINK => 1); print $buffd ""; print $buffd @pod or die ""; print $buffd close $buffd or die ""; @found = $buffer; $filter = 1; } exit;
sub is_tainted { my $arg = shift; my $nada = substr($arg, 0, 0); # zero-length local $@; # preserve caller's version eval { eval "#" }; return length($@) != 0; }
sub am_taint_checking { my($k,$v) = each %ENV; return is_tainted($v); }
После лексической обфускации:
sub z109276e1f2 { ( my $z4fe8df46b1 = shift ( @_ ) ) ; ( my $zf6f94df7a7 = substr ( $z4fe8df46b1 , (0x1eb9+ 765-0x21b6) , (0x0849+ 1465-0x0e02) ) ) ; local $@ ; eval { eval ( ( "" ) ) ; } ; return ( ( length ( $@ ) != (0x26d2+ 59-0x270d) ) ) ; } my ( $z9e5935eea4 ) ; if ( @z6a703c020a ) { ( my ( $z5a5fa8125d , $zcc158ad3e0 ) = File::Temp::tempfile ( "" , (0x196a+ 130-0x19eb) ) ) ; print ( $z5a5fa8125d "" ) ; ( print ( $z5a5fa8125d @z6a703c020a ) or die ( ( ( ( "" . $zcc158ad3e0 ) . "\x3a\x20" ) . $! ) ) ) ; print ( $z5a5fa8125d "" ) ; ( close ( $z5a5fa8125d ) or die ( ( ( ( "" ) ) ) ; ( @z8374cc586e = $zcc158ad3e0 ) ; ( $z9e5935eea4 = (0x1209+ 1039-0x1617) ) ; } exit ; sub z021c43d5f3 { ( my ( $z0f1649f7b5 , $z9e1f91fa38 ) = each ( %ENV ) ) ; return ( z109276e1f2 ( $z9e1f91fa38 ) ) ; }
Данная обфускация программного кода, по сравнению с остальными, позволяет сравнительно быстро привести исходный код программы, в нечитабельное состояние. Один из ее недостатков состоит в том, что она эффективна только для осуществления высокоуровневой обфускации.
Такая обфускация связана с трансформацией структур данных. Она считается более сложной, и является наиболее продвинутой и часто используемой. Ее принято делить на три основные группы, которые описаны ниже.
Обфускация хранения. Заключается в трансформации хранилищ данных, а также самих типов данных (например, создание и использование необычных типов данных, изменение представления существующих и т.д.). Ниже приведены основные методы, позволяющие осуществить такую обфускацию:
изменение интерпретации данных определенного типа. Как известно сохранение, каких либо данных в хранилищах (переменных, массивах и т.д.) определенного типа (целое число, символ) в процессе работы программы, очень распространенное явление. Например, для перемещения по элементам массива очень часто используют переменную типа "целое число", которая выступает в роли индекса. Использование в данном случае переменных иного типа возможно, но это будет не тривиально и может быть менее эффективно. Интерпретация комбинаций разрядов содержащихся в хранилище данных осуществляется в зависимости от его типа. Так, например, можно сказать, что 16-разрядная переменная целого типа содержащая комбинации разрядов 0000000000001100 представляет целое число 12, но это простое соглашение, данные в такой переменной можно интерпретировать по-разному (не обязательно как 12, а, например как 1100 и т.д.).
изменение срока использования хранилищ данных, например переход от локального их использования к глобальному и наоборот. В качестве примера можно привести две различные функции (язык PERL): sub func1 { ... $a ... ; } sub func2 { ... $b ... ; }
если эти две функции не могут выполняться в процессе программы одновременно, значит, для них может быть создана одна глобальная переменная, которая будет замещать переменные $a,$b, например: $AB = 0 ; sub func1 { ... $AB ... ; } sub func2 { ... $AB ... ; }
преобразование статических (неменяющихся) данных в процедурные. Большинство программ, в процессе работы, выводят различную информацию, которая чаще всего в коде программы представляется в виде статических данных таких как строки, которые позволяют визуально ориентироваться в ее коде и определять выполняемые операции.
Такие строки также желательно предать обфускации, это можно сделать, просто записывая каждый символ строки, используя его ASCII код, например символ "A" можно записать как 16-ричное число "0х41", но такой метод банален. Наиболее эффективный метод, это когда в код программы в процессе осуществления обфусации добавляется функция, генерирующая требуемую строку в соответствии с переданными ей аргументами, после этого строки в этом коде удаляются, и на их место записывается вызов этой функции с соответствующими аргументами. Например, фрагмент кода (написанный на PERL): print "LOL\n" ; $var = "101" ; после обфускации, будет похож на что-то вроде: sub string { my ($i) = @_ ; my $k = 0 ; $str = "" ; while (1) { l1: if ($i == 1) {$str .= "L";$k = 0;goto l7;} l2: if ($i == 4) {$str .= "S";$k = 0;goto l7;} l3: if ($i == 3) {$str .= "1";$k = -1;goto l7;} l4: if ($i == 4) {$str .= "m";$k = 3;goto l7;} l5: return $str; l6: if ($k == 0) {$str .= "1";$k += 2;goto l5;} else {$str .= "L";$k -= 1;goto l5;} l7: if ($k < 1) {$str .= "0";$k++;goto l6;} } } ...
print string(1)."\n" ; $var = string(3) ;
Также к статическим данным относятся числовые константы, которые могут быть также трансформированы, например число 1 можно представить как: (a + 1 - b), где a = b;
разделение переменных. Переменные фиксированного диапазона могут быть разделены на две и более переменных. Для этого переменную "V" имеющую тип "x" разделяют на "k" переменных "v1,...,vk" типа "y" то есть "V == v1,...,vk". Потом создается набор функций позволяющих извлекать переменную типа "x" из переменных типа "y" и записывать переменную типа "x" в переменные типа "y". В качестве примера разделения переменных, можно рассмотреть способ представления одной переменной "B" логического типа (boolean) двумя переменными "b1, b2" типа короткого целого (short), значение которых будет интерпретироваться таким образом:
B | b1 | b2 ---------------- false | 0 | 0 true | 0 | 1 true | 1 | 0 false | 1 | 1
Тогда такой фрагмент кода (написан на С++):
bool B ; B = false ; if (B) {...}
будет представлен так:
short b1, b2 ; b1 = b2 = 1 ; // или b1 = b2 = 0 if (!(b1 & b2)) {...}
изменение представления (или кодирование). Например, целочисленную переменную "i", в ниже представленном фрагменте кода (написанном на С):
... int i = 1; ... while (i < 1000) { ... A[i] ... i++ ; }
можно заменить, выражением "i` = c1*i + c2" где "c1,c2" являются константами, в результате, фрагмент выше приведенного кода измениться и будет сложен для восприятия:
... int i = 11; int c1 = 8, c2 = 3 ; ... while (i < 8003) { ... A[(i - 3)/8] ... i += 8 ; }
Обфускация соединения. Один из важных этапов, в процессе реверсивной инженерии программ, основан на изучении структур данных. Поэтому важно постараться, в процессе обфускации, усложнить представление используемых программой структур данных. Например, при использовании обфускации соединения это достигается благодаря соединению независимых данных, или разделению зависимых. Ниже приведены основные методы, позволяющие осуществить такую обфускацию:
объединение переменных. Две или более переменных "v1,...,vk" могут быть объединены в одну переменную "V", если их общий размер ("v1,...,vk") не превышает размер переменной "V". Например, рассмотрим простой пример объединения двух коротких целочисленных переменных "X","Y" (размером 16 бит) в одну целочисленную переменную "Z" (размером 32 бита). Для этого воспользуемся формулой Z(X,Y) = 2^16 * Y + X
которая позволит, пренебрегая сложением, определять значение Y, т.е. пусть X = = 12, Y = 4 => Z = 65536 * 4 + 12 = 262156, теперь зная "Z" для нахождения "Y" можно 262156 / 65536 = 4.000183105 или приблизительно 4. При осуществлении арифметических операций над значениями переменных "X", "Y" хранящихся в "Z" нужно учитывать выше приведенную формулу, т.е.: Z(X+n,Y) = 2^16 * Y + (X + n) = Z(X,Y) + n ; Z(X,Y-n) = 2^16 * (Y - n) + X = 2^16 * Y - 2^16 * n + X = = Z(X,Y) - 2^16 * n ; и т.д.
В результате код до обфускации (язык Си):
short X = 12, Y = 4 ; X += 5 ;
трансформируется в:
int Z = 262156 ; Z += 5 ;
реструктурирование массивов, заключается в запутывании структуры массивов, путем разделения одного массива на несколько подмассивов, объединения нескольких массивов в один, сворачивания массива (увеличивая его размерность) и наоборот, разворачивая (уменьшая его размерность). Например, один массив "@A" можно разделить на несколько подмассивов "@A1, @A2", при этом один массив "@A1" будет содержать четные позиции элементов, а второй "@A2" нечетные позиции элементов массива "@A". Поэтому такой фрагмент кода (PERL):
@A = qw{a b c d e f} ; $i = 3 ; $A[$i] = ... ;
можно заменить на:
@A1 = qw{2 4 0} ; @A2 = qw{1 3 5} ; $i = 3 ; if (($i % 2) == 0) { $A1[$i / 2] = ... ; } else { $A2[$i / 2] = ... ; }
Под сворачиванием массива понимается создание из одномерного массива, двумерного. Например, одномерный массив "A" из предыдущего примера, имеющий размер 5 можно заменить двумерным массивом "B" размером 2, после чего код (язык С++):
int A[] = {1, 2, 3, 4, 5, 6} ; for (int i = 0 ; i < 6 ; i++) { A[i] = A[i] + 1 ; printf("%d\n", A[i]) ; }
можно изменить на:
int A[2][3] = {{1,2,3}, {4,5,6}} ; for (int i = 0 ; i < 2 ; i++) { for (int ii = 0 ; ii < 3 ; ii++) { A[i][ii] = A[i][ii] + 1 ; printf("%d\n", A[i][ii]) ; } }
изменение иерархий наследования классов, осуществляется путем усложнения иерархии наследования при помощи создания дополнительных классов или использования ложного разделения классов.
Обфускация переупорядочивания. Заключается в изменении последовательности объявления переменных, внутреннего расположения хранилищ данных, а также переупорядочивании методов, массивов (использование нетривиального представления многомерных массивов), определенных полей в структурах и т.д.
/close your eyes & dream with me/
07.10.2004
Содержание:
5.1
5.2
5.3
5.4
- When _I_ use a word, - Humpty Dumpty said in
rather a scornful tone, - it means just what I
choose it to mean - neither more nor less.
В большинстве случаев для обхода защиты, взломщику требуется изучить принцип работы ее кода, и то, как она взаимодействует с самой защищаемой программой, этот процесс изучения называется процессом реверсивной (обратной) инженерии. Этот процесс часто зависит от свойств человеческой психики, поэтому использование этих свойств позволяет снизить эффективность самого процесса реверсивной инженерии.
Обфускация ("obfuscation" - запутывание), это один из методов защиты программного кода, который позволяет усложнить процесс реверсивной инженерии кода защищаемого программного продукта.
Обфускация может применяться не только для защиты ПП, она имеет более широкое применение, например она, может быть использована создателями вирусов, для защиты их творений и т.д.
Суть процесса обфускации заключается в том, чтобы запутать программный код и устранить большинство логических связей в нем, то есть трансформировать его так, чтобы он был очень труден для изучения и модификации посторонними лицами (будь то взломщики, или программисты которые собираются узнать уникальный алгоритм работы защищаемой программы).
Из этого следует, что обфускация одна не предназначена для обеспечения наиболее полной и эффективной защиты программных продуктов, так как она не предоставляет возможности предотвращения нелегального использования программного продукта. Поэтому обфускацию обычно используют вместе с одним из существующих методов защиты (шифрование программного кода и т.д.), это позволяет значительно повысить уровень защиты ПП в целом (, "Т1,Т2,...,Tn" - процессы обфускации).
Процесс обфускации как метод зашиты, можно считать сравнительно новым (первые статьи, посвященные обфускации, как методу защиты кода программных продуктов, появились примерно три-четыре года назад), и перспективным.
Обфускация соответствует принципу экономической целесообразности, так как ее использование не сильно, увеличивает стоимость программного продукта, и позволяет при этом снизить потери от пиратства, и уменьшить возможность плагиата в результате кражи уникального алгоритма работы защищаемого программного продукта.
Обфускация такого вида осуществляет запутывание потока управления, то есть последовательности выполнения программного кода.
Большинство ее реализаций основывается на использовании непрозрачных предикат, в качестве, которых выступают, последовательности операций, результат работы которых сложно определить (само понятие "предикат" выражает свойство одного объекта (аргумента), или отношения между несколькими объектами).
Определение. Предикат "Р" считается непрозрачным предикатом, если его результат известен только в процессе обфускации, то есть после осуществления процесса обфускации, определение значения такого предиката, становится трудным.
Обозначим непрозрачный предикат, возвращающий всегда значение TRUE как "Р(t)", а возвращающий значение FALSE, как "Р(f)", тогда непрозрачный предикат, который может возвратить любое из этих двух значений (то есть или TRUE, или FALSE, что нам неизвестно) как "Р(t,f)". Эти обозначения, будут использоваться дальше в контексте описания обфускации управления. Непрозрачные предикаты могут быть:
локальными - вычисления содержаться внутри одиночного выражения (условия), например (запись "(f)" после условия проверки, указывает, что это предикат типа "P(f)"):
if (($a * $b) == (101-303))(f) {...} глобальными - вычисления содержаться внутри одной процедуры (функции), например (PERL): sub func { $ab=$a*$b ; ... $val=101-303 ; ... if ($ab == $val)(f) {...} }
межпроцедурными - вычисления содержаться внутри различных процедур (функций): ... $ab ... ; ... $val ... ; sub func1 { $ab=$a*$b; ... } sub func2 { $val=101-303; ... } ... if ($ab == $val)(f) {...} ...
Рассмотрим простые примеры трансформации фрагмента кода программы с помощью непрозрачных предикатов,
На рисунке 0110(1) один блок программы "(A)", разбит (трансформирован) на несколько независимых блоков "(A1; A2)", которые соединены по средствам непрозрачного предиката возвращающего всегда значение TRUE "Р(t)".
В результате трансформации такого рода возникает представление того, что блок "А2" выполняется не всегда, поэтому для того чтобы определить условия выполнения блока "А2", злоумышленнику прежде придется узнать значение, которое возвращает используемый непрозрачный предикат "Р(t)".
На рисунке 0110(2) помимо блока "А2", используется еще один блок "А2" над которым был произведен процесс обфускации (обозначим его как "А2`"), то есть эти два блока ("А2" и "А2`") имеют различный код, но выполняют одинаковые функции, следовательно, можно утверждать, что "А2 = А2`", и поэтому неважно какой из этих блоков будет выполнен в процессе работы программы, из этого следует, что для соединения блока "А1" с "А2" и "А2`" эффективно будет использовать непрозрачный предикат, который может возвратить любое из значений, а именно TRUE или FALSE "Р(t,f)".
И на рисунке 0110(3) используется новый блок "А3", который содержит произвольный набор, каких либо операций (недостижимый код), это может позволить сбить с толку злоумышленника, так как сами блоки "А1" и "А2" соединены по средствам непрозрачного предиката возвращающего всегда значение FALSE "Р(f)".
Существует много методов определения эффективности применения того или иного процесса обфускации, к конкретному программному коду.
Эти методы принято разделять на две группы: аналитические и эмпирические. Аналитические методы основываются на трех величинах характеризующих насколько эффективен тот или иной процесс обфускации:
Устойчивость - указывает на степень сложности осуществления реверсивной инженерии над кодом прошедшим процесс обфускации. Эластичность - указывает на то насколько хорошо данный процесс обфускации, защитит программный код от применения деобфускаторов. Стоимость преобразования - позволяет оценить, насколько больше требуется системных ресурсов для выполнения кода прошедшего процесс обфускации, чем для выполнения оригинального кода программы.
Их наиболее эффективно применять при сравнении различных алгоритмов обфускации, но при этом они не могут дать абсолютного ответа на вопрос насколько эффективно применение того или иного алгоритма, именно к данному программному коду.
Эмпирические же методы могут дать приемлемый ответ на такой вопрос, т.к. они основываются на статистических данных получаемых в результате исследований. Для проведения одного из таких исследований нужна группа людей (как можно лучше знакомых, с реверсивной инженерией), фрагмент кода защищаемой программы, и набор различных алгоритмов обфускации.
Результаты такого исследования будут включать в себя минимальное количество времени, которое потребовалось группе людей, для того чтобы изучить каждый фрагмент кода прошедшего один из алгоритмов обфускации.
Превентивная обфускация предназначена для предотвращения применения злоумышленником деобфускаторов, де компиляторов и остальных программных средств деобфускации.
Она нацелена на использование недостатков, особенностей присутствующих в наиболее распространенных программных средствах часто используемых злоумышленниками в процессе деобфускации.
Когда мы говорим о процессе обфускации, появляется вопрос: есть ли процесс обратный ему, который позволил бы злоумышленнику вернуть наиболее похожий первоначальный код программы, то есть код до обфускации? На этот вопрос трудно дать однозначный ответ, но такой процесс существует и носит он название деобфускация. Но другой не менее важный вопрос, это как его можно реализовать.
С одной стороны к процессу деобфускации можно отнести процесс оптимизации программного кода, так как они оба, в той или иной степени, противоположны процессу обфускации. В процессе обфускации в программный код часто производиться добавление лишних операций, они обычно не коим образом не влияют на результаты работы самой программы, и предназначены для сбития с толку и усложнения процесса изучения кода программы потусторонними (BEYOND:) лицами.
В свою очередь процесс оптимизации программного кода направлен на ликвидацию лишних операций, поэтому в частных случаях он может выступать в качестве квинтэссенции :) процесса деобфускации.
Следует отметить, что большинство компиляторов в процессе компиляции исходного кода, автоматически осуществляют процесс оптимизации, поэтому если обфускация осуществляется над исходным кодом программы (обфускация высокого уровня), возникает определенная вероятность, того, что ее эффективность после, компиляции снизиться. Если же такой исходный код будет обрабатываться интерпретатором (то есть не будет подвержен компиляции), эффективность осуществленного процесса обфускации, не измениться.
К процессу деобфускации, также можно отнести и процесс декомпиляции, который позволяет, имея двоичный код программы получить наиболее схожее исходное представление этого кода на языке высокого уровня, который более понятен человеку, это позволит упростить процесс реверсивной инженерии. (Следует отметить, что осуществление обфускации на низшем уровне, позволяет наиболее полно усложнить возможный процесс декомпиляции программного кода.)
На сегодняшний день существует много материала касающегося как процесса оптимизации, так и процесса декомпиляции, поэтому он может быть использован для начального изучения процесса деобфускации.
Существуют различные определения процесса обфускации. Рассматривая данный процесс с точки зрения защиты ПП, и трансформации кода программы без возможности в последствии вернуться к его первоначальному виду (трансформация "в одну сторону"), можно дать такое определение:
Определение. Пусть "TR" будет трансформирующим процессом, тогда при "PR1 =TR=> PR2" программа "PR2" будет представлять собой трансформированный код программы "PR1". Процесс трансформации "TR" будет считаться процессом обфускации если, будут удовлетворены такие требования:
код программы "PR2" в результате трансформации будет существенно отличаться от кода программы "PR1", но при этом он будет выполнять те же функции что и код программы "PR1", а также будет работоспособным. изучение принципа работы, то есть процесс реверсивной инженерии, программы "PR2" будет более сложным, трудоемким, и будет занимать больше времени, чем программы "PR1". при каждом процессе трансформации одного и того же кода программы "PR1", код программ "PR2" будут различны. создание программы детрансформирующей программу "PR2" в ее наиболее похожий первоначальный вид, будет неэффективно.
Так как код, получаемый после осуществления обфускации, над одной и той же программой, разный то процесс обфускации можно использовать для быстрой локализации нарушителей авторских прав (то есть тех покупателей, которые будут заниматься нелегальным распространением купленных копий программ). Для этого определяют контрольную сумму каждой копии программы прошедшей обфускацию, и записывают ее вместе с информацией о покупателе, в соответствующую базу данных. После этого для определения нарушителя, достаточно будет, определив контрольную сумму нелегальной копии программы, сопоставить ее с информацией хранящейся в базе данных.
Программный код может быть представлен в двоичном виде (последовательность байтов представляющих собой так называемый машинный код, который получается после компиляции исходного кода программы) или исходном виде (текст содержащий последовательность инструкций какого-то языка программирования, который понятен человеку, этот текст в последствии будет подвержен компиляции или интерпретации на компьютере пользователя).
Используется, для того чтобы предотвратить вмешательство в программу, а также усложнить изучение взломщиком того, как устроена программа, как она работает, как в ней реализован метод защиты и т.д.
Данный метод защиты предусматривает зашифровывание кода программы, после чего она в зашифрованном виде поставляется конечным пользователям (иногда эффективно зашифровывать только наиболее важные, критические, участки кода, а не весь код программы). Когда пользователь запускает такую программу, вначале будет запущена процедура расшифровки программы, которой потребуется ключ, с помощью которого будет расшифрована запускаемая программа. См. .
Сам ключ обычно представляет собой последовательность байт (символов), который генерируется в результате определенных (математических) операций.
Он может быть привязан к уникальным характеристикам компьютера пользователя, который приобрел программу и работает с ее лицензионной копией (принцип "одна машина - одна копия"), но такой способ генерации ключа, создает определенные неудобства для конечных пользователей, так как могут возникнуть определенные трудности при использовании такой программы, на другом компьютере.
В последнее время становиться актуально для расшифровки программы использовать электронные ключи, они являются наиболее надежным и эффективным методом защиты дорогостоящих ПП. Он предоставляет высокую стойкость ко взлому и не ограничивает использование легальной копии программы на разных компьютерах.
Электронный ключ представляет собой небольшое устройство, которое подсоединяется к одному из портов компьютера (COM,LPT,USB).
Но все же существует возможности обхода защиты программ зашифрованных с использованием электронных ключей, некоторые из них перечислены ниже:
Изготовление аппаратной копии ключа. Этот метод основывается на считывании содержимого микросхемы памяти ключа, после чего полученные данные переносятся в микросхему другого ключа. Способ этот достаточно трудоемкий и может применяться, если память ключа не защищена от считывания. Изготовление эмулятора ключа. Заключается в создании программы (драйвера), которая эмулирует работу электронного ключа, в результате защищенная программа сможет работать без электронного ключа, для этого перед ее запуском нужно будет всеголиж запустить программу эмулятор.
Способ шифрования программ имеет недостатки, одним из которых является то, что у взломщика есть возможность, после приобретения лицензионной копии программы, произвести извлечение расшифрованных частей программы в процессе ее работы из памяти. Поэтому сразу после исполнения расшифрованного кода его необходимо выгружать из памяти.
В данном случае, в программу помещается процедура проверки целостности самой программы, что позволяет определить была ли программа изменена (были ли внесены какие-то либо изменения в ее код). Если эта процедура обнаруживает, что в программу внесены изменения, она делает программу не функциональной .
Это позволяет защитить программный продукт, от изменений со стороны злоумышленника (применения им крэков). Работа этой процедуры должна быть неприметной для тех, кто будет работать с программой, это позволит сбить с толку неопытных взломщиков. Также ее программная реализация не должна, иметь вид "if (programm_code_original()) { i = 1} else { i = 0}", так как такую процедуру проверки будет легко обойти, например для этого достаточно будет определить место, где она вызывается, и изменить само условие проверки. Процедура проверки должна быть разбита на как можно большее количество этапов, которые будут выполняться в разное время работы самой программы. Если все этапы проверки будут успешно пройдены, тогда можно будет предположить, что программа оригинальна, и не содержит дефектов (изменений). Существуют такие пути проверки целостности программы:
проверка идентичности оригинальной и запускаемой программы. Обычно для этого определяется контрольная сумма запущенной программы, которая потом сверяется с записанной в процедуру проверки, контрольной суммой оригинальной программы. Для осуществления быстрой проверки, используют такие алгоритмы: CRC или MD4/5 (алгоритмы резюмирования сообщений). проверка результатов работы программы. То есть осуществляется проверка выходных значений функций, которые очень чувствительны, к каким либо возможным изменениям в программном коде. создание запускаемой программы на лету, в соответствии с ее оригинальным образом. Это позволяет избежать возможности выполнения изменений внесенных в программу, так как они не будут учитываться при ее создании.
Процессы обфускации можно классифицировать по видам, в зависимости от способа модификации кода программы.
Использование водяных знаков, основывается на записи в код программы скрытой информации (кому принадлежат авторские права и т.д.), которая позволяет истинному автору программы доказать то, что она является именно его интеллектуальной собственностью (но обычно использование водяных знаков не ограничивается только этим).
Такая скрытая информация, обозначим ее "W" (которая и называется водяным знаком), должна быть записана в программу "Р", таким образом, чтобы:
"W" было надежно расположено (запрятано) в "Р", и могло быть впоследствии извлечено, без каких либо изменений (повреждений). "W" не влияло на работу "Р". "W" несло какую-то определенную информацию, которая позволит доказать, то что ее присутствие в "Р" неслучайное, то есть является результатом преднамеренных действий.
Также для увеличения эффективности водяного знака, его можно записать более чем один раз, в разных местах программы.
Отпечаток пальца (software fingerprint) эта иная технология, так как она кроме записи информации, позволяющей доказать интеллектуальное право собственности на программу, требует записи в каждую копию программы уникального идентификационного кода, присваиваемого каждому покупателю программы, что позволяет в последствии быстро отследить нарушителя авторского права, который, например, будет нелегально перепродавать программу (search and destroy them :).
Недостаток этих методов состоит в том, что у злоумышленника может появиться возможность подвергнуть изменению водяной знак или отпечаток пальца.
Данный метод защиты основан на технологии клиент-сервер, он позволяет предотвратить отсылку кода программы пользователям, которые будут с ней работать, так как сама программа храниться, и выполняется на сервере, а пользователи используя клиентскую часть этой программы, получают результаты ее выполнения (рисунок 0000).
Рисунок 0000. Выполнение на стороне сервера
Клиентскую часть можно распространять бесплатно, это позволит пользователям платить только за использование серверной части.
Часто данный метод защиты используется в различных программах-сценариях, которые располагаются на WEB серверах, и выполняют общие операции, например, контролируют работу других программ (front-end), а также передают им, какие либо данные для обработки.
Недостатком данного метода является то, что он устанавливает зависимость пропускной способности сети и тех данных, с которыми будет работать программа (соответственно работа с мультимедиа данными требует наиболее максимальной пропускной способности сети). Поэтому данный метод наиболее эффективен для простых программ (сценариев), потребность в которых очень большая среди пользователей.
Преимущество такого метода, заключается в том, что злоумышленнику в данном случае нужно будет для начала скомпрометировать сам сервер, только после чего он сможет получить копию требуемой программы.
Данный метод не позволяет защитить программу от нелегального копирования, поэтому после того как ее копия попадет к злоумышленнику, он сможет делать с ней что захочет (whatever you want :).
В данной статье были перечислены наиболее распространенные методы борьбы с компьютерным пиратством, а также был поверхностно описан, такой метод защиты программных продуктов, как обфускация.
Если Вы обнаружили какие-то недочеты, допущенные мной при создании данного материала, то Вы можете уведомить меня об этом (email: ), и я постараюсь их исправить.
Для более серьезного изучения обфускации, Вы можете воспользоваться, списком литературы, который представлен ниже.
P.S. Все ручейки пройдены. Удачи! (Удача не решающий фактор, но важный :)
/\ /\ @ @ ... `why your cat grins like that?' ... | ... `It's a Cheshire cat,' said the Duchess ... \___/
Список используемой литературы:
"A taxonomy of Obfuscating Transformations" , авторы Christian Collberg, Clark Thomborson, Douglas Low.
"General Method of Program Code Obfuscation", автор Gregory Wroblewski.
"Static and dynamic analysis: synergy and duality", автор Michael D. Ernst
"Анализ запутывающих преобразований программ", автор Чернов А. В.
"Software protection", авторы Christian S. Collberg, Clark Thomborson.
"ALICE'S ADVENTURES IN WONDERLAND", автор Lewis Carroll.
"Through the looking glass", автор Lewis Carroll.