Разработка библиотеки программных компонентов определения форматов файлов и ее использование в системах безопасности промышленных сетей
Описание промышленных компьютерных сетей. Анализ файлов, передаваемых по ним и общие требования к реализуемой библиотеке. Архитектура и уровни интерфейса библиотеки, принципы реализации алгоритмов исполняемых и неисполняемых структурированных файлов.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 12.08.2017 |
Размер файла | 883,5 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Определение драйверов операционной системы Windows
Для определения драйвера Windows необходимо и достаточно проверить значение поля Subsystem в опциональном заголовке PE-файла. Для драйвера установлена константа IMAGE_SUBSYSTEM_NATIVE со значением равным единице.
Определение файлов.NET
Платформа.NET корпорации Microsoft расширила формат PE с помощью функций, которые поддерживают общеязыковую среду исполнения (Common Language Runtime - CLR). Дополнением является директория ClrDirectory и секция данных CLR. Идентификация компонентов.NET производится поиском директории ClrDirectory в таблице директорий, которая располагается в конце опционального заголовка. В данной директории содержатся виртуальный адрес загрузки и размер данных. Если PE - файл является.NET - компонентом, то значения данных полей отличны от нуля.
Определение COM-компонентов
COM (англ. Component Object Model - объектная модель компонентов) - это технологический стандарт от компании Microsoft, предназначенный для создания программного обеспечения на основе взаимодействующих компонентов, каждый из которых может использоваться во многих программах одновременно. Стандарт воплощает в себе идеи полиморфизма и инкапсуляции объектно-ориентированного программирования. Каждый COM-компонент содержит в своей таблице экспорта функцию DllGetClassObject, которая одновременно является и точкой входа для компонента.
Для идентификации COM-компонента необходимо и достаточно найти в таблице экспорта файла имя функции «DllGetClassObject».
2. Проектирование и реализация
2.1 Разработка архитектуры библиотеки
Общий подход к проектированию и разработке библиотеки
Создание данного программного продукта производится по спиральной модели. Реализованный в данной работе функционал является лишь частью задуманного и в будущем разработка библиотеки будет продолжена. Для того, чтобы дальнейшее развитие программного продукта было максимально эффективным и не приводило к излишним затратам времени и сил, был применён подход к разработке, называемый принципами SOLID.
Принципы SOLID - это первые пять принципов, названных Робертом Мартином в начале 2000-х [5] [6], которые означают пять основных принципов объектно-ориентированного программирования и проектирования. Эти принципы предназначены для повышения качества кода и помогают создать код, который будет легко поддерживать и расширять в течение долгого времени. Это особенно актуально при спиральном подходе, так как при правильном проектировании очередной итерации создаются условия для более лёгкой и быстрой реализации функционала последующей итерации. В свою очередь, количество затраченного времени на написание кода на каждой итерации определяет стоимость конечного программного продукта, частью которого является данная библиотека.
Признаками плохой архитектуры и реализации программного кода являются следующие [5]:
1) сильная связанность компонентов (авт. rigidity) - выражается в том, что при внесении изменений в один из компонентов кода, появляется необходимость вносить каскадные изменения во все зависимые компоненты;
2) неустойчивость (авт. fragility) - внесение изменений в один компонент кода приводит к сбоям в работе других, которые могут даже не иметь прямой связи с изменёнными компонентами;
3) сложность повторного использования (авт. immobility) - систему сложно разделить на отдельные компоненты, которые можно использовать повторно;
4) вязкость (авт. viscosity) дизайна и окружения - сложность внести что-то новое согласно существующему дизайну интерфейса, архитектуры. Необходимость использования грубых решений, нарушающих существующую концепцию;
5) неустойчивость к изменениям (авт. Changing Requirements) - под воздействием новых требований существующая стройная концепция архитектуры быстро разрушается. Чем больше изменений, тем быстрее происходит разрушение архитектуры;
Для того, чтобы предотвратить подобные проблемы применяются следующие принципы:
1) принцип единой ответственности (англ. The Single Responsibility Principle, SRP) - означает, что каждый объект должен иметь одну ответственность и эта ответственность должна быть полностью инкапсулирована в класс. Автор определяет ответственность как причину изменения и заключает, что классы должны иметь одну и только одну причину для изменений. На практике ответственность представляет собой задачу, которую выполняет класс. Основным признаком нарушения данного принципа является тот факт, что при изменении кода, отвечающего за одну ответственность (задачу), в приложении появляются исправления кода, отвечающего за другую ответственность (задачу);
2) принцип открытости / закрытости (англ. The Open Closed Principle, OCP) - программные сущности (классы, модули, функции и проч.) должны быть открыты для расширения, но закрыты для изменения. Открыты для расширения означает, что поведение сущности может быть расширено, путём создания новых типов сущностей. Закрыты для изменения: в результате расширения поведения сущности, не должны вноситься изменения в код, который эти сущности используют (например, унаследованный код);
3) принцип подстановки Барбары Лисков (англ. Liskov Substitution Principle, LSP) - если D является производным типом от B, тогда объекты типа B в программе могут быть замещены объектами типа D без каких-либо изменений свойств этой программы;
4) принцип разделения интерфейса (англ. Interface Segregation Principle, ISP) - общие интерфейсы с множеством разнонаправленных методов нужно разделять на узкие и специфические, чтобы их клиенты знали только о тех методах, которые необходимы им в работе. Как результат, при изменении метода интерфейса не должны меняться клиенты, которые не используют этот метод;
5) принцип инверсии зависимостей (англ. Dependency inversion principle, DIP) - уменьшение зависимостей различных модулей, сущностей друг от друга. Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций, а не от конкретных реализаций;
Принцип SRP применён в библиотеке следующим образом: класс FFilter несёт ответственность только за определение формата файла. Его интерфейс выглядит следующим образом:
интерфейс программный компьютерный сеть
class FFilter
{
public:
FFilter(){}
virtual bool test (const char* buffer, size_t buffSize) = 0;
virtual FileFormatName getFormatName() = 0;
virtual size_t getFileSize (const char* buffer, size_t buffSize) = 0;
virtual ~FFilter(){}
};
Единственная задача метода test(…), это ответить на вопрос имеет ли целевой файл формат, указанный типом производного класса. Получение размера файла - это взаимосвязанная операция, т.к. её реализация зависит от формата. Метод getFileSize(…) - возвращает размер целевого файла, вычисленный согласно структуре его формата. Метод getFormatName(…) возвращает идентификатор файла.
Единственным формальным нарушением данного принципа является класс FileHandler, интерфейс которого предоставляет множество различных функций. Данный факт не следует считать нарушением, так как данный класс представляет собой интерфейс самого верхнего уровня, и его цель максимально скрывать внутреннюю реализацию.
Принцип ISP прослеживается в следующем: базовые классы FFilter и ExecClassifier содержат только те методы, которые необходимы пользователю при использовании интерфейса нижнего уровня (непосредственно классов-фильтров и классов-классификаторов конкретных форматов и типов). Это, в первую очередь, методы для определения формата либо типа исполняемых файлов. Остальные методы этих интерфейсов являются взаимосвязанными с основной задачей класса, поэтому их нельзя считать нарушением принципа ISP. Все специфические для конкретных задач методы и данные инкапсулированы в промежуточных подклассах и конечных класса-наследниках. Для примера, набор констант для формата ELF инкапсулирован в выделенный отдельно промежуточный абстрактный базовый класс FfilterELF. Все подклассы, не связанные с ELF - форматом не видят этих данных. Аналогичная ситуация с классификаторами NetworkClassifier и DriverModClassifier.
Примером использования принципа DIP является класс DetectPool. Первоначально, в процессе разработки он выглядел так:
template<typename T>
class DetectPool
{
typedef typename std:vector<T>:iterator FPIterator;
public:
DetectPool(){}
virtual ~DetectPool()
{
for (auto i: m_pool)
delete i;
}
virtual FPIterator begin() {return m_pool.begin();}
virtual FPIterator end() {return m_pool.end();}
protected:
std:vector<T> m_pool; // < - зависимость на уровне реализации
public:
DetectPool (const DetectPool &) = delete;
const DetectPool & operator = (const DetectPool &) = delete;
};
В интерфейс класса помимо открытых методов входят также и шаблонные параметры. В данном варианте имеется зависимость на уровне реализации, путём привязки к конкретному виду контейнера std:vector - это закрытый член std:vector<T> m_pool. Если возникнет необходимость заменить блочный контейнер std:vector, например, на какой-либо пользовательский, то это приведёт к необходимости внесения изменений в реализацию класса DetectPool, и, вероятнее всего, его классов-наследников, что является также нарушением принципа OCP. На практике это выльется в дополнительную работу по отладке и тестированию всех изменённых классов.
Более правильный вариант выглядит, таким образом, что зависимость на уровне реализации превращается в зависимость на уровне интерфейса (контейнер становится параметром шаблона):
template< template<class…> class Container, typename T>
class DetectPool
{
public:
typedef typename Container<T>:iterator FPIterator;
DetectPool(){}
virtual ~DetectPool()
{
for (auto i: m_pool)
delete i;
}
virtual FPIterator begin() {return m_pool.begin();}
virtual FPIterator end() {return m_pool.end();}
protected:
Container<T> m_pool;
public:
DetectPool (const DetectPool &) = delete;
const DetectPool & operator = (const DetectPool &) = delete;
};
Также, принцип DIP используется для уменьшения зависимостей на уровне интерфейса. Методы которые использует клиент при работе с нижним уровнем библиотеки выполнены с максимально простыми сигнатурами без зависимостей на уровне интерфейса.
Пример: в процессе разработки метод test(…) выглядел так:
FileFormatName test (const char* buffer, size_t buffSize, Ffd & ffdOut)
где в объект ffdOut помещался конечный результат работы, такой как тип (в случае исполняемого файла), размер файла, смещение и т.д. При этом, получалась дополнительная зависимость на уровне интерфейса, т.к. метод test(…) должен был знать об устройстве класса Ffd. Что при изменении структуры Ffd привело бы к необходимости вмешательства в реализацию всех методов test(…) всех классов-фильтров и их повторному тестированию. В условиях, когда постоянно появляются новые требования к функциональности библиотеки, это привело бы к значительным дополнительным затратам. Возвращаемое значение заменено на bool по той же причине - оно может измениться в будущем, поэтому проще возвращать его с помощью отдельного метода (который выглядит тривиально), чем вмешиваться в «дорогой» в разработке метод test(…). Итоговый вариант сигнатуры метода выглядит так:
bool test (const char* buffer, size_t buffSize).
Общая архитектура библиотеки
Основная функциональная часть библиотеки представлена двумя иерархиями классов: классами-фильтрами и классами-классификаторами. Классы-фильтры содержат методы для определения форматов файлов, классы-классификаторы для определения типа исполняемых файлов. Классы-фильтры унаследованы от абстрактного базового класса FFilter, классы-классификаторы от ExecClassifier. Общий вид иерархии классов фильтров представлен на рисунке 2.7:
Рисунок 2.7. Общий вид иерархии классов-фильтров
Рисунок 2.8. Общий вид иерархии классов-классификаторов
Каждая иерархия включает в себя абстрактный базовый класс-предок, интерфейс которого наследуют классы-потомки. Интерфейс базового класса иерархии классов-фильтров выглядит следующим образом:
class FFilter
{
public:
FFilter(){}
virtual bool test (const char* buffer, size_t buffSize) = 0;
virtual FileFormatName getFormatName() = 0;
virtual size_t getFileSize (const char* buffer, size_t buffSize) = 0;
virtual ~FFilter(){}
};
Основным методом классов-фильтров является виртуальный метод test со следующей сигнатурой:
bool test (const char* buffer, size_t buffSize),
где buffer - это указатель на буфер, который содержит целевой файл, формат которого нужно определить, buffSize - его размер. Метод возвращает булево значение, которое сигнализирует о том, имеет ли целевой файл указанный формат. Каждый класс-фильтр имеет только один метод test (…) и может определить только один формат. Метод getFormatName() возвращает идентификатор формата файла, метод getFileSize(…) вычисляет размер идентифицированного файла путём разбора полей его заголовка и вычисления смещения до его конца.
Интерфейс базового класса иерархии классов-классификаторов выглядит следующим образом:
class ExecClassifier
{
public:
ExecClassifier(){}
virtual ~ExecClassifier(){}
virtual bool detect (const char* buff, size_t buffSize, FileFormatName format) = 0;
virtual ExecTypeName getExecTypeName() = 0;
};
Основным методом классов-классификаторов является виртуальный метод detect со следующей сигнатурой:
bool detect (const char* buffer, size_t buffSize, FileFormatName format),
где buffer - это указатель на буфер, который содержит целевой исполняемый файл, тип которого нужно определить, buffSize - его размер, format - идентификатор формата. Метод возвращает булево значение, которое сигнализирует о том, имеет ли целевой исполняемый файл указанный тип. Каждый класс-классификатор имеет только один метод detect (…) и может определить только один тип исполняемого файла. Метод getExecTypeName() возвращает идентификатор типа исполняемого файла.
Библиотека содержит следующий набор программных сущностей, описанных в терминах объектно-ориентированного программирования:
1) класс Ffd представляет собой описатель конечного результата обработки целевого файла. Он содержит набор полей, которые необходимы для описания формата файла и его типа если файл является исполняемым;
2) класс FileHandler реализует интерфейс верхнего уровня библиотеки и позволяет определить формат файла и тип исполняемого файла.
3) класс FFilter является корнем иерархии классов-фильтров и предоставляет интерфейс своим потомкам;
4) класс FFilterELF инкапсулирует общие для всех ELF-файлов данные, является промежуточным звеном между классами-фильтрами и корнем иерархии;
5) класс ExecClassifier является корнем иерархии классов-классификаторов.
6) класс NetworkClassifier является промежуточным звеном в иерархии классов-классификаторов и расширяет интерфейс ExecClassifier общими данными для всех классификаторов сетевых возможностей;
7) класс DriverModClassifier является промежуточным звеном в иерархии классов-классификаторов и расширяет интерфейс ExecClassifier общими данными для всех классификаторов драйверов и модулей ядра;
8) класс DetectPool содержит контейнер с указателями на объекты классов-фильтров, предоставляет интерфейс итераторов для перемещения по контейнеру, является предком для классов FilterPool и ClassifierPool, которые наследуют его интерфейс;
9) набор классов-фильтров и классов-классификаторов унаследованных от FFilter и ExecClassifier;
Уровни интерфейса библиотеки
Библиотека имеет два уровня абстракции интерфейса: интерфейс нижнего уровня и интерфейс верхнего уровня.
Интерфейс нижнего уровня
Интерфейс нижнего уровня предоставляет возможность использовать каждый компонент библиотеки отдельно по своему усмотрению и более глубоко интегрировать функционал библиотеки в клиентский код если это необходимо. Данный интерфейс представлен набором классов фильтров и классификаторов, каждый из которых можно создать и использовать в клиентском приложении отдельно от остальных. Пример использования интерфейса нижнего уровня представлен в Приложении 1.1.
Интерфейс верхнего уровня
Интерфейс верхнего уровня устроен таким образом, чтобы скрывать все детали реализации. Такой подход позволяет получить конечный результат при минимальных действиях пользователя, что, в свою очередь, способствует минимизации возможных ошибок при разработке приложения с использованием библиотеки. Основным элементом интерфейса верхнего уровня является класс FileHandler, интерфейс которого выглядит следующим образом:
class FileHandler
{
public:
FileHandler();
Ffd easyCheck (const char* buff, size_t fileSize);
LDF: ExecTypeName parseExecType (const char* buff, size_t fileSize, LDF: FileFormatName format);
private:
void tryFilters (Ffd & ffdOut, const char* buff, const size_t buffSize);
FilterPool m_filterPool;
ClassifierPool m_classifierPool;
};
Для определения формата файла предусмотрен метод easyCheck(), для определения типа исполняемого файла - метод getExecType(). Для того, чтобы определить формат файла пользователю достаточно выполнить следующие действия (Полный код примера использования приведён в Приложении 1.2):
1) Создать объект класса FileHandler.
2) Вызвать метод easyCheck() класса FileHandler передав ему указатель на буфер и размер буфера.
В качестве результата метод easyCheck() вернёт объект класса Ffd, который содержит идентификатор формата файла.
Класс FileHandler содержит в себе два набора объектов, инкапсулированных в классы FilterPool и ClassifierPool. FilterPool используется в методе easyCheck(). Этот класс является наследником абстрактного базового класса DetectPool и содержит в себе набор указателей на объекты классов-фильтров, которые создаются в его конструкторе. Класс DetectPool выполнен в виде шаблона, который параметризируется типом указателя на базовый класс фильтра либо классификатора. Указатели хранятся в объекте std:vector стандартной библиотеки языка С++. Такая компоновка позволяет используя цикл обойти весь набор объектов вызывая метод test каждого объекта через указатель. Класс ClassifierPool устроен аналогичным образом и содержит набор указателей на объекты классов-классификаторов. Он используется в методе getExecType() который определяет тип исполняемого файла.
2.2 Реализация алгоритма определения формата ELF и типов исполняемых файлов
Реализация алгоритма определения формата ELF
Заголовок файла формата ELF для архитектур х86 и х86-64 представлен структурой Elf32Ehdr и Elf64Ehdr соответственно, которые описаны в файле библиотеки common.h. Данная структура проецируется на входной файл через указатель что позволяет выполнять сравнение полей структуры с заданными константами используя этот указатель. Для определения формата происходит последовательное сравнение полей структуры с константами, которые заданы в спецификации на формат ELF. Если значение какого-либо поля не соответствует заданному значению, то проверка прерывается с возвращением булевого значения false. Код представлен в Приложении А.
Реализация алгоритма определения сетевых возможностей исполняемых файлов формата ELF
Определение сетевых возможностей исполняемого файла сводится к поиску символьных имён сетевых системных вызовов в таблице символов файла. К сетевым системным вызовам относятся следующие: socket, connect, accept, listen, sendto, recvfrom, select, poll, epoll.
Для поиска символьных имён необходимо проделать следующую последовательность действий:
1) извлечь из поля e_shoff заголовка ElfHeader смещение до таблицы заголовков секций (англ. - section header table). Данная таблица содержит набор структур, каждая из кторых описывает одну из секций. В библиотеке данная структура представлена структурами Elf32Shdr и Elf64Shdr которые описаны в заголовочном файле common.h;
2) найти в таблице структуру.shstrtab которая содержит список имен всех секций файла. Каждая секция имеет поле sh_name, которое содержит индекс по которому расположено имя данной секции внутри секции.shstrtab. Для того, чтобы найти данную секцию, необходимо вычислить смещение до неё от начала файла. Смещение вычисляется путём сложения значения из поля e_shoff заголовка ElfHeader со значением, полученным путём умножения размера структуры заголовка (поле e_shentsize заголовка ElfHeader) на индекс структуры.shstrtab. Значение индекса содержится в поле e_shstrndx заголовка ElfHeader. Вычисление смещения в общем выглядит следующим образом: offset = e_shoff + (e_shentsize * e_shstrndx);
3) найти смещение до секции.strtab, которая содержит строки, представляющие собой символьные имена используемых функций и системных вызовов. Поиск смещения происходит путём обхода таблицы заголовков секций, где из каждого заголовка извлекается индекс имени секции. По данному индексу из таблицы.shstrtab извлекается строка, которая является именем секции. Данная строка сравнивается с искомой строкой «.strtab». При совпадении, извлекается смещение до данной секции;
4) найти символьные имена сетевых системных вызовов в секции.strtab, которая представляет собой массив нуль-терминированных строк символьных имён. Поиск осуществляется с применением алгоритма поиска подстроки в строке;
Список символьных имён системных вызовов содержит имена тех системных вызовов, которые могут быть использованы только для передачи либо приёма данных по сети. Таким образом, нахождение хотя бы одного совпадения достаточно, чтобы установить тот факт, что данный исполняемый файл будучи запущен в операционной системе может принимать либо передавать данные по сети.
Реализация алгоритма определения драйверов и модулей ядра исполняемых файлов формата ELF
Каждый динамически подгружаемый драйвер либо модуль ядра должен экспортировать следующие методы для загрузки и выгрузки: «init_module», «cleanup_module». При отсутствии данных методов в таблице символьных имён загрузка файла как модуля ядра становится невозможна. Поиск данных символьных имён происходит аналогично поиску символьных имён сетевых системных вызовов.
2.3 Реализация алгоритма определения формата PE и возможностей исполняемых файлов PE
Реализация алгоритма определения формата PE
Алгоритм определения формата PE аналогичен алгоритму для формата ELF. В начале файла PE располагается набор заголовков, которому соответствует следующий набор структур библиотеки: PeDosHdr, PeNtHdr, PeNtFileHdr, PeDataDir, PeOptHdr32, PeOptHdr64, PeImageSectionHeader, PeExportDirTable. Для определения формата происходит последовательное сравнение полей структуры с константами, которые заданы в спецификации на формат PE. В начале любого файла формата PE находится заголовок IMAGE_DOS_HEADER, унаследованный от операционной системы MS-DOS. Далее расположен заголовок IMAGE_NT_HEADER, поля которого и содержат необходимую для идентификации информацию. Для идентификации формата производится проверка значения magic bytes, а также ещё некоторых полей заголовка. Код представлен в Приложении А.
Реализация алгоритма определения сетевых возможностей исполняемых файлов формата PE
Для определения сетевых возможностей исполняемого файла формата PE как и в случае с форматом ELF производится поиск символьных имён сетевых системных вызовов. Кроме этого, производится поиск символьного имени процедуры WSAStartup, которая является точкой входа в библиотеку WINSOCK.DLL. В ОС Windows интерфейс сетевых системных вызовов находится в динамической библиотеке WINSOCK.DLL, которую каждое приложение, которое осуществляет сетевое взаимодействие должно загрузить в память процесса. Таким образом, нахождение символьного имени точки входа данной библиотеки является необходимым для установления факта использования сети запущенным исполняемым файлом.
Для поиска указанных выше символьных имён необходимо выполнить следующую последовательность действий:
1) получить смещение от начала файла до заголовка IMAGE_NT_HEADER. Значение данного смещения находится в поле e_lfanew заголовка IMAGE_DOS_HEADER;
2) вычислить смещение до таблицы символов. Для этого используются поля заголовков IMAGE_FILE_HEADER, который является частью IMAGE_NT_HEADER. Необходимо извлечь следующие значения: смещение до таблицы символов и число символьных имён в данной таблице;
3) найти в таблице строк символьное имя «WSAStartup» соответствующее библиотеке WINSOCK.DLL, а также имена сетевых системных вызовов;
Реализация алгоритма определения драйверов Windows
Для установления того факта, что исполняемый файл формата PE является драйвером, необходимо и достаточно проверить значение поля e_subsystem в заголовке COFF Optional Header. Его значение согласно спецификации должно быть равно 1. Код представлен в Приложении А.
Реализация алгоритма определения COM-компонентов Windows
Согласно спецификации [15], каждый COM-компонент должен содержать функцию загрузки с именем DllGetClassObject, символьное имя которой содержится в таблице экспорта. Для идентификации COM-компонентов необходимо и достаточно выявить наличие данного символьного имени в таблице экспорта. Для этого необходимо выполнить следующую последовательность действий:
4) получить смещение от начала файла до заголовка IMAGE_NT_HEADER. Значение данного смещения находится в поле e_lfanew заголовка IMAGE_DOS_HEADER;
5) вычислить смещение до таблицы секций. Для этого используются поля заголовков IMAGE_OPTIONAL_HEADER и IMAGE_FILE_HEADER, которые являются частью IMAGE_NT_HEADER. Необходимо извлечь следующие значения: число секций в файле; предпочтительный адрес образа процесса когда он загружается в память; структуру IMAGE_DATA_DIRECTORY, которая соответствует таблице экспорта; виртуальный адрес данной таблицы; размер заголовка IMAGE_OPTIONAL_HEADER. Используя эти данные можно вычислить смещение до таблицы секций и адрес таблицы экспорта;
6) используя адрес таблицы экспорта найти секцию, содержащую эту таблицу в таблице секций;
7) перейдя по полученному смещению получить смещение до таблицы символов таблицы экспорта;
8) найти в таблице символов секции экспорта символьное имя «DllGetClassObject»;
Реализация алгоритма определения.NET-компонентов Windows
Для определения того факта, что файл является.NET-компонентом необходимо проверить значение поля таблицы e_dataDirectory заголовка IMAGE_OPTIONAL_HEADER по индексу 14. Если значение данного поля не равно нулю, то это значит, что в файле присутствует таблица COM+ Runtime Header, что в свою очередь, позволяет однозначно определить.NET-компонент. Код представлен в Приложении А.
2.4 Реализация алгоритмов определения неисполняемых структурированных файлов
Алгоритм определения неисполняемых структурированных файлов является общим для форматов U-boot, Squashfs, ICO, TAR, GZIP, ZIP, GIF. Он сводится к поиску набора «магических байт», который, как правило, расположен в начале любого файла указанных форматов. При совпадении значений «магических байт» с заданными в спецификациях форматов значениями алгоритм возвращает булево значение true, иначе false.
2.5 Реализация алгоритмов определения файлов исполняемых скриптов командной оболочки
Алгоритм определения фалов исполняемых скриптов командной оболочки для форматов скриптов bash и sh реализован с помощью алгоритма поиска подстроки в строке. Для каждой из подстрок, указанных в параграфе 1.6.3 производится поиск в первой строке целевого файла.
2.6 Создание примеров использования интерфейсов библиотеки
Для более полного понимания методов и возможностей использования библиотеки при разработке прикладного программного обеспечения был создан набор примеров использования различных интерфейсов библиотеки для определения форматов файлов и типов исполняемых файлов. Примеры описывают использование интерфейсов верхнего и нижнего уровней библиотеки, применение классов-фильтров и классов-классификаторов. Данный набор является неотъемлемой частью библиотеки и поставляется вместе с её исходным кодом. Код примеров представлен в Приложении Б.
2.7 Тестирование кода библиотеки
Для тестирования библиотеки применялся метод модульного тестирования.
Данный вид тестирования представляет собой проверку отдельных классов и их методов нижнего и верхнего уровней библиотеки. В качестве инструмента тестирования использовался фреймворк Boost Test [16], который является специализированным инструментом модульного тестирования исходных кодов программ на языке программирования С++. Данный фреймворк предоставляет удобный интерфейс для написания тестов и получения результатов тестирования. Для выполнения тестирования была написана программа, включавшая в себя набор тестов, в которых проверялась работа основных методов классов-фильтров и классов-классификаторов. Основной задачей тестов было выявление ложноположительного результата работы этих методов, а также выявление ошибок сегментации памяти при выполнении операций с буфером, который содержит исходный файл. На вход программе тестирования подавались заранее подготовленные файлы различных форматов, в том числе намеренно искажённые. Тестирование выполнялось в несколько итерации с последующим устранением выявленных ошибок.
В результате проведённого тестирования было установлено, что каждый тестируемый модуль работает корректно, ошибок сегментации нет.
Заключение
В результате работы над проектом было проведено изучение предметной области систем безопасности промышленных сетей, в результате которого было выяснено, что наибольший интерес с точки зрения обеспечения безопасности и предотвращения вторжений представляет поиск в сетевом трафике исполняемых файлов, файлов архивов, файлов компонентов файловых систем, файлов изображений. Было проведено изучение методик определения следующих форматов файлов: ELF, PE, U-boot, ZIP, GZIP, TAR, GIF, ICO. Также, была выполнена разработка методики определения возможностей исполняемых файлов, изучение существующих решений. Результатом работы стало проектирование и разработка библиотеки прикладного программирования, которая реализует функции, заявленные в задании выпускной квалификационной работы. При проектировании применялись принципы разработки SOLID, основанные на многолетнем опыте разработки программного обеспечения многих специалистов. Было проведено успешное тестирование готового программного продукта.
Список использованных источников
1. Формат ELF [Электронный ресурс]: ELF specification - Режим доступа: http://www.skyfree.org/linux/references/ELF_Format.pdf
2. Справка по Linux system calls [Электронный ресурс]: Linux Programmer's Manual - Режим доступа: http://man7.org/linux/man-pages/man2/syscalls.2.html
3. Формат PE [Электронный ресурс]: PE pecification - Режим доступа: https://msdn.microsoft.com/ruru/library/windows/desktop/ms680547 (v=vs.85).aspx
4. Справка по Winsock.dll [Электронный ресурс]: Microsoft Winsock.dll - Режим доступа: https://support.microsoft.com/ru-ru/help/122928/description-of-the-winsock.dll-file
5. Формат ZIP [Электронный ресурс]: ZIP specification - Режим доступа:
https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
6. Формат GZIP [Электронный ресурс]: GZIP specification - Режим доступа: https://tools.ietf.org/html/rfc1952
7. Формат TAR [Электронный ресурс]: TAR specification - Режим доступа:
https://www.gnu.org/software/tar/manual/html_node/Standard.html
8. Формат ICO [Электронный ресурс]: ICO format - Режим доступа: https://msdn.microsoft.com/ru-ru/library/windows/desktop/gg430024 (v=vs.85).aspx
9. Справка по загрузчику Uboot [Электронный ресурс]: Uboot manual - Режим доступа: http://ftp1.digi.com/support/documentation/90000852_K.pdf
10. Справка по файловой системе Squashfs [Электронный ресурс]: Squashfs description - Режим доступа: https://www.kernel.org/doc/Documentation/filesystems/squashfs.txt
11. Corbet, J. Linux Device Drivers, 3rd Edition. / J. Corbet, A. Rubini, G. Kroah-Hartman. - Cambridge: 2005 O'Reilly. - 640 p.
12. Мартин Р.С. Быстрая разработка программ. Принципы, примеры, практика / Р.С. Мартин, Д.В. Ньюкирк, Р.С. Косс. - Москва: Вильямс, 2004. - 753 стр.
13. Майоров А. Проектирование информационных систем. / А. Майоров, И. Соловьев. - Санкт-Петербург: Академический проект, 2009. - 400 стр.
14. Фаулер М. Рефакторинг. Улучшение существующего кода. - Санкт-Петербург: Символ-Плюс, 2003. - 432 стр.
15. Справка по Windows API DllGetClassObject [Электронный ресурс]: Microsoft COM - Режим доступа: https://msdn.microsoft.com/ruru/library/windows/desktop/ms680760 (v=vs.85).aspx
16. Справка по фреймворку Boost Test [Электронный ресурс]: Boost Test - Режим доступа: http://www.boost.org/doc/libs/1_64_0/libs/test/doc/html/index.html
17. Формат GIF [Электронный ресурс]: GIF89 - Режим доступа: https://www.w3.org/Graphics/GIF/spec-gif89a.txt
Размещено на Allbest.ru
Подобные документы
Компиляция программ на языке C/C++. Компиляция нескольких файлов. Библиотеки объектных файлов. Создание статической и динамической библиотеки. Функции работы. Создание динамической библиотеки для решения системы линейных уравнений.
курсовая работа [27,4 K], добавлен 07.08.2007Характеристика форматов файлов wav и mp3. Построение диаграмм прецедентов, разработка графического интерфейса и архитектуры приложения. Разработка алгоритмов работы программы: метод TrimWavFile, TrimMp3, ChangeVolume, speedUpX1_2, speedDownX1_2.
курсовая работа [2,7 M], добавлен 20.12.2013Снижение трудоемкости выборки файлов; поиск текста при производстве компьютерных экспертиз. Автоматизированная индексация файлов и формализация задач; разработка инфологической, физической моделей системы с привязкой к СУБД; выбор языка программирования.
дипломная работа [4,1 M], добавлен 24.09.2013Что такое компьютерные вирусы. Цикл функционирования вирусов. "Вакцинация" программ. Заголовок исполняемых файлов. Защита вновь создаваемых программ. Модуль F_Anti. Защита существующих ехе-файлов. Описание программ SetFag.pas и Fag.asm.
реферат [38,2 K], добавлен 19.03.2004Особенности работы "поисковика" дублирующихся файлов на диске. Выбор среды программирования. Разработка программного продукта. Основные требования, предъявляемые к программе, производящей поиск дублирующихся файлов на диске. Отображение скрытых файлов.
курсовая работа [1,8 M], добавлен 28.03.2015Функциональные характеристики программы форматирования текстовых файлов, требования к ее интерфейсу и данным. Схема взаимодействия компонентов системы, выбор среды исполнения и программная реализация алгоритмов. Тестирование и оценка качества программы.
курсовая работа [61,1 K], добавлен 25.07.2012Проектирование программного обеспечения. Схема начального формирования каталога файлов, вывода на экран каталога файлов, удаления файлов, сортировки файлов по имени, дате создания и размеру методом прямого выбора. Управление каталогом в файловой системе.
курсовая работа [804,0 K], добавлен 08.01.2014Проектирование структуры и архитектуры программного продукта. Реализация программы конвертера файлов баз данных. Описание пользовательского интерфейса. Выбор порядка конвертации dbf файлов. Создание и исполнение шаблонов. Расчет себестоимости продукта.
дипломная работа [2,2 M], добавлен 21.06.2013Общая характеристика системы программирования Delphi, а также принципы создания ее компонентов. Описание значений файлов приложения, созданного с помощью Delphi. Структура и свойства библиотеки визуальных компонентов (Visual Component Library или VCL).
отчет по практике [1,1 M], добавлен 07.12.2010Архитектура сети: одноранговая, клиент - сервер, терминал - главный компьютер. Разработка конструктора электронных моделей компьютерных сетей с функциями проектирования сети и её диагностики. Требования к проектированию структурированных кабельных систем.
курсовая работа [1,6 M], добавлен 19.11.2010