Skip to content

Instantly share code, notes, and snippets.

@MichalStrehovsky
Created August 3, 2018 13:12
Show Gist options
  • Save MichalStrehovsky/23183ff7960d1ae9d866e4d5c064b5e3 to your computer and use it in GitHub Desktop.
Save MichalStrehovsky/23183ff7960d1ae9d866e4d5c064b5e3 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
namespace MemberScanner
{
class Program
{
static bool ReferencesAnyMember(MetadataReader reader, Reference[] references)
{
// Walk the MemberRef table looking for a reference that matches one of the specified reference names
foreach (MemberReferenceHandle memberRefHandle in reader.MemberReferences)
{
MemberReference memberRef = reader.GetMemberReference(memberRefHandle);
foreach (Reference r in references)
{
if (IsMatch(reader, memberRef, r))
return true;
}
}
return false;
}
private static bool IsMatch(MetadataReader reader, MemberReference memberRef, Reference reference)
{
MetadataStringComparer stringComparer = reader.StringComparer;
// If the member name matches, look at the type name
if (stringComparer.Equals(memberRef.Name, reference.MemberName))
{
switch (memberRef.Parent.Kind)
{
case HandleKind.MethodDefinition:
// Supports vararg method invoke
case HandleKind.ModuleReference:
// Supports references to global members in other modules
case HandleKind.TypeDefinition:
// MemberRef to a TypeDef is not ectually a MemberRef
break;
case HandleKind.TypeReference:
if (IsMatch(reader, (TypeReferenceHandle)memberRef.Parent, reference.TypeNamespace, reference.TypeName))
return true;
break;
case HandleKind.TypeSpecification:
// We have a type specification. The only interesting case is when this is a generic type instance
// over a type reference
TypeSpecification typeSpec = reader.GetTypeSpecification((TypeSpecificationHandle)memberRef.Parent);
BlobReader br = reader.GetBlobReader(typeSpec.Signature);
SignatureTypeCode typeCode = br.ReadSignatureTypeCode();
if (typeCode == SignatureTypeCode.GenericTypeInstance)
{
typeCode = br.ReadSignatureTypeCode();
if (typeCode == SignatureTypeCode.TypeHandle)
{
EntityHandle definitionHandle = br.ReadTypeHandle();
if (definitionHandle.Kind == HandleKind.TypeReference &&
IsMatch(reader, (TypeReferenceHandle)definitionHandle, reference.TypeNamespace, reference.TypeName))
return true;
}
}
break;
throw new NotImplementedException();
}
}
return false;
}
private static bool IsMatch(MetadataReader reader, TypeReferenceHandle typeRefHandle, string typeNamespace, string typeName)
{
// Read the type reference record and compare the namespace and name
MetadataStringComparer stringComparer = reader.StringComparer;
TypeReference typeRef = reader.GetTypeReference(typeRefHandle);
return stringComparer.Equals(typeRef.Name, typeName) &&
stringComparer.Equals(typeRef.Namespace, typeNamespace);
}
static void Main(string[] args)
{
using (PEReader peReader = new PEReader(File.OpenRead(args[0])))
{
// Check if this is a .NET module
if (!peReader.HasMetadata)
return;
MetadataReader reader = peReader.GetMetadataReader();
ReferencesAnyMember(reader, new Reference[]
{
new Reference("System.Collections.Generic", "List`1", "Add")
});
}
}
public struct Reference
{
public readonly string TypeNamespace;
public readonly string TypeName;
public readonly string MemberName;
public Reference(string typeNamespace, string typeName, string memberName)
{
TypeName = typeName;
TypeNamespace = typeNamespace;
MemberName = memberName;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment