Created
August 3, 2018 13:12
-
-
Save MichalStrehovsky/23183ff7960d1ae9d866e4d5c064b5e3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.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