Разработка приложения, способного защищать исполняемые файлы, страница 7

Для шифрования используется суммирование без учёта переноса байтов программы с байтами пароля. Если пароль имеет длину n байт, то первый байт кода складывается с первым байтом пароля, второй — со вторым, а (n+1) байт — снова с первым. Это вызвано тем, что в процессе загрузки программы (то есть до дешифрования) загрузчик обрабатывает релокешены, и последующее дешифрование, например гаммированием «испортило» бы адреса.

Организация подключения DLL расшифровки на стадии загрузки представляется практически невыполнимой, так как в Import Directory Table нет свободного места. Поэтому необходима динамическая загрузка библиотек. Для неё необходимо использовать функции WinAPI LoadModule и GetProcAddress. Так как мы не можем быть уверены, что защищаемая программа использует эти функции, нам нужно воспользоваться функциями GetModuleHandle и GetProcAddress, чьи адреса также нужно каким то образом узнать. Этот замкнутый круг размыкается следующим образом: Вместо адресов имён первых двух функций импортируемых из KERNEL32.DLL (программа может защищать продукты, импортирующие из этой библиотеки не менее 2-х функций) подставляются адреса имён функций GetModuleHandle и GetProcAddress. Поэтому адреса этих функций для нас находит загрузчик. Сохранив эти адреса секция дешифрации находит адреса тех функций, которые изначально были задействованы в программе (при защите программы мы сохранили адреса имён этих функций) и прописывает их в соответствующие строки Import Address Table.

Таким образом, мы получаем адреса нужных нам функций, а защищаемая программа — адреса, нужные ей. Разработка этой части программы (которая обрабатывает секцию импорта) была наиболее трудоёмка, так как описание формата этой секции и способ её интерпретации загрузчиком, описанные в спецификации формата Portable Executable фирмы Microsoft не вполне соответствуют действительности. Во время разработки программы мной были тщательно исследованы несколько десятков PE файлов, и выявлены несколько способов заполнения IDT, ILT и IAT и соответствующих им способов поведения загрузчика. Разработанная программа корректно обрабатывает эти типы файлов, однако нет никакой гарантии, что не существует других вариантов, с которыми программа работать не сможет.

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


Алгоритм работы программы защиты

Сразу после запуска программа проверяет наличие в её директории файлов Peguard.bin (в нём хранится код добавляемой секции). Если этот файл отсутствует программа выдаёт предупреждение и закрывается.

После нажатия кнопки SetGuard программа открывает выбранный файл (при условии, что файл выбран). Далее создаётся мэппинг для данного файла с правом чтения и размером, равным размеру файла. Затем этот мэппинг проецируется на адресное пространство программы. По смещению 3Ch считывается адрес начала PE заголовка. Если по этому адресу не найдена сигнатура PE файла, выдаётся соответствующее  сообщение и обработка файла завершается. Считав поле MagicNumber из заголовка программа проверяет, имеет ли файл формат PE32. Далее программа убеждается в наличии свободного места в Section Table (так как заголовки и Section Table должны быть выровнены на границу, кратную File Alignment, свободное место обычно есть). Затем выполняется поиск секции, в которой находится Import Table, для выяснения её смещения в файле. Следующим шагом является выяснение, использует ли файл KERNEL32.DLL и какая строка Import Directory Table отвечает за эту библиотеку. Сразу после этого выясняются файловые смещения ILT и IAT и проверка количества функций, импортируемых из KERNEL32.DLL. Затем просматриваются имена всех секций и сравниваются с именем добавляемой нами секции для выяснения не защищена ли уже данная программа. Далее находится адрес в файле, с которого начнётся наша секция дешифрования (он должен быть кратен File Alignment). После этого выполняется поиск секции содержащий адрес, указанный в поле Code Base заголовка (для выяснения файлового смещения начала шифруемого кода). Если все проверки прошли успешно, мэппинг для чтения закрывается и начинается процесс модификации файла. Прежде всего, запрашивается пароль. Затем создаётся резервная копия защищаемого файла.