Теория и практика защиты программ

Способы внедрения РПС посредством инструментальных средств


Современный этап развития технологии создания программных комплексов характеризуется ориентацией практически всех специализированных организаций на применение методов проблемно-ориентированного программирования. При этом повышение качества программ основывается на использовании мощных инструментальных средств разработки и отладки программ. Использование для автоматизации процессов производства в области программотехники инструментальных средств автоматизации программирования значительно осложняет проблему выявления и устранения РПС. Это обусловлено тем, что программист практически не имеет возможности контролировать непосредственно создаваемые программы, так как работает на уровне логических конструкций языковых средств.

Если целью атаки является нанесение как можно большего вреда, то заманчивой целью для нарушителя, пытающегося внедрить РПС, являются программы, которые используют много различных пользователей, например, компиляторы[РПС]. Для того чтобы понять, как это можно сделать рассмотрим следующую упрощенную структуру компилятора, которая дает представление об общих принципах его работы:

compile:

  get (line);

translate(line);

Согласно этой структуры компилятор сначала «получает строку», а затем транслирует ее. Конечно, настоящий компилятор устроен намного сложнее, чем эта схема, но этой иллюстрации отдано предпочтение потому, что она в виде некой модели разъясняет фазы лексического анализа трансляции компилятора. Целью РПС будет поиск новых текстовых участков во входных программах, которые будут транслироваться, и вставление в эти участки различного кода. В примере, представленном ниже, компилятор ищет текстовый участок «read_pwd(p)», наличие которого в функции входа в данную компьютерную систему известно, как мы предполагаем, нападающей программе. Когда этот участок будет найден, компилятор не будет транслировать «read_pwd(p)», а вместо этого буде транслировать вставку из РПС, которая может устанавливать «лазейку», которая потом позволит злоумышленнику легко получить доступ к системе.
Измененный код компилятора следующий:

compile;

get (line)

if line=«readpwd(p)» then

translate (destructive means insertion);

else



translate(line);

fi;

В этом измененном коде, компилятор получает строку, ищет нужный код текст, и если находит, то транслирует код РПС. Код РПС может включать в себя простую проверку пароля «черного входа» (например, может признаваться правильный пароль «12345» для любого пользователя). Это особенно опасно, поскольку код источника больше не отражает того, что находится в объектном коде и просмотр кода источника (не смотря на то, что проверяется и компилятор) никогда не позволит уловить эту атаку (см рис.9.1).

Заметим, что на рис.9.1 исходный текст или исполняемый код, включающий только те выражения, которые предлагались его разработчиком назван чистым, а код, содержащий РПС, - грязным. Далее заметим, что если компилируется атакованный компилятор и грязный исполняемый код устанавливается код в какой-либо рабочий каталог (так обычно и бывает), то компилятор с внедренным РПС может быть обнаружен, только если кто-нибудь вернется к источнику компилятора и проверит его (что редко случается). Но настоящий источник может быть восстановлен злоумышленником после компилирования грязного источника и создания грязного исполняемого компилятора. Это, вообще говоря, потом поможет восстановить настоящий исполняемый компилятор при рекомпиляции источника, но это редкий случай.

Более изощренный метод внедрения РПС заключается в реализации следующего алгоритма [То].

compile;

get (line)

if line=«pattern_1» then

translate (destructive means insertion_N1);

if line=«pattern_2» then

translate (destructive means insertion_N2);

else

translate(line);

fi;

Сущность метода заключается в простом добавлении еще одного РПС к уже существующему. Второй образец настроен на сам компилятор.


Заменяющим текстом может служить самовоспроизводящаяся программа [То], которая вставляет оба РПС в компилятор. В этом случае необходима также фаза обучения. Сначала компилируется модифицированный исходный текст нормальным компилятором, когда получается готовая программа с РПС. Затем устанавливается эта готовая программа как официальный компилятор. Теперь можно удалить РПС из исходного текста компилятора, а новый компилятор будет воспроизводить РПС при каждой перекомпиляции. Команда login (например для ОС Unix), естественно, будет оставаться с РПС без всякого следа в каких-либо исходных текстах.

Таким образом, по мнению лауреата премии Тьюринга К. Томпсона [То]: «Нельзя доверять программе, которую вы не написали полностью сами. Сколько бы вы не исследовали и не верифицировали исходный текст - это не защитит вас от троянской программы. Для демонстрации атаки такого рода я выбрал компилятор Си. Я мог бы выбрать любую программу, обрабатывающую другие программы - ассемблер, загрузчик или даже микропрограмму, зашитую в аппаратуру. Чем ниже уровень программы, тем труднее и труднее обнаруживать подобные «жучки». Мастерски встроенный «жучок» в микропрограмме будет почти невозможно обнаружить».


Содержание раздела