Как просто взять и посмотреть .NET сборки в SQL Server с помощью ICSharpCode.Decompiler

в 18:44, , рубрики: .net, ilspy, Microsoft SQL Server, sql, sqlclr

Можно конечно взять сторонние утилиты, например какой-нибудь опенсорсный ILSpy, сохранить сборку на диск и потом декомпилировать.

image

Но хочется просто подключиться к БД и посмотреть все сборки и что там внутри.

И к тому же, есть очень много качественных Opensource компонент на все случаи программистской жизни, да и писать на C# удобно и легко :)

Итак.

Для этого нам потребуется Nuget-пакет

image

Читаем из базы все сборки

SqlDataReader-ом, SQL-запрос тривиальный:

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

Инициализируем сборку

i.e. загружаем наши байты в класс AssemblyDefinition

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

rdr — тут как раз SqlDataReader, но можно зачитать все сборки в какой-нибудь список, например список объектов вот такого простенького класса

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

Поскольку сборок обычно много, то их удобно выводить на экран в виде списка или таблички, а вот внутренности в виде дерева конечно же!

Примерно так будет норм

image

Выводим на экран

например в TreeView

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

Декомпиляция

Всего три строчки кода! (например я сделал в событии treeView1_AfterSelect)

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

Сам исходник, где всё сведено воедино

Выглядит в итоге примерно так

image

Немного о подводных камнях

Естественно сборки могут зависеть от сборок, и всё это может лежать в SQL базе.

Тут если декомпилировать «в лоб» — будет ошибка декомпиляции.

Избежать ее легко (т. к. в ICSharpCode.Decompiler есть AssemblyResolver):

Напишем свой резолвер, просто передав ему все доступные сборки в анализируемой SQL базе:

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

Переменная _listItems — это как раз список всех сборок из sys.assembly_files

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

Теперь при декомпиляции все зависимости удается разрешить!

image

P.S.: Лили Джеймс была использована для привлечения внимания.

Автор: skaeff

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js