Получить AST из сборки.Net без исходного кода (код IL)

Я хотел бы проанализировать сборки.Net, чтобы они не зависели от языка C#, VB.NET или чего-либо еще.
Я знаю Roslyn и NRefactory, но они работают только на уровне исходного кода C#?
Существует также проект " Общая инфраструктура компилятора: модель кода и AST API" в CodePlex, который утверждает, что "поддерживает иерархическую объектную модель, которая представляет блоки кода в не зависящей от языка структурированной форме", что звучит именно для того, что я искал.
Однако я не могу найти какую-либо полезную документацию или код, который действительно делает это.
Любой совет, как заархивировать это?
Может Mono.Cecil, может быть, что-то делает?

4 ответа

Вы можете сделать это, и есть также один (хотя и крошечный) пример этого в источнике ILSpy.

var assembly = AssemblyDefinition.ReadAssembly("path/to/assembly.dll");
var astBuilder = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
astBuilder.SyntaxTree...

Модель кода CCI находится где-то между дизассемблером IL и полным декомпилятором C#: она дает вашему коду некоторую структуру (например, if операторы и выражения), но он также содержит некоторые операции стека низкого уровня, такие как push а также pop,

CCI содержит образец, который показывает это: PeToText.

Например, чтобы получить модель кода для первого метода Program тип (в глобальном пространстве имен), вы можете использовать код, подобный этому:

string fileName = "whatever.exe";

using (var host = new PeReader.DefaultHost())
{
    var module = (IModule)host.LoadUnitFrom(fileName);
    var type = (ITypeDefinition)module.UnitNamespaceRoot.Members
        .Single(m => m.Name.Value == "Program");
    var method = (IMethodDefinition)type.Members.First();
    var methodBody = new SourceMethodBody(method.Body, host, null, null);
}

Чтобы продемонстрировать, что если вы декомпилируете приведенный выше код и покажете его с помощью PeToText, вы получите:

Microsoft.Cci.ITypeDefinition local_3;
Microsoft.Cci.ILToCodeModel.SourceMethodBody local_5;
string local_0 = "C:\\code\\tmp\\nuget tmp 2015\\bin\\Debug\\nuget tmp 2015.exe";
Microsoft.Cci.PeReader.DefaultHost local_1 = new Microsoft.Cci.PeReader.DefaultHost();
try
{
    push (Microsoft.Cci.IModule)local_1.LoadUnitFrom(local_0).UnitNamespaceRoot.Members;
    push Program.<>c.<>9__0_0;
    if (dup == default(System.Func<Microsoft.Cci.INamespaceMember, bool>))
    {
        pop;
        push Program.<>c.<>9.<Main0>b__0_0;
        Program.<>c.<>9__0_0 = dup;
    }
    local_3 = (Microsoft.Cci.ITypeDefinition)System.Linq.Enumerable.Single<Microsoft.Cci.INamespaceMember>(pop, pop);
    local_5 = new Microsoft.Cci.ILToCodeModel.SourceMethodBody((Microsoft.Cci.IMethodDefinition)System.Linq.Enumerable.First<Microsoft.Cci.ITypeDefinitionMember>(local_3.Members).Body, local_1, (Microsoft.Cci.ISourceLocationProvider)null, (Microsoft.Cci.ILocalScopeProvider)null, 0);
}
finally
{
    if (local_1 != default(Microsoft.Cci.PeReader.DefaultHost))
    {
        local_1.Dispose();
    }
}

Следует отметить, что все эти push, pop а также dup заявления и условие лямбда-кэширования.

Если вы рассматриваете двоичный файл.net как поток байтов, у вас должна быть возможность его "хорошо проанализировать".

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

Затем вы можете построить AST, используя стандартное строительное оборудование AST для механизма синтаксического анализа (самостоятельно для YACC, автоматически с ANTLR4).

Конечно, вы обнаружите, что "разбора" недостаточно; вам все еще нужно будет построить таблицы символов и выполнить анализ управления и потока данных, если вы собираетесь серьезно проанализировать соответствующий код. Смотрите мое эссе на LifeAfterParsing.

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

Насколько я знаю, невозможно построить AST из двоичного кода (без источников), поскольку сам AST генерируется синтаксическим анализатором как часть процесса компиляции из источников. Mono.Cecil не поможет, потому что вы можете изменять только коды операций / метаданные с ними, но не анализировать сборку.

Но так как это.NET, вы можете выгрузить IL-код из dll с помощью ildasm. Затем вы можете передать сгенерированные источники в любой парсер с подключенным словарем CIL и получить AST от парсера. Проблема в том, что, насколько мне известно, существует только одна общедоступная грамматика CIL для синтаксического анализатора, поэтому у вас действительно нет выбора. И ECMA-355 достаточно велик, поэтому плохая идея написать свою собственную грамматику. Поэтому я могу предложить вам только одно решение:

  1. Передайте сборку ildasm.exe, чтобы получить CIL.
  2. Затем передайте CIL в синтаксический анализатор ANTLR v3 с подключенной грамматикой CIL (обратите внимание, она немного устарела - грамматика, созданная в 2004 году, и последняя спецификация CIL - 2006, но CIL на самом деле не сильно меняется)
  3. После этого вы можете свободно получить доступ к AST, сгенерированному ANTLR

Обратите внимание, что вам понадобится ANTLR v3, а не v4, поскольку грамматика написана для третьей версии, и вряд ли возможно перенести ее на v4 без хорошего знания синтаксиса ANTLR.

Также вы можете попробовать поискать новыеисходники компилятора Microsoft ryujit на github (часть CoreCLR) - я не уверен, что это помогает, но теоретически он должен содержать реализации грамматики CIL и синтаксического анализатора, поскольку он работает с кодом CIL. Но он написан на CPP, имеет огромную базу кода и нехватку документации, так как он находится на активной стадии разработки, так что может быть легче застрять с ANTLR.

Другие вопросы по тегам