Постановка задачи 7
Глава 1. Обзор 8
Обфускация 8
Компилятор МАК 9
Многопоточные приложения в ОС Windows 9
Стандартные примитивы синхронизации 10
Глава 2. Обзор средств низкоуровневой синхронизации в архитектуре x86 12
Глава 3. Изучение возможных вариантов архитектуры 14
Архитектура с флагами состояния и блокировки 15
Архитектура c изменяемым указателем 16
Архитектура с внешним управлением состояния потока 18
Архитектура с использованием неблокирующей синхронизации 18
Глава 4. Реализация прототипов 20
Архитектура с использованием флагов 20
Архитектура с использованием изменяющегося указателя 21
Архитектура с использованием диспетчера 24
Архитектура с использованием неблокирующей синхронизации 24
Глава 5. Тестирование и сравнение 27
Заключение 30
Список литературы
Практически любое современное приложение является многопоточным. Без использования многопоточности нельзя создать даже простое “оконное” приложение, в котором бы интерфейс не блокировался на время обработки данных. Без многопоточности не обойтись при создании простого приложения-чата для общения двух пользователей: один поток необходим для отправки сообщений, второй для приема. Кроме того, во многих случаях многопоточность позволяет ускорить работу приложения. Подробно такие примеры рассмотрены в [1].
Важной особенностью многопоточных приложений, отличающей их от классических однопоточных (последовательных) приложений, является наличие разделяемых ресурсов. Разделяемый ресурс может представлять из себя как переменные, структуры, так и системные ресурсы, файлы, события и т.п.
В основе любого приложения лежит алгоритм, который, зачастую, является интеллектуальной собственностью разработчика (отдельного человека или целой компании). В то же время, предоставляя приложение пользователям, разработчик передает все алгоритмы, связанные с ним в формате исполняемого файла. В связи с этим остро встает вопрос защиты этой собственности от взлома с целью модификации или кражи, в том числе посредством реверс-инжиниринга - дизассемблирования, статического и динамического анализа кода приложения.
Для защиты от реверс-инжиниринга применяются различные приемы обфускации. Обфускация - это запутывание кода (как непосредственно на уровне машинных команд, так и на высоком уровне языков программирования), организация исполняемого кода таким образом, что его анализ становится крайне затруднительным. Подробный обзор методов обфускации приводится в статье [2].
В течении нескольких последних лет на кафедре системного программирования СПбГУ разрабатывается компилятор МАК для языка программирования Си. Одной из его отличительных особенностей является простота применения обфускации на уровне машинных команд. В данный момент компилятор МАК поддерживает работу с однопоточными приложениями с обфускацией и с многопоточными приложениями без обфускации
Главным отличием компилятора МАК является разбиение кода приложения на линейные участки - фрагменты кода, все инструкции внутри которых выполняются последовательно.
Такой подход позволяет использовать множество приемов обфускации на уровне ассемблера, в частности, изменять код во время выполнения программы, модифицируя линейные участки, которые в данный момент не используются. Под модификацией можно понимать как собственно изменение фрагмента (XOR с каким-то известным участком или другая модификация), так и копирование из другого участка памяти, либо преобразования в обратную сторону.
Очевидно, что это накладывает серьезные ограничения на многопоточные программы: в случае, если модификация некоторого линейного участка находится внутри многопоточной части программы, то преобразуемый участок будет модифицирован несколько раз, и это во многих случаях нарушает корректность работы программы. Например, двойное применение XOR с некоторым ключом даст исходное состояние модифицируемого линейного участка. Кроме того, без применения методов синхронизации для линейных участков возможна ситуация, когда один поток начнет модифицировать линейный участок, выполняемый другим потоком. Все это делает распараллеливание без использования дополнительных механизмов синхронизации невозможным.
Для того, чтобы использовать обфускацию в многопоточных приложениях, необходим модуль, отвечающий за синхронизацию доступа к линейному участку и его модификации.
В рамках данной работы были выполнены следующие задачи.
• Изучены механизмы синхронизации на уровне ассемблера в архитектуре x86.
• Рассмотрены пять архитектур модуля синхронизации.
• Реализованы прототипы для каждого из рассмотренных шаблонов на языке ассемблера x86.
• Проведено тестирование и сравнение полученных прототипов, которое показало преимущества использования неблокирующей синхронизации.
[1] К. Ю. Богачев Основы параллельного программирования
Изд. Бином
[3] Ю. Лифшиц. Обфускация (запутывание) программ. Обзор. URL: https://logic.pdmi.ras.ru/~yura/of/survey1 .pdf
[3] Дж. Рихтер. Windows для профессионалов. Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows. Изд-ва: Питер, Русская Редакция, 2001
[4] М. Руссинович, Д. Соломон. Внутреннее устройство Microsoft Windows. В 2х частях. Изд-во Питер.
[5] URL: https://software.intel.com/en-us/node/506090.
[6] Paul E. McKenney Is Parallel Programming Hard, And, If So, What Can You Do About It? January 2, 2017
[7] Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2 Instruction Set Reference. September 2016
[8] Камерон Хьюз, Трейси Хьюз. Параллельное и распределенное программирование с использованием С++. Изд-во Вильямс, 2004