Установление авторства кода мобильных приложений (часть 2)

 

Введение

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

В последнее время фокус злоумышленников сместился на мобильные устройства, поэтому их защита, как и определение автора появившихся вирусов, становится все более актуальной задачей.

Таким образом, выбранная тема «Установление авторства кода мобильных приложений» важна и имеет практическое значение.

Общие сведения о IL-коде

IL — язык программирования для стековой машины платформы .NET, который является «посредником» между языком программирования исходного кода и ассемблером. IL-код одинаковый для всех платформ и операционных систем, но для каждой операционной системы преобразуется в разный ассемблерный и машинные коды.

Существуют специальные программы для декомпиляции .NET-приложений и получения их IL-кода. В частности, к таким относятся open-source программа ILSpy и бесплатная dotPeek от Jetbrains, которая и использовалась в рамках данного семинара.

Стабильность IL-кода на разных целевых платформах

Один и тот же код можно скомпилировать в разных условиях, выбрав режим Debug/Release или сменив версию целевой платформы .NET Framework. Для более точного определения авторства было необходимо изучить, как такие изменения влияют на результирующий код.

Существуют несколько платформ для .NET-приложений: старый .NET Framework, новый .NET Core (2.1 и 3.1), а также последняя .NET 5.0. Такое разнообразие целевых платформ приложений может привести к тому, что компилятор будет генерировать различный IL-код для разных платформ, что усложнит детекцию ПО одного автора.

Для проверки данной гипотезы было написано несколько мелких программ на языке C#, которые затем были откомпилированы под вышеуказанные целевые платформы. Затем для каждой версии были получены IL-коды, которые затем сравнивались друг с другом.

Среди разных версий .NET Framework IL-коды были абсолютно одинаковыми. Полностью совпал и результат компиляции под .NET Core 2.1 и .NET Core 3.1. Между .NET Core и .NET 5.0 различия минимальны, в основном связанные с изменением пространства имен некоторых методов стандартной библиотеки. Например, если на платформе .NET Core 3.1 вызов метода Math.Floor выглядит так:

call float64 [System.Runtime.Extensions]System.Math::Floor(float64)

то на .NET 5.0 этот же вызов будет немного короче:

call float64 [System.Runtime]System.Math::Floor(float64)

Иных различий между этими платформами обнаружено не было. IL-коды совпадают на 97–98%.

Наибольшее изменение результата было отмечено при смене платформы с .NET Framework 4.7.2 на .NET Core 2.1. Больше всего различий выявлено снова в пространствах имен. Ниже приведены небольшие фрагменты IL-кода на .NET Framework 4.7.2:

call    float64 [mscorlib]System.Math::Floor(float64)
box    [mscorlib]System.Double
call    string [mscorlib]System.String::Format(string, object)

и того же фрагмента на .NET Core 2.1:

call    float64 [System.Runtime.Extensions]System.Math::Floor(float64)
box    [System.Runtime]System.Double
call    string [System.Runtime]System.String::Format(string, object)

Однако в некоторых случаях между этими платформами результирующий код отличался не только в вызовах функций, но и их теле (разными инструкциями и их порядком).

Заключение

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

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

  1. Унификация пространств имен или их полное удаление. Библиотека mscorlib в .NET Framework 4.7.2 — это то же самое, что и пространство имен System.Runtime в .NET Core 3.1 (или какое-либо вложенное в него пространство имен). Из IL-кода можно удалить указание пространств имен стандартных библиотек для решения данной проблемы.
  2. Удаление адресов инструкций. .NET дизассемблеры присваивают каждой инструкции свой адрес в виде метки, причем в каждом методе адресация своя и начинается с 0x0. Однако это лишь может добавить различий в код, если в начало или середину блока добавится инструкция, поэтому эти адреса стоит удалять (а метки, используемые для переходов, оставлять, но сгенерировать для них новые метки).

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

Для обработки IL-кода его необходимо разобрать на лексемы и построить абстрактное синтаксическое дерево (AST). Для этого необходимо реализовать лексер и парсер для IL-кода.