Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Защита информации в компьютерных системах.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
401 Кб
Скачать
☆

Контекстная зависимость

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

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

Хуки

Хуки ("крючья") - изящный, но ныне практически забытый прием программирования. Его суть заключается в совмещении нескольких разнотипных данных в одном аргументе. Например, если значение аргумента по модулю меньше 0x400000, функция считает его непосредственным значением, в противном случае - указателем на функцию, результат выполнения которой следует поставить на его место. Это увеличивает гибкость программы, но и затрудняет ее анализ, не позволяя быстро определить, происходит ли передача переменной по значению или по указателю. Указатели на переменную, в свою очередь, становятся неотличимы от указателей на функцию. Разумеется, отказ от строгой типизации может приводить к ошибкам, но вероятность их появления в тщательно продуманной программе невелика.

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

Существует еще множество других способов запутать того, кто пытается проанализировать исходный текст. Например, можно использовать совершенно корректные с точки зрения языка, но необычные конструкции, ставящие в тупик незнакомого с ними человека. Классический пример - перестановка индекса и имени массива в Си. С точки зрения языка, выражения "buff[666]" и "666[buf]" абсолютно равнозначны, но всякий ли об этом помнит?

Препроцессор Си также имеет свои тонкости. Возможно, самая популярная из них заключается в чувствительности к пробелам при объявлении макроса: "#define x(a,b) a+b" создаст макрос x(a,b), заменяющийся суммой своих аргументов, но "#define x (a,b) a+b" создаст макрос x, заменяющийся последовательностью "(a,b) a+b". Если не обратить внимание на лишний пробел, можно получить совсем не тот результат.

В той или иной степени эти, а также другие приемы используются в большинстве свободно распространяемых "открытых текстов". Последнее словосочетание заключено в кавычки для придания ему ироничного оттенка: одно лишь наличие исходного текста еще не обеспечивает открытости, - требуется, по меньшей мере, грамотно продуманная и качественно составленная документация, а еще лучше - опыт работы с этим текстом. Разобраться с исходными текстами редактора emacs или операционной системы Linux не намного проще, чем написать их "с нуля", - слишком уж скупы их разработчики на комментарии, а документация зачастую и вовсе отсутствует.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]