Задумался я тут над смыслом подписания компоновочных блоков .Net. Наверняка Вы тоже подписывали свои библиотеки, что бы установить их в GAC.
В ходе расследования мы научимся изменять подписанные сборки, не обладая исходниками и секретными ключами.
При подписании библиотеки (назначении строгого имени) открытый ключ записывается в манифест. Таким образом, что бы внести изменения в чужую подписанную библиотеку, нужно просто заменить публичный ключ на свой. Или, еще проще, сделать новую сборку с таким же именем и подписать на своем ключе.
При использовании библиотеки любой публичный ключ будет принят как доверенный.
Проведем следующий эксперимент. Создадим небольшую библиотечку.
Подпишем её и добавим к проекту консольного приложения:
Затем скомпилируем релиз проекта.
С помощью .NET Reflector и плагина Reflexil отредактируем IL код подписанной библиотеки (signedLib.dll), так что GetNumber() будет возвращать не «1», а «2». Консольное приложение не заметило подмены и вывело «2».
Вывод такой: подменить/изменить приватную сборку со строгим именем очень просто. Другие сборки ссылающиеся на измененную никак на это не реагируют, не смотря на то, что были скомпилированы с оригинальной.
Обращаю внимание что речь идет именно о приватных сборках, со сборками в GAC дело обстоит иначе.
Приватные это те которые не в GAC.
Как мы только что убедились подписанные приватные компоновочные блоки можно легко модифицировать. При этом не обязательно обладать ни исходниками, ни секретным ключом, ни правами администратора.
Вносить изменения в сборки установленные в GAC не многим сложнее.
В случаи с приватными сборками не играет ни какой роли подписаны они или нет. Подпись не проверяется, а «полный идентификатор приватного компоновочного блока состоит из имени компоновочного блока и числового номера его версии» (из книги Э. Троелсена).
Сборки устанавливаемые в GAC должны иметь так называемое строгое имя. Сборка получает строгое имя как только вы её подписываете. Идентификаторы сборок в GAC дополняются параметрами публичного ключа, подписи проверяются.
Окружили демоны:
Но не нужно быть криптографом что бы все же изменить библиотеку в GAC, а нужно обладать правами администратора и знать параметры утилиты sn.exe.
Страдальцы не имеющие студии вручную используют стандартную утилиту sn.exe для подписания компоновочных блоков.
Итак, возьмем проект уже знакомой библиотеки signedLib.dll (см. листинг 1). подпишем её и установим в GAC.
Добавим референс к консольному приложению changeKey.exe (см. листинг 2). Компилируем релиз, убеждаемся что в папке с программой нет файла signedLib.dll (значит сборка будет загружена из GAC). Запускаем changeKey.exe — приложение показывает «1».
С этого момента воображаем себя атакующими — у нас нет исходников, нет секретного ключа. Но нам надо что бы метод GetNumber() возвращал не 1 а 2.
Структуру файлов ниже C:\Windows\assembly проводник windows не показывает. Создадим псевдодиск на который будет проецироваться нужный каталог:
В проводнике появился диск B.

.Net сборки попадают в папку GAC_MSIL, находим нужную папку (её название совпадает с названием .dll файла). Внутри будет еще одна папка, а в ней наконец signedLib.dll. Копируем signedLib.dll на рабочий стол.
С помощью замечательной программы .NET Reflector и не менее замечательного плагина Reflexil будем редактировать библиотеку. Предварительно перепишем токен публичного ключа и его значение в блокнот (они нам пригодятся позже). Как мы уже знаем публичный ключ записан в самой сборке, теперь в этом можно окончательно убедиться.

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

Нажимаем «Remove Strong Name» — удалить цифровую подпись. Закрываем сборку.
Теоретически закрывать сборку нет необходимости и нам должен подойти вариант «Register it for verification skipping». Однако у меня эта операция заканчивается ошибкой. К тому же в обучающих целях лучше проделать все операции вручную.
Теперь у нас есть:
Осталось установить её в GAC. Для этого воспользуемся механизмом отложенной подписи. Если сборка содержит информацию о публичном ключе, но не имеет цифровой подписи — говорят что она имеет отложенную подпись. Придумал это какой-то извращенный мозг из микрософт «для тестирования».
Сделать такую сборку с помощью .NET Reflector не составляет никакой сложности — нужно заполнить соответствующие поля, они выделены желтым на рис.2. (Помните мы копировали их значения в блокнот?). И не забудьте поставить галочку «HasPublicKey».
В теории публичный ключ нужно извлекать из секретного с помощью утилиты sn.exe, и потом с помощью неё же создавать отложенную подпись.
Мы получили сборку которая называется так же как оригинальная, имеет такую же версию и такой же публичный ключ. Т.е. если, её установить в GAC она получит точно такой же идентификатор как и оригинальная (см. начало начало статьи). Как я писал выше, по умолчанию у сборок в GAC проверяется подпись, однако проверку подписи можно отключить — опять же «для тестирования».
Что бы отключить проверку подписи dll на данном компьютере нужно воспользоваться sn.exe
Удаляем оригинальную сборку из GAC:
устанавливаем измененную:
Радуемся, глядя на выведенную gacutil.exe надпись:
Вот мы и добились желаемого — изменили библиотеку установленную в GAC. Что бы еще раз порадоваться (и проверить результат) запускаем наше приложение changeKey.exe, которое в начале статьи выводило 1, теперь он покажет 2.
Публичный ключ записан в самой сборке (точнее в манифесте);
В случаи с приватными сборками подписи не проверяются.
Что бы изменить сборку в CAG нужно:
Для шагов 5, 6, 7 нужно обладать правами администратора.
В ходе расследования мы научимся изменять подписанные сборки, не обладая исходниками и секретными ключами.
Приватные сборки
При подписании библиотеки (назначении строгого имени) открытый ключ записывается в манифест. Таким образом, что бы внести изменения в чужую подписанную библиотеку, нужно просто заменить публичный ключ на свой. Или, еще проще, сделать новую сборку с таким же именем и подписать на своем ключе.
При использовании библиотеки любой публичный ключ будет принят как доверенный.
Проведем следующий эксперимент. Создадим небольшую библиотечку.
namespace signedLib
{
public class sLib
{
public static int GetNumber() { return 1; }
}
}
Листинг 1. Библиотека signedLib.dll
Подпишем её и добавим к проекту консольного приложения:
namespace changeKey
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(signedLib.sLib.GetNumber());
Console.ReadLine();
}
}
}
Листинг 2. Консольное приложение changeKey.exe
Затем скомпилируем релиз проекта.
С помощью .NET Reflector и плагина Reflexil отредактируем IL код подписанной библиотеки (signedLib.dll), так что GetNumber() будет возвращать не «1», а «2». Консольное приложение не заметило подмены и вывело «2».
Вывод такой: подменить/изменить приватную сборку со строгим именем очень просто. Другие сборки ссылающиеся на измененную никак на это не реагируют, не смотря на то, что были скомпилированы с оригинальной.
Обращаю внимание что речь идет именно о приватных сборках, со сборками в GAC дело обстоит иначе.
Приватные это те которые не в GAC.
Сборки в GAC
Как мы только что убедились подписанные приватные компоновочные блоки можно легко модифицировать. При этом не обязательно обладать ни исходниками, ни секретным ключом, ни правами администратора.
Вносить изменения в сборки установленные в GAC не многим сложнее.
В случаи с приватными сборками не играет ни какой роли подписаны они или нет. Подпись не проверяется, а «полный идентификатор приватного компоновочного блока состоит из имени компоновочного блока и числового номера его версии» (из книги Э. Троелсена).
Сборки устанавливаемые в GAC должны иметь так называемое строгое имя. Сборка получает строгое имя как только вы её подписываете. Идентификаторы сборок в GAC дополняются параметрами публичного ключа, подписи проверяются.
Окружили демоны:
- незаметно внести изменения не получится — подпись проверку не пройдет
- свой публичный ключ не подсунешь — идентификатор сборки изменится
Но не нужно быть криптографом что бы все же изменить библиотеку в GAC, а нужно обладать правами администратора и знать параметры утилиты sn.exe.
Страдальцы не имеющие студии вручную используют стандартную утилиту sn.exe для подписания компоновочных блоков.
Итак, возьмем проект уже знакомой библиотеки signedLib.dll (см. листинг 1). подпишем её и установим в GAC.
gacutil.exe /i D:\projects\changeKey\signedLib\bin\Release\signedLib.dll
Добавим референс к консольному приложению changeKey.exe (см. листинг 2). Компилируем релиз, убеждаемся что в папке с программой нет файла signedLib.dll (значит сборка будет загружена из GAC). Запускаем changeKey.exe — приложение показывает «1».
С этого момента воображаем себя атакующими — у нас нет исходников, нет секретного ключа. Но нам надо что бы метод GetNumber() возвращал не 1 а 2.
Структуру файлов ниже C:\Windows\assembly проводник windows не показывает. Создадим псевдодиск на который будет проецироваться нужный каталог:
subst b: C:\Windows\assembly
В проводнике появился диск B.
рис. 1. Папки ниже C:\Windows\assembly
.Net сборки попадают в папку GAC_MSIL, находим нужную папку (её название совпадает с названием .dll файла). Внутри будет еще одна папка, а в ней наконец signedLib.dll. Копируем signedLib.dll на рабочий стол.
С помощью замечательной программы .NET Reflector и не менее замечательного плагина Reflexil будем редактировать библиотеку. Предварительно перепишем токен публичного ключа и его значение в блокнот (они нам пригодятся позже). Как мы уже знаем публичный ключ записан в самой сборке, теперь в этом можно окончательно убедиться.
рис. 2. Параметры публичного ключа
После правки IL кода и сохранения изменений, программа сообщит о том что цифровая подпись нарушена и предложит варианты дальнейших действий:
Нажимаем «Remove Strong Name» — удалить цифровую подпись. Закрываем сборку.
Теоретически закрывать сборку нет необходимости и нам должен подойти вариант «Register it for verification skipping». Однако у меня эта операция заканчивается ошибкой. К тому же в обучающих целях лучше проделать все операции вручную.
Теперь у нас есть:
- измененная, не подписанная dll библиотека;
- публичный ключ оригинальной библиотеки.
Осталось установить её в GAC. Для этого воспользуемся механизмом отложенной подписи. Если сборка содержит информацию о публичном ключе, но не имеет цифровой подписи — говорят что она имеет отложенную подпись. Придумал это какой-то извращенный мозг из микрософт «для тестирования».
Сделать такую сборку с помощью .NET Reflector не составляет никакой сложности — нужно заполнить соответствующие поля, они выделены желтым на рис.2. (Помните мы копировали их значения в блокнот?). И не забудьте поставить галочку «HasPublicKey».
В теории публичный ключ нужно извлекать из секретного с помощью утилиты sn.exe, и потом с помощью неё же создавать отложенную подпись.
Мы получили сборку которая называется так же как оригинальная, имеет такую же версию и такой же публичный ключ. Т.е. если, её установить в GAC она получит точно такой же идентификатор как и оригинальная (см. начало начало статьи). Как я писал выше, по умолчанию у сборок в GAC проверяется подпись, однако проверку подписи можно отключить — опять же «для тестирования».
Что бы отключить проверку подписи dll на данном компьютере нужно воспользоваться sn.exe
sn -Vr C:\Users\Alex\Desktop\signedLib.dll
Удаляем оригинальную сборку из GAC:
gacutil /u signedLib,Version=1.0.0.0,Culture=neutral,PublicKeyToken=2b1b71846e76146e
устанавливаем измененную:
gacutil /i C:\Users\Alex\Desktop\signedLib.dll
Радуемся, глядя на выведенную gacutil.exe надпись:
Assembly successfully added to the cache
Вот мы и добились желаемого — изменили библиотеку установленную в GAC. Что бы еще раз порадоваться (и проверить результат) запускаем наше приложение changeKey.exe, которое в начале статьи выводило 1, теперь он покажет 2.
Подведем итог
Публичный ключ записан в самой сборке (точнее в манифесте);
В случаи с приватными сборками подписи не проверяются.
Что бы изменить сборку в CAG нужно:
- Сделать копию нужного dll файла из C:\Windows\assembly (воспользовавшись командой subst)
- Извлечь из сборки публичный ключ
- Модифицировать IL код сборки и удалить цифровую подпись
- Добавить к измененному файлу публичный ключ, полученный на шаге 2 (создадим отложенную подпись)
- Отменить проверку цифровой подписи для модифицированной сборки на данном компьютере
- Удалить оригинальную сборку из GAC
- Установить модифицированную сборку.
Для шагов 5, 6, 7 нужно обладать правами администратора.