// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.IO; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Security; using System.Threading; using dnlib.PE; using dnlib.Utils; using dnlib.IO; using dnlib.DotNet.MD; using dnlib.DotNet.Emit; using dnlib.DotNet.Pdb; using dnlib.W32Resources; using DNW = dnlib.DotNet.Writer; using dnlib.DotNet.Pdb.Symbols; using System.Runtime.CompilerServices; namespace dnlib.DotNet { /// /// Created from a row in the Module table /// public sealed class ModuleDefMD : ModuleDefMD2, IInstructionOperandResolver { /// The file that contains all .NET metadata MetadataBase metadata; IMethodDecrypter methodDecrypter; IStringDecrypter stringDecrypter; StrongBox moduleRidList; SimpleLazyList listModuleDefMD; SimpleLazyList listTypeRefMD; SimpleLazyList listTypeDefMD; SimpleLazyList listFieldDefMD; SimpleLazyList listMethodDefMD; SimpleLazyList listParamDefMD; SimpleLazyList2 listInterfaceImplMD; SimpleLazyList2 listMemberRefMD; SimpleLazyList listConstantMD; SimpleLazyList listDeclSecurityMD; SimpleLazyList listClassLayoutMD; SimpleLazyList2 listStandAloneSigMD; SimpleLazyList listEventDefMD; SimpleLazyList listPropertyDefMD; SimpleLazyList listModuleRefMD; SimpleLazyList2 listTypeSpecMD; SimpleLazyList listImplMapMD; SimpleLazyList listAssemblyDefMD; SimpleLazyList listAssemblyRefMD; SimpleLazyList listFileDefMD; SimpleLazyList listExportedTypeMD; SimpleLazyList listManifestResourceMD; SimpleLazyList listGenericParamMD; SimpleLazyList2 listMethodSpecMD; SimpleLazyList2 listGenericParamConstraintMD; /// /// Gets/sets the method decrypter /// public IMethodDecrypter MethodDecrypter { get => methodDecrypter; set => methodDecrypter = value; } /// /// Gets/sets the string decrypter /// public IStringDecrypter StringDecrypter { get => stringDecrypter; set => stringDecrypter = value; } /// /// Returns the .NET metadata interface /// public Metadata Metadata => metadata; /// /// Returns the #~ or #- tables stream /// public TablesStream TablesStream => metadata.TablesStream; /// /// Returns the #Strings stream /// public StringsStream StringsStream => metadata.StringsStream; /// /// Returns the #Blob stream /// public BlobStream BlobStream => metadata.BlobStream; /// /// Returns the #GUID stream /// public GuidStream GuidStream => metadata.GuidStream; /// /// Returns the #US stream /// public USStream USStream => metadata.USStream; /// protected override void InitializeTypes() { var list = Metadata.GetNonNestedClassRidList(); var tmp = new LazyList(list.Count, this, list, (list2, index) => ResolveTypeDef(list2[index])); Interlocked.CompareExchange(ref types, tmp, null); } /// protected override void InitializeExportedTypes() { var list = Metadata.GetExportedTypeRidList(); var tmp = new LazyList(list.Count, list, (list2, i) => ResolveExportedType(list2[i])); Interlocked.CompareExchange(ref exportedTypes, tmp, null); } /// protected override void InitializeResources() { var table = TablesStream.ManifestResourceTable; var tmp = new ResourceCollection((int)table.Rows, null, (ctx, i) => CreateResource((uint)i + 1)); Interlocked.CompareExchange(ref resources, tmp, null); } /// protected override Win32Resources GetWin32Resources_NoLock() => metadata.PEImage.Win32Resources; /// protected override VTableFixups GetVTableFixups_NoLock() { var vtableFixupsInfo = metadata.ImageCor20Header.VTableFixups; if (vtableFixupsInfo.VirtualAddress == 0 || vtableFixupsInfo.Size == 0) return null; return new VTableFixups(this); } /// /// Creates a instance from a file /// /// File name of an existing .NET module/assembly /// Module context or null /// A new instance public static ModuleDefMD Load(string fileName, ModuleContext context) => Load(fileName, new ModuleCreationOptions(context)); /// /// Creates a instance from a file /// /// File name of an existing .NET module/assembly /// Module creation options or null /// A new instance public static ModuleDefMD Load(string fileName, ModuleCreationOptions options = null) => Load(MetadataFactory.Load(fileName, options?.Runtime ?? CLRRuntimeReaderKind.CLR), options); /// /// Creates a instance from a byte[] /// /// Contents of a .NET module/assembly /// Module context or null /// A new instance public static ModuleDefMD Load(byte[] data, ModuleContext context) => Load(data, new ModuleCreationOptions(context)); /// /// Creates a instance from a byte[] /// /// Contents of a .NET module/assembly /// Module creation options or null /// A new instance public static ModuleDefMD Load(byte[] data, ModuleCreationOptions options = null) => Load(MetadataFactory.Load(data, options?.Runtime ?? CLRRuntimeReaderKind.CLR), options); /// /// Creates a instance from a reflection module /// /// An existing reflection module /// A new instance public static ModuleDefMD Load(System.Reflection.Module mod) => Load(mod, (ModuleCreationOptions)null, GetImageLayout(mod)); /// /// Creates a instance from a reflection module /// /// An existing reflection module /// Module context or null /// A new instance public static ModuleDefMD Load(System.Reflection.Module mod, ModuleContext context) => Load(mod, new ModuleCreationOptions(context), GetImageLayout(mod)); /// /// Creates a instance from a reflection module /// /// An existing reflection module /// Module creation options or null /// A new instance public static ModuleDefMD Load(System.Reflection.Module mod, ModuleCreationOptions options) => Load(mod, options, GetImageLayout(mod)); static ImageLayout GetImageLayout(System.Reflection.Module mod) { var fqn = mod.FullyQualifiedName; if (fqn.Length > 0 && fqn[0] == '<' && fqn[fqn.Length - 1] == '>') return ImageLayout.File; return ImageLayout.Memory; } /// /// Creates a instance from a reflection module /// /// An existing reflection module /// Module context or null /// Image layout of the module in memory /// A new instance public static ModuleDefMD Load(System.Reflection.Module mod, ModuleContext context, ImageLayout imageLayout) => Load(mod, new ModuleCreationOptions(context), imageLayout); static IntPtr GetModuleHandle(System.Reflection.Module mod) { #if NETSTANDARD var GetHINSTANCE = typeof(Marshal).GetMethod("GetHINSTANCE", new[] { typeof(System.Reflection.Module) }); if (GetHINSTANCE is null) return IntPtr.Zero; return (IntPtr)GetHINSTANCE.Invoke(null, new[] { mod }); #else return Marshal.GetHINSTANCE(mod); #endif } /// /// Creates a instance from a reflection module /// /// An existing reflection module /// Module creation options or null /// Image layout of the module in memory /// A new instance public static ModuleDefMD Load(System.Reflection.Module mod, ModuleCreationOptions options, ImageLayout imageLayout) { var addr = GetModuleHandle(mod); if (addr != IntPtr.Zero && addr != new IntPtr(-1)) return Load(addr, options, imageLayout); var location = mod.FullyQualifiedName; if (string.IsNullOrEmpty(location) || location[0] == '<') throw new InvalidOperationException($"Module {mod} has no HINSTANCE"); return Load(location, options); } /// /// Creates a instance from a memory location /// /// Address of a .NET module/assembly /// A new instance public static ModuleDefMD Load(IntPtr addr) => Load(MetadataFactory.Load(addr, CLRRuntimeReaderKind.CLR), (ModuleCreationOptions)null); /// /// Creates a instance from a memory location /// /// Address of a .NET module/assembly /// Module context or null /// A new instance public static ModuleDefMD Load(IntPtr addr, ModuleContext context) => Load(MetadataFactory.Load(addr, CLRRuntimeReaderKind.CLR), new ModuleCreationOptions(context)); /// /// Creates a instance from a memory location /// /// Address of a .NET module/assembly /// Module creation options or null /// A new instance public static ModuleDefMD Load(IntPtr addr, ModuleCreationOptions options) => Load(MetadataFactory.Load(addr, options?.Runtime ?? CLRRuntimeReaderKind.CLR), options); /// /// Creates a instance /// /// PE image /// A new instance public static ModuleDefMD Load(IPEImage peImage) => Load(MetadataFactory.Load(peImage, CLRRuntimeReaderKind.CLR), (ModuleCreationOptions)null); /// /// Creates a instance /// /// PE image /// Module context or null /// A new instance public static ModuleDefMD Load(IPEImage peImage, ModuleContext context) => Load(MetadataFactory.Load(peImage, CLRRuntimeReaderKind.CLR), new ModuleCreationOptions(context)); /// /// Creates a instance /// /// PE image /// Module creation options or null /// A new instance public static ModuleDefMD Load(IPEImage peImage, ModuleCreationOptions options) => Load(MetadataFactory.Load(peImage, options?.Runtime ?? CLRRuntimeReaderKind.CLR), options); /// /// Creates a instance from a memory location /// /// Address of a .NET module/assembly /// Module context or null /// Image layout of the file in memory /// A new instance public static ModuleDefMD Load(IntPtr addr, ModuleContext context, ImageLayout imageLayout) => Load(MetadataFactory.Load(addr, imageLayout, CLRRuntimeReaderKind.CLR), new ModuleCreationOptions(context)); /// /// Creates a instance from a memory location /// /// Address of a .NET module/assembly /// Module creation options or null /// Image layout of the file in memory /// A new instance public static ModuleDefMD Load(IntPtr addr, ModuleCreationOptions options, ImageLayout imageLayout) => Load(MetadataFactory.Load(addr, imageLayout, options?.Runtime ?? CLRRuntimeReaderKind.CLR), options); /// /// Creates a instance from a stream /// /// This will read all bytes from the stream and call . /// It's better to use one of the other Load() methods. /// The stream (owned by caller) /// A new instance /// If is null public static ModuleDefMD Load(Stream stream) => Load(stream, (ModuleCreationOptions)null); /// /// Creates a instance from a stream /// /// This will read all bytes from the stream and call . /// It's better to use one of the other Load() methods. /// The stream (owned by caller) /// Module context or null /// A new instance /// If is null public static ModuleDefMD Load(Stream stream, ModuleContext context) => Load(stream, new ModuleCreationOptions(context)); /// /// Creates a instance from a stream /// /// This will read all bytes from the stream and call . /// It's better to use one of the other Load() methods. /// The stream (owned by caller) /// Module creation options or null /// A new instance /// If is null public static ModuleDefMD Load(Stream stream, ModuleCreationOptions options) { if (stream is null) throw new ArgumentNullException(nameof(stream)); if (stream.Length > int.MaxValue) throw new ArgumentException("Stream is too big"); var data = new byte[(int)stream.Length]; stream.Position = 0; if (stream.Read(data, 0, data.Length) != data.Length) throw new IOException("Could not read all bytes from the stream"); return Load(data, options); } /// /// Creates a instance from a /// /// The metadata /// Module creation options or null /// A new instance that now owns internal static ModuleDefMD Load(MetadataBase metadata, ModuleCreationOptions options) => new ModuleDefMD(metadata, options); /// /// Constructor /// /// The metadata /// Module creation options or null /// If is null ModuleDefMD(MetadataBase metadata, ModuleCreationOptions options) : base(null, 1) { #if DEBUG if (metadata is null) throw new ArgumentNullException(nameof(metadata)); #endif if (options is null) options = ModuleCreationOptions.Default; this.metadata = metadata; context = options.Context; Initialize(); InitializeFromRawRow(); location = metadata.PEImage.Filename ?? string.Empty; Kind = GetKind(); Characteristics = Metadata.PEImage.ImageNTHeaders.FileHeader.Characteristics; DllCharacteristics = Metadata.PEImage.ImageNTHeaders.OptionalHeader.DllCharacteristics; RuntimeVersion = Metadata.VersionString; Machine = Metadata.PEImage.ImageNTHeaders.FileHeader.Machine; Cor20HeaderFlags = Metadata.ImageCor20Header.Flags; Cor20HeaderRuntimeVersion = (uint)(Metadata.ImageCor20Header.MajorRuntimeVersion << 16) | Metadata.ImageCor20Header.MinorRuntimeVersion; TablesHeaderVersion = Metadata.TablesStream.Version; corLibTypes = new CorLibTypes(this, options.CorLibAssemblyRef ?? FindCorLibAssemblyRef() ?? CreateDefaultCorLibAssemblyRef()); InitializePdb(options); } void InitializePdb(ModuleCreationOptions options) { if (options is null) return; LoadPdb(CreateSymbolReader(options)); } SymbolReader CreateSymbolReader(ModuleCreationOptions options) { if (options.PdbFileOrData is not null) { var pdbFileName = options.PdbFileOrData as string; if (!string.IsNullOrEmpty(pdbFileName)) { var symReader = SymbolReaderFactory.Create(options.PdbOptions, metadata, pdbFileName); if (symReader is not null) return symReader; } if (options.PdbFileOrData is byte[] pdbData) return SymbolReaderFactory.Create(options.PdbOptions, metadata, pdbData); if (options.PdbFileOrData is DataReaderFactory pdbStream) return SymbolReaderFactory.Create(options.PdbOptions, metadata, pdbStream); } if (options.TryToLoadPdbFromDisk) return SymbolReaderFactory.CreateFromAssemblyFile(options.PdbOptions, metadata, location ?? string.Empty); return null; } /// /// Loads symbols using /// /// PDB symbol reader public void LoadPdb(SymbolReader symbolReader) { if (symbolReader is null) return; if (pdbState is not null) throw new InvalidOperationException("PDB file has already been initialized"); var orig = Interlocked.CompareExchange(ref pdbState, new PdbState(symbolReader, this), null); if (orig is not null) throw new InvalidOperationException("PDB file has already been initialized"); } /// /// Loads symbols from a PDB file /// /// PDB file name public void LoadPdb(string pdbFileName) => LoadPdb(ModuleCreationOptions.DefaultPdbReaderOptions, pdbFileName); /// /// Loads symbols from a PDB file /// /// PDB reader options /// PDB file name public void LoadPdb(PdbReaderOptions options, string pdbFileName) => LoadPdb(SymbolReaderFactory.Create(options, metadata, pdbFileName)); /// /// Loads symbols from a byte array /// /// PDB data public void LoadPdb(byte[] pdbData) => LoadPdb(ModuleCreationOptions.DefaultPdbReaderOptions, pdbData); /// /// Loads symbols from a byte array /// /// PDB reader options /// PDB data public void LoadPdb(PdbReaderOptions options, byte[] pdbData) => LoadPdb(SymbolReaderFactory.Create(options, metadata, pdbData)); /// /// Loads symbols from a stream /// /// PDB file stream which is now owned by us public void LoadPdb(DataReaderFactory pdbStream) => LoadPdb(ModuleCreationOptions.DefaultPdbReaderOptions, pdbStream); /// /// Loads symbols from a stream /// /// PDB reader options /// PDB file stream which is now owned by us public void LoadPdb(PdbReaderOptions options, DataReaderFactory pdbStream) => LoadPdb(SymbolReaderFactory.Create(options, metadata, pdbStream)); /// /// Loads symbols if a PDB file is available /// public void LoadPdb() => LoadPdb(ModuleCreationOptions.DefaultPdbReaderOptions); /// /// Loads symbols if a PDB file is available /// /// PDB reader options public void LoadPdb(PdbReaderOptions options) => LoadPdb(SymbolReaderFactory.CreateFromAssemblyFile(options, metadata, location ?? string.Empty)); internal void InitializeCustomDebugInfos(MDToken token, GenericParamContext gpContext, IList result) { var ps = pdbState; if (ps is null) return; ps.InitializeCustomDebugInfos(token, gpContext, result); } ModuleKind GetKind() { if (TablesStream.AssemblyTable.Rows < 1) return ModuleKind.NetModule; var peImage = Metadata.PEImage; if ((peImage.ImageNTHeaders.FileHeader.Characteristics & Characteristics.Dll) != 0) return ModuleKind.Dll; return peImage.ImageNTHeaders.OptionalHeader.Subsystem switch { Subsystem.WindowsCui => ModuleKind.Console, _ => ModuleKind.Windows, }; } void Initialize() { var ts = metadata.TablesStream; listModuleDefMD = new SimpleLazyList(ts.ModuleTable.Rows, rid2 => rid2 == 1 ? this : new ModuleDefMD2(this, rid2)); listTypeRefMD = new SimpleLazyList(ts.TypeRefTable.Rows, rid2 => new TypeRefMD(this, rid2)); listTypeDefMD = new SimpleLazyList(ts.TypeDefTable.Rows, rid2 => new TypeDefMD(this, rid2)); listFieldDefMD = new SimpleLazyList(ts.FieldTable.Rows, rid2 => new FieldDefMD(this, rid2)); listMethodDefMD = new SimpleLazyList(ts.MethodTable.Rows, rid2 => new MethodDefMD(this, rid2)); listParamDefMD = new SimpleLazyList(ts.ParamTable.Rows, rid2 => new ParamDefMD(this, rid2)); listInterfaceImplMD = new SimpleLazyList2(ts.InterfaceImplTable.Rows, (rid2, gpContext) => new InterfaceImplMD(this, rid2, gpContext)); listMemberRefMD = new SimpleLazyList2(ts.MemberRefTable.Rows, (rid2, gpContext) => new MemberRefMD(this, rid2, gpContext)); listConstantMD = new SimpleLazyList(ts.ConstantTable.Rows, rid2 => new ConstantMD(this, rid2)); listDeclSecurityMD = new SimpleLazyList(ts.DeclSecurityTable.Rows, rid2 => new DeclSecurityMD(this, rid2)); listClassLayoutMD = new SimpleLazyList(ts.ClassLayoutTable.Rows, rid2 => new ClassLayoutMD(this, rid2)); listStandAloneSigMD = new SimpleLazyList2(ts.StandAloneSigTable.Rows, (rid2, gpContext) => new StandAloneSigMD(this, rid2, gpContext)); listEventDefMD = new SimpleLazyList(ts.EventTable.Rows, rid2 => new EventDefMD(this, rid2)); listPropertyDefMD = new SimpleLazyList(ts.PropertyTable.Rows, rid2 => new PropertyDefMD(this, rid2)); listModuleRefMD = new SimpleLazyList(ts.ModuleRefTable.Rows, rid2 => new ModuleRefMD(this, rid2)); listTypeSpecMD = new SimpleLazyList2(ts.TypeSpecTable.Rows, (rid2, gpContext) => new TypeSpecMD(this, rid2, gpContext)); listImplMapMD = new SimpleLazyList(ts.ImplMapTable.Rows, rid2 => new ImplMapMD(this, rid2)); listAssemblyDefMD = new SimpleLazyList(ts.AssemblyTable.Rows, rid2 => new AssemblyDefMD(this, rid2)); listFileDefMD = new SimpleLazyList(ts.FileTable.Rows, rid2 => new FileDefMD(this, rid2)); listAssemblyRefMD = new SimpleLazyList(ts.AssemblyRefTable.Rows, rid2 => new AssemblyRefMD(this, rid2)); listExportedTypeMD = new SimpleLazyList(ts.ExportedTypeTable.Rows, rid2 => new ExportedTypeMD(this, rid2)); listManifestResourceMD = new SimpleLazyList(ts.ManifestResourceTable.Rows, rid2 => new ManifestResourceMD(this, rid2)); listGenericParamMD = new SimpleLazyList(ts.GenericParamTable.Rows, rid2 => new GenericParamMD(this, rid2)); listMethodSpecMD = new SimpleLazyList2(ts.MethodSpecTable.Rows, (rid2, gpContext) => new MethodSpecMD(this, rid2, gpContext)); listGenericParamConstraintMD = new SimpleLazyList2(ts.GenericParamConstraintTable.Rows, (rid2, gpContext) => new GenericParamConstraintMD(this, rid2, gpContext)); for (int i = 0; i < 64; i++) { var tbl = TablesStream.Get((Table)i); lastUsedRids[i] = tbl is null ? 0 : (int)tbl.Rows; } } static readonly Dictionary preferredCorLibs = new Dictionary(StringComparer.OrdinalIgnoreCase) { // .NET Framework { "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 100 }, { "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 90 }, { "mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 60 }, { "mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 50 }, // Silverlight { "mscorlib, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", 80 }, { "mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", 70 }, // Zune { "mscorlib, Version=3.5.0.0, Culture=neutral, PublicKeyToken=e92a8b81eba7ceb7", 60 }, // Compact Framework { "mscorlib, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac", 60 }, { "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac", 50 }, }; static readonly string[] corlibs = new string[] { "System.Private.CoreLib", "System.Runtime", "netstandard", "mscorlib", }; /// /// Finds a mscorlib /// /// An existing instance or null if it wasn't found AssemblyRef FindCorLibAssemblyRef() { var numAsmRefs = TablesStream.AssemblyRefTable.Rows; AssemblyRef corLibAsmRef = null; int currentPriority = int.MinValue; for (uint i = 1; i <= numAsmRefs; i++) { var asmRef = ResolveAssemblyRef(i); if (!preferredCorLibs.TryGetValue(asmRef.FullName, out int priority)) continue; if (priority > currentPriority) { currentPriority = priority; corLibAsmRef = asmRef; } } if (corLibAsmRef is not null) return corLibAsmRef; foreach (var corlib in corlibs) { for (uint i = 1; i <= numAsmRefs; i++) { var asmRef = ResolveAssemblyRef(i); if (!UTF8String.ToSystemStringOrEmpty(asmRef.Name).Equals(corlib, StringComparison.OrdinalIgnoreCase)) continue; if (IsGreaterAssemblyRefVersion(corLibAsmRef, asmRef)) corLibAsmRef = asmRef; } if (corLibAsmRef is not null) return corLibAsmRef; } // If we've loaded mscorlib itself, it won't have any AssemblyRefs to itself. var asm = Assembly; if (asm is not null && (asm.IsCorLib() || Find("System.Object", false) is not null)) { IsCoreLibraryModule = true; return UpdateRowId(new AssemblyRefUser(asm)); } return corLibAsmRef; } /// /// Called when no corlib assembly reference was found /// /// AssemblyRef CreateDefaultCorLibAssemblyRef() { var asmRef = GetAlternativeCorLibReference(); if (asmRef is not null) return UpdateRowId(asmRef); if (IsClr40) return UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR40()); if (IsClr20) return UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR20()); if (IsClr11) return UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR11()); if (IsClr10) return UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR10()); return UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR40()); } AssemblyRef GetAlternativeCorLibReference() { foreach (var asmRef in GetAssemblyRefs()) { if (IsAssemblyRef(asmRef, systemRuntimeName, contractsPublicKeyToken)) return asmRef; } foreach (var asmRef in GetAssemblyRefs()) { if (IsAssemblyRef(asmRef, corefxName, contractsPublicKeyToken)) return asmRef; } return null; } static bool IsAssemblyRef(AssemblyRef asmRef, UTF8String name, PublicKeyToken token) { if (asmRef.Name != name) return false; var pkot = asmRef.PublicKeyOrToken; if (pkot is null) return false; return token.Equals(pkot.Token); } static readonly UTF8String systemRuntimeName = new UTF8String("System.Runtime"); static readonly UTF8String corefxName = new UTF8String("corefx"); static readonly PublicKeyToken contractsPublicKeyToken = new PublicKeyToken("b03f5f7f11d50a3a"); /// protected override void Dispose(bool disposing) { // Call base first since it will dispose of all the resources, which will // eventually use metadata that we will dispose base.Dispose(disposing); if (disposing) { var md = metadata; if (md is not null) md.Dispose(); metadata = null; } } /// /// Resolves a token /// /// The metadata token /// Generic parameter context /// A or null if is invalid public override IMDTokenProvider ResolveToken(uint token, GenericParamContext gpContext) { uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Module => ResolveModule(rid), Table.TypeRef => ResolveTypeRef(rid), Table.TypeDef => ResolveTypeDef(rid), Table.Field => ResolveField(rid), Table.Method => ResolveMethod(rid), Table.Param => ResolveParam(rid), Table.InterfaceImpl => ResolveInterfaceImpl(rid, gpContext), Table.MemberRef => ResolveMemberRef(rid, gpContext), Table.Constant => ResolveConstant(rid), Table.DeclSecurity => ResolveDeclSecurity(rid), Table.ClassLayout => ResolveClassLayout(rid), Table.StandAloneSig => ResolveStandAloneSig(rid, gpContext), Table.Event => ResolveEvent(rid), Table.Property => ResolveProperty(rid), Table.ModuleRef => ResolveModuleRef(rid), Table.TypeSpec => ResolveTypeSpec(rid, gpContext), Table.ImplMap => ResolveImplMap(rid), Table.Assembly => ResolveAssembly(rid), Table.AssemblyRef => ResolveAssemblyRef(rid), Table.File => ResolveFile(rid), Table.ExportedType => ResolveExportedType(rid), Table.ManifestResource => ResolveManifestResource(rid), Table.GenericParam => ResolveGenericParam(rid), Table.MethodSpec => ResolveMethodSpec(rid, gpContext), Table.GenericParamConstraint => ResolveGenericParamConstraint(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public ModuleDef ResolveModule(uint rid) => listModuleDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public TypeRef ResolveTypeRef(uint rid) => listTypeRefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public TypeDef ResolveTypeDef(uint rid) => listTypeDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public FieldDef ResolveField(uint rid) => listFieldDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public MethodDef ResolveMethod(uint rid) => listMethodDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public ParamDef ResolveParam(uint rid) => listParamDefMD[rid - 1]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public InterfaceImpl ResolveInterfaceImpl(uint rid) => listInterfaceImplMD[rid - 1, new GenericParamContext()]; /// /// Resolves an /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public InterfaceImpl ResolveInterfaceImpl(uint rid, GenericParamContext gpContext) => listInterfaceImplMD[rid - 1, gpContext]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public MemberRef ResolveMemberRef(uint rid) => listMemberRefMD[rid - 1, new GenericParamContext()]; /// /// Resolves a /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public MemberRef ResolveMemberRef(uint rid, GenericParamContext gpContext) => listMemberRefMD[rid - 1, gpContext]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public Constant ResolveConstant(uint rid) => listConstantMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public DeclSecurity ResolveDeclSecurity(uint rid) => listDeclSecurityMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public ClassLayout ResolveClassLayout(uint rid) => listClassLayoutMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public StandAloneSig ResolveStandAloneSig(uint rid) => listStandAloneSigMD[rid - 1, new GenericParamContext()]; /// /// Resolves a /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public StandAloneSig ResolveStandAloneSig(uint rid, GenericParamContext gpContext) => listStandAloneSigMD[rid - 1, gpContext]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public EventDef ResolveEvent(uint rid) => listEventDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public PropertyDef ResolveProperty(uint rid) => listPropertyDefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public ModuleRef ResolveModuleRef(uint rid) => listModuleRefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public TypeSpec ResolveTypeSpec(uint rid) => listTypeSpecMD[rid - 1, new GenericParamContext()]; /// /// Resolves a /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public TypeSpec ResolveTypeSpec(uint rid, GenericParamContext gpContext) => listTypeSpecMD[rid - 1, gpContext]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public ImplMap ResolveImplMap(uint rid) => listImplMapMD[rid - 1]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public AssemblyDef ResolveAssembly(uint rid) => listAssemblyDefMD[rid - 1]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public AssemblyRef ResolveAssemblyRef(uint rid) => listAssemblyRefMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public FileDef ResolveFile(uint rid) => listFileDefMD[rid - 1]; /// /// Resolves an /// /// The row ID /// A instance or null if is invalid public ExportedType ResolveExportedType(uint rid) => listExportedTypeMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public ManifestResource ResolveManifestResource(uint rid) => listManifestResourceMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public GenericParam ResolveGenericParam(uint rid) => listGenericParamMD[rid - 1]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public MethodSpec ResolveMethodSpec(uint rid) => listMethodSpecMD[rid - 1, new GenericParamContext()]; /// /// Resolves a /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public MethodSpec ResolveMethodSpec(uint rid, GenericParamContext gpContext) => listMethodSpecMD[rid - 1, gpContext]; /// /// Resolves a /// /// The row ID /// A instance or null if is invalid public GenericParamConstraint ResolveGenericParamConstraint(uint rid) => listGenericParamConstraintMD[rid - 1, new GenericParamContext()]; /// /// Resolves a /// /// The row ID /// Generic parameter context /// A instance or null if is invalid public GenericParamConstraint ResolveGenericParamConstraint(uint rid, GenericParamContext gpContext) => listGenericParamConstraintMD[rid - 1, gpContext]; /// /// Resolves a /// /// A TypeDefOrRef coded token /// A or null if is invalid public ITypeDefOrRef ResolveTypeDefOrRef(uint codedToken) => ResolveTypeDefOrRef(codedToken, new GenericParamContext()); /// /// Resolves a /// /// A TypeDefOrRef coded token /// Generic parameter context /// A or null if is invalid public ITypeDefOrRef ResolveTypeDefOrRef(uint codedToken, GenericParamContext gpContext) { if (!CodedToken.TypeDefOrRef.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.TypeDef => ResolveTypeDef(rid), Table.TypeRef => ResolveTypeRef(rid), Table.TypeSpec => ResolveTypeSpec(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// A HasConstant coded token /// A or null if is invalid public IHasConstant ResolveHasConstant(uint codedToken) { if (!CodedToken.HasConstant.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Field => ResolveField(rid), Table.Param => ResolveParam(rid), Table.Property => ResolveProperty(rid), _ => null, }; } /// /// Resolves a /// /// A HasCustomAttribute coded token /// A or null if is invalid public IHasCustomAttribute ResolveHasCustomAttribute(uint codedToken) => ResolveHasCustomAttribute(codedToken, new GenericParamContext()); /// /// Resolves a /// /// A HasCustomAttribute coded token /// Generic parameter context /// A or null if is invalid public IHasCustomAttribute ResolveHasCustomAttribute(uint codedToken, GenericParamContext gpContext) { if (!CodedToken.HasCustomAttribute.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Method => ResolveMethod(rid), Table.Field => ResolveField(rid), Table.TypeRef => ResolveTypeRef(rid), Table.TypeDef => ResolveTypeDef(rid), Table.Param => ResolveParam(rid), Table.InterfaceImpl => ResolveInterfaceImpl(rid, gpContext), Table.MemberRef => ResolveMemberRef(rid, gpContext), Table.Module => ResolveModule(rid), Table.DeclSecurity => ResolveDeclSecurity(rid), Table.Property => ResolveProperty(rid), Table.Event => ResolveEvent(rid), Table.StandAloneSig => ResolveStandAloneSig(rid, gpContext), Table.ModuleRef => ResolveModuleRef(rid), Table.TypeSpec => ResolveTypeSpec(rid, gpContext), Table.Assembly => ResolveAssembly(rid), Table.AssemblyRef => ResolveAssemblyRef(rid), Table.File => ResolveFile(rid), Table.ExportedType => ResolveExportedType(rid), Table.ManifestResource => ResolveManifestResource(rid), Table.GenericParam => ResolveGenericParam(rid), Table.MethodSpec => ResolveMethodSpec(rid, gpContext), Table.GenericParamConstraint => ResolveGenericParamConstraint(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// A HasFieldMarshal coded token /// A or null if is invalid public IHasFieldMarshal ResolveHasFieldMarshal(uint codedToken) { if (!CodedToken.HasFieldMarshal.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Field => ResolveField(rid), Table.Param => ResolveParam(rid), _ => null, }; } /// /// Resolves a /// /// A HasDeclSecurity coded token /// A or null if is invalid public IHasDeclSecurity ResolveHasDeclSecurity(uint codedToken) { if (!CodedToken.HasDeclSecurity.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.TypeDef => ResolveTypeDef(rid), Table.Method => ResolveMethod(rid), Table.Assembly => ResolveAssembly(rid), _ => null, }; } /// /// Resolves a /// /// A MemberRefParent coded token /// A or null if is invalid public IMemberRefParent ResolveMemberRefParent(uint codedToken) => ResolveMemberRefParent(codedToken, new GenericParamContext()); /// /// Resolves a /// /// A MemberRefParent coded token /// Generic parameter context /// A or null if is invalid public IMemberRefParent ResolveMemberRefParent(uint codedToken, GenericParamContext gpContext) { if (!CodedToken.MemberRefParent.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.TypeDef => ResolveTypeDef(rid), Table.TypeRef => ResolveTypeRef(rid), Table.ModuleRef => ResolveModuleRef(rid), Table.Method => ResolveMethod(rid), Table.TypeSpec => ResolveTypeSpec(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// A HasSemantic coded token /// A or null if is invalid public IHasSemantic ResolveHasSemantic(uint codedToken) { if (!CodedToken.HasSemantic.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Event => ResolveEvent(rid), Table.Property => ResolveProperty(rid), _ => null, }; } /// /// Resolves a /// /// A MethodDefOrRef coded token /// A or null if is invalid public IMethodDefOrRef ResolveMethodDefOrRef(uint codedToken) => ResolveMethodDefOrRef(codedToken, new GenericParamContext()); /// /// Resolves a /// /// A MethodDefOrRef coded token /// Generic parameter context /// A or null if is invalid public IMethodDefOrRef ResolveMethodDefOrRef(uint codedToken, GenericParamContext gpContext) { if (!CodedToken.MethodDefOrRef.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Method => ResolveMethod(rid), Table.MemberRef => ResolveMemberRef(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// A MemberForwarded coded token /// A or null if is invalid public IMemberForwarded ResolveMemberForwarded(uint codedToken) { if (!CodedToken.MemberForwarded.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Field => ResolveField(rid), Table.Method => ResolveMethod(rid), _ => null, }; } /// /// Resolves an /// /// An Implementation coded token /// A or null if is invalid public IImplementation ResolveImplementation(uint codedToken) { if (!CodedToken.Implementation.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.File => ResolveFile(rid), Table.AssemblyRef => ResolveAssemblyRef(rid), Table.ExportedType => ResolveExportedType(rid), _ => null, }; } /// /// Resolves a /// /// A CustomAttributeType coded token /// A or null if is invalid public ICustomAttributeType ResolveCustomAttributeType(uint codedToken) => ResolveCustomAttributeType(codedToken, new GenericParamContext()); /// /// Resolves a /// /// A CustomAttributeType coded token /// Generic parameter context /// A or null if is invalid public ICustomAttributeType ResolveCustomAttributeType(uint codedToken, GenericParamContext gpContext) { if (!CodedToken.CustomAttributeType.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Method => ResolveMethod(rid), Table.MemberRef => ResolveMemberRef(rid, gpContext), _ => null, }; } /// /// Resolves a /// /// A ResolutionScope coded token /// A or null if is invalid public IResolutionScope ResolveResolutionScope(uint codedToken) { if (!CodedToken.ResolutionScope.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.Module => ResolveModule(rid), Table.ModuleRef => ResolveModuleRef(rid), Table.AssemblyRef => ResolveAssemblyRef(rid), Table.TypeRef => ResolveTypeRef(rid), _ => null, }; } /// /// Resolves a /// /// A TypeOrMethodDef> coded token /// A or null if is invalid public ITypeOrMethodDef ResolveTypeOrMethodDef(uint codedToken) { if (!CodedToken.TypeOrMethodDef.Decode(codedToken, out uint token)) return null; uint rid = MDToken.ToRID(token); return MDToken.ToTable(token) switch { Table.TypeDef => ResolveTypeDef(rid), Table.Method => ResolveMethod(rid), _ => null, }; } /// /// Reads a signature from the #Blob stream /// /// #Blob stream offset of signature /// A new instance or null if /// is invalid. public CallingConventionSig ReadSignature(uint sig) => SignatureReader.ReadSig(this, sig, new GenericParamContext()); /// /// Reads a signature from the #Blob stream /// /// #Blob stream offset of signature /// Generic parameter context /// A new instance or null if /// is invalid. public CallingConventionSig ReadSignature(uint sig, GenericParamContext gpContext) => SignatureReader.ReadSig(this, sig, gpContext); /// /// Reads a type signature from the #Blob stream /// /// #Blob stream offset of signature /// A new instance or null if /// is invalid. public TypeSig ReadTypeSignature(uint sig) => SignatureReader.ReadTypeSig(this, sig, new GenericParamContext()); /// /// Reads a type signature from the #Blob stream /// /// #Blob stream offset of signature /// Generic parameter context /// A new instance or null if /// is invalid. public TypeSig ReadTypeSignature(uint sig, GenericParamContext gpContext) => SignatureReader.ReadTypeSig(this, sig, gpContext); /// /// Reads a type signature from the #Blob stream /// /// #Blob stream offset of signature /// If there's any extra data after the signature, it's saved /// here, else this will be null /// A new instance or null if /// is invalid. public TypeSig ReadTypeSignature(uint sig, out byte[] extraData) => SignatureReader.ReadTypeSig(this, sig, new GenericParamContext(), out extraData); /// /// Reads a type signature from the #Blob stream /// /// #Blob stream offset of signature /// If there's any extra data after the signature, it's saved /// here, else this will be null /// Generic parameter context /// A new instance or null if /// is invalid. public TypeSig ReadTypeSignature(uint sig, GenericParamContext gpContext, out byte[] extraData) => SignatureReader.ReadTypeSig(this, sig, gpContext, out extraData); /// /// Reads a from the blob /// /// Table of owner /// Row ID of owner /// Generic parameter context /// A new instance or null if there's no field /// marshal for this owner. internal MarshalType ReadMarshalType(Table table, uint rid, GenericParamContext gpContext) { if (!TablesStream.TryReadFieldMarshalRow(Metadata.GetFieldMarshalRid(table, rid), out var row)) return null; return MarshalBlobReader.Read(this, row.NativeType, gpContext); } /// /// Reads a CIL method body /// /// Method parameters /// RVA /// A new instance. It's empty if RVA is invalid (eg. 0 or /// it doesn't point to a CIL method body) public CilBody ReadCilBody(IList parameters, RVA rva) => ReadCilBody(parameters, rva, new GenericParamContext()); /// /// Reads a CIL method body /// /// Method parameters /// RVA /// Generic parameter context /// A new instance. It's empty if RVA is invalid (eg. 0 or /// it doesn't point to a CIL method body) public CilBody ReadCilBody(IList parameters, RVA rva, GenericParamContext gpContext) { if (rva == 0) return new CilBody(); // Create a full stream so position will be the real position in the file. This // is important when reading exception handlers since those must be 4-byte aligned. // If we create a partial stream starting from rva, then position will be 0 and always // 4-byte aligned. All fat method bodies should be 4-byte aligned, but the CLR doesn't // seem to verify it. We must parse the method exactly the way the CLR parses it. var offset = metadata.PEImage.ToFileOffset(rva); if (offset == 0) return new CilBody(); var reader = metadata.PEImage.CreateReader(); reader.Position = (uint)offset; return MethodBodyReader.CreateCilBody(this, reader, parameters, gpContext, Context); } /// /// Returns the owner type of a field /// /// The field /// The owner type or null if none internal TypeDef GetOwnerType(FieldDefMD field) => ResolveTypeDef(Metadata.GetOwnerTypeOfField(field.OrigRid)); /// /// Returns the owner type of a method /// /// The method /// The owner type or null if none internal TypeDef GetOwnerType(MethodDefMD method) => ResolveTypeDef(Metadata.GetOwnerTypeOfMethod(method.OrigRid)); /// /// Returns the owner type of an event /// /// The event /// The owner type or null if none internal TypeDef GetOwnerType(EventDefMD evt) => ResolveTypeDef(Metadata.GetOwnerTypeOfEvent(evt.OrigRid)); /// /// Returns the owner type of a property /// /// The property /// The owner type or null if none internal TypeDef GetOwnerType(PropertyDefMD property) => ResolveTypeDef(Metadata.GetOwnerTypeOfProperty(property.OrigRid)); /// /// Returns the owner type/method of a generic param /// /// The generic param /// The owner type/method or null if none internal ITypeOrMethodDef GetOwner(GenericParamMD gp) => ResolveTypeOrMethodDef(Metadata.GetOwnerOfGenericParam(gp.OrigRid)); /// /// Returns the owner generic param of a generic param constraint /// /// The generic param constraint /// The owner generic param or null if none internal GenericParam GetOwner(GenericParamConstraintMD gpc) => ResolveGenericParam(Metadata.GetOwnerOfGenericParamConstraint(gpc.OrigRid)); /// /// Returns the owner method of a param /// /// The param /// The owner method or null if none internal MethodDef GetOwner(ParamDefMD pd) => ResolveMethod(Metadata.GetOwnerOfParam(pd.OrigRid)); /// /// Reads a module /// /// File rid /// The assembly owning the module we should read /// A new instance or null if /// is invalid or if it's not a .NET module. internal ModuleDefMD ReadModule(uint fileRid, AssemblyDef owner) { var fileDef = ResolveFile(fileRid); if (fileDef is null) return null; if (!fileDef.ContainsMetadata) return null; var fileName = GetValidFilename(GetBaseDirectoryOfImage(), UTF8String.ToSystemString(fileDef.Name)); if (fileName is null) return null; ModuleDefMD module; try { module = Load(fileName); } catch { module = null; } if (module is not null) { // share context module.context = context; var asm = module.Assembly; if (asm is not null && asm != owner) asm.Modules.Remove(module); } return module; } /// /// Gets a list of all File rids that are .NET modules. Call /// to read one of these modules. /// /// A new instance internal RidList GetModuleRidList() { if (moduleRidList is null) InitializeModuleList(); return moduleRidList.Value; } void InitializeModuleList() { if (moduleRidList is not null) return; uint rows = TablesStream.FileTable.Rows; var newModuleRidList = new List((int)rows); var baseDir = GetBaseDirectoryOfImage(); for (uint fileRid = 1; fileRid <= rows; fileRid++) { var fileDef = ResolveFile(fileRid); if (fileDef is null) continue; // Should never happen if (!fileDef.ContainsMetadata) continue; var pathName = GetValidFilename(baseDir, UTF8String.ToSystemString(fileDef.Name)); if (pathName is not null) newModuleRidList.Add(fileRid); } Interlocked.CompareExchange(ref moduleRidList, new StrongBox(RidList.Create(newModuleRidList)), null); } /// /// Concatenates the inputs and returns the result if it's a valid path /// /// Base dir /// File name /// Full path to the file or null if one of the inputs is invalid static string GetValidFilename(string baseDir, string name) { if (baseDir is null) return null; string pathName; try { if (name.IndexOfAny(Path.GetInvalidPathChars()) >= 0) return null; pathName = Path.Combine(baseDir, name); if (pathName != Path.GetFullPath(pathName)) return null; if (!File.Exists(pathName)) return null; } catch { return null; } return pathName; } /// /// Gets the base directory where this .NET module is located on disk /// /// Base directory or null if unknown or if an error occurred string GetBaseDirectoryOfImage() { var imageFileName = Location; if (string.IsNullOrEmpty(imageFileName)) return null; try { return Path.GetDirectoryName(imageFileName); } catch (IOException) { } catch (ArgumentException) { } return null; } /// /// Creates a instance /// /// ManifestResource rid /// A new instance Resource CreateResource(uint rid) { if (!TablesStream.TryReadManifestResourceRow(rid, out var row)) return new EmbeddedResource(UTF8String.Empty, Array2.Empty(), 0) { Rid = rid }; if (!CodedToken.Implementation.Decode(row.Implementation, out MDToken token)) return new EmbeddedResource(UTF8String.Empty, Array2.Empty(), 0) { Rid = rid }; var mr = ResolveManifestResource(rid); if (mr is null) return new EmbeddedResource(UTF8String.Empty, Array2.Empty(), 0) { Rid = rid }; if (token.Rid == 0) { if (TryCreateResourceStream(mr.Offset, out var dataReaderFactory, out uint resourceOffset, out uint resourceLength)) return new EmbeddedResourceMD(this, mr, dataReaderFactory, resourceOffset, resourceLength); return new EmbeddedResourceMD(this, mr, Array2.Empty()); } if (mr.Implementation is FileDef file) return new LinkedResourceMD(this, mr, file); if (mr.Implementation is AssemblyRef asmRef) return new AssemblyLinkedResourceMD(this, mr, asmRef); return new EmbeddedResourceMD(this, mr, Array2.Empty()); } // Required attributes on .NET Framework 4.0 // HandleProcessCorruptedStateExceptions is obsolete on .NET Core and newer #if !NETCOREAPP [HandleProcessCorruptedStateExceptions] #endif [SecurityCritical] bool TryCreateResourceStream(uint offset, out DataReaderFactory dataReaderFactory, out uint resourceOffset, out uint resourceLength) { dataReaderFactory = null; resourceOffset = 0; resourceLength = 0; try { var peImage = metadata.PEImage; var cor20Header = metadata.ImageCor20Header; var resources = cor20Header.Resources; if (resources.VirtualAddress == 0 || resources.Size == 0) return false; var fullReader = peImage.CreateReader(); var resourcesBaseOffs = (uint)peImage.ToFileOffset(resources.VirtualAddress); if (resourcesBaseOffs == 0 || (ulong)resourcesBaseOffs + offset > uint.MaxValue) return false; if ((ulong)offset + 4 > resources.Size) return false; if ((ulong)resourcesBaseOffs + offset + 4 > fullReader.Length) return false; fullReader.Position = resourcesBaseOffs + offset; resourceLength = fullReader.ReadUInt32(); // Could throw resourceOffset = fullReader.Position; if (resourceLength == 0 || (ulong)fullReader.Position + resourceLength > fullReader.Length) return false; if ((ulong)fullReader.Position - resourcesBaseOffs + resourceLength - 1 >= resources.Size) return false; if (peImage.MayHaveInvalidAddresses) { var rsrcReader = peImage.CreateReader((FileOffset)fullReader.Position, resourceLength); for (; rsrcReader.Position < rsrcReader.Length; rsrcReader.Position += Math.Min(rsrcReader.BytesLeft, 0x1000)) rsrcReader.ReadByte(); // Could throw rsrcReader.Position = rsrcReader.Length - 1; // length is never 0 if we're here rsrcReader.ReadByte(); // Could throw } dataReaderFactory = peImage.DataReaderFactory; return true; } catch (IOException) { } catch (AccessViolationException) { } return false; } /// /// Reads a /// /// Custom attribute rid /// A new instance or null if /// is invalid public CustomAttribute ReadCustomAttribute(uint caRid) => ReadCustomAttribute(caRid, new GenericParamContext()); /// /// Reads a /// /// Custom attribute rid /// Generic parameter context /// A new instance or null if /// is invalid public CustomAttribute ReadCustomAttribute(uint caRid, GenericParamContext gpContext) { if (!TablesStream.TryReadCustomAttributeRow(caRid, out var caRow)) return null; return CustomAttributeReader.Read(this, ResolveCustomAttributeType(caRow.Type, gpContext), caRow.Value, gpContext); } /// /// Reads data somewhere in the address space of the image /// /// RVA of data /// Size of data /// All the data or null if or /// is invalid public byte[] ReadDataAt(RVA rva, int size) { if (size < 0) return null; var peImage = Metadata.PEImage; var reader = peImage.CreateReader(rva, (uint)size); if (reader.Length < size) return null; return reader.ReadBytes(size); } /// /// Gets the native entry point or 0 if none /// public RVA GetNativeEntryPoint() { var cor20Header = Metadata.ImageCor20Header; if ((cor20Header.Flags & ComImageFlags.NativeEntryPoint) == 0) return 0; return (RVA)cor20Header.EntryPointToken_or_RVA; } /// /// Gets the managed entry point (a Method or a File) or null if none /// public IManagedEntryPoint GetManagedEntryPoint() { var cor20Header = Metadata.ImageCor20Header; if ((cor20Header.Flags & ComImageFlags.NativeEntryPoint) != 0) return null; return ResolveToken(cor20Header.EntryPointToken_or_RVA) as IManagedEntryPoint; } /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal FieldDefMD ReadField(uint rid) => new FieldDefMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal MethodDefMD ReadMethod(uint rid) => new MethodDefMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal EventDefMD ReadEvent(uint rid) => new EventDefMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal PropertyDefMD ReadProperty(uint rid) => new PropertyDefMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal ParamDefMD ReadParam(uint rid) => new ParamDefMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal GenericParamMD ReadGenericParam(uint rid) => new GenericParamMD(this, rid); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// A new instance internal GenericParamConstraintMD ReadGenericParamConstraint(uint rid) => new GenericParamConstraintMD(this, rid, new GenericParamContext()); /// /// Reads a new instance. This one is not cached. /// /// Row ID /// Generic parameter context /// A new instance internal GenericParamConstraintMD ReadGenericParamConstraint(uint rid, GenericParamContext gpContext) => new GenericParamConstraintMD(this, rid, gpContext); /// /// Reads a method body /// /// Method /// Method RVA /// Method impl attrs /// Generic parameter context /// A or null if none internal MethodBody ReadMethodBody(MethodDefMD method, RVA rva, MethodImplAttributes implAttrs, GenericParamContext gpContext) { var mDec = methodDecrypter; if (mDec is not null && mDec.GetMethodBody(method.OrigRid, rva, method.Parameters, gpContext, out var mb)) { if (mb is CilBody cilBody) return InitializeBodyFromPdb(method, cilBody); return mb; } if (rva == 0) return null; var codeType = implAttrs & MethodImplAttributes.CodeTypeMask; if (codeType == MethodImplAttributes.IL) return InitializeBodyFromPdb(method, ReadCilBody(method.Parameters, rva, gpContext)); if (codeType == MethodImplAttributes.Native) return new NativeMethodBody(rva); return null; } /// /// Updates with the PDB info (if any) /// /// Owner method /// Method body /// Returns originak value CilBody InitializeBodyFromPdb(MethodDefMD method, CilBody body) { var ps = pdbState; if (ps is not null) ps.InitializeMethodBody(this, method, body); return body; } internal void InitializeCustomDebugInfos(MethodDefMD method, CilBody body, IList customDebugInfos) { if (body is null) return; var ps = pdbState; if (ps is not null) ps.InitializeCustomDebugInfos(method, body, customDebugInfos); } /// /// Reads a string from the #US heap /// /// String token /// A non-null string public string ReadUserString(uint token) { var sDec = stringDecrypter; if (sDec is not null) { var s = sDec.ReadUserString(token); if (s is not null) return s; } return USStream.ReadNoNull(token & 0x00FFFFFF); } internal MethodExportInfo GetExportInfo(uint methodRid) { if (methodExportInfoProvider is null) InitializeMethodExportInfoProvider(); return methodExportInfoProvider.GetMethodExportInfo(0x06000000 + methodRid); } void InitializeMethodExportInfoProvider() => Interlocked.CompareExchange(ref methodExportInfoProvider, new MethodExportInfoProvider(this), null); MethodExportInfoProvider methodExportInfoProvider; /// /// Writes the mixed-mode module to a file on disk. If the file exists, it will be overwritten. /// /// Filename public void NativeWrite(string filename) => NativeWrite(filename, null); /// /// Writes the mixed-mode module to a file on disk. If the file exists, it will be overwritten. /// /// Filename /// Writer options public void NativeWrite(string filename, DNW.NativeModuleWriterOptions options) { var writer = new DNW.NativeModuleWriter(this, options ?? new DNW.NativeModuleWriterOptions(this, optimizeImageSize: true)); writer.Write(filename); } /// /// Writes the mixed-mode module to a stream. /// /// Destination stream public void NativeWrite(Stream dest) => NativeWrite(dest, null); /// /// Writes the mixed-mode module to a stream. /// /// Destination stream /// Writer options public void NativeWrite(Stream dest, DNW.NativeModuleWriterOptions options) { var writer = new DNW.NativeModuleWriter(this, options ?? new DNW.NativeModuleWriterOptions(this, optimizeImageSize: true)); writer.Write(dest); } /// /// Reads data from the #Blob. The following columns are returned: /// Field.Signature /// Method.Signature /// MemberRef.Signature /// Constant.Value /// CustomAttribute.Value /// FieldMarshal.NativeType /// DeclSecurity.PermissionSet /// StandAloneSig.Signature /// Property.Type /// TypeSpec.Signature /// Assembly.PublicKey /// AssemblyRef.PublicKeyOrToken /// File.HashValue /// MethodSpec.Instantiation /// /// A token /// The value in the #Blob or null if is invalid public byte[] ReadBlob(uint token) { uint rid = MDToken.ToRID(token); switch (MDToken.ToTable(token)) { case Table.Field: if (!TablesStream.TryReadFieldRow(rid, out var fieldRow)) break; return BlobStream.Read(fieldRow.Signature); case Table.Method: if (!TablesStream.TryReadMethodRow(rid, out var methodRow)) break; return BlobStream.Read(methodRow.Signature); case Table.MemberRef: if (!TablesStream.TryReadMemberRefRow(rid, out var mrRow)) break; return BlobStream.Read(mrRow.Signature); case Table.Constant: if (!TablesStream.TryReadConstantRow(rid, out var constRow)) break; return BlobStream.Read(constRow.Value); case Table.CustomAttribute: if (!TablesStream.TryReadCustomAttributeRow(rid, out var caRow)) break; return BlobStream.Read(caRow.Value); case Table.FieldMarshal: if (!TablesStream.TryReadFieldMarshalRow(rid, out var fmRow)) break; return BlobStream.Read(fmRow.NativeType); case Table.DeclSecurity: if (!TablesStream.TryReadDeclSecurityRow(rid, out var dsRow)) break; return BlobStream.Read(dsRow.PermissionSet); case Table.StandAloneSig: if (!TablesStream.TryReadStandAloneSigRow(rid, out var sasRow)) break; return BlobStream.Read(sasRow.Signature); case Table.Property: if (!TablesStream.TryReadPropertyRow(rid, out var propRow)) break; return BlobStream.Read(propRow.Type); case Table.TypeSpec: if (!TablesStream.TryReadTypeSpecRow(rid, out var tsRow)) break; return BlobStream.Read(tsRow.Signature); case Table.Assembly: if (!TablesStream.TryReadAssemblyRow(rid, out var asmRow)) break; return BlobStream.Read(asmRow.PublicKey); case Table.AssemblyRef: // HashValue is also in the #Blob but the user has to read it some other way if (!TablesStream.TryReadAssemblyRefRow(rid, out var asmRefRow)) break; return BlobStream.Read(asmRefRow.PublicKeyOrToken); case Table.File: if (!TablesStream.TryReadFileRow(rid, out var fileRow)) break; return BlobStream.Read(fileRow.HashValue); case Table.MethodSpec: if (!TablesStream.TryReadMethodSpecRow(rid, out var msRow)) break; return BlobStream.Read(msRow.Instantiation); } return null; } } }