// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; namespace dnlib.DotNet { /// /// A high-level representation of a row in the DeclSecurity table /// [DebuggerDisplay("{Action} Count={SecurityAttributes.Count}")] public abstract class DeclSecurity : IHasCustomAttribute, IHasCustomDebugInformation { /// /// The row id in its table /// protected uint rid; /// public MDToken MDToken => new MDToken(Table.DeclSecurity, rid); /// public uint Rid { get => rid; set => rid = value; } /// public int HasCustomAttributeTag => 8; /// /// From column DeclSecurity.Action /// public SecurityAction Action { get => action; set => action = value; } /// protected SecurityAction action; /// /// From column DeclSecurity.PermissionSet /// public IList SecurityAttributes { get { if (securityAttributes is null) InitializeSecurityAttributes(); return securityAttributes; } } /// protected IList securityAttributes; /// Initializes protected virtual void InitializeSecurityAttributes() => Interlocked.CompareExchange(ref securityAttributes, new List(), null); /// /// Gets all custom attributes /// public CustomAttributeCollection CustomAttributes { get { if (customAttributes is null) InitializeCustomAttributes(); return customAttributes; } } /// protected CustomAttributeCollection customAttributes; /// Initializes protected virtual void InitializeCustomAttributes() => Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null); /// public bool HasCustomAttributes => CustomAttributes.Count > 0; /// public int HasCustomDebugInformationTag => 8; /// public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0; /// /// Gets all custom debug infos /// public IList CustomDebugInfos { get { if (customDebugInfos is null) InitializeCustomDebugInfos(); return customDebugInfos; } } /// protected IList customDebugInfos; /// Initializes protected virtual void InitializeCustomDebugInfos() => Interlocked.CompareExchange(ref customDebugInfos, new List(), null); /// /// true if is not empty /// public bool HasSecurityAttributes => SecurityAttributes.Count > 0; /// /// Gets the blob data or null if there's none /// /// Blob data or null public abstract byte[] GetBlob(); /// /// Returns the .NET Framework 1.x XML string or null if it's not a .NET Framework 1.x format /// /// public string GetNet1xXmlString() => GetNet1xXmlStringInternal(SecurityAttributes); internal static string GetNet1xXmlStringInternal(IList secAttrs) { if (secAttrs is null || secAttrs.Count != 1) return null; var sa = secAttrs[0]; if (sa is null || sa.TypeFullName != "System.Security.Permissions.PermissionSetAttribute") return null; if (sa.NamedArguments.Count != 1) return null; var na = sa.NamedArguments[0]; if (na is null || !na.IsProperty || na.Name != "XML") return null; if (na.ArgumentType.GetElementType() != ElementType.String) return null; var arg = na.Argument; if (arg.Type.GetElementType() != ElementType.String) return null; var utf8 = arg.Value as UTF8String; if (utf8 is not null) return utf8; if (arg.Value is string s) return s; return null; } } /// /// A DeclSecurity row created by the user and not present in the original .NET file /// public class DeclSecurityUser : DeclSecurity { /// /// Default constructor /// public DeclSecurityUser() { } /// /// Constructor /// /// The security action /// The security attributes (now owned by this) public DeclSecurityUser(SecurityAction action, IList securityAttrs) { this.action = action; securityAttributes = securityAttrs; } /// public override byte[] GetBlob() => null; } /// /// Created from a row in the DeclSecurity table /// sealed class DeclSecurityMD : DeclSecurity, IMDTokenProviderMD { /// The module where this instance is located readonly ModuleDefMD readerModule; readonly uint origRid; readonly uint permissionSet; /// public uint OrigRid => origRid; /// protected override void InitializeSecurityAttributes() { var gpContext = new GenericParamContext(); var tmp = DeclSecurityReader.Read(readerModule, permissionSet, gpContext); Interlocked.CompareExchange(ref securityAttributes, tmp, null); } /// protected override void InitializeCustomAttributes() { var list = readerModule.Metadata.GetCustomAttributeRidList(Table.DeclSecurity, origRid); var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index])); Interlocked.CompareExchange(ref customAttributes, tmp, null); } /// protected override void InitializeCustomDebugInfos() { var list = new List(); var gpContext = new GenericParamContext(); readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list); Interlocked.CompareExchange(ref customDebugInfos, list, null); } /// /// Constructor /// /// The module which contains this DeclSecurity row /// Row ID /// If is null /// If is invalid public DeclSecurityMD(ModuleDefMD readerModule, uint rid) { #if DEBUG if (readerModule is null) throw new ArgumentNullException("readerModule"); if (readerModule.TablesStream.DeclSecurityTable.IsInvalidRID(rid)) throw new BadImageFormatException($"DeclSecurity rid {rid} does not exist"); #endif origRid = rid; this.rid = rid; this.readerModule = readerModule; bool b = readerModule.TablesStream.TryReadDeclSecurityRow(origRid, out var row); Debug.Assert(b); permissionSet = row.PermissionSet; action = (SecurityAction)row.Action; } /// public override byte[] GetBlob() => readerModule.BlobStream.Read(permissionSet); } }