/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System.Collections.Generic; using System.Runtime.InteropServices; using dnlib.DotNet; namespace dnSpy.Contracts.Decompiler { /// /// Custom attributes utils /// public static class CustomAttributesUtils { static bool IsType(TypeDef type, (UTF8String @namespace, UTF8String name)[] typeNames) { if (type.DeclaringType is not null) return false; var name = type.Name; var @namespace = type.Namespace; foreach (var info in typeNames) { if (name == info.name && @namespace == info.@namespace) return true; } return false; } /// /// Checks whether is a pseudo custom attribute type /// /// Type to check /// public static bool IsPseudoCustomAttributeType(TypeDef type) { if (!(type.BaseType is ITypeDefOrRef baseType)) return false; bool canCheck = false; if (baseType.Name == attributeName && baseType.Namespace == systemName) canCheck = true; else if (IsSecurityAttribute(type)) return true; return canCheck && IsType(type, pseudoCANames); } static bool IsSecurityAttribute(TypeDef type) { for (int i = 0; i < 1000; i++) { if (type.Name == securityAttributeName && type.Namespace == systemSecurityPermissionsName) return true; if (!(type.BaseType is ITypeDefOrRef baseType)) break; if (!(baseType.ResolveTypeDef() is TypeDef bt)) break; type = bt; } return false; } /// /// Checks whether is a pseudo custom attribute related type /// /// Type to check /// public static bool IsPseudoCustomAttributeOtherType(TypeDef type) { var nonNestedType = type; while (nonNestedType.DeclaringType is TypeDef declType) nonNestedType = declType; if (nonNestedType.Namespace == systemSecurityPermissionsName && IsPublic(type)) return true; return IsType(type, pseudoCAOtherTypeNames); } static bool IsPublic(TypeDef type) { for (;;) { if (type.DeclaringType is TypeDef declType) { if (!(type.IsNestedFamily || type.IsNestedFamilyOrAssembly || type.IsNestedPublic)) return false; type = declType; } else return type.IsPublic; } } /// /// Gets custom attributes and pseudo custom attributes /// /// Object with custom attributes /// public static IEnumerable GetCustomAttributes(this IHasCustomAttribute hca) { switch (hca) { case AssemblyDef asm: return asm.GetCustomAttributes(); case ModuleDef mod: return mod.GetCustomAttributes(); case TypeDef type: return type.GetCustomAttributes(); case GenericParam gp: return gp.GetCustomAttributes(); case FieldDef field: return field.GetCustomAttributes(); case PropertyDef property: return property.GetCustomAttributes(); case EventDef @event: return @event.GetCustomAttributes(); case MethodDef method: return method.GetCustomAttributes(); case ParamDef parameter: return parameter.GetCustomAttributes(); default: return hca.CustomAttributes; } } /// /// Gets custom attributes and pseudo custom attributes /// /// Generic parameter /// public static IEnumerable GetCustomAttributes(this GenericParam gp) => gp.CustomAttributes; /// /// Gets custom attributes and pseudo custom attributes /// /// Event /// public static IEnumerable GetCustomAttributes(this EventDef @event) => @event.CustomAttributes; static IEnumerable GetSecurityDeclarations(ModuleDef module, IHasDeclSecurity hds) { TypeSig? securityActionType = null; foreach (var ds in hds.DeclSecurities) { if (securityActionType is null) securityActionType = new ValueTypeSig(new TypeRefUser(module, systemSecurityPermissionsName, securityActionName, module.CorLibTypes.AssemblyRef)); foreach (var secAttr in ds.SecurityAttributes) { var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, securityActionType), secAttr.AttributeType)); ca.ConstructorArguments.Add(new CAArgument(securityActionType, (int)ds.Action)); foreach (var namedArg in secAttr.NamedArguments) ca.NamedArguments.Add(namedArg); yield return ca; } } } /// /// Gets custom attributes and pseudo custom attributes /// /// Assembly /// public static IEnumerable GetCustomAttributes(this AssemblyDef assembly) { var module = (ModuleDef?)assembly.ManifestModule; if (module is not null) { if (assembly.HashAlgorithm != AssemblyHashAlgorithm.SHA1) { var declType = new TypeRefUser(module, systemReflectionName, assemblyAlgorithmIdAttributeName, module.CorLibTypes.AssemblyRef); var enumDeclType = new ValueTypeSig(new TypeRefUser(module, systemConfigurationAssembliesName, assemblyHashAlgorithmName, module.CorLibTypes.AssemblyRef)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, enumDeclType), declType)); ca.ConstructorArguments.Add(new CAArgument(enumDeclType, (int)assembly.HashAlgorithm)); yield return ca; } if (!UTF8String.IsNullOrEmpty(assembly.Culture)) { var declType = new TypeRefUser(module, systemReflectionName, assemblyCultureAttributeName, module.CorLibTypes.AssemblyRef); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.String), declType)); ca.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, assembly.Culture)); yield return ca; } var asmAttrs = assembly.Attributes & ~AssemblyAttributes.PublicKey; if (asmAttrs != AssemblyAttributes.None) { var declType = new TypeRefUser(module, systemReflectionName, assemblyFlagsAttributeName, module.CorLibTypes.AssemblyRef); var enumDeclType = new ValueTypeSig(new TypeRefUser(module, systemReflectionName, assemblyNameFlagsName, module.CorLibTypes.AssemblyRef)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, enumDeclType), declType)); ca.ConstructorArguments.Add(new CAArgument(enumDeclType, (int)asmAttrs)); yield return ca; } { var declType = new TypeRefUser(module, systemReflectionName, assemblyVersionAttributeName, module.CorLibTypes.AssemblyRef); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.String), declType)); ca.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, new UTF8String(assembly.Version.ToString()))); yield return ca; } } foreach (var ca in assembly.CustomAttributes) yield return ca; if (module is not null) { foreach (var ca in GetSecurityDeclarations(module, assembly)) yield return ca; } foreach (var asmModule in assembly.Modules) { TypeSig? typeType = null; TypeRefUser? typeForwardedToAttributeType = null; MemberRefUser? ctor = null; foreach (var exportedType in asmModule.ExportedTypes) { if (!exportedType.MovedToAnotherAssembly) continue; if (typeForwardedToAttributeType is null) typeForwardedToAttributeType = new TypeRefUser(asmModule, systemRuntimeCompilerServicesName, typeForwardedToAttributeName, asmModule.CorLibTypes.AssemblyRef); if (typeType is null) typeType = new ClassSig(new TypeRefUser(asmModule, systemName, typeName, asmModule.CorLibTypes.AssemblyRef)); if (ctor is null) ctor = new MemberRefUser(asmModule, ctorName, MethodSig.CreateInstance(asmModule.CorLibTypes.Void, typeType), typeForwardedToAttributeType); var ca = new CustomAttribute(ctor); ca.ConstructorArguments.Add(new CAArgument(typeType, exportedType.ToTypeRef().ToTypeSig())); yield return ca; } } } /// /// Gets custom attributes and pseudo custom attributes /// /// Module /// public static IEnumerable GetCustomAttributes(this ModuleDef module) => module.CustomAttributes; /// /// Gets custom attributes and pseudo custom attributes /// /// Type /// public static IEnumerable GetCustomAttributes(this TypeDef type) { foreach (var ca in type.CustomAttributes) yield return ca; var module = type.Module; foreach (var ca in GetSecurityDeclarations(module, type)) yield return ca; if (type.IsSerializable) { var declType = new TypeRefUser(module, systemName, serializableAttributeName, GetSystemRuntimeSerializationFormattersAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } if (type.IsImport) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, comImportAttributeName, GetSystemRuntimeInteropServicesAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } { var layoutKind = LayoutKind.Auto; switch (type.Layout) { case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break; case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break; } var charSet = CharSet.None; switch (type.StringFormat) { case TypeAttributes.AnsiClass: charSet = CharSet.Ansi; break; case TypeAttributes.AutoClass: charSet = CharSet.Auto; break; case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break; } bool isValueType = type.IsValueType; var defaultLayoutKind = isValueType && !type.IsEnum ? LayoutKind.Sequential : LayoutKind.Auto; if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || ShowClassLayout(type, isValueType)) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, structLayoutAttributeName, module.CorLibTypes.AssemblyRef); var layoutKindType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, layoutKindName, module.CorLibTypes.AssemblyRef)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, layoutKindType), declType)); ca.ConstructorArguments.Add(new CAArgument(layoutKindType, (int)layoutKind)); if (charSet != CharSet.Ansi) { var charSetType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, charSetName, module.CorLibTypes.AssemblyRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, charSetType, charSetName, new CAArgument(charSetType, (int)charSet))); } if (type.PackingSize != ushort.MaxValue && type.PackingSize > 0) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, packName, new CAArgument(module.CorLibTypes.Int32, (int)type.PackingSize))); if (type.ClassSize != uint.MaxValue && type.ClassSize > 0) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, sizeName, new CAArgument(module.CorLibTypes.Int32, (int)type.ClassSize))); yield return ca; } } } static bool ShowClassLayout(TypeDef type, bool isValueType) { if (!isValueType) return type.HasClassLayout; if (type.HasClassLayout) { foreach (var field in type.Fields) { if (!field.IsStatic) return true; } } return false; } /// /// Gets custom attributes and pseudo custom attributes /// /// Field /// public static IEnumerable GetCustomAttributes(this FieldDef field) { foreach (var ca in field.CustomAttributes) yield return ca; var module = field.Module; if (field.IsNotSerialized) { var declType = new TypeRefUser(module, systemName, nonSerializedAttributeName, GetSystemRuntimeSerializationFormattersAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } if (field.FieldOffset != null) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, fieldOffsetAttributeName, module.CorLibTypes.AssemblyRef); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.Int32), declType)); ca.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.Int32, (int)field.FieldOffset.Value)); yield return ca; } if (field.MarshalType is MarshalType mt) yield return CreateMarshalTypeCustomAttribute(module, mt); } /// /// Gets custom attributes and pseudo custom attributes /// /// Method /// public static IEnumerable GetCustomAttributes(this MethodDef method) { foreach (var ca in method.CustomAttributes) yield return ca; var module = method.Module; foreach (var ca in GetSecurityDeclarations(module, method)) yield return ca; var implAttr = method.ImplAttributes & ~MethodImplAttributes.CodeTypeMask; if (method.ImplMap is ImplMap implMap) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, dllImportAttributeName, GetSystemRuntimeInteropServicesAssemblyRef(module)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.String), declType)); ca.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, implMap.Module?.Name ?? UTF8String.Empty)); if (implMap.IsBestFitDisabled) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, bestFitMappingName, new CAArgument(module.CorLibTypes.Boolean, false))); else if (implMap.IsBestFitEnabled) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, bestFitMappingName, new CAArgument(module.CorLibTypes.Boolean, true))); System.Runtime.InteropServices.CallingConvention callingConvention; switch (implMap.CallConv) { case PInvokeAttributes.CallConvCdecl: callingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl; break; case PInvokeAttributes.CallConvFastcall: callingConvention = System.Runtime.InteropServices.CallingConvention.FastCall; break; case PInvokeAttributes.CallConvStdCall: callingConvention = System.Runtime.InteropServices.CallingConvention.StdCall; break; case PInvokeAttributes.CallConvThiscall: callingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall; break; case PInvokeAttributes.CallConvWinapi: callingConvention = System.Runtime.InteropServices.CallingConvention.Winapi; break; default: callingConvention = 0; break; } if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) { var callingConventionType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, callingConventionName, module.CorLibTypes.AssemblyRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, callingConventionType, callingConventionName, new CAArgument(callingConventionType, (int)callingConvention))); } var charSet = CharSet.None; switch (implMap.Attributes & PInvokeAttributes.CharSetMask) { case PInvokeAttributes.CharSetAnsi: charSet = CharSet.Ansi; break; case PInvokeAttributes.CharSetAuto: charSet = CharSet.Auto; break; case PInvokeAttributes.CharSetUnicode: charSet = CharSet.Unicode; break; } if (charSet != CharSet.None) { var charSetType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, charSetName, module.CorLibTypes.AssemblyRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, charSetType, charSetName, new CAArgument(charSetType, (int)charSet))); } if (!UTF8String.IsNullOrEmpty(implMap.Name) && implMap.Name != method.Name) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.String, entryPointName, new CAArgument(module.CorLibTypes.String, implMap.Name))); if (implMap.IsNoMangle) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, exactSpellingName, new CAArgument(module.CorLibTypes.Boolean, true))); if ((implAttr & MethodImplAttributes.PreserveSig) == 0) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, preserveSigName, new CAArgument(module.CorLibTypes.Boolean, false))); implAttr &= ~MethodImplAttributes.PreserveSig; if (implMap.SupportsLastError) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, setLastErrorName, new CAArgument(module.CorLibTypes.Boolean, true))); if (implMap.IsThrowOnUnmappableCharDisabled) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, throwOnUnmappableCharName, new CAArgument(module.CorLibTypes.Boolean, false))); else if (implMap.IsThrowOnUnmappableCharEnabled) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Boolean, throwOnUnmappableCharName, new CAArgument(module.CorLibTypes.Boolean, true))); yield return ca; } if (implAttr == MethodImplAttributes.PreserveSig) { implAttr = 0; var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, preserveSigAttributeName, GetSystemRuntimeInteropServicesAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } if (implAttr != 0) { var declType = new TypeRefUser(module, systemRuntimeCompilerServicesName, methodImplAttributeName, module.CorLibTypes.AssemblyRef); var enumDeclType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeCompilerServicesName, methodImplOptionsName, module.CorLibTypes.AssemblyRef)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, enumDeclType), declType)); ca.ConstructorArguments.Add(new CAArgument(enumDeclType, (int)implAttr)); yield return ca; } } static Parameter? GetParameter(MethodDef method, int sequence) { if (sequence == 0) return method.Parameters.ReturnParameter; int index = method.IsStatic ? -1 : 0; index += sequence; if ((uint)index < (uint)method.Parameters.Count) return method.Parameters[index]; return null; } static bool HasIsReadOnlyAttribute(IHasCustomAttribute hca) => Find(hca, systemRuntimeCompilerServicesName, isReadOnlyAttributeName) is not null; /// /// Gets custom attributes and pseudo custom attributes /// /// Parameter /// public static IEnumerable GetCustomAttributes(this ParamDef parameter) { foreach (var ca in parameter.CustomAttributes) yield return ca; var method = parameter.DeclaringMethod; var module = method.Module; if (parameter.MarshalType is MarshalType mt) yield return CreateMarshalTypeCustomAttribute(module, mt); var p = GetParameter(method, parameter.Sequence); bool isByRefParam = p?.Type.RemovePinnedAndModifiers().GetElementType() == ElementType.ByRef; bool ignoreAttr = isByRefParam && ((!parameter.IsIn && parameter.IsOut)/*out*/ || HasIsReadOnlyAttribute(parameter)/*in*/); if (!ignoreAttr) { if (parameter.IsIn) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, inAttributeName, GetSystemRuntimeInteropServicesAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } if (parameter.IsOut) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, outAttributeName, module.CorLibTypes.AssemblyRef); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } } if (parameter.IsOptional && parameter.Constant == null) { var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, optionalAttributeName, GetSystemRuntimeInteropServicesAssemblyRef(module)); yield return new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); } } static CustomAttribute CreateMarshalTypeCustomAttribute(ModuleDef module, MarshalType mt) { var interopAsmRef = GetSystemRuntimeInteropServicesAssemblyRef(module); var declType = new TypeRefUser(module, systemRuntimeInteropServicesName, marshalAsAttributeName, interopAsmRef); var unmanagedTypeType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, unmanagedTypeName, interopAsmRef)); var ca = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void, unmanagedTypeType), declType)); ca.ConstructorArguments.Add(new CAArgument(unmanagedTypeType, (int)mt.NativeType)); if (mt is FixedArrayMarshalType fami) { if (fami.IsSizeValid) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, sizeConstName, new CAArgument(module.CorLibTypes.Int32, fami.Size))); if (fami.IsElementTypeValid) ca.NamedArguments.Add(new CANamedArgument(isField: true, unmanagedTypeType, arraySubTypeName, new CAArgument(unmanagedTypeType, (int)fami.ElementType))); } if (mt is SafeArrayMarshalType sami) { if (sami.IsVariantTypeValid) { var varEnumType = new ValueTypeSig(new TypeRefUser(module, systemRuntimeInteropServicesName, varEnumName, interopAsmRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, varEnumType, safeArraySubTypeName, new CAArgument(varEnumType, (int)sami.VariantType))); } if (sami.IsUserDefinedSubTypeValid) { var typeType = new ClassSig(new TypeRefUser(module, systemName, typeName, module.CorLibTypes.AssemblyRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, typeType, safeArrayUserDefinedSubTypeName, new CAArgument(typeType, sami.UserDefinedSubType))); } } if (mt is ArrayMarshalType ami) { if (ami.IsElementTypeValid && ami.ElementType != NativeType.Max) ca.NamedArguments.Add(new CANamedArgument(isField: true, unmanagedTypeType, arraySubTypeName, new CAArgument(unmanagedTypeType, (int)ami.ElementType))); if (ami.IsSizeValid) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, sizeConstName, new CAArgument(module.CorLibTypes.Int32, ami.Size))); if (ami.Flags != 0 && ami.ParamNumber >= 0) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int16, sizeParamIndexName, new CAArgument(module.CorLibTypes.Int16, (short)ami.ParamNumber))); } if (mt is CustomMarshalType cmi) { if (cmi.CustomMarshaler != null) { var typeType = new ClassSig(new TypeRefUser(module, systemName, typeName, module.CorLibTypes.AssemblyRef)); ca.NamedArguments.Add(new CANamedArgument(isField: true, typeType, marshalTypeRefName, new CAArgument(typeType, cmi.CustomMarshaler))); } if (!UTF8String.IsNullOrEmpty(cmi.Cookie)) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.String, marshalCookieName, new CAArgument(module.CorLibTypes.String, cmi.Cookie))); } if (mt is FixedSysStringMarshalType fssmi) { if (fssmi.IsSizeValid) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, sizeConstName, new CAArgument(module.CorLibTypes.Int32, fssmi.Size))); } if (mt is InterfaceMarshalType imti) { if (imti.IsIidParamIndexValid) ca.NamedArguments.Add(new CANamedArgument(isField: true, module.CorLibTypes.Int32, iidParameterIndexName, new CAArgument(module.CorLibTypes.Int32, imti.IidParamIndex))); } return ca; } static CustomAttribute? Find(IHasCustomAttribute hca, UTF8String @namespace, UTF8String name) { var cas = hca.CustomAttributes; for (int i = 0; i < cas.Count; i++) { var ca = cas[i]; var type = ca.AttributeType; if (type.Name != name || type.Namespace != @namespace) continue; if (type.DeclaringType is not null) continue; return ca; } return null; } /// /// Gets custom attributes and pseudo custom attributes /// /// Property /// public static IEnumerable GetCustomAttributes(this PropertyDef property) { foreach (var ca in property.CustomAttributes) yield return ca; var defMemCa = Find(property.DeclaringType, systemReflectionName, defaultMemberAttributeName); if (defMemCa is not null && defMemCa.ConstructorArguments.Count > 0 && defMemCa.ConstructorArguments[0].Value is UTF8String defMember && defMember != itemName && defMember == property.Name) { var module = property.Module; var declType = new TypeRefUser(module, systemRuntimeCompilerServicesName, indexerNameAttributeName, module.CorLibTypes.AssemblyRef); var newCa = new CustomAttribute(new MemberRefUser(module, ctorName, MethodSig.CreateInstance(module.CorLibTypes.Void), declType)); newCa.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, defMember)); yield return newCa; } } static IResolutionScope GetSystemRuntimeInteropServicesAssemblyRef(ModuleDef module) { foreach (var asmRef in module.GetAssemblyRefs()) { if (asmRef.Name == systemRuntimeInteropServicesName && contractsPublicKeyToken.Equals(asmRef.PublicKeyOrToken.Token)) return asmRef; } return module.CorLibTypes.AssemblyRef; } static AssemblyRef GetSystemRuntimeSerializationFormattersAssemblyRef(ModuleDef module) { foreach (var asmRef in module.GetAssemblyRefs()) { if (asmRef.Name == systemRuntimeSerializationFormattersName && contractsPublicKeyToken.Equals(asmRef.PublicKeyOrToken.Token)) return asmRef; } return module.CorLibTypes.AssemblyRef; } static readonly UTF8String ctorName = new UTF8String(".ctor"); static readonly UTF8String systemRuntimeInteropServicesName = new UTF8String("System.Runtime.InteropServices"); static readonly UTF8String systemRuntimeSerializationFormattersName = new UTF8String("System.Runtime.Serialization.Formatters"); static readonly UTF8String systemRuntimeCompilerServicesName = new UTF8String("System.Runtime.CompilerServices"); static readonly UTF8String systemName = new UTF8String("System"); static readonly UTF8String systemReflectionName = new UTF8String("System.Reflection"); static readonly UTF8String systemConfigurationAssembliesName = new UTF8String("System.Configuration.Assemblies"); static readonly UTF8String systemSecurityPermissionsName = new UTF8String("System.Security.Permissions"); static readonly UTF8String inAttributeName = new UTF8String("InAttribute"); static readonly UTF8String outAttributeName = new UTF8String("OutAttribute"); static readonly UTF8String optionalAttributeName = new UTF8String("OptionalAttribute"); static readonly UTF8String methodImplAttributeName = new UTF8String("MethodImplAttribute"); static readonly UTF8String methodImplOptionsName = new UTF8String("MethodImplOptions"); static readonly UTF8String preserveSigAttributeName = new UTF8String("PreserveSigAttribute"); static readonly UTF8String nonSerializedAttributeName = new UTF8String("NonSerializedAttribute"); static readonly UTF8String serializableAttributeName = new UTF8String("SerializableAttribute"); static readonly UTF8String comImportAttributeName = new UTF8String("ComImportAttribute"); static readonly UTF8String assemblyAlgorithmIdAttributeName = new UTF8String("AssemblyAlgorithmIdAttribute"); static readonly UTF8String assemblyHashAlgorithmName = new UTF8String("AssemblyHashAlgorithm"); static readonly UTF8String assemblyCultureAttributeName = new UTF8String("AssemblyCultureAttribute"); static readonly UTF8String assemblyFlagsAttributeName = new UTF8String("AssemblyFlagsAttribute"); static readonly UTF8String assemblyNameFlagsName = new UTF8String("AssemblyNameFlags"); static readonly UTF8String assemblyVersionAttributeName = new UTF8String("AssemblyVersionAttribute"); static readonly UTF8String fieldOffsetAttributeName = new UTF8String("FieldOffsetAttribute"); static readonly UTF8String structLayoutAttributeName = new UTF8String("StructLayoutAttribute"); static readonly UTF8String layoutKindName = new UTF8String("LayoutKind"); static readonly UTF8String charSetName = new UTF8String("CharSet"); static readonly UTF8String packName = new UTF8String("Pack"); static readonly UTF8String sizeName = new UTF8String("Size"); static readonly UTF8String dllImportAttributeName = new UTF8String("DllImportAttribute"); static readonly UTF8String bestFitMappingName = new UTF8String("BestFitMapping"); static readonly UTF8String callingConventionName = new UTF8String("CallingConvention"); static readonly UTF8String entryPointName = new UTF8String("EntryPoint"); static readonly UTF8String exactSpellingName = new UTF8String("ExactSpelling"); static readonly UTF8String preserveSigName = new UTF8String("PreserveSig"); static readonly UTF8String setLastErrorName = new UTF8String("SetLastError"); static readonly UTF8String throwOnUnmappableCharName = new UTF8String("ThrowOnUnmappableChar"); static readonly UTF8String attributeName = new UTF8String("Attribute"); static readonly UTF8String marshalAsAttributeName = new UTF8String("MarshalAsAttribute"); static readonly UTF8String unmanagedTypeName = new UTF8String("UnmanagedType"); static readonly UTF8String sizeConstName = new UTF8String("SizeConst"); static readonly UTF8String arraySubTypeName = new UTF8String("ArraySubType"); static readonly UTF8String varEnumName = new UTF8String("VarEnum"); static readonly UTF8String safeArraySubTypeName = new UTF8String("SafeArraySubType"); static readonly UTF8String typeName = new UTF8String("Type"); static readonly UTF8String safeArrayUserDefinedSubTypeName = new UTF8String("SafeArrayUserDefinedSubType"); static readonly UTF8String sizeParamIndexName = new UTF8String("SizeParamIndex"); static readonly UTF8String marshalTypeRefName = new UTF8String("MarshalTypeRef"); static readonly UTF8String marshalCookieName = new UTF8String("MarshalCookie"); static readonly UTF8String iidParameterIndexName = new UTF8String("IidParameterIndex"); static readonly UTF8String typeForwardedToAttributeName = new UTF8String("TypeForwardedToAttribute"); static readonly UTF8String securityActionName = new UTF8String("SecurityAction"); static readonly UTF8String securityAttributeName = new UTF8String("SecurityAttribute"); static readonly UTF8String indexerNameAttributeName = new UTF8String("IndexerNameAttribute"); static readonly UTF8String itemName = new UTF8String("Item"); static readonly UTF8String defaultMemberAttributeName = new UTF8String("DefaultMemberAttribute"); static readonly UTF8String isReadOnlyAttributeName = new UTF8String("IsReadOnlyAttribute"); static readonly PublicKeyToken contractsPublicKeyToken = new PublicKeyToken("b03f5f7f11d50a3a"); static readonly (UTF8String @namespace, UTF8String name)[] pseudoCANames = new (UTF8String, UTF8String)[] { (systemName, nonSerializedAttributeName), (systemName, serializableAttributeName), (systemReflectionName, assemblyAlgorithmIdAttributeName), (systemReflectionName, assemblyCultureAttributeName), (systemReflectionName, assemblyFlagsAttributeName), (systemReflectionName, assemblyVersionAttributeName), (systemRuntimeCompilerServicesName, methodImplAttributeName), (systemRuntimeCompilerServicesName, typeForwardedToAttributeName), (systemRuntimeInteropServicesName, comImportAttributeName), (systemRuntimeInteropServicesName, dllImportAttributeName), (systemRuntimeInteropServicesName, fieldOffsetAttributeName), (systemRuntimeInteropServicesName, inAttributeName), (systemRuntimeInteropServicesName, marshalAsAttributeName), (systemRuntimeInteropServicesName, optionalAttributeName), (systemRuntimeInteropServicesName, outAttributeName), (systemRuntimeInteropServicesName, preserveSigAttributeName), (systemRuntimeInteropServicesName, structLayoutAttributeName), (systemRuntimeCompilerServicesName, indexerNameAttributeName), }; static readonly (UTF8String @namespace, UTF8String name)[] pseudoCAOtherTypeNames = new (UTF8String, UTF8String)[] { (systemConfigurationAssembliesName, assemblyHashAlgorithmName), (systemReflectionName, assemblyNameFlagsName), (systemRuntimeCompilerServicesName, methodImplOptionsName), (systemRuntimeInteropServicesName, callingConventionName), (systemRuntimeInteropServicesName, charSetName), (systemRuntimeInteropServicesName, layoutKindName), (systemRuntimeInteropServicesName, unmanagedTypeName), (systemRuntimeInteropServicesName, varEnumName), (systemName, typeName), }; } }