Skip to content

Instantly share code, notes, and snippets.

@jbe2277
Created July 2, 2017 17:52
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jbe2277/f91ef12df682f3bfb6293aabcb47be2a to your computer and use it in GitHub Desktop.
Save jbe2277/f91ef12df682f3bfb6293aabcb47be2a to your computer and use it in GitHub Desktop.
AssemblyAnalyzer via System.Reflection.Metadata
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography;
namespace AssemblyAnalyzer
{
// NuGet Package: System.Reflection.Metadata
internal class Program
{
private static void Main(string[] args)
{
using (var stream = File.OpenRead(args.FirstOrDefault() ?? Assembly.GetEntryAssembly().Location))
using (var reader = new PEReader(stream))
{
var metadata = reader.GetMetadataReader();
ReadAssembly(metadata);
}
if (Debugger.IsAttached) Console.ReadKey();
}
private static void ReadAssembly(MetadataReader reader)
{
var assembly = reader.GetAssemblyDefinition();
Console.WriteLine($"{assembly.Name.ToString(reader)}, Version={assembly.Version}, Culture={(assembly.Culture.ToString(reader) ?? "neutral")}, "
+ $"PublicKey={(assembly.PublicKey.FormatPublicKeyToken(reader) ?? "null")}, Flags={assembly.Flags}, "
+ $"HashAlgorithm={assembly.HashAlgorithm}");
Console.WriteLine("\nAssembly References:");
foreach (var reference in reader.AssemblyReferences.Select(reader.GetAssemblyReference))
{
Console.WriteLine($" {reference.Name.ToString(reader)}, Version={reference.Version}, Culture={(reference.Culture.ToString(reader) ?? "neutral")}, "
+ $"PublicKeyToken={(reference.PublicKeyOrToken.FormatPublicKeyToken(reader) ?? "null")}, Flags={reference.Flags}");
}
Console.WriteLine("\nManifest Resources:");
foreach (var resource in reader.ManifestResources.Select(reader.GetManifestResource))
{
Console.WriteLine($" {resource.Name.ToString(reader)}, Attributes={resource.Attributes}");
}
Console.WriteLine("\nCustom Attributes:");
foreach (var attribute in assembly.GetCustomAttributes().Select(reader.GetCustomAttribute))
{
var ctor = reader.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
var attrType = reader.GetTypeReference((TypeReferenceHandle)ctor.Parent);
Console.WriteLine($" {reader.GetString(attrType.Name)} > {string.Join(";", attribute.GetParameterValues(reader))}");
}
Console.WriteLine("\nType Definitions:");
foreach (var type in reader.TypeDefinitions.Select(reader.GetTypeDefinition))
{
Console.WriteLine($" {string.Join(".", new[] { reader.GetString(type.Namespace), reader.GetString(type.Name) }.Where(x => !string.IsNullOrEmpty(x)))}");
}
}
}
internal static class MetadataHelper
{
public static string ToString(this StringHandle handle, MetadataReader reader)
{
return handle.IsNil ? null : reader.GetString(handle);
}
public static string FormatPublicKeyToken(this BlobHandle handle, MetadataReader metadataReader)
{
if (handle.IsNil) return null;
byte[] bytes = metadataReader.GetBlobBytes(handle);
if (bytes == null || bytes.Length <= 0) return null;
if (bytes.Length > 8) // Strong named assembly
{
using (var sha1 = SHA1.Create()) // Get the public key token, which is the last 8 bytes of the SHA-1 hash of the public key
{
var token = sha1.ComputeHash(bytes);
bytes = new byte[8];
int count = 0;
for (int i = token.Length - 1; i >= token.Length - 8; i--)
{
bytes[count] = token[i];
count++;
}
}
}
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
}
public static ImmutableArray<string> GetParameterValues(this CustomAttribute customAttribute, MetadataReader reader)
{
if (customAttribute.Constructor.Kind != HandleKind.MemberReference) throw new InvalidOperationException();
var ctor = reader.GetMemberReference((MemberReferenceHandle)customAttribute.Constructor);
var provider = new StringParameterValueTypeProvider(reader, customAttribute.Value);
var signature = ctor.DecodeMethodSignature(provider, null);
return signature.ParameterTypes;
}
}
internal sealed class StringParameterValueTypeProvider : ISignatureTypeProvider<string, object>
{
private readonly BlobReader valueReader;
public StringParameterValueTypeProvider(MetadataReader reader, BlobHandle value)
{
Reader = reader;
valueReader = reader.GetBlobReader(value);
var prolog = valueReader.ReadUInt16();
if (prolog != 1) throw new BadImageFormatException("Invalid custom attribute prolog.");
}
public MetadataReader Reader { get; }
public string GetArrayType(string elementType, ArrayShape shape) => "";
public string GetByReferenceType(string elementType) => "";
public string GetFunctionPointerType(MethodSignature<string> signature) => "";
public string GetGenericInstance(string genericType, ImmutableArray<string> typestrings) => "";
public string GetGenericInstantiation(string genericType, ImmutableArray<string> typeArguments) { throw new NotImplementedException(); }
public string GetGenericMethodParameter(int index) => "";
public string GetGenericMethodParameter(object genericContext, int index) { throw new NotImplementedException(); }
public string GetGenericTypeParameter(int index) => "";
public string GetGenericTypeParameter(object genericContext, int index) { throw new NotImplementedException(); }
public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) => "";
public string GetPinnedType(string elementType) => "";
public string GetPointerType(string elementType) => "";
public string GetPrimitiveType(PrimitiveTypeCode typeCode)
{
if (typeCode == PrimitiveTypeCode.String) return valueReader.ReadSerializedString();
return "";
}
public string GetSZArrayType(string elementType) => "";
public string GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => "";
public string GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => "";
public string GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => "";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment