ILSpy, как разрешить зависимости? - PullRequest
6 голосов
/ 31 декабря 2011

Я хочу разобрать всю сборку .NET с помощью ILSpy.

Я использовал этот код в качестве базы:
http://skysigal.xact -solutions.com / Блог / табетический / 427 / EntryID / 2488 / Default.aspx

И все работает нормально, только когда у меня есть сборка, которая ссылается на Npgsql.dll (или любую другую сборку, отличную от gac), я получаю исключение AssemblyResolutionException.

Не удалось разрешить сборку: 'Npgsql, версия = 2.0.11.92, культура = нейтральная, PublicKeyToken = 5d8b90d52f46fda7'

Я знаю, как получить ссылочные сборки, но как я могу добавить их в ast?

    // SqlWebAdmin.Models.Decompiler.DecompileAssembly("xy.dll");
    public static string DecompileAssembly(string pathToAssembly)
    {
        //Assembly assembly = Assembly.LoadFrom(pathToAssembly);
        System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
        //assembly.GetReferencedAssemblies();

        //assembly.GetReferencedAssemblies(assembly);
        Mono.Cecil.AssemblyDefinition assemblyDefinition =
            Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly);



        ICSharpCode.Decompiler.Ast.AstBuilder astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
        astBuilder.AddAssembly(assemblyDefinition);


        //new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
        using (System.IO.StringWriter output = new System.IO.StringWriter())
        {
            astBuilder.GenerateCode(new ICSharpCode.Decompiler.PlainTextOutput(output));
            string result = output.ToString();
            return result;
        }

        return "";
    } // End Function DecompileAssembly

Ответы [ 4 ]

13 голосов
/ 02 января 2012

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

var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory("path/to/my/assemblies");

var parameters = new ReaderParameters
{
    AssemblyResolver = resolver,
};

var assembly = AssemblyDefinition.ReadAssembly(pathToAssembly, parameters);

Это наиболее естественный способ сообщить Сесилу, где разрешать ссылочные сборки.Таким образом, вы можете удалить строку, в которую вы загружаете сборку, используя System.Reflection, и использовать только стек ILSpy.

4 голосов
/ 29 января 2016

Это улучшенный ответ @Nayan.Если вы хотите игнорировать отсутствующие сборки, скопируйте этот класс:

using Mono.Cecil;

public class IgnoringExceptionsAssemblyResolver : DefaultAssemblyResolver
{
    public override AssemblyDefinition Resolve(AssemblyNameReference name)
    {
        try
        {
            return base.Resolve(name);
        }
        catch
        {
            return null;
        }
    }
}

и используйте его так:

var assembly = AssemblyDefinition.ReadAssembly(path, new ReaderParameters() {
    AssemblyResolver = new IgnoringExceptionsAssemblyResolver()
});
2 голосов
/ 06 августа 2013

В дополнение к тому, что предложил JB Evain, этот код поможет избежать исключения. Все, что вам нужно сделать, это обработать исключение в resolver.

Не лучший способ, я признаю. Но это работает для этого сценария: "If I am decompiling a DLL on a system where the referred assemblies are not present, the decompilation fails (with exception.) At least, i would like to see the decompile code, for whatever has been resolved."

using System;
using System.Collections.Generic;
using Mono.Cecil;

public class MyAssemblyResolver : BaseAssemblyResolver
{
    private readonly IDictionary<string, AssemblyDefinition> cache;
    public MyAssemblyResolver()
    {
        this.cache = new Dictionary<string, AssemblyDefinition>(StringComparer.Ordinal);
    }
    public override AssemblyDefinition Resolve(AssemblyNameReference name)
    {
        if (name == null)
            throw new ArgumentNullException("name");
        AssemblyDefinition assemblyDefinition = null;
        if (this.cache.TryGetValue(name.FullName, out assemblyDefinition))
            return assemblyDefinition;
        try  //< -------- My addition to the code.
        {
            assemblyDefinition = base.Resolve(name);
            this.cache[name.FullName] = assemblyDefinition;
        }
        catch { } //< -------- My addition to the code.
        return assemblyDefinition;
    }
    protected void RegisterAssembly(AssemblyDefinition assembly)
    {
        if (assembly == null)
            throw new ArgumentNullException("assembly");
        string fullName = assembly.Name.FullName;
        if (this.cache.ContainsKey(fullName))
            return;
        this.cache[fullName] = assembly;
    }
}

И используйте это так:

var rp = new Mono.Cecil.ReaderParameters() { AssemblyResolver = new MyAssemblyResolver() };
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp);
var astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(
     new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
astBuilder.AddAssembly(assemblyDefinition);




Я бы хотел увидеть улучшение в декомпиляторе: в данный момент он игнорирует ReaderParameters, заданный пользователем, в классе DefaultAssemblyResolver.

Использование:

var rp = new Mono.Cecil.ReaderParameters();
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp);

Текущий DefaultAssemblyResolver код:

public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
    if (name == null)
    {
        throw new ArgumentNullException("name");
    }
    AssemblyDefinition assemblyDefinition;
    if (this.cache.TryGetValue(name.FullName, out assemblyDefinition))
    {
        return assemblyDefinition;
    }
    assemblyDefinition = base.Resolve(name); // <---------
// Is the `ReaderParameters` object set by user, used to resolve in `base` class?

    this.cache[name.FullName] = assemblyDefinition;
    return assemblyDefinition;
}
1 голос
/ 01 января 2012

Исходя из источника Mono.Cecil, я бы предположил, что вы могли бы справиться с этим, используя класс Mono.Cecil.DefaultAssemblyResolver.

Вместо этого кода:

Mono.Cecil.AssemblyDefinition assemblyDefinition =
    Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly);

попробуйте это:

Mono.Cecil.AssemblyDefinition assemblyDefinition =
    new Mono.Cecil.DefaultAssemblyResolver().Resolve(System.Reflection.AssemblyName.GetAssemblyName(pathToAssembly).ToString());

РЕДАКТИРОВАТЬ

Хотя мое первоначальное предложение можетили может не сработать (я никогда не делал этого, так что никаких гарантий), вы можете обратиться к сборке Mono.Addins.CecilReflector.dll из проекта Mono.Addins , чтобы помочь решить подобные проблемы.Он также основан на Mono.Cecil (как и ILSpy), поэтому, хотя общая предпосылка о том, что Mono.Addins - это библиотека расширяемости, не отвечает вашим потребностям, она может содержать некоторый код, используемый для ваших целей или, по крайней мере, учиться у него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...