[英]ILSpy, how to resolve dependencies?
我想用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
您需要告訴Cecil,ILSpy正在使用的基礎元數據讀取器,程序集所在的位置。 你可以寫:
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堆棧。
這是改進@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()
});
除了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);
我真的希望在反編譯器中看到一個增強功能:它當前忽略了用戶在DefaultAssemblyResolver
類中設置的ReaderParameters
。
用法:
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;
}
基於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項目中的Mono.Addins.CecilReflector.dll
程序集,以幫助緩解這些問題。 它也基於Mono.Cecil(就像ILSpy一樣),所以盡管Mono.Addins是一個可擴展性庫的一般前提不能滿足您的需求,但它可能包含一些代碼用於您的目的或至少可以學習。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.