2011-12-31 39 views
6

Tôi muốn tháo rời toàn bộ hội đồng .NET với ILSpy.ILSpy, cách giải quyết các phụ thuộc?

tôi đã sử dụng mã này như cơ sở:
http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/2488/Default.aspx

Và nó hoạt động tốt, chỉ khi tôi có một hội đồng tham chiếu Npgsql.dll (hoặc bất kỳ lắp ráp phi gấc khác), sau đó tôi nhận được một AssemblyResolutionException.

Không thể giải quyết lắp ráp: 'Npgsql, Version = 2.0.11.92, Văn hóa = trung tính, PublicKeyToken = 5d8b90d52f46fda7'

Tôi biết làm thế nào tôi có thể nhận được các hội đồng tham chiếu, nhưng làm thế nào tôi có thể thêm chúng vào 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 
+0

'//assembly.GetReferencedAssemblies(); 'trong mã gốc từ liên kết của bạn là' GetReferencedAssemblies (assembly); ', bạn đã bỏ nó ra vì họ không định nghĩa' GetReferencedAssemblies' là gì trong bài viết? Mã đó có lẽ sẽ giúp bạn. –

+0

@ M.Babcock: Đúng nhưng mã này không có ở đâu để tìm. Và trong ObjectManager, không có phương thức GetReferencedAssemblies nào lấy assembly làm tham số ... –

Trả lời

13

Bạn cần phải nói cho Cecil, trình đọc siêu dữ liệu cơ bản mà ILSpy đang sử dụng, nơi các hội đồng của bạn đang sử dụng. Bạn có thể viết:

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

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

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

Đây là cách tự nhiên nhất để nói cho Cecil biết nơi giải quyết hội đồng được tham chiếu. Bằng cách này bạn có thể loại bỏ các dòng nơi bạn tải lắp ráp bằng cách sử dụng System.Reflection, và chỉ sử dụng ngăn xếp ILSpy.

+0

Có một góc khác cho vấn đề này, @JB Evain. Nếu tôi decompiling một DLL trên một hệ thống mà các hội đồng được giới thiệu không có mặt, các decompilation không (với ngoại lệ.) Ít nhất, tôi muốn xem mã dịch ngược, cho bất cứ điều gì đã được giải quyết. Tôi đang đăng một giải pháp bổ sung, nhưng giải pháp của bạn là lý tưởng. – Nayan

1

Dựa trên nguồn Mono.Cắt, tôi đoán bạn có thể xử lý điều này bằng cách sử dụng lớp Mono.Cecil.DefaultAssemblyResolver.

Thay vì mã này:

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

thử điều này:

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

EDIT

Trong khi đề nghị ban đầu của tôi có thể hoặc không thể làm việc (Tôi chưa bao giờ làm được điều đó, vì vậy không có bảo đảm), bạn có thể muốn xem xét lắp ráp Mono.Addins.CecilReflector.dll từ Mono.Addins project để giúp giảm thiểu các loại các vấn đề. Nó cũng dựa trên Mono.Cecil (giống như ILSpy) vì vậy mặc dù tiền đề chung rằng Mono.Addins là một thư viện mở rộng không đáp ứng nhu cầu của bạn nó có thể chứa một số mã sử dụng cho mục đích của bạn hoặc ít nhất là học hỏi từ.

2

Ngoài những gì JB Evain đề xuất, mã này sẽ giúp tránh trường hợp ngoại lệ. Tất cả những gì bạn phải làm là xử lý ngoại lệ trong trình phân giải.

Không phải cách tốt nhất, tôi thừa nhận. Nhưng nó hoạt động cho kịch bản này: "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; 
    } 
} 

Và sử dụng nó như thế này:

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); 




Tôi thực sự muốn nhìn thấy sự tăng cường trong decompiler: nó hiện bỏ qua số ReaderParameters mà người dùng đặt, trong lớp DefaultAssemblyResolver.

Cách sử dụng:

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

hiện DefaultAssemblyResolver mã:

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; 
} 
+2

Rực rỡ, điều này cho phép tôi hiển thị mã nguồn mà không có các hội đồng được tham chiếu. – TaintedLemon

+1

@Nayan: Cảm ơn, điều đó rất tuyệt. –

+0

@Nayan: Điều này có thể đạt được dễ dàng hơn nhiều. Nhìn vào câu trả lời của tôi. Sao chép mã nguồn của các lớp cơ sở không phải là cách tốt nhất để tăng cường chúng. –

4

này được cải thiện câu trả lời @Nayan. Nếu bạn muốn bỏ qua hội mất tích, sao chép lớp này:

using Mono.Cecil; 

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

và sử dụng nó như thế:

var assembly = AssemblyDefinition.ReadAssembly(path, new ReaderParameters() { 
    AssemblyResolver = new IgnoringExceptionsAssemblyResolver() 
}); 
+2

Vâng, điều này sạch hơn nhiều. Tôi là một tân binh, khi tôi viết câu trả lời đó :) – Nayan

Các vấn đề liên quan