Защита на .net приложения от любопитни очи
„Как да защитите кода на вашето .net приложение?“ - един от онези въпроси, които често могат да се чуят в различни форуми.
Защитата ще се основава на криптиране на модули със симетричен ключ и динамичното им дешифриране по време на работа на приложението. Ключът за криптиране ще бъде дефиниран от потребителя по време на фазата на внедряване и въведен като парола при стартиране.
Нека разделим всичко на етапи:
- Предварителна работа
- Въвеждане на парола
- Декриптиране на сглобяването
- Отмяна на зареждането на сглобката
- Стартиране на приложение
- Черешката на тортата
- Допълнителни настройки на проекта
- Внедряване и криптиране на сборки
Предварителна работа
Тъй като трябва по някакъв начин да дешифрираме приложението преди стартиране, ще направим обвивка, която ще поеме тази неблагодарна работа.
Обвивката ще бъде нормално конзолно приложение.
Въвеждане на парола
При въвеждане въведените знаци няма да се показват на екрана и след натискане на Enter въвеждането ще приключи. _password е поле за клас, което съхранява паролата, въведена от потребителя.
Декриптиране на сглобяването
Криптирането е разделено на два вида: симетрично и асиметрично. Symmetric използва един и същ ключ за криптиране и декриптиране, докато asymmetric използва различни ключове.
Тъй като не се нуждаем от различни ключове, ще се съсредоточим върху симетричното криптиране.
За да дешифрираме нещо криптирано, имаме нужда от три компонента:
- Криптирани данни;
- Ключът, с който са криптирани;
- Инициализационният вектор (IV) са несекретните данни, използвани за първия етап на криптиране.
За да улесним работата, ще напишем специален клас CryptedData:
Последният метод, GetKey, има малко магия в него.
Първата точка е, че дължината на ключа трябва да бъде равна на 128, 192 или 256 бита. И като парола за стартиране може да има низ с произволна дължина. Следователно ние просто хешираме низа на паролата с помощта на sha256 и получаваме дължината, която търсим.
Втората магия е по-готина и е свързана със SecureString. Този клас е само за запис и за да получим съдържанието му, трябва да използваме опасен код:
Какво се случва в този код?
- Подготвят се две части от кода, едната е основната, която върши цялата работа, втората е кодът за почистване в случай на изключение;
- Основният код създава нов низ, който ще съдържа стойността на SecureString и ще бъде принудително изчистен в метода Dispose;
- Копира данни от SecureString във вътрешен низ чрез указатели и заключва вътрешния низ за събирача на отпадъци;
- Чрез вътрешния низ можем да получим данните SecureString.
Важно е да запазите жизнения прозорец на екземпляр на InsecureString възможно най-кратък, за да сведете до минимум риска дебъгерът да прочете защитените низови данни.
Хеширането, описано по-горе, помага за това, тъй като имаме нужда само от екземпляра InsecureString, за да получим хеша, а след това работим със самия хеш, от който не можем да извлечем оригиналната стойност на SecureString.
Отмяна на зареждането на сглобката
Тъй като те може вече да са необходими, когато влязат в Main, ще предефинираме механизма по-рано, в конструктора на типове. На същото място, за удобство, ще закрепим обработката на изключение:
Стартиране на приложение
черешаторта
Скриване на прозореца на конзолата
Маскиране на приложението
Ясно е, че това няма да работи срещу разглобителя, но ще отнесе безделниците.
Допълнителни настройки на проекта
За да работи правилно, опасният код трябва да бъде разрешен в модула на зареждащия механизъм. Най-лесният начин да направите това е чрез настройките на проекта.
Внедряване и криптиране на сборки
Послеслов
Очевидно слабото място на такава защита е необходимостта да се знае паролата за всеки, който ще използва приложението. Важно е също така да разберете, че асемблиращият код може да бъде получен от дизасемблер, докато използвате приложението.
Но ако има нужда да скриете какво прави помощната програма, която използвате сами, от любопитни очи, този подход се оправдава.
Hardcore conf в C++. Каним само професионалисти.
Чете сега
Курс на MIT "Сигурност на компютърните системи". Лекция 22: „Информационна сигурност на MIT“, част 2
Курс на MIT "Сигурност на компютърните системи". Лекция 22: „Информационна сигурност на MIT“, част 1
Как да празнуваме деня на информационната сигурност
Коментари 16
това няма да работи срещу разглобител, но ще отнеме безделниците
Ще трябва да импортираме няколко естествени метода и да скрием самия прозорец Скриване на конзолата
Какъв е смисълът от стореното? Човекът в ILSpy ще отвори основния модул, ще намери кода за декриптиране и бързо ще дешифрира вашите сборки. И като цяло няма голяма стойност в самите алгоритми и ако трябва да използвате програмата без ограничения, тогава вашият метод не само няма да спре, но дори ще забави нападателя.
Просто объркването е по-надеждно.
Очевидно слабото място на такава защита е необходимостта да се знаепарола за всички, които ще използват приложението. Важно е също така да разберете, че асемблиращият код може да бъде получен от дизасемблер, докато използвате приложението.
Но ако има нужда да скриете какво прави помощната програма, която използвате сами, от любопитни очи, този подход се оправдава.
Основният проблем не е да се открадне код, а да се открадне четим и поддържаем код. Така че объркаността е по-добра. Още по-добре е да комбинирате двата метода.
И даването на кода заедно с паролата не е много по-трудно от просто даването на кода - това е в случай на злонамерено доверено лице. По този начин всички тези трикове работят само в случай на загуба на контрол над неволно разпространение на код.
Говорейки за използването на SHA-256 като ключ: струва ми се, че намирането на слаба парола с шифрован сбор ще бъде доста лесно. (Ако паролата е силна, най-вероятно ще бъде в текстов файл до сборката). AEC, както знаете, е блоков шифър, той работи на блокове според размера на ключа. Асамблеята трябва да има свой собствен добре дефиниран формат, особено в началото. По този начин, за да определите валидността на ключа по време на селекцията, трябва да опитате да дешифрирате първите 256 байта, и да видите дали са валидни, тоест не е необходимо да декриптирате целия сбор, което значително ще увеличи загубата на време за селекция.
Не е необходимо да избирате всички 256 бита, по-лесно е да изберете парола - до определена дължина има просто по-малко възможности от 2 ^ 256.
Умниците, които пишат тук за дешифриране на AES-256 без парола - нека пробват, аз бих го погледнал. Някой съветва да се използва лицензиране като Portable.Licensing, .NET Reactor и др. всички тези боклуци са заснети от de4dotслед минутка,
Обърканият, но възстановен код на имена като Class1, Class2 може да бъде доста разбираем, за да разберете логиката/идеята на вашия софтуер и да направите аналог или да накарате софтуера да работи на друго място.
Методът от статията, разбира се, не е панацея и ако желаете, можете да изхвърлите дешифрирания сбор от паметта на работещия процес.