Задумався я тут над сенсом підписання компонувальних блоків. Net. Напевно, ти теж підписував свої бібліотеки, щоб встановити їх в GAC. У ході сьогоднішнього розслідування ми навчимося змінювати підписані збірки, не володіючи исходниками і секретними ключами.
Приватні збірки

При підписанні бібліотеки (призначення суворого імені) відкритий ключ записується в маніфест. Таким чином, щоб внести зміни в чужу підписану бібліотеку, потрібно просто замінити публічний ключ на свій. Або - ще простіше - зробити нову збірку з таким же ім'ям і підписати на своєму ключі.

При використанні бібліотеки будь-який публічний ключ буде прийнятий як довірений.

Проведемо експеримент, створимо невелику бібліотечку:

Бібліотека signedLib.dll

namespace signedLib
{
public class sLib
{
public static int GetNumber () {return 1;}
}
}

Підпишемо її і додамо до проекту консольного програми:

Консольний додаток changeKey.exe

namespace changeKey
{
class Program
{
static void Main (string [] args)
{
Console.WriteLine (signedLib.sLib.GetNumber ());
Console.ReadLine ();
}
}
}

Потім скомпіліруем реліз проекту. З допомогою. NET Reflector [1] і плагіна Reflexil [2] відредагуємо IL-код підписаної бібліотеки (signedLib.dll), так що GetNumber () буде повертати не "1", а "2". Консольний додаток не помітило підміни і вивело "2". Висновок: підмінити / змінити приватну збірку із суворим ім'ям дуже просто. Інші збірки, що посилаються на змінену, ніяк на це не реагують, незважаючи на те, що вони були скомпільовані з оригінальною. Звертаю увагу, що мова йде саме про приватних збірках, зі складками в GAC справа йде інакше.
Складання в GAC

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

Вносити зміни до збірки, встановлені в GAC, не багатьом складніше. У випадку з приватними збірками їх "підписання" ніякої ролі не грає. Підпис не перевіряється, а "повний ідентифікатор приватного компоновочного блоку складається з імені компоновочного блоку і числового номера його версії" (з книги Е. Троелсен).

Складання, встановлювані в GAC, повинні мати так зване строге ім'я. Збірка отримує суворе ім'я в момент її підписання. Ідентифікатори збірок в GAC доповнюються параметрами публічного ключа, підписи перевіряються. Замурували, демони! Що ж це виходить? Оточили з усіх боків:

    * Непомітно внести зміни не вийде - підпис перевірку не пройде;
    * Свій публічний ключ не подсунешь - ідентифікатор збірки зміниться.

Тим не менш, не потрібно бути криптографом, щоб все ж таки змінити бібліотеку в GAC. Потрібно всього лише володіти правами адміністратора і знати параметри утиліти sn.exe (страждальці, що не мають Студії, вручну використовують стандартну утиліту sn.exe для підписання компонувальних блоків).

Отже, візьмемо проект вже знайомої бібліотеки signedLib.dll. Підпишемо її і встановимо в GAC.

gacutil.exe / i D: \ projects \ changeKey \ signedLib \ bin \ Release \ signedLib.dll

Додамо референс до консольного додатком changeKey.exe. Компілюємо реліз, переконуємося, що в папці з програмою немає файлу signedLib.dll (це означає, що збірка буде завантажена з GAC). Запускаємо changeKey.exe - додаток показує "1".

З цього моменту уявляємо себе атакуючими - у нас немає вихідного, немає секретного ключа. Але треба, щоб метод GetNumber () повертав не 1, а 2.

Структуру файлів нижче C: \ Windows \ assembly провідник Windows не показує. Створимо псевдодіск, на який буде проектуватися потрібний каталог:

subst b: C: \ Windows \ assembly

У провіднику з'явився диск B.

. Net збірки потрапляють в папку GAC_MSIL; знаходимо потрібну папку (її назва співпадає з назвою. Dll файлу). Усередині буде ще одна папка, а в ній, нарешті, signedLib.dll. Копіюємо signedLib.dll на робочий стіл.

За допомогою чудової програми. NET Reflector і не менш чудового плагіна Reflexil (на нашому диску все це господарство тебе вже зачекалася) ми будемо редагувати бібліотеку. Попередньо перепишемо токен публічного ключа і його значення в блокнот (знадобляться пізніше). Як ми вже знаємо, публічний ключ записаний в самій збірці, і тепер в цьому можна остаточно переконатися.

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

Натискаємо "Remove Strong Name" - видалити цифровий підпис. Закриваємо збірку (теоретично закривати збірку немає необхідності і нам повинен підійти варіант "Register it for verification skipping", однак у мене ця операція закінчується помилкою; до того ж, у навчальних цілях краще виконати всі операції вручну).

Тепер у нас є:

    * Змінена, не підписана dll;
    * Публічний ключ оригінальної бібліотеки.

Залишилося встановити її в GAC. Для цього скористаємося механізмом відкладеної підпису. Якщо збірка містить інформацію про публічний ключі, але не має цифрового підпису - кажуть, що вона має відкладену підпис (придумав це якийсь надмозг з Майкрософт "з метою тестування").

Зробити таку збірку з допомогою. NET Reflector не становить ніякої складності - потрібно заповнити відповідні поля, вони виділені жовтим на малюнку "Параметри публічного ключа" (пам'ятаєш, ми копіювали їх значення в блокнот?). І не забудь поставити галочку "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, потрібно:

   1. Зробити копію потрібного dll-файлу з C: \ Windows \ assembly (скориставшись командою subst).
   2. Витягти з збирання публічний ключ.
   3. Модифікувати IL-код складання і видалити цифровий підпис.
   4. Додати до зміненого файлу публічний ключ, отриманий на кроці 2 (створимо відкладену підпис).
   5. Скасувати перевірку цифрового підпису для модифікованої збірки на даному комп'ютері.
   6. Видалити оригінальну збірку з GAC.
   7. Встановити модифіковану збірку.

Для реалізації кроків 5-7 потрібно мати права адміністратора. Ось і все! На цьому дозволь попрощатися і побажати тобі величезних творчих узбеків на ниві досліджень програмного забезпечення.
INFO

Для комфортного читання статті потрібно володіти базовими знаннями в області криптографії з відкритим ключем.