Идеи продвинутого шифрования исполняемых файлов .NET в реальном времени

Идеи продвинутого шифрования исполняемых файлов .NET в реальном времени

Динамический шифратор (runtime-cryptor) шифрует двоичные исполняемые файлы с сохранением их функциональности. При запуске сначала расшифровывается тело файла, а затем исполняется код. Такой подход позволяет запускать вредоносные программы в защищенных средах и затрудняет детектирование по сигнатуре и блокирование подозрительных файлов антивирусными средствами.

Автор: Кристиан Амманн (Christian Ammann)

1 Введение

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

В последнем документе [1] изложены теоретические аспекты шифрования в реальном времени (runtime encryption) PE-заголовка [2] и продемонстрирована базовая реализация PE-шифратора Гиперион (Hyperion). Гиперион генерирует случайный ключ и использует этот ключ для шифрования входного файла с использованием алгоритма AES-128 [3]. При запуске файла происходит его расшифровка путем подбора (bruteforcing) нужного ключа. AES-ключ не содержится внутри шифрованного файла, что затрудняет детектирование зашифрованной области антивирусными средствами. Однако основная задача еще не решена: Гиперион шифрует лишь стандартные PE-файлы (regular portable executables) и не поддерживает байт-код, который используется Microsoft в приложениях, написанных на C# [5], J# [6] и Visual Basic [7].

В этом документе рассказываются аспекты шифрования в реальном времени для платформы .NET и представляется пилотная версия для шифратора Гиперион. Структура документа: В разделе 2 описываются основы формата исполняемых файлов платформы .NET и интеграция таких файлов в стандартные PE-файлы. В разделе 3 рассматривается возможность реализации шифрования в реальном времени для NET-приложений. В разделе 3.1 в Гиперион добавляется поддержка шифрования в реальном времени и исследуются вопросы реверс-инжиниринга (reverse engineering)DLL-библиотек. Даже когда Гиперион загрузил дешифрованный файл в память, среда выполнения .NET считывает заголовочную информацию из соответствующего образа диска, но поскольку образ зашифрован, среда выполнения аварийно завершает свою работу. В разделе 3.2 мы решим эту проблему, путем частичного шифрования NET-файлов и представим пилотную реализацию. Некоторые продвинутые техники шифрования NET-приложений в реальном времени описываются в разделе 4.

2 Формат исполняемых приложений платформы .NET

Данный раздел описывает формат NET-приложений и механизм их загрузки/запуска в оперативной памяти. .NET framework – это платформа, созданная компанией Microsoft, позволяющая разрабатывать и запускать программные приложения. В отличие от других языков, например C, компилятор .NET не создает собственного машинного кода (native code), а преобразует исходник в байт-код, который называется Common Intermediate Language (CIL). Вдобавок к этому среда Common Language Runtime (CLR) является частью платформы .NET framework и функционирует в качестве среды исполнения. При запуске CIL-файл передается в среду CLR, которая трансформирует его байт-код в собственные машинные инструкции и запускает соответствующее приложение. Также существует возможность преобразования NET-исходника в собственный машинный код при помощи Native Image Generator (NGEN).

Платформа .NET была разработана компанией Microsoft для операционной системы Windows. Соответственно, код NET-приложений встроен в стандартные PE-файлы, которые имеют следующий формат:

Наименование

Содержание

MZ-заглушка

MSDOS-заголовок, MSDOS-заглушка, указатель на Image FileHeader

Магическое PE-значение

Сигнатура

Image File Header

Размер опционального заголовка, количество секций

Image Optional Header

Адрес точки входа, база образа, размер образа

Data Directories

Указатели на таблицы импорта и экспорта

Таблица секций

Список заголовков секций

Секции

Секции .code, .data и т. д.

Как и стандартные PE-файлы, NET-приложения содержат MZ-заглушку, Image File Header, Image Optional Header, Dada Directory и соответствующие секции. Детальное описание этих терминов выходит за рамки данной статьи. С более подробным объяснением этих понятий вы можете ознакомиться в документах [1] и [2]. При открытии NET-приложения в PE-редакторе (например, вLord PE) [8], можно увидеть следующую структуру:

  • Секция .text, содержащую таблицу импорта (import table), таблицу импортируемых адресов (import address table) и CIL-код.
  • Секция .rsrc, содержащую иконку файла (file icon).
  • Секцию .reloc, содержащую таблицу релокаций (relocation table). В этой таблице хранится только одна запись, инструкция точки входа (entry point instruction).

При запуске NET-приложение загружается в память как обычный исполняемый файл. Когда процесс загрузки окончен, адреса секций преобразуются к виртуальным адресам, и PE-загрузчик определяет, содержит ли файл собственный машинный код или CIL-код. Если файл содержит собственный машинный код, тогда загрузчик переходит к точке входа и далее приложение исполняется процессором. В случае с CIL-кодом управление передается среде CLR. Таким образом, массив указателей (data directory) каждого PE-файла содержит запись заголовка среды исполнения CLR (CLR Runtime Header), при помощи которого можно отличить стандартный исполняемый файл от NET-приложения. Если файл содержит байт-код CIL, тогда в секции CLRRuntime Header присутствует указатель на CIL-заголовок. В случае стандартного исполняемого файла этот указатель равен 0.

В спецификации PE-формата секция CLR Runtime Header описывается так: недокументированный формат метаданных, который может использоваться CLR-интерфейсами для обработки метаданных. К счастью, это утверждение потеряло смысл, после того, как Microsoft обнародовал спецификации для CIL и CLR [9]. Вдобавок к этому, компания Microsoft представила Shared SourceCommon Language Infrastructure (SSCLI), платформу .NET с открытым исходным кодом [10], которая написана на C++ и используется разработчика для изучения внутреннего устройства .NETframework. Лицензия разрешает применение SSCLI только в учебных целях и запрещает ее коммерческое использование.

Один из наиболее интересных классов SSCLI – класс PEReader, который можно найти в соответствующей поддиректории: samples/utilities/getcliversion/pereader.cs. Этот класс разбирает PE-заголовок входного файла, включая CIL-заголовок. Кроме того, синтаксис и семантика формата .NET также прекрасно описана в статье Дэниэла Пистелли (Daniel Pistelli) [11]. Согласно этим ресурсам, NET-код, который содержится в PE-файле в соответствующей записи data directory, имеет следующий формат:

  1. CIL-заголовок.
  2. CIL-код и ресурсы.
  3. Заголовок метаданных (MetaData header).
  4. Потоки (Streams).
  5. Таблицы метаданных (MetaData tables).

Описание формата не является полностью правильным, поскольку CIL-код не расположен между CIL-заголовком и заголовком метаданных. На самом деле, это описание – результат практических исследований и анализа исполняемых файлов .NET. Кроме того, это лишь краткое введение в NET-компоненты. За более подробной информацией обращайтесь к соответствующей литературе.

CIL-заголовок содержит базовое описание NET-файла. В двух записях представлены предыдущая/последующая версии среды выполнения (runtime environment version), которые необходимы для запуска CIL-кода. Также CIL-заголовок содержит указатели на секцию с NET-ресурсами и заголовок метаданных.

Заголовок метаданных содержит магическое число и, также как CIL-заголовок, хранит информацию о предыдущей/последующей версии среды выполнения (runtime version), которые, согласно [11], игнорируются загрузчиком. Важными элементами заголовка метаданных являются заголовки потоков (stream headers). Каждый такой заголовок содержит имя, размер и смещение (offset). По умолчанию в каждом NET-файле присутствую потоки Strings или Blob. Поток Strings содержит информацию о строках, а Blob – двоичные данные.

Элементы потоков – это ссылки на таблицы метаданных, которые являются частью потока #~. Таким образом, формат NET-файлов, о котором рассказано выше, нуждается в корректировке: таблицы метаданных являются частью секции потоков. Хочется подчеркнуть, что семантика этого потока отличается от семантики остальных потоков и вынесена в дополнительный раздел. Таблицы метаданных содержат следующие элементы:

  • Имена классов, подклассов и т. п.
  • Имена переменных, типов и их начальные значения.
  • Имена констант и их значения.
  • Имена методов, параметры, тело метода, возвращаемые значения и т. п.

Следующий пример демонстрирует взаимосвязь CIL-кода, таблиц метаданных и потоков. Допустим, в NET-приложение объявлена константа со значением 1. Кроме того, там же присутствует класс B, в котором реализован метод c(). Идентификаторы a, B и c хранятся в потоке Strings, а значение константы в потоке Blob. В таблице метаданных хранятся записи класса, константы и метода. По сути, эти записи являются ссылками на соответствующие элементы потока. К тому же, в таблице присутствует запись-ссылка на CIL-код, который запускается при вызове функции. Еще раз обращаем внимание на то, что это лишь краткое описание формата, и за более подробной информацией рекомендуем обратиться к соответствующим источникам.

Теперь вам знакома структура NET-приложения, которая встроена в структуру PE-файла. Остался еще один аспект, который не описан – запуск CIL-кода по его загрузке в оперативную память. Для этого загрузчик сначала проверяет содержание ссылки на CIL-заголовок в data directory файла. Когда корректная ссылка найдена, в память загружается MsCorEE.dll, а затем вызывается функция _CorValidateImage(). Эта функция модифицирует PE-заголовок, перезаписывая точку входа. Новая точка входа является адресом функции _CorExeMain(), которая передает управление среде CLR.

3 Шифрование NET-файлов в реальном времени

В предыдущем разделе описан формат NET-приложений и механизм их запуска. В этом разделе будет рассмотрено два способа шифрования NET-файлов в реальном времени. Далее будет представлена базовая реализация шифратора Гиперион и рассмотрена проблема механизма загрузки зашифрованного файла в память. Затем эта проблема будет решена и представлена пилотная версия шифратора, которую можно использовать для реализации более изощренного алгоритма шифрования NET-файлов в реальном времени.

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

CIL-код избавлен от подобных ограничений, поскольку может использовать возможности reflection в .NET framework. Reflection framework содержит перегруженную функцию Assembly.Load(), которая в качестве параметра может принимать как строку с именем NET-приложения, так и массив байтов, содержащий образ NET-файла. Таким образом, в отличии стандартных Windows-приложений и функции CreateProcess(), CIL-код можно выполнить в другой NET-программе, напрямую из памяти без переопределения PE-загрузчика.

При помощи reflection API шифрование NET-приложений в реальном времени может быть реализовано следующим образом: динамический шифратор считывает входной файл, шифрует его, оставляя незашифрованную часть в виде исполняемого файла загрузчика (dropper executable) (например, в качестве ресурса). При запуске загрузчик расшифровывает основную программу в памяти и запускает ее при помощи функции Assembly.Load(). Данный механизм прост и понятен, но содержит следующие недостатки:

  • Assembly.Load() связана с CIL-кодом.
  • Антивирус может легко обнаружить вызов функции Assembly.Load() и затем запустить эвристический анализ.

Для устранения этих недостатков, используется еще один подход при реализации динамического шифратора. Согласно разделу 2, NET-файлы загружаются в память подобно обычным PE-файлам, а затем запускается функция _CorExeMain(). В соответствии с этим, Гиперион можно модифицировать так: когда файл находится в памяти, записи data directory могут быть проверены. В случае обнаружения CIL-заголовка вызывается функция _CorValidateImage(). В конце концов, загрузчик переходит к функции _CorExeMain() и выполняется CIL-код. Функции _CorExeMain() и _CorValidateImage() нужно динамически подгрузить, используя функцию GetProcAddress() и другие методы обфускации. Все это позволит создать эффективную защиту от детектирования исполняемого файла антивирусными средствами.

3.1 Гиперион 1.0 и платформа .NET

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

Рис. 1. Сообщение об ошибке после распаковки файла.

Следующий участок кода показывает, как Гиперион переходит к точке входа после расшифровки файла:

01. ;...
02. mov edx,[image_base]
03. mov eax,[edx+IMAGE_DOS_HEADER.e_lfanew]
04. add eax,edx
05. add eax,4
06. ;image file header now in eax
07. add eax,sizeof.IMAGE_FILE_HEADER
08. mov eax,[eax+IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint]
09. add eax,[image_base]
10. ;entry point of original exe is now in eax
11. jmp eax

Рассмотрим листинг подробнее. Базовый образ (base image) расшифрованного файла хранится в регистре edx. Далее вычисляется и сохраняется в регистре eax адрес PE-заголовка. PE-заголовок используется для получения опционального заголовка, который содержит соответствующую точку входа. После перехода к точке входа происходит запуск исполняемого файла. Для NET-файлов вышеприведенный листинг добавляется небольшая модификация: в строке 1 появляется функция, которая получает в качестве параметра адрес загрузки расшифрованного файла и разбирает PE-заголовки для получения массива указателей (data directory). Если data directory содержит указатель на CIL-заголовок, вызывается функция _CorValidateImage(), которая изменяет адрес точки входа, и Гиперион переходит к функции _CorExeMain().

Такая модификация кода позволяет использовать шифрование в реальном времени для NET-файлов. Результаты тестирования простой реализации этого механизма (файл blah.exe) представлены на рис. 1, где видно сообщение об ошибке при попытке считать версию среды выполнения. Информация о предыдущей/последующей версии среды выполнения содержится в CIL-заголовке (см. главу 2).

Первое, что приходит на ум – в Гиперионе произошла ошибка, и файл некорректно загрузился/расшифровался в памяти. После анализа образа расшифрованного файла был сделан вывод, что загрузка и расшифровка произошла успешно. Таким образом, текущая ситуация такова:

  • Поскольку файл был расшифрован, значит, NET-приложение работает корректно, и правильная рабочая версия доступна в системе.
  • После расшифровки файла, среда исполнения не может прочитать CIL-заголовок, даже в случае корректной загрузки файла в память.

Далее была запущена отладка зашифрованного файла с использованием Immunity [12] и точкой останова на функции _CorExeMain() (которая является точкой входа среды CLR) и пошагово пройден файл. Результаты отладки показаны на рис. 2 (выделено красным прямоугольником).

Рис. 2. Процесс отладки NET-приложения.

CIL framework открывает файл при помощи CreateFileW(), обращаясь к образу диска. Такое поведение странно, поскольку в нем нет необходимости, так как файл уже загружен в память PE-загрузчиком. Дальнейшие исследования выявили следующую картину:

  • Вызываются функции CreateFileW, CreateFileMapping and MapViewOfFile() для мапирования образа диска в память
  • Далее происходит разбор и обработка PE-заголовка файла образа диска

Эта проблема возникла потому, что образ диска зашифрован. Среда CLR не может считать предыдущую/последующую версию среды выполнения в CLI-заголовке, и в Гиперионе возникает ошибка при работе с исполняемыми файлами .NET.

3.2 Частичное шифрование NET-файлов

Исследование в предыдущем разделе показало, что CIL framework обращается к файлу образа диска даже в том случае, когда файл уже загружен в память PE-загрузчиком. Следовательно, при загрузке исполняемых файлов NET, зашифрованных Гиперионом, возникает ошибка, поскольку среда CLR не может считать CIL-заголовок. В этом разделе будет представлена пилотная реализация шифрования в режиме реального времени для NET-приложений, где CLI-заголовок остается незашифрованным. Новый метод шифрования разделен на две части:

  • Шифровщик: шифруется только CIL-код; PE-заголовок, CIL-заголовок и метаданные остаются нетронутыми.
  • Загрузчик: стартует зашифрованный файл при помощи функции CreateProcess(). Главный поток находится в состоянии ожидания. Загрузчик расшифровывает CIL-код и возвращается в главный поток.

Само собой, при такой реализации приложение не защищено от статического анализа антивирусами, поскольку остаются незашифрованные места. В разделе 4 будет реализовано расширение для Гипериона, которое будет шифровать все NET-файлы.

3.2.1 Шифровщик

На входе шифровщик получает входной файл и копирует его в память. Далее происходит разбор заголовков файла, чтобы определить местонахождение CIL-кода и зашифровать его.

Каждый PE-файл начинается с MZ-заголовка, содержащего указатель на заголовок COFF. Размер заголовка COFF является постоянным, за ним следуют опциональные стандартные заголовки (optional standard headers) и windows-заголовки (optional windows headers), которые также фиксированного размера. После опциональных windows-заголовков находится data directory, размер которого определяется переменной NumberOfRvaAndSizes, являющейся элементом опционального windows-заголовка. Поскольку размер data directory может быть равным нулю, рекомендуется высчитывать размер опционального заголовка через переменную SizeOfOptionalHeader, а не обращаться к переменной NumberOfRvaAndSizes. Data directory представляет из себя массив структурImageDataDirectory:

01. struct ImageDataDirectory f
02. uint32_t VirtualAddress;
03. uint32_t Size;
04. g;

Каждая запись содержит относительный виртуальный адрес (relative virtual address, rva) и относительный адрес. Если rva равен нулю, то эта запись не используется в PE-файле. Следующий код проверяет присутствие в файле CIL-кода:

01. ImageCor20Header* rva_cil_header = (ImageCor20Header*)
02. data_directory [CLR_RUNTIME_HEADER]).VirtualAddress;
03.
04. if(rva_cil_header==0)f
05. printf("no clr runtime header found");
06. return false;
07. g

CIL-заголовок представлен структурой ImageCor20Header, которая имеет такой формат:

01. struct ImageCor20Header
02. f
03. uint32_t cb;
04. uint16_t MajorRuntimeVersion;
05. uint16_t MinorRuntimeVersion;
06. struct ImageDataDirectory MetaData;
07. uint32_t Flags;
08. uint32_t EntryPoint;
09. struct ImageDataDirectory Resources;
10. struct ImageDataDirectory StrongNameSignature;
11. struct ImageDataDirectory CodeManagerTable;
12. struct ImageDataDirectory VTableFixups;
13. struct ImageDataDirectory ExportAddressTableJumps;
14. struct ImageDataDirectory ManagedNativeHeader;
15. g;

Для реализации шифровщика важным элементом является указатель на метаданные, представленный структурой ImageDataDirectory. Как только получен CIL-заголовок, шифровщик считывает следующую информацию:

  • Размер и относительный адрес CIL-заголовка.
  • Размер и относительный адрес заголовка метаданных.

Согласно спецификации формата .NET, описанной в главе 2, CIL-код находится между CIL-заголовком и заголовком метаданных. Исходя из полученных данных, шифровщик высчитывает смещение (offset) CIL-кода и производит простое XOR-шифрование.

Здесь упущен один аспект: входной файл смапирован в память по определенному адресу загрузки (image base). Заголовки PE-файлов содержат указатели, являющие относительными виртуальными адресами (rva). Rva должен быть трансформирован в соответствующий физический адрес (raw address), после чего будет доступна запись и чтение данных. Для преобразования адреса используется функция:

01. unsigned char* rvaToOffset(unsigned char* base,

02. struct SectionHeader* sections,
03. uint16_t sections_size, uint32_t rva)
04. f
05. unsigned char* ret = 0;
06. for(int i=0;i<sections_size;i++)f
07. if(rva >= sections[i].VirtualAddress &&
08. rva < sections[i].VirtualAddress + sections[i].VirtualSize)f
09. ret = base + sections[i].PointerToRawData +
10. (rva - sections[i].VirtualAddress);
11. g
12. g
13. return ret;
14. g

Метод rvaToOffset() на входе получает следующие параметры: адрес загрузки файла в память, указатель на секцию заголовков, число секций заголовков и относительный адрес, который необходимо преобразовать. В начале работы происходит поиск секции, содержащей относительный виртуальный адрес. Далее к адресу загрузки файла добавляется смещение секцииPointerToRawData и разность между относительным виртуальным адресом и виртуальным адресом секции VirtualAddress, а затем возвращается итоговое значение преобразованного адреса.

3.2.2 Загрузчик

В предыдущем разделе был рассмотрен процесс шифровки CIL-кода NET-приложения. Загрузчик запускает зашифрованный файл, используя метод CreateProcess(). При этом главный поток приостанавливается. После дешифровки CIL-кода загрузчик вновь возвращается в главный поток.

01. STARTUPINFOA startupinfo;
02. memset(&startupinfo, 0, sizeof(startupinfo));
03. startupinfo.cb = sizeof(STARTUPINFOA);
04. PROCESS_INFORMATION process_information;
05. memset(&process_information, 0, sizeof(process_information));
06. CreateProcessA(application_name_and_path, 0, 0, 0,
07. false, NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED, 0, 0, &startupinfo,
08. &process_information);

Метод CreateProcess() использует две структуры: STARTUPINFO и PROCESS INFORMATION. В вышеприведенном листинге сначала обе структуры инициализированы нулевыми байтами, а затем CreateProcess() запускает приложение. Информация о созданном процессе хранится в структуре process_information. CIL-код расшифровывается при помощи следующего алгоритма:

  • Метод VirtualProtectEx() делает участок памяти процесса доступной для записи
  • Метод ReadProcessMemory() копирует участок память процесса в буфер. Туда же попадает выше заполненная структура process_information
  • Дешифруется CIL-код
  • Обновленный буфер копируется обратно в память процесса с использованием метода WriteProcessMemory()
  • VirtualProtectEx() восстанавливает прежние атрибуты участка памяти процесса

После отработки алгоритма загрузчик возвращается в потом, используя конструкцию ResumeThread(process information.hThread);.

4 Заключение и направление дальнейшей работы

В этой статье описывается формат NET-файлов. Затем реализуется шифратор Гиперион, в котором реализовано шифрование NET-файлов в реальном времени. Такой подход не годится, поскольку среда исполнения .NET аварийно завершает работу, поскольку обращается к образу диска и не может считать версию среды выполнения. Далее алгоритм работы был модифицирован. Стал шифроваться лишь CIL-код, а CIL-заголовок и метаданные остались нетронутыми.

Хотя такая реализация может использоваться для шифрования .NET файлов в реальном времени, у нее есть несколько недостатков:

  • Используется простое XOR-шифрование, в то время как Гиперион может использовать алгоритм AES-128.
  • Шифруется только CIL-код, а заголовок и метаданные остаются уязвимыми для статического анализа антивирусными средствами.

В дальнейшем функционал шифровщика будет доработан, и Гиперион сможет шифровать все NET-файлы по следующему алгоритму: сначала происходит перехват (hook) методов CreateFileW(),CreateFileMapping() and MapViewOfFile() в модуле kernel32.dll. Перехватчик проверяет, пытается ли среда исполнения обратиться к файлу образа диска. Если такое происходит, тогда возвращается указатель образа ранее дешифрованного файла и среда CLR получает доступ к CIL-заголовку. Это решает проблему, описанную в разделе 3.1, что позволяет полностью зашифровать NET-файлы.

5 Благодарности

Мы хотим выразить благодарность Крису Каулингу (Chris Cowling), Яну Квисту (Ian Qvist) и Томасу Педерсену (Thomas Pedersen) за помощь при работе над данной статьей. Кроме того, мы хотим сказать спасибо всей команде Nullsecurity за плодотворные беседы и (что более важно) за прекрасную вечеринку на Berlin-Sides 2012.

Лицензия

Идеи продвинутого шифрования в реальном времени исполняемых файлов .NET Кристиана Амманна распространяются под лицензией Creative Commons Attribution 3.0 Unported License. Подробности см. здесь: http://creativecommons.org/licenses/by/3.0/ for details.

Ссылки

[1] Christian Ammann. Hyperion: Implementation of a PE-Crypter. http://nullsecurity.net/papers/nullsec-pe-crypter.pdf.

[2] Microsoft Cooperation. Microsoft PE and COFF Specification. http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx.

[3] Information Technology Laboratory (National Institute of Standards and Technology). Announcing

the Advanced Encryption Standard (AES) [electronic resource]. Computer Security Division, Information Technology Laboratory, National Institute of Standards and Technology, Gaithersburg, MD :, 2001.

[4] Microsoft Cooperation. The .NET Framework. http://www.microsoft.com/net.

[5] Microsoft Cooperation. C# Programming Guide. http://msdn.microsoft.com/en-us/library/67ef8sbd.aspx.

[6] Microsoft Cooperation. J-Sharp. http://msdn.microsoft.com/en-us/vstudio/bb188593.

[7] Microsoft Cooperation. Visual Basic. http://msdn.microsoft.com/en-us/vstudio/hh388568.aspx.

[8] y0da. Lord PE. http://www.woodmann.com/collaborative/tools/index.php/LordPE.

[9] Microsoft Cooperation. Standard ECMA-335 - Common Language Infrastructure (CLI).

http://www.ecma-international.org/publications/standards/Ecma-335.htm.

[10] Microsoft Cooperation. Shared Source Common Language Infrastructure. http://www.microsoft.com/en-us/download/details.aspx?id=4917.

[11] Daniel Pistelli. The .NET File Format. http://www.codeproject.com/Articles/12585/The-NET-File-Format.

[12] Immunity Inc. Immunity Debugger. https://www.immunityinc.com/products-immdbg.shtml.

Где кванты и ИИ становятся искусством?

На перекрестке науки и фантазии — наш канал

Подписаться