Всем привет!
Мы хотим рассказать о нашем опыте исследования цифровых подписей Windows PE файлов и возможном варианте использования их особенностей в своих целях. Если вам интересны технические подробности или просто чтиво о, казалось бы, давно известных вещах, добро пожаловать под кат.
User Account Control
Многие из вас знают, что с приходом Windows Vista, появилась такая интересная вещь под названием UAC (User Account Control). Этот механизм сделан для повышения безопасности, и его суть заключается в ограничении доступа приложений к критически важным частям операционной системы. Однако возможность добраться до этих частей всё-таки существует, и контроль над этим есть у пользователя.
Любое Windows приложение может содержать манифест – XML файл, используемый Windows при запуске приложения. В этом манифесте может быть описано требование для запуска приложения с повышенными привилегиями, и в этом случае при запуске приложения пользователь увидит то самое UAC окно с вопросом – а стоит ли доверять приложению и позволить ему запуститься с максимальными правами?
Для того, чтобы облегчить пользователю задачу на данном этапе, а разработчикам позволить быть уверенными в целостности и оригинальности передаваемых файлов, Microsoft предлагает авторам легального и безвредного ПО использовать цифровые подписи. Они удостоверяют автора, и, что более важно, подлинность оригинального файла.
Видя запрос на запуск с информацией о проверенном издателе, пользователь может быть уверен, что содержимое исполняемой части этого файла не изменилось, и его можно запускать с чистой совестью (если он, конечно, доверяет этому автору). Однако при запросе на запуск приложения от непроверенного издателя, стоит задуматься, проанализировать возможные причины и последствия.
Ближе к теме
Но что, если мы (авторы этих приложений) хотим передавать в них какую-либо дополнительную информацию, которая будет известна только в момент скачивания? Ведь любое изменение файла автоматически делает цифровую подпись недействительной. Какие у нас есть варианты?
- Дописывать в название отдаваемого файла требуемые для передачи данные, а веб-сервером через регулярные выражения перенаправлять подобные запросы на один физический файл.
+ легко реализуемо;
+ внутренности файла остаются нетронутыми и подпись всегда верна;
– передать можно лишь небольшой набор данных (например, несколько идентификаторов);
– при переименовании файла информация пропадает. - Изменять данные внутри файла и переподписывать его при отдаче.
+ передать можно любой объем данных;
+ при переименовании ничего не теряется;
– переподписывание – очень долгий процесс, если речь идёт про отдачу сотен больших (100 MB+) дистрибутивов игр в секунду, как в нашем случае. - Изменять данные внутри файла и НЕ переподписывать его, сохраняя при этом корректную цифровую подпись.
+ передать можно любой объем данных;
+ при переименовании ничего не теряется;
+ не нужно переподписывать файл;
– это невозможно (или возможно?).
Немного теории
Ниже представлена структура Windows PE файла с информацией о том, из каких его частей формируется цифровая подпись, а какие блоки пропускаются в этом процессе.
Также показан формат блока цифровой подписи (структура PKCS#7), используемый Microsoft.
Ключевой момент в этой схеме — наличие блоков, исключаемых при генерации и проверке цифровой подписи. Эти блоки описываются простейшими C структурами:
«Таблица сертификатов» в секции «Директории данных» – это структура IMAGE_DATA_DIRECTORY:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
где:
- VirtualAddress — прямой указатель на атрибуты таблицы сертификатов в PE файле;
- Size — размер этого блока в PE файле.
«Атрибуты таблицы сертификатов» – это структура WIN_CERTIFICATE:
typedef struct _WIN_CERTIFICATE
{
DWORD dwLength;
WORD wRevision;
WORD wCertificateType;
BYTE bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
элементы которой содержат следующие значения:
- dwLength — размер секции Бинарных данных сертификата;
- wRevision — используемая версия структуры WIN_CERTIFICATE;
- wCertificateType — устанавливается в значение 0x0002 для цифровых подписей PE файлов. Значение определено в Wintrust.h как WIN_CERT_TYPE_PKCS_SIGNED_DATA;
- bCertificate — набор данных, содержащий цифровую подпись в формате PKCS#7.
При подписывании PE файла секция атрибутов таблицы сертификатов всегда помещается в конец файла (блок «Оставшееся содержимое» отсутствует). Зная об этой особенности, можно провернуть небольшой трюк с очень заманчивыми результатами.
Невозможное возможно
Фокус заключается вот в чём: размер секции, описанный в IMAGE_DATA_DIRECTORY может отличаться от фактического размера структуры WIN_CERTIFICATE, а при проверке цифровой подписи исключается вся секция, размер которой описан в IMAGE_DATA_DIRECTORY. При этом добавленное вручную содержимое в эту секцию уже не является частью цифровой подписи и по сути может содержать любой набор данных. Таким образом можно с легкостью добавлять любые данные в содержимое блока «Атрибуты таблицы сертификатов», предварительно изменив размер секции в структуре IMAGE_DATA_DIRECTORY, не повредив при этом цифровую подпись файла.
Вы должны понимать возможные последствия при использовании этого метода, иметь в виду тип передаваемых данных, объем, возможную их обработку и потенциальные дыры, связанные с этим. В ваших же интересах передавать там только такую информацию, которую можно безболезненно удалить/заменить/испортить (в случае, если кто-то захочет это сделать намеренно), но при этом не потерять основную функциональность.
«Конечно, а как же контрольная сумма PE файла?» — спросите вы. Спешу вас успокоить — она не играет никакой роли при запуске и работе обычных EXE файлов. Контрольная сумма проверяется только на критически важных системных файлах, например на неё ориентируется сервис System File Checker (для диагностики пропавших или повреждённых системных файлов).
В качестве заключения: кто и как этим пользуется?
Эту возможность использует Google при распространении своих продуктов через автоматический апдейтер Google Omaha. Возможно, вы замечали, что при загрузке Google Chrome или Google Earth, вам предлагают сделать некоторые настройки ещё перед скачиванием, например, установить вместе с Earth браузер Chrome. Эти настройки передаются как раз с помощью тегирования дистрибутива — процесса дописывания данных в EXE файл, которые Omaha в дальнейшем обрабатывает на локальной машине пользователя.
Также эту возможность удобно использовать в различных партнёрских сетях – отдача дистрибутивов с трекингом партнёра — необходимость в различных компаниях.
Механизм по отдаче файлов с веб-сервера с использованием этой фичи может быть реализован с помощью самописного плагина для nginx, виртуальной файловой системы на основе FUSE, или ещё каким-нибудь более экзотическим способом (расскажите в комментах, если придумали свой вариант).
Информацию о цифровых подписях PE файлов можно почерпнуть из этого документа: Windows Authenticode Portable Executable Signature Format.
Автор: Dipp