Описание способа защиты
Данный способ основан на использовании прозрачного шифрования. При таком подходе работающая с данными программа не замечает, что данные зашифрованы. Иными словами, когда библиотеки ADODB нашей программы обращаются к файлу БД - они видят самый обычный файл. Но если с этими данными начинает работать чужая программа - она видит зашифрованные данные. Подобный подход используется в HASP Envelope. Но с его помощью шифруется весь файл, что сильно снижает производительность. Между тем, достаточно зашифровать только заголовок БД чтобы получить приемлемый уровень защиты.
Для работы с БД Access в настоящее время используется ADODB. Сначала создаётся подключение к файлу БД (ADODB.Connection). Когда заданы все параметры подключения - вызывается метод Open, который открывает БД. При этом, происходит чтение первых &H10000 байт файла БД. Здесь и срабатывает защита. Мы эти &H10000 байт предварительно зашифруем. Программа перехватывает вызов API функции ReadFile, сама считывает заголовок БД, и возвращает дешифрованные данные.
Чтобы перехватить вызов API функции ReadFile необходимо сделать следующее:
- получить идентификатор процесса с помощью функции GetCurrentProcessId
- получить описатель процесса, используя OpenProcess
- получить адрес замещающей функции, используя AddressOf
- получить описатель модуля kernel32 с помощью GetModuleHandle
- получить адрес функции ReadFile с помощью GetProcAddress
- прочитать и сохранить первые оригинальные 6 байт стандартной API функции ReadFile с помощью ReadProcessMemory
- записать с помощью WriteProcessMemory вместо этих 6 байт код ASM инструкции push и ret, указав в качестве аргумента инструкции push адрес замещающей функции
Таким образом, сначала мы меняем код API функции ReadFile на вызов нашей замещающей функции. Поле вызова метода Open объекта Connection - одна из библиотек ADODB начинает читать файл БД, используя ReadFile. Так как эта функция была нами модифицирована - она обращается к замещающей функции.
Замещающая функция имеет тот же набор аргументов, что и оригинальная ReadFile. Таким образом, получив управление в свои руки, мы знаем - откуда и сколько надо считать и куда результат поместить. При вызове замещающеё функции происходит следующее:
- возвращаем оригинальные 6 байт стандартной API функции ReadFile на место с помощью WriteProcessMemory
- вызываем ReadFile с теми же аргументами, с какими её вызывала библиотека ADODB
- так как нам известен размер считанных данных и адрес, куда они были прочитаны - мы дешифруем эти данные
- всё. библиотека ADODB получает управление обратно, даже не заметив наших действий. С её точки зрения - она просто вызвала функцию ReadFile, которая считала блок данных из файла. Повторное чтение файла функцией ReadFile будет происходить как обычно, так как мы вернули её в исходное состояние
Развитие проекта
- Этот материал ранее был опубликован на sql.ru в форуме по Access
- Предлагаю поучаствовать в дальнейшем совершенствовании этой технологии. На мой взгляд, она достаточно эффективна в плане защиты, проста в использовании и пригодна для добавления в существующие проекты
- Может, кому удастся перевести код на VBA. Основная проблема в использовании AddressOf. В таком случае можно будет интегрировать код в mde файл, и избежать той глупой ошибки, которую я допустил, возвращая Recordset из Active-X dll
- Также можно реализовать не только чтение, но и запись заголовка и сделать возможной работу под win98
Скачать пример Sample.zip 131 КБ