📜 ⬆️ ⬇️

How easy it is to take and view .NET assemblies in SQL Server using ICSharpCode.Decompiler

You can of course take third-party utilities, such as some kind of open-source ILSpy, save the assembly to disk and then decompile.

image

But you just want to connect to the database and see all the assemblies and what's inside.

And besides, there are a lot of high-quality Opensource components for all cases of programmer life, and writing in C # is convenient and easy :)
')
So.

For this we need a Nuget package.

image

We read from the base all the builds


SqlDataReader, SQL query trivial:

SELECT af.name, af.content FROM sys.assemblies a INNER JOIN sys.assembly_files af ON a.assembly_id = af.assembly_id 

Initialize the build


ie load our bytes into the AssemblyDefinition class

 var _assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(new MemoryStream(rdr.GetSqlBytes(1).Value), pars); 

rdr - here is just a SqlDataReader, but you can read all the assemblies into some list, for example a list of objects of such a simple class

 public class SqlAssemblyObject { public string AssemblyName { get; set; } public SqlBytes Data { get; set; } } 

Since there are usually a lot of assemblies, they are conveniently displayed on the screen in the form of a list or a plate, but the insides are in the form of a tree, of course!

Something like this will be the norm

image

We display


for example in a treeview

 foreach (var typeInAssembly in _assemblyDefinition.MainModule.Types) { if (typeInAssembly.IsPublic) { var node = new TreeNode(typeInAssembly.FullName); node.Tag = typeInAssembly; } treeView1.Nodes.Add(node); } 

Decompilation


Only three lines of code! (for example, I did in the treeView1_AfterSelect event)

 var decompiler = new ICSharpCode.Decompiler.CSharp.CSharpDecompiler(_assemblyDefinition.MainModule, new DecompilerSettings()); var str = decompiler.DecompileAsString(e.Node.Tag as IMemberDefinition); textbox1.Text = str; 

The source itself, where everything is brought together

It looks like this in the end.

image

Little about pitfalls


Naturally assemblies may depend on assemblies, and all this may lie in the SQL database.

Then if you decompile "in the forehead" - there will be a decompilation error.

It is easy to avoid it (since ICSharpCode.Decompiler has AssemblyResolver):

Let's write your resolver, just passing it all the available assemblies in the analyzed SQL database:

 public class DatabaseAssemblyResolver : IAssemblyResolver { List<SqlAssemblyObject> _databaseLibs; DefaultAssemblyResolver _resolver; public DatabaseAssemblyResolver(List<SqlAssemblyObject> dlls) { _databaseLibs = dlls; _resolver = new DefaultAssemblyResolver(); } public void Dispose() { //throw new NotImplementedException(); } public AssemblyDefinition Resolve(AssemblyNameReference name) { foreach (var item in _databaseLibs) { if(item.AssemblyName.Contains(name.Name)) { return AssemblyDefinition.ReadAssembly(new MemoryStream(item.Data.Value)); } } return _resolver.Resolve(name); } public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) { foreach (var item in _databaseLibs) { if (item.AssemblyName.Contains(name.Name)) { return AssemblyDefinition.ReadAssembly(new MemoryStream(item.Data.Value)); } } return _resolver.Resolve(name, parameters); } 

The _listItems variable is just a list of all assemblies from sys.assembly_files

 var pars = new ReaderParameters(); pars.AssemblyResolver = new DatabaseAssemblyResolver(_listItems); _assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(new MemoryStream(_listItems[idx].Data.Value), pars); 

Now when decompiling, all dependencies can be resolved!

image

PS: Lily James was used to attract attention.

Source: https://habr.com/ru/post/425799/


All Articles