Драйвер подмены сертификатов

в 14:13, , рубрики: driver, Драйвер, подпись, разработка под windows, сертификат

Вступление

Authenticode (Аутентификация) является форматом цифровой подписи, который используется, чтобы определить издателя и целостность двоичных файлов программного обеспечения. Authenticode основан на стандартах криптографии с открытым ключом (PKCS) и использует X.509 v3 сертификаты, чтобы связать Authenticode-подписанный файл с идентификационными данными издателя программного обеспечения.

Одно важное использование подписей Authenticode – это подпись PE файлов, которые включают .exe, .dll и .sys файлы.

Подпись исполняемых файлов

Создание тестового сертификата

Для нашей работы сначала мы создадим тестовый сертификат с открытым и закрытым ключом. Для этого предварительно необходимо установить Microsoft Windows SDK for Windows 7. Данный пакет содержит два необходимых файла для создания сертификата:

  • Makecert.exe
  • Pvk2pfx.exe

Запускаем командную строку и переходим в директорию с установленным SDK:

  • cd "C:Program FilesMicrosoft SDKsWindowsv7.0Abin"

Создаем сертификат и файл с закрытым ключом:

  • makecert -sv "Vladimir Ivanov.pvk" -n "cn=Vladimir Ivanov" "Vladimir Ivanov.cer" -b 01/01/2017 -e 01/01/2020 -r

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

Драйвер подмены сертификатов - 1

В нашем случае рекомендуется не вводить пароль, оставив его пустым. Нажмите кнопку «Отсутствует».

В итоге у нас создадутся два файла:

  • Vladimir Ivanov.cer
  • Vladimir Ivanov.pvk

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

Воспользуемся утилитой Pvk2pfx.exe:

  • PVK2PFX –pvk "Vladimir Ivanov.pvk" –spc "Vladimir Ivanov.cer" –pfx "Vladimir Ivanov.pfx"

После отработки данной утилиты мы получаем наш самоподписанный сертификат Vladimir Ivanov.pfx.

Драйвер подмены сертификатов - 2

Как мы можем видеть, сертификат не действителен. Чтобы он стал действителен, а так же все наши последующие действия с подписями исполняемых файлов были валидными необходимо установить сертификат в хранилище корневых сертификатов центров сертификации. Для этого нажмем «Установить сертификат…», выберем «Локальный компьютер» и принудительно выберем необходимые параметры:

Драйвер подмены сертификатов - 3

После выполнения указанных действий еще раз можно проверить наш созданный сертификат, и мы сможем увидеть, что он стал действителен:

Драйвер подмены сертификатов - 4

Драйвер подмены сертификатов - 5

Ручная подпись исполняемых файлов утилитой signtool.exe

Одним из методов подписи исполняемых (далее exe) файлов является использование утилиты signtool.exe. Для теста будем использовать два файла wmplayer.exe (Windows Media Player) и iexplore.exe (Internet Explorer). Изначально файл wmplayer.exe не имеет цифровой подписи, а файл iexplore.exe имеет:

Драйвер подмены сертификатов - 6

Драйвер подмены сертификатов - 7

Итак, запустим командную строку и выполним два действия:

  • SignTool sign /f "Vladimir Ivanov.pfx" iexplore.exe
  • SignTool sign /f "Vladimir Ivanov.pfx" wmplayer.exe

После этого мы можем наблюдать подписанные приложения нашим сертификатом:

Драйвер подмены сертификатов - 8

Драйвер подмены сертификатов - 9

Также видно, что подпись в файле iexplore.exe была заменена на нашу, с удалением предыдущей.

Так как наш сертификат добавлен в корневой центр сертификации на данном компьютере, то подпись является действительной и Windows укажет, что файл подписан корректно при его запуске с включенным компонентом UAC.

Драйвер подмены сертификатов - 10

Хранение сертификата в exe файле. Структура PE-файла

Структурно PE-файл состоит из заголовка (header), страничного имиджа (image page) и необязательного оверлея (overlay). Представление PE-файла в памяти называется его виртуальным образом (virtual image) или просто образом, а на диске – файлом или дисковым образом. Если не оговорено обратное, то под образом всегда понимается виртуальный образ.

Образ характеризуется двумя фундаментальными – адресом базовой загрузки (image base) и размером (image size). При наличии перемещаемой информации (relocation/fixup table) образ может быть загружен по адресу, отличному от image base и назначаемому непосредственно самой операционной системой.

Образ делится на страницы (pages), а файл – на секторы (sectors). Виртуальный размер страниц/секторов задается явно в заголовке файла и не обязательно должен совпадать с физическим.

Для работы с PE-файлами используются три различные схемы адресации: физические адреса (называемые также сырыми указателями или смещениями raw pointers/raw offset или просто offset), отсчитываемые от начала файла; виртуальные адреса (virtual address или сокращенное VA), отсчитываемые от начала адресного пространства процесса, и относительные виртуальные адреса (relative virtual address или сокращенно RVA), отсчитываемые от базового адреса загрузки.

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

Все секции совершенно равноправны, и тип каждой из них тесно связан с ее атрибутами, интерпретируемыми довольно неоднозначным и противоречивым образом. Реально мы имеем два аппаратных и два программных атрибута: Accessible/Writeable и Shared/Loadable соответственно.

«Секция кода», «секция данных», «секция импорта» – не более чем образные выражения, своеобразный рудимент старины, оставшийся в наследство от сегментной модели памяти, когда код, данные и стек действительно находились в различных сегментах, а не были сведены в один, как это происходит сейчас.

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

Схематичное изображение PE-файла:

https://habrastorage.org/storage2/5fa/e91/375/5fae9137566e0506fd7cc1a622cf726d.png

Полное описание всей структуры PE-заголовка нас в данный момент не интересует. Рассмотрим только как можно узнать есть ли в файле цифровая подпись, и как добраться до ее структуры. Также определим возможность ее замены.

Для этого разберем подписанный нашим сертификатом файл wmplayer.exe.

Воспользуемся бесплатной программой HexEdit (www.hexedit.com). Программа является простым в использовании шестнадцатеричным редактором.

Открываем файл в редакторе:

Драйвер подмены сертификатов - 12

Первый признак того, что перед нами PE-заголовок, это сигнатура MZ в начале файла. Она досталась в наследство от Марка Збиновски – ведущего разработчика MS-DOS и генерального архитектора EXE-формата.

PE-заголовок, в подавляющем большинстве случаев начинающийся непосредственно за концом old-exe программы, на самом деле может быть расположен в любом месте файла – хоть в середине, хоть в конце, т.к. загрузчик определяет его положение по двойному слову e_lfanew, смещенному на 0x3C байт от начала файла. Находим это смещение:

Драйвер подмены сертификатов - 13

В нашем случае смещение на начало PE-заголовка равно 0x00E8.

PE-заголовок представляет собой 0x18-байтовую структуру данных, описывающую фундаментальные характеристики файла и содержащую «PEx0x0»-сигнатуру, по которой файл, собственно говоря, и отождествляется.

Драйвер подмены сертификатов - 14

Итак, мы нашли начало PE-заголовка. Следующие два байта от заголовка определяют тип процессора:

  • 0x014C — Intel 386 or later processors and compatible processors
  • 0x8664 — x64

От этого будут определятся окончательные смещения для нахождения сертификата. Однако мы поступим по-другому, и определим разрядность файла по опциональному заголовку. Для этого отступим от PE-заголовка 0x18 байт и проверим «Magic number» (начало опционального заголовка):

  • 0x00E8 + 0x18 = 0x0100

Драйвер подмены сертификатов - 15

Есть два варианта:

  • 0x010B – соответствует PE32. 32-х разрядный файл
  • 0x020B – соответствует PE32+. 64-х разрядный файл.

В нашем варианте файл 32-х битный. Теперь находим количество элементов в DATA_DIRECTORY. Каждая структура данных содержит виртуальный адрес и размер.

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

Смещение до количества элементов от начала опционального заголовка равно 0x5C (PE32+ = 0x6C):

  • 0x0100 + 0x5C = 0x015C (PE32)

Драйвер подмены сертификатов - 16

Количество элементов (не байт) в DATA_DIRECTORY, следующей непосредственно за этим полем. Из-за грубых ошибок в системном загрузчике компоновщики от Borland и Microsoft всегда выставляют полный размер директории, равный 10h, даже если реально его не используют.

Нас интересует смещение от начала опционального заголовка на 0x80 (0x90). Это смещение соответствует структуре IMAGE_DIRECTORY_ENTRY_SECURITY. Указывает на Certificate Table (таблицу сертификатов), располагающуюся строго в .debug-секции и адресуемой не по RVA-адресам, а по физическим смещениям внутри файла (так происходит потому, что таблица сертификатов не грузится в память и обитает исключительно на диске):

  • 0x0100 + 0x80 = 0x0180 (PE32)

Драйвер подмены сертификатов - 17

Исходя из выше описанной структуры IMAGE_DATA_DIRECTORY, получаем:

  • 0x00028400 – адрес начала атрибутов таблицы сертификата,
  • 0x000003B0 – размер таблицы.

Драйвер подмены сертификатов - 18

Перейдя по адресу, мы также видим размер таблицы 0x000003B0. Так же можно получить следующие параметры:

  • 0x0200 – версия. В данном случае WIN_CERT_REVISION_2_0
  • 0x0002 – тип сертификата. В данном случае WIN_CERT_TYPE_PKCS_SIGNED_DATA. Что означает, что сертификат содержит PKCS#7 структуру.

Если прибавить к адресу начала таблицы сертификата его размер, то мы получим конец файла:

  • 0x00028400 + 0x000003B0 = 0x000287B0

Драйвер подмены сертификатов - 19

После структуры нулями происходит дополнение до кратного Quadword (64 бита).
Итак, делаем выводы.

  • С помощью PE-заголовка мы может получить адрес начала и размер структуры сертификата, которым подписан файл. Причем адрес начала данной структуры является окончание файла, т.е. сертификат, которым подписан файл всегда хранится в конце файла.
  • Если же в структуре IMAGE_DIRECTORY_ENTRY_SECURITY адрес и размер указан ноль, то файл не подписан.

Ручная подпись файла

Для ручной подписи неподписанного файла или для подмены сертификата в файле нам необходимо сделать следующее:

  • Сохранить структуру сертификата из ранее подписанного нами файла нашим сертификатом. В приведенном выше примере необходимо сохранить в отдельный файл структуру начиная с адреса 0x00028400 размером 0x000003B0 (или до конца файла).
  • В заданном файле определить адрес куда необходимо дописать нашу структуру. Для этого или получаем адрес на уже существующий сертификат или, если его нет, за адрес будем считать конец файла.
  • Создаем новый файл и копируем в него со старого файла все данные до найденного выше адреса.
  • Далее дописываем ранее сохраненную нами структуру с нашим сертификатом.
  • На последнем этапе необходимо в PE-заголовке нового файла изменить адрес и размер структуры IMAGE_DIRECTORY_ENTRY_SECURITY. Адрес должен указывать на наш, найденный во втором пункте, а размер – размер нашей структуры с нашим сертификатом.

В конце мы получим файл, подписанный нашим сертификатом, однако если проверить его цифровую подпись, то мы обнаружим, что она не действительна. Проблем тут кроется в том, что при замене или при добавлении нашей структуры мы не вычисляем хеш-сумму файла и не шифруем ее закрытым ключом. ТУТ МОЖНО ЭТО ВЫДЕЛИТЬ В КАК В АЛЬТЕРНАТИВНЫЙ МЕТОД. Т.е. вручную считать хеш сумму, шифровать ее закрытым ключом в драйвере и самому создавать структуру WIN_CERTIFICATE и записывать ее в новый файл.

Данный метод реализован в первой версии драйвера (см. ниже).

Драйвер подмены сертификатов - 20

Подпись файла с помощью недокументированной функции SignerSignEx

Функция SignerSignEx позволяет подписывать файл сертификатом pfx, загруженным как с диска, так и из памяти. Для ее работы достаточно загрузить вспомогательными функциями pfx сертификат, скомпилированный вместе с программой в формате BASE64 (для простоты необходимой замены) и затем подписать указанный файл. Файл будет подписан так же, как и утилитой signtool.exe. После этого сертификат будет действителен, так как хеш сумма будет вычислена правильно и зашифрована закрытым ключом.

Данный метод реализован во второй версии драйвера.

Драйвер подмены сертификатов - 21

Описание работы драйвера

Сборка драйвера

Код драйвера написан на языке программирования C++ в среде Microsoft Visual Studio 2012.
Для компиляции необходимо установить пакет Windows Driver Kit Version 7.1.0.

Настройка работы драйвера

Обе версии драйвера имеют одинаковые настройки, которые прописываются в реестре.
Ветка реестра:

  • HKEY_LOCAL_MACHINESYSTEMcertchange

Параметры:

  • IncludeFilter – Данный параметр может содержать список файлов, которые будут обрабатываться драйвером. Разделителем служит точка с запятой;
  • ExcludeFilter – Данный параметр может содержать список файлов, которые будут драйвером пропускаться. Разделителем служит точка с запятой.

Пример:

  • IncludeFilter = wmplayer.exe;iexplore.exe
  • ExcludeFilter = svchost.exe

Драйвер подмены сертификатов - 22

Если задан параметр IncludeFilter, то параметр ExcludeFilter будет игнорироваться. Драйвер будет обрабатывать только файлы, заданные параметром IncludeFilter.

Если параметр IncludeFilter не задан (или пустой), то драйвер будет обрабатывать все exe файлы, которые не заданы в параметре ExcludeFilter.

Удаление драйвера из системы

Для удаления драйвера достаточно запустить реестр и удалить ветку реестра:

  • HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicescertchange

После этого необходимо перезагрузить компьютер.

Установка драйвера

Для установки драйвера любой из версий необходимо зайти в соответствующую папку. На файле certchange.inf нажать правой кнопкой мышки и выбрать пункт «Установить».

Драйвер подмены сертификатов - 23

После перезагрузки драйвер запустится автоматически.

Драйвер. Версия 1

В данной версии драйвера реализован описанный ранее метод «Ручная подпись файла».

Драйвер подмены сертификатов - 24

После запуска драйвер читает из реестра параметры. Регистрирует себя как фильтр файловой системы. И подписывается на событие IRP_MJ_CREATE.

При срабатывании события драйвер вычленяет из полученных данных имя файла.

Происходит проверка на первый символ файла. Если он равен символу нижнее подчеркивание (_), то данный файл пропускается (см. описание дальше).

Затем происходит проверка расширения файла. Если оно отлично от EXE, то файл так же пропускается.

Далее имя файла проходит через фильтр. Если фильтр не пройден, то файл пропускается.
Из текущего имени файла генерируется новое. Для этого путь к файлу остается неизменным, а к имени спереди добавляется символ нижнее подчеркивание (_).

Например, из файла wmplayer.exe новое имя будет сгенерировано таким _wmplayer.exe.

Проверяем существует ли новый файл. Если файл уже есть такой, то драйвер при возврате управления подменяет оригинальное имя файла на новое.

Если нового файла нет, то драйвер создает его. Для этого создается буфер в памяти равный размеру исходного файла. Этот буфер обрабатывается соответствующим образом:

  • В PE заголовке ищем смещение PE.
    peStart = get32(buf, 0x3C);
  • Затем читаем 16 битное число по смещению 24 и проверяем файл 32 битный или же 64 битный.
    peMagic = peStart + 24;
    temp = get16(buf, peMagic);
    if(get16(buf, peMagic) == 0x020B) Is64 = TRUE;
    Если значение temp = 0x020B значит перед нами 64-х битный файл.
  • В зависимости от пункта 2 смещаемся на 144 или 128 байт для начала структуры описания сертификата:
    addrCertStruct = peMagic+(Is64? 144: 128);
  • Читаем начала смещения сертификата в файле и его размер.
    addrCertStart = get32(buf, addrCertStruct);
    addrCertSize = get32(buf, addrCertStruct + 4);
  • Декодируем из системы BASE64 наш сертификат, который мы будем записывать в файл.
    CERTbuf = base64_decode(CERT64, strlen(CERT64), &CERTbuflenght);
  • Задаем новое смещение сертификата в файле если его не было, а так же новый его размер
    if(addrCertStart == 0) addrCertStart = bufsize;
    newbufsize = addrCertStart + CERTbuflenght;
  • Создаем новый буфер для файла с учетом нового размера сертификата. Копируем в буфер файл, а затем в конец добавляем наш сертификат.
  • Записываем в новый буфер по смещению структуры сертификата новое его смещение и размер.

Буфер записывает с новым именем файла. Так же новому файлу выставляется атрибут скрытый.

Далее драйвер возвращает управление, так же подменив старое имя файла на новое.

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

Скриншоты работы драйвера:

Драйвер. Версия 2

В данной версии драйвера реализован описанный ранее метод «Подпись файла с помощью недокументированной функции SignerSignEx».

Драйвер подмены сертификатов - 25

После запуска драйвер читает из реестра параметры. Регистрирует себя как фильтр файловой системы. И подписывается на событие IRP_MJ_CREATE.

При срабатывании события драйвер вычленяет из полученных данных имя файла. Происходит проверка на первый символ файла. Если он равен символу нижнее подчеркивание (_), то данный файл пропускается (см. описание дальше).

Затем происходит проверка расширения файла. Если оно отлично от EXE, то файл так же пропускается.

Далее имя файла проходит через фильтр. Если фильтр не пройден, то файл пропускается.
Из текущего имени файла генерируется новое. Для этого путь к файлу остается неизменным, а к имени спереди добавляется символ нижнее подчеркивание (_).

Например, из файла wmplayer.exe новое имя будет сгенерировано таким _wmplayer.exe.

Проверяем существует ли новый файл. Если файл уже есть такой, то драйвер при возврате управления подменяет оригинальное имя файла на новое.

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

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

Вспомогательная программа для драйвера версии 2

В данной версии драйвера основную работу по подписи файла осуществляет вспомогательная программа.

После старта драйвера он обрабатывает все события, но не производит никаких действий с файлами, прошедшими заданный параметрами фильтр пока будет не запущена программа certchangesign.exe.

После загрузки Windows будет загружен драйвер. Для его работы вручную запустите вспомогательную программу (далее программу):

Драйвер подмены сертификатов - 26

После запуска программы при успешном подключении к драйверу увидите сообщение «Подключение установлено». Внимание программа должна запускаться от имени администратора.

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

Программа после получения сообщения от драйвера с именем нового файла. Подписывает его распакованным из BASE64 формата сертификатом pfx.

Чтобы данная подпись была действительной необходимо сертификат добавить в Доверенные корневые центры сертификации.

Автор: BDEsoft

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js