diff --git a/Confuser.Core/DnlibUtils.cs b/Confuser.Core/DnlibUtils.cs index f3d3c5c12..8241615b7 100644 --- a/Confuser.Core/DnlibUtils.cs +++ b/Confuser.Core/DnlibUtils.cs @@ -6,453 +6,516 @@ using dnlib.DotNet.Emit; using dnlib.IO; -namespace Confuser.Core { - /// - /// Provides a set of utility methods about dnlib - /// - public static class DnlibUtils { - /// - /// Finds all definitions of interest in a module. - /// - /// The module. - /// A collection of all required definitions - public static IEnumerable FindDefinitions(this ModuleDef module) { - yield return module; - foreach (TypeDef type in module.GetTypes()) { - yield return type; - - foreach (MethodDef method in type.Methods) - yield return method; - - foreach (FieldDef field in type.Fields) - yield return field; - - foreach (PropertyDef prop in type.Properties) - yield return prop; - - foreach (EventDef evt in type.Events) - yield return evt; - } - } - - /// - /// Finds all definitions of interest in a type. - /// - /// The type. - /// A collection of all required definitions - public static IEnumerable FindDefinitions(this TypeDef typeDef) { - yield return typeDef; - - foreach (TypeDef nestedType in typeDef.NestedTypes) - yield return nestedType; - - foreach (MethodDef method in typeDef.Methods) - yield return method; - - foreach (FieldDef field in typeDef.Fields) - yield return field; - - foreach (PropertyDef prop in typeDef.Properties) - yield return prop; - - foreach (EventDef evt in typeDef.Events) - yield return evt; - } - - /// - /// Determines whether the specified type is visible outside the containing assembly. - /// - /// The type. - /// Visibility of executable modules. - /// true if the specified type is visible outside the containing assembly; otherwise, false. - public static bool IsVisibleOutside(this TypeDef typeDef, bool exeNonPublic = true) { - // Assume executable modules' type is not visible - if (exeNonPublic && (typeDef.Module.Kind == ModuleKind.Windows || typeDef.Module.Kind == ModuleKind.Console)) - return false; - - do { - if (typeDef.DeclaringType == null) - return typeDef.IsPublic; - if (!typeDef.IsNestedPublic && !typeDef.IsNestedFamily && !typeDef.IsNestedFamilyOrAssembly) - return false; - typeDef = typeDef.DeclaringType; - } while (typeDef != null); - - throw new UnreachableException(); - } - - /// - /// Determines whether the object has the specified custom attribute. - /// - /// The object. - /// The full name of the type of custom attribute. - /// true if the specified object has custom attribute; otherwise, false. - public static bool HasAttribute(this IHasCustomAttribute obj, string fullName) { - return obj.CustomAttributes.Any(attr => attr.TypeFullName == fullName); - } - - /// - /// Determines whether the specified type is COM import. - /// - /// The type. - /// true if specified type is COM import; otherwise, false. - public static bool IsComImport(this TypeDef type) { - return type.IsImport || - type.HasAttribute("System.Runtime.InteropServices.ComImportAttribute") || - type.HasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute"); - } - - /// - /// Determines whether the specified type is compiler generated. - /// - /// The type. - /// true if specified type is compiler generated; otherwise, false. - public static bool IsCompilerGenerated(this TypeDef type) { - return type.HasAttribute("System.Runtime.CompilerServices.CompilerGeneratedAttribute"); - } - - /// - /// Determines whether the specified type is a delegate. - /// - /// The type. - /// true if the specified type is a delegate; otherwise, false. - public static bool IsDelegate(this TypeDef type) { - if (type.BaseType == null) - return false; - - string fullName = type.BaseType.FullName; - return fullName == "System.Delegate" || fullName == "System.MulticastDelegate"; - } - - /// - /// Determines whether the specified type is inherited from a base type in corlib. - /// - /// The type. - /// The full name of base type. - /// true if the specified type is inherited from a base type; otherwise, false. - public static bool InheritsFromCorlib(this TypeDef type, string baseType) { - if (type.BaseType == null) - return false; - - TypeDef bas = type; - do { - bas = bas.BaseType.ResolveTypeDefThrow(); - if (bas.ReflectionFullName == baseType) - return true; - } while (bas.BaseType != null && bas.BaseType.DefinitionAssembly.IsCorLib()); - return false; - } - - /// - /// Determines whether the specified type is inherited from a base type. - /// - /// The type. - /// The full name of base type. - /// true if the specified type is inherited from a base type; otherwise, false. - public static bool InheritsFrom(this TypeDef type, string baseType) { - if (type.BaseType == null) - return false; - - TypeDef bas = type; - do { - bas = bas.BaseType.ResolveTypeDefThrow(); - if (bas.ReflectionFullName == baseType) - return true; - } while (bas.BaseType != null); - return false; - } - - /// - /// Determines whether the specified type implements the specified interface. - /// - /// The type. - /// The full name of the type of interface. - /// true if the specified type implements the interface; otherwise, false. - public static bool Implements(this TypeDef type, string fullName) { - do { - foreach (InterfaceImpl iface in type.Interfaces) { - if (iface.Interface.ReflectionFullName == fullName) - return true; - } - - if (type.BaseType == null) - return false; - - type = type.BaseType.ResolveTypeDefThrow(); - } while (type != null); - throw new UnreachableException(); - } - - /// - /// Resolves the method. - /// - /// The method to resolve. - /// A instance. - /// The method couldn't be resolved. - public static MethodDef ResolveThrow(this IMethod method) { - var def = method as MethodDef; - if (def != null) - return def; - - var spec = method as MethodSpec; - if (spec != null) - return spec.Method.ResolveThrow(); - - return ((MemberRef)method).ResolveMethodThrow(); - } - - /// - /// Resolves the field. - /// - /// The field to resolve. - /// A instance. - /// The method couldn't be resolved. - public static FieldDef ResolveThrow(this IField field) { - var def = field as FieldDef; - if (def != null) - return def; - - return ((MemberRef)field).ResolveFieldThrow(); - } - - /// - /// Find the basic type reference. - /// - /// The type signature to get the basic type. - /// A instance, or null if the typeSig cannot be resolved to basic type. - public static ITypeDefOrRef ToBasicTypeDefOrRef(this TypeSig typeSig) { - while (typeSig.Next != null) - typeSig = typeSig.Next; - - if (typeSig is GenericInstSig) - return ((GenericInstSig)typeSig).GenericType.TypeDefOrRef; - if (typeSig is TypeDefOrRefSig) - return ((TypeDefOrRefSig)typeSig).TypeDefOrRef; - return null; - } - - /// - /// Find the type references within the specified type signature. - /// - /// The type signature to find the type references. - /// A list of instance. - public static IList FindTypeRefs(this TypeSig typeSig) { - var ret = new List(); - FindTypeRefsInternal(typeSig, ret); - return ret; - } - - static void FindTypeRefsInternal(TypeSig typeSig, IList ret) { - while (typeSig.Next != null) { - if (typeSig is ModifierSig) - ret.Add(((ModifierSig)typeSig).Modifier); - typeSig = typeSig.Next; - } - - if (typeSig is GenericInstSig) { - var genInst = (GenericInstSig)typeSig; - ret.Add(genInst.GenericType.TypeDefOrRef); - foreach (TypeSig genArg in genInst.GenericArguments) - FindTypeRefsInternal(genArg, ret); - } - else if (typeSig is TypeDefOrRefSig) { - var type = ((TypeDefOrRefSig)typeSig).TypeDefOrRef; - while (type != null) { - ret.Add(type); - type = type.DeclaringType; - } - } - } - - /// - /// Determines whether the specified property is public. - /// - /// The property. - /// true if the specified property is public; otherwise, false. - public static bool IsPublic(this PropertyDef property) { - if (property.GetMethod != null && property.GetMethod.IsPublic) - return true; - - if (property.SetMethod != null && property.SetMethod.IsPublic) - return true; - - return property.OtherMethods.Any(method => method.IsPublic); - } - - /// - /// Determines whether the specified property is static. - /// - /// The property. - /// true if the specified property is static; otherwise, false. - public static bool IsStatic(this PropertyDef property) { - if (property.GetMethod != null && property.GetMethod.IsStatic) - return true; - - if (property.SetMethod != null && property.SetMethod.IsStatic) - return true; - - return property.OtherMethods.Any(method => method.IsStatic); - } - - /// - /// Determines whether the specified event is public. - /// - /// The event. - /// true if the specified event is public; otherwise, false. - public static bool IsPublic(this EventDef evt) { - if (evt.AddMethod != null && evt.AddMethod.IsPublic) - return true; - - if (evt.RemoveMethod != null && evt.RemoveMethod.IsPublic) - return true; - - if (evt.InvokeMethod != null && evt.InvokeMethod.IsPublic) - return true; - - return evt.OtherMethods.Any(method => method.IsPublic); - } - - /// - /// Determines whether the specified event is static. - /// - /// The event. - /// true if the specified event is static; otherwise, false. - public static bool IsStatic(this EventDef evt) { - if (evt.AddMethod != null && evt.AddMethod.IsStatic) - return true; - - if (evt.RemoveMethod != null && evt.RemoveMethod.IsStatic) - return true; - - if (evt.InvokeMethod != null && evt.InvokeMethod.IsStatic) - return true; - - return evt.OtherMethods.Any(method => method.IsStatic); - } - - /// - /// Replaces the specified instruction reference with another instruction. - /// - /// The method body. - /// The instruction to replace. - /// The new instruction. - public static void ReplaceReference(this CilBody body, Instruction target, Instruction newInstr) { - foreach (ExceptionHandler eh in body.ExceptionHandlers) { - if (eh.TryStart == target) - eh.TryStart = newInstr; - if (eh.TryEnd == target) - eh.TryEnd = newInstr; - if (eh.HandlerStart == target) - eh.HandlerStart = newInstr; - if (eh.HandlerEnd == target) - eh.HandlerEnd = newInstr; - } - foreach (Instruction instr in body.Instructions) { - if (instr.Operand == target) - instr.Operand = newInstr; - else if (instr.Operand is Instruction[]) { - var targets = (Instruction[])instr.Operand; - for (int i = 0; i < targets.Length; i++) - if (targets[i] == target) - targets[i] = newInstr; - } - } - } - - /// - /// Determines whether the specified method is array accessors. - /// - /// The method. - /// true if the specified method is array accessors; otherwise, false. - public static bool IsArrayAccessors(this IMethod method) { - var declType = method.DeclaringType.ToTypeSig(); - if (declType is GenericInstSig) - declType = ((GenericInstSig)declType).GenericType; - - if (declType.IsArray) { - return method.Name == "Get" || method.Name == "Set" || method.Name == "Address"; - } - return false; - } - } - - - /// - /// wrapper of . - /// - public class ImageStream : Stream { - /// - /// Initializes a new instance of the class. - /// - /// The base stream. - public ImageStream(IImageStream baseStream) { - BaseStream = baseStream; - } - - /// - /// Gets the base stream of this instance. - /// - /// The base stream. - public IImageStream BaseStream { get; private set; } - - /// - public override bool CanRead { - get { return true; } - } - - /// - public override bool CanSeek { - get { return true; } - } - - /// - public override bool CanWrite { - get { return false; } - } - - /// - public override long Length { - get { return BaseStream.Length; } - } - - /// - public override long Position { - get { return BaseStream.Position; } - set { BaseStream.Position = value; } - } - - /// - public override void Flush() { } - - /// - public override int Read(byte[] buffer, int offset, int count) { - return BaseStream.Read(buffer, offset, count); - } - - /// - public override long Seek(long offset, SeekOrigin origin) { - switch (origin) { - case SeekOrigin.Begin: - BaseStream.Position = offset; - break; - case SeekOrigin.Current: - BaseStream.Position += offset; - break; - case SeekOrigin.End: - BaseStream.Position = BaseStream.Length + offset; - break; - } - return BaseStream.Position; - } - - /// - public override void SetLength(long value) { - throw new NotSupportedException(); - } - - /// - public override void Write(byte[] buffer, int offset, int count) { - throw new NotSupportedException(); - } - } +namespace Confuser.Core +{ + /// + /// Provides a set of utility methods about dnlib + /// + public static class DnlibUtils + { + /// + /// Finds all definitions of interest in a module. + /// + /// The module. + /// A collection of all required definitions + public static IEnumerable FindDefinitions(this ModuleDef module) + { + yield return module; + foreach (TypeDef type in module.GetTypes()) + { + yield return type; + + foreach (MethodDef method in type.Methods) + yield return method; + + foreach (FieldDef field in type.Fields) + yield return field; + + foreach (PropertyDef prop in type.Properties) + yield return prop; + + foreach (EventDef evt in type.Events) + yield return evt; + } + } + + /// + /// Finds all definitions of interest in a type. + /// + /// The type. + /// A collection of all required definitions + public static IEnumerable FindDefinitions(this TypeDef typeDef) + { + yield return typeDef; + + foreach (TypeDef nestedType in typeDef.NestedTypes) + yield return nestedType; + + foreach (MethodDef method in typeDef.Methods) + yield return method; + + foreach (FieldDef field in typeDef.Fields) + yield return field; + + foreach (PropertyDef prop in typeDef.Properties) + yield return prop; + + foreach (EventDef evt in typeDef.Events) + yield return evt; + } + + /// + /// Determines whether the specified type is visible outside the containing assembly. + /// + /// The type. + /// Visibility of executable modules. + /// true if the specified type is visible outside the containing assembly; otherwise, false. + public static bool IsVisibleOutside(this TypeDef typeDef, bool exeNonPublic = true) + { + // Assume executable modules' type is not visible + if (exeNonPublic && (typeDef.Module.Kind == ModuleKind.Windows || typeDef.Module.Kind == ModuleKind.Console)) + return false; + + do + { + if (typeDef.DeclaringType == null) + return typeDef.IsPublic; + if (!typeDef.IsNestedPublic && !typeDef.IsNestedFamily && !typeDef.IsNestedFamilyOrAssembly) + return false; + typeDef = typeDef.DeclaringType; + } while (typeDef != null); + + throw new UnreachableException(); + } + + /// + /// Determines whether the object has the specified custom attribute. + /// + /// The object. + /// The full name of the type of custom attribute. + /// true if the specified object has custom attribute; otherwise, false. + public static bool HasAttribute(this IHasCustomAttribute obj, string fullName) + { + return obj.CustomAttributes.Any(attr => attr.TypeFullName == fullName); + } + + /// + /// Determines whether the specified type is COM import. + /// + /// The type. + /// true if specified type is COM import; otherwise, false. + public static bool IsComImport(this TypeDef type) + { + return type.IsImport || + type.HasAttribute("System.Runtime.InteropServices.ComImportAttribute") || + type.HasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute"); + } + + /// + /// Determines whether the specified type is compiler generated. + /// + /// The type. + /// true if specified type is compiler generated; otherwise, false. + public static bool IsCompilerGenerated(this TypeDef type) + { + return type.HasAttribute("System.Runtime.CompilerServices.CompilerGeneratedAttribute"); + } + + /// + /// Determines whether the specified type is a delegate. + /// + /// The type. + /// true if the specified type is a delegate; otherwise, false. + public static bool IsDelegate(this TypeDef type) + { + if (type.BaseType == null) + return false; + + string fullName = type.BaseType.FullName; + return fullName == "System.Delegate" || fullName == "System.MulticastDelegate"; + } + + /// + /// Determines whether the specified type is inherited from a base type in corlib. + /// + /// The type. + /// The full name of base type. + /// true if the specified type is inherited from a base type; otherwise, false. + public static bool InheritsFromCorlib(this TypeDef type, string baseType) + { + if (type.BaseType == null) + return false; + + TypeDef bas = type; + do + { + bas = bas.BaseType.ResolveTypeDefThrow(); + if (bas.ReflectionFullName == baseType) + return true; + } while (bas.BaseType != null && bas.BaseType.DefinitionAssembly.IsCorLib()); + return false; + } + + /// + /// Determines whether the specified type is inherited from a base type. + /// + /// The type. + /// The full name of base type. + /// true if the specified type is inherited from a base type; otherwise, false. + public static bool InheritsFrom(this TypeDef type, string baseType) + { + if (type.BaseType == null) + return false; + + TypeDef bas = type; + do + { + bas = bas.BaseType.ResolveTypeDefThrow(); + if (bas.ReflectionFullName == baseType) + return true; + } while (bas.BaseType != null); + return false; + } + + /// + /// Determines whether the specified type implements the specified interface. + /// + /// The type. + /// The full name of the type of interface. + /// true if the specified type implements the interface; otherwise, false. + public static bool Implements(this TypeDef type, string fullName) + { + do + { + foreach (InterfaceImpl iface in type.Interfaces) + { + if (iface.Interface.ReflectionFullName == fullName) + return true; + } + + if (type.BaseType == null) + return false; + + type = type.BaseType.ResolveTypeDefThrow(); + } while (type != null); + throw new UnreachableException(); + } + + /// + /// Resolves the method. + /// + /// The method to resolve. + /// A instance. + /// The method couldn't be resolved. + public static MethodDef ResolveThrow(this IMethod method) + { + var def = method as MethodDef; + if (def != null) + return def; + + var spec = method as MethodSpec; + if (spec != null) + return spec.Method.ResolveThrow(); + + return ((MemberRef)method).ResolveMethodThrow(); + } + + /// + /// Resolves the field. + /// + /// The field to resolve. + /// A instance. + /// The method couldn't be resolved. + public static FieldDef ResolveThrow(this IField field) + { + var def = field as FieldDef; + if (def != null) + return def; + + return ((MemberRef)field).ResolveFieldThrow(); + } + + /// + /// Find the basic type reference. + /// + /// The type signature to get the basic type. + /// A instance, or null if the typeSig cannot be resolved to basic type. + public static ITypeDefOrRef ToBasicTypeDefOrRef(this TypeSig typeSig) + { + while (typeSig.Next != null) + typeSig = typeSig.Next; + + if (typeSig is GenericInstSig) + return ((GenericInstSig)typeSig).GenericType.TypeDefOrRef; + if (typeSig is TypeDefOrRefSig) + return ((TypeDefOrRefSig)typeSig).TypeDefOrRef; + return null; + } + + /// + /// Find the type references within the specified type signature. + /// + /// The type signature to find the type references. + /// A list of instance. + public static IList FindTypeRefs(this TypeSig typeSig) + { + var ret = new List(); + FindTypeRefsInternal(typeSig, ret); + return ret; + } + + static void FindTypeRefsInternal(TypeSig typeSig, IList ret) + { + while (typeSig.Next != null) + { + if (typeSig is ModifierSig) + ret.Add(((ModifierSig)typeSig).Modifier); + typeSig = typeSig.Next; + } + + if (typeSig is GenericInstSig) + { + var genInst = (GenericInstSig)typeSig; + ret.Add(genInst.GenericType.TypeDefOrRef); + foreach (TypeSig genArg in genInst.GenericArguments) + FindTypeRefsInternal(genArg, ret); + } + else if (typeSig is TypeDefOrRefSig) + { + var type = ((TypeDefOrRefSig)typeSig).TypeDefOrRef; + while (type != null) + { + ret.Add(type); + type = type.DeclaringType; + } + } + } + + /// + /// Determines whether the specified property is public. + /// + /// The property. + /// true if the specified property is public; otherwise, false. + public static bool IsPublic(this PropertyDef property) + { + return property.AllMethods().Any(method => method.IsPublic); + } + + /// + /// Determines whether the specified property is static. + /// + /// The property. + /// true if the specified property is static; otherwise, false. + public static bool IsStatic(this PropertyDef property) + { + return property.AllMethods().Any(method => method.IsStatic); + } + + /// + /// Determines whether the specified event is public. + /// + /// The event. + /// true if the specified event is public; otherwise, false. + public static bool IsPublic(this EventDef evt) + { + return evt.AllMethods().Any(method => method.IsPublic); + } + + /// + /// Determines whether the specified event is static. + /// + /// The event. + /// true if the specified event is static; otherwise, false. + public static bool IsStatic(this EventDef evt) + { + return evt.AllMethods().Any(method => method.IsStatic); + } + + /// + /// Determines whether the specified method is an explictly implemented interface member. + /// + /// The method. + /// true if the specified method is an explictly implemented interface member; otherwise, false. + public static bool IsExplicitlyImplementedInterfaceMember(this MethodDef method) + { + return method.IsFinal && method.IsPrivate; + } + + /// + /// Determines whether the specified property is an explictly implemented interface member. + /// + /// The method. + /// true if the specified property is an explictly implemented interface member; otherwise, false. + public static bool IsExplicitlyImplementedInterfaceMember(this PropertyDef property) + { + return property.AllMethods().Any(IsExplicitlyImplementedInterfaceMember); + } + + /// + /// Determines whether the specified event is an explictly implemented interface member. + /// + /// The event. + /// true if the specified eve is an explictly implemented interface member; otherwise, false. + public static bool IsExplicitlyImplementedInterfaceMember(this EventDef evt) + { + return evt.AllMethods().Any(IsExplicitlyImplementedInterfaceMember); + } + + private static IEnumerable AllMethods(this EventDef evt) + { + return new[] { evt.AddMethod, evt.RemoveMethod, evt.InvokeMethod } + .Concat(evt.OtherMethods) + .Where(m => m != null); + } + + private static IEnumerable AllMethods(this PropertyDef property) + { + return new[] { property.GetMethod, property.SetMethod } + .Concat(property.OtherMethods) + .Where(m => m != null); + } + + /// + /// Replaces the specified instruction reference with another instruction. + /// + /// The method body. + /// The instruction to replace. + /// The new instruction. + public static void ReplaceReference(this CilBody body, Instruction target, Instruction newInstr) + { + foreach (ExceptionHandler eh in body.ExceptionHandlers) + { + if (eh.TryStart == target) + eh.TryStart = newInstr; + if (eh.TryEnd == target) + eh.TryEnd = newInstr; + if (eh.HandlerStart == target) + eh.HandlerStart = newInstr; + if (eh.HandlerEnd == target) + eh.HandlerEnd = newInstr; + } + foreach (Instruction instr in body.Instructions) + { + if (instr.Operand == target) + instr.Operand = newInstr; + else if (instr.Operand is Instruction[]) + { + var targets = (Instruction[])instr.Operand; + for (int i = 0; i < targets.Length; i++) + if (targets[i] == target) + targets[i] = newInstr; + } + } + } + + /// + /// Determines whether the specified method is array accessors. + /// + /// The method. + /// true if the specified method is array accessors; otherwise, false. + public static bool IsArrayAccessors(this IMethod method) + { + var declType = method.DeclaringType.ToTypeSig(); + if (declType is GenericInstSig) + declType = ((GenericInstSig)declType).GenericType; + + if (declType.IsArray) + { + return method.Name == "Get" || method.Name == "Set" || method.Name == "Address"; + } + return false; + } + } + + + /// + /// wrapper of . + /// + public class ImageStream : Stream + { + /// + /// Initializes a new instance of the class. + /// + /// The base stream. + public ImageStream(IImageStream baseStream) + { + BaseStream = baseStream; + } + + /// + /// Gets the base stream of this instance. + /// + /// The base stream. + public IImageStream BaseStream { get; private set; } + + /// + public override bool CanRead + { + get { return true; } + } + + /// + public override bool CanSeek + { + get { return true; } + } + + /// + public override bool CanWrite + { + get { return false; } + } + + /// + public override long Length + { + get { return BaseStream.Length; } + } + + /// + public override long Position + { + get { return BaseStream.Position; } + set { BaseStream.Position = value; } + } + + /// + public override void Flush() { } + + /// + public override int Read(byte[] buffer, int offset, int count) + { + return BaseStream.Read(buffer, offset, count); + } + + /// + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + BaseStream.Position = offset; + break; + case SeekOrigin.Current: + BaseStream.Position += offset; + break; + case SeekOrigin.End: + BaseStream.Position = BaseStream.Length + offset; + break; + } + return BaseStream.Position; + } + + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } } \ No newline at end of file