6

ILSpy を使用して .NET アセンブリ全体を逆アセンブルしたいと考えています。

このコードをベースとして使用しました:
http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/2488/Default.aspx

そして、Npgsql.dll (または他の非 gac アセンブリ) を参照するアセンブリがある場合にのみ、正常に動作し、AssemblyResolutionException が発生します。

アセンブリの解決に失敗しました: 'Npgsql, Version=2.0.11.92, Culture=neutral, 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

4 に答える 4

14

ILSpy が使用している基になるメタデータ リーダーである Cecil に、アセンブリの場所を伝える必要があります。あなたは書ける:

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

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

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

これは、参照されたアセンブリを解決する場所を Cecil に伝える最も自然な方法です。このようにして、System.Reflection を使用してアセンブリをロードする行を削除し、ILSpy スタックのみを使用できます。

于 2012-01-02T18:20:54.417 に答える
2

JB Evain が提案したことに加えて、このコードは例外を回避するのに役立ちます。リゾルバーで例外を処理するだけです。

最善の方法ではないことは認めます。ただし、このシナリオでは機能します。"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;
}
于 2013-08-06T12:33:33.977 に答える