Skip to content

Commit

Permalink
analyze .NET assemblies
Browse files Browse the repository at this point in the history
  • Loading branch information
IS4Code committed May 30, 2023
1 parent 5dc7a63 commit 5c24ec9
Show file tree
Hide file tree
Showing 4 changed files with 471 additions and 0 deletions.
1 change: 1 addition & 0 deletions SFI.Application/Inspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public Inspector()
Analyzers.Add(XmlAnalyzer = new XmlAnalyzer());
Analyzers.Add(new MediaTypeAnalyzer());
Analyzers.Add(new X509CertificateAnalyzer());
Analyzers.Add(new AssemblyAnalyzer());
Analyzers.Add(new FormatObjectAnalyzer());

if(BuiltInHash.MD5 != null)
Expand Down
325 changes: 325 additions & 0 deletions SFI.ExternalFormats/Modules/CliModuleFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
using IS4.SFI.Tools;
using System;
using System.Buffers;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Threading.Tasks;

namespace IS4.SFI.Formats
{
/// <summary>
/// Represents the PE module format storing a .NET assembly.
/// </summary>
public class CliModuleFormat : ModuleFormat<Assembly>
{
const string baseType = "application/vnd.microsoft.portable-executable";

/// <inheritdoc cref="FileFormat{T}.FileFormat(string, string)"/>
public CliModuleFormat() : base("PE", baseType + ";type=cli", null)
{

}

/// <inheritdoc/>
public override string? GetExtension(Assembly value)
{
return value.EntryPoint == null ? "dll" : "exe";
}

/// <inheritdoc/>
public override string? GetMediaType(Assembly value)
{
return baseType;
}

readonly ArrayPool<MetadataLoadContext?> contextPool = ArrayPool<MetadataLoadContext?>.Create(1, 50);

const string coreAssemblyName = "netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null";

/// <inheritdoc/>
public async override ValueTask<TResult?> Match<TResult, TArgs>(Stream stream, MatchContext context, ResultFactory<Assembly, TResult, TArgs> resultFactory, TArgs args) where TResult : default
{
using var leash = contextPool.Rent(1, out var buffer);
var loadContext = buffer[0] ??= new(Resolver.Instance, coreAssemblyName);
var assembly = loadContext.LoadFromStream(stream);
try{
return await resultFactory(assembly, args);
}finally{
loadContext.Dispose();
buffer[0] = null;
}
}

class Resolver : MetadataAssemblyResolver
{
public static readonly Resolver Instance = new();

public override Assembly? Resolve(MetadataLoadContext context, AssemblyName assemblyName)
{
if(coreAssemblyName == assemblyName.FullName)
{
return context.LoadFromByteArray(dummyCore);
}else if(assemblyName.Name is "netstandard" or "mscorlib" or "System.Runtime")
{
return context.LoadFromAssemblyName(new AssemblyName(coreAssemblyName));
}
return null;
}
}

static readonly byte[] dummyCore = Decompress(dummyCoreBase64);

/// <summary>
/// The following is a base64-encoded DEFLATE-compressed assembly
/// with a few basic types from .NET Standard.
/// The assembly is used only to pose as the core assembly for
/// <see cref="MetadataLoadContext.MetadataLoadContext(MetadataAssemblyResolver, string?)"/>,
/// and is deliberately empty to speed up the loading.
/// </summary>
/// <remarks>
/// <code>
/// .assembly netstandard
/// {
/// .ver 2:0:0:0
/// }
/// .module netstandard.dll
///
/// .class public auto ansi beforefieldinit System.Object
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor() runtime managed
/// {}
/// }
///
/// .class public abstract auto ansi beforefieldinit System.ValueType extends System.Object
/// {
/// .method family hidebysig specialname rtspecialname instance void .ctor() runtime managed
/// {}
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Void extends System.ValueType
/// {
/// .pack 0
/// .size 1
/// }
///
/// .class public auto ansi sealed beforefieldinit System.String extends System.Object
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Char extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Boolean extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Byte extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.SByte extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Int16 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.UInt16 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Int32 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.UInt32 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Int64 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.UInt64 extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.IntPtr extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.UIntPtr extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Single extends System.ValueType
/// {
/// }
///
/// .class public sequential ansi sealed beforefieldinit System.Double extends System.ValueType
/// {
/// }
///
/// .class public abstract auto ansi beforefieldinit System.Enum extends System.ValueType
/// {
/// .method family hidebysig specialname rtspecialname instance void .ctor() runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed System.Configuration.Assemblies.AssemblyHashAlgorithm extends System.Enum
/// {
/// .field public specialname rtspecialname int32 value__
/// }
///
/// .class public auto ansi sealed System.Reflection.AssemblyNameFlags extends System.Enum
/// {
/// .field public specialname rtspecialname int32 value__
/// }
///
/// .class public abstract auto ansi beforefieldinit System.Attribute extends System.Object
/// {
/// .method family hidebysig specialname rtspecialname instance void .ctor() runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyAlgorithmIdAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(uint32 algorithmId) runtime managed
/// {}
///
/// .method public hidebysig specialname rtspecialname instance void .ctor(valuetype System.Configuration.Assemblies.AssemblyHashAlgorithm algorithmId) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyCompanyAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string company) runtime managed
/// {}
///
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyConfigurationAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string configuration) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyCopyrightAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string copyright) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyCultureAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string culture) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyDefaultAliasAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string defaultAlias) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyDelaySignAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(bool delaySign) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyDescriptionAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string description) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyFileVersionAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string version) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyFlagsAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(valuetype System.Reflection.AssemblyNameFlags assemblyFlags) runtime managed
/// {}
///
/// .method public hidebysig specialname rtspecialname instance void .ctor(uint32 'flags') runtime managed
/// {}
///
/// .method public hidebysig specialname rtspecialname instance void .ctor(int32 assemblyFlags) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyInformationalVersionAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string informationalVersion) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyKeyFileAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string keyFile) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyKeyNameAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string keyName) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyMetadataAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string key, string 'value') runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyProductAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string product) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblySignatureKeyAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string publicKey, string countersignature) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyTitleAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string title) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyTrademarkAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string trademark) runtime managed
/// {}
/// }
///
/// .class public auto ansi sealed beforefieldinit System.Reflection.AssemblyVersionAttribute extends System.Attribute
/// {
/// .method public hidebysig specialname rtspecialname instance void .ctor(string version) runtime managed
/// {}
/// }
/// </code>
/// </remarks>
const string dummyCoreBase64 = "vZVNbBtFFMff2rFru4nrkJImFVI3DQKBwGrTNuGAUOJ80EBCA05CqaqWsXdib7veNbvjtEaoaqSChJAQILj0BDdAXCqQaJHKBQ5IqFyAK+TEBQ45caiEypu3Y3unNgL1wCb7f/ObN5/vzY6XT70DcQDow/fOHYDrED7T8O/PZXyzB77KwhfpW2PXjaVbY6tVOzDrvlfxWc0sM9f1hFnipt9wTds1504UzZpn8fzAQOZBNcbKPMCSYcDkwqbVGncb4mO7jRRA5q4JzdbCpsNyLFw3QMeSPxYW4zD9OkCO/ju2bf7fxwQ4HsG84BcF2p106KO9xrq6vJz3ueOVVcW0sv16O6wu3OuyjtO0CVjByT7EtRj3OpB6CsVnCoYaRS5zcyJ/KH/s0NTElKxJgIO6jckav4R5T2DeZLkofNutBLLFCq4BMw/ja0U4mQ5zNf702uIc2iryE5ILjldS82HIjBe3AGQY4bZxBIbDPcgz/Wjoh/34jkBY33oBHlY2CYMY/CS2kHpQHTpDqfzLUYsElbeQRhTFIG3kMPoZnN3AGQ2keeWLk2+p7ZP0vEYvaXRGI0ujcxq9otEFjS5pdEWjtzR6T6OrGn3Upi2kg5H9AXwMX8MAUh/RL7CDFEOScYkZcu9x8uWg39iB00gJokcU7SIqKEoRMUVpotcUZYg+ULSb6HNF/UQ/KBog+l1RligVC2kP0QFF94U5UjREdEbRXqILiu4nelfRMNGnivYRfadohOhXRaNEtxXth2RyNJ5VCnQu3xgZimfU+YrDlf9Mst+gRsPqwgjpATrzHerTKKFRUqNdERqjr6/jS2uUidBDmJPoyvoj9BjmJNovq9EejXIROoxfWtQ3pPn2ar5hjfZpFH7tY/GOPk56jHSWdJl0jbRE6pBeJL1M+nak/D7pJ6TXSG/E5f1yk8rfkH5PNT9T+TfSPyJjtn6l9Gv+z7heY8BUq/jksmc1HP4UFJuB4DU4UTrHywLWmdPgq806h3m3UQOXi0Aw12K+lbccB2pB2fMduwTrnm1BeLfCbJX5UPA8hzMXCk3BoUi66IrDk7AWGtQjEwRoUCePEqBBXRE+kbRFHNLhMOc1SmhmgoDXSk7zOAuqM07F821Rrak152c9d8OuNHwmbM/Nq6Y2D9q9nmM1vuAwvP5Vjxf4hoPbxOYwI3D1pYbozNEef9Hqds56tTpzm70ckUX0ctebvl2pih6uhiMaPu92zPENhr4Zx2ZBL6/DmkW70mOyOR6UfbveeyULtsPXuR/0dsoodVcvuhueX6OtMecfOz/LafCeDpmCbscyF8xignV7Vnw8l+Ue0ZI7ZjJeOGi3d9UWvRaw6jOL15h/vtvVtZt8WXg+bMoP4OxZYJ3DAOUw92gjqUZSmYVymEiwInlDUGnCUjsrsBnOCiwad9ggtXsEG86HsZVWhlLacI1QDyMFdfxQ7DJGBVfUcIXspyIFQkYFRCsI0c+ZrjSTroLgam7t1I2flj+L/Vj56+a1byH15aun10ePbr+JDYxYMtVnGkY6gTK4KotZKTHik7KYSpgxI5uFu5+/AQ==";

static byte[] Decompress(string base64)
{
var bytes = Convert.FromBase64String(base64);
using var buffer = new MemoryStream(bytes);
using var deflate = new DeflateStream(buffer, CompressionMode.Decompress);
using var output = new MemoryStream();
deflate.CopyTo(output);
return output.ToArray();
}
}
}
1 change: 1 addition & 0 deletions SFI.ExternalFormats/SFI.ExternalFormats.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<PackageReference Include="Svg" Version="3.2.3" />
<PackageReference Include="SwfDotNet.IO" Version="1.0.0.1" />
<PackageReference Include="System.Drawing.Common" Version="5.0.3" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" />
<PackageReference Include="TagLibSharp" Version="2.2.0" />
</ItemGroup>

Expand Down
Loading

0 comments on commit 5c24ec9

Please sign in to comment.