Created
July 2, 2017 17:52
-
-
Save jbe2277/f91ef12df682f3bfb6293aabcb47be2a to your computer and use it in GitHub Desktop.
AssemblyAnalyzer via System.Reflection.Metadata
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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