From d0d2f5cf3c562e659ce5969d7a6baf7a0444726b Mon Sep 17 00:00:00 2001 From: Sam Byass Date: Wed, 16 Mar 2022 19:09:50 +0000 Subject: [PATCH 01/51] Use ConcurrentDictionary as backing cache for DefaultMetadataResolver --- src/AsmResolver.DotNet/DefaultMetadataResolver.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs index 839feaa96..2d0031695 100644 --- a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs +++ b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using AsmResolver.DotNet.Signatures; using AsmResolver.DotNet.Signatures.Types; @@ -24,7 +25,7 @@ public class DefaultMetadataResolver : IMetadataResolver public DefaultMetadataResolver(IAssemblyResolver assemblyResolver) { AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); - _typeCache = new Dictionary(); + _typeCache = new ConcurrentDictionary(); } /// From 826e0552d36c4fa04f7f402f6611353ac323edfd Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 18:46:22 +0100 Subject: [PATCH 02/51] Add nested typedef import test. --- .../ReferenceImporterTest.cs | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index be9f40fc4..1563dd71c 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -11,9 +11,9 @@ namespace AsmResolver.DotNet.Tests { public class ReferenceImporterTest { - private static readonly SignatureComparer _comparer = new SignatureComparer(); + private static readonly SignatureComparer Comparer = new(); - private readonly AssemblyReference _dummyAssembly = new AssemblyReference("SomeAssembly", new Version(1, 2, 3, 4)); + private readonly AssemblyReference _dummyAssembly = new("SomeAssembly", new Version(1, 2, 3, 4)); private readonly ModuleDefinition _module; private readonly ReferenceImporter _importer; @@ -28,7 +28,7 @@ public void ImportNewAssemblyShouldAddToModule() { var result = _importer.ImportScope(_dummyAssembly); - Assert.Equal(_dummyAssembly, result, _comparer); + Assert.Equal(_dummyAssembly, result, Comparer); Assert.Contains(result, _module.AssemblyReferences); } @@ -52,7 +52,7 @@ public void ImportNewTypeShouldCreateNewReference() var type = new TypeReference(_dummyAssembly, "SomeNamespace", "SomeName"); var result = _importer.ImportType(type); - Assert.Equal(type, result, _comparer); + Assert.Equal(type, result, Comparer); Assert.Equal(_module, result.Module); } @@ -78,7 +78,7 @@ public void ImportTypeDefFromDifferentModuleShouldReturnTypeRef() var result = _importer.ImportType(definition); Assert.IsAssignableFrom(result); - Assert.Equal(definition, result, _comparer); + Assert.Equal(definition, result, Comparer); } [Fact] @@ -100,11 +100,32 @@ public void ImportNestedTypeShouldImportParentType() var result = _importer.ImportType(nested); - Assert.Equal(nested, result, _comparer); + Assert.Equal(nested, result, Comparer); Assert.Equal(_module, result.Module); Assert.Equal(_module, result.DeclaringType.Module); } + [Fact] + public void ImportNestedTypeDefinitionShouldImportParentType() + { + var otherAssembly = new AssemblyDefinition(_dummyAssembly.Name, _dummyAssembly.Version); + var otherModule = new ModuleDefinition("OtherModule"); + otherAssembly.Modules.Add(otherModule); + + var objectType = otherModule.CorLibTypeFactory.Object.ToTypeDefOrRef(); + var declaringType = new TypeDefinition("SomeNamespace", "SomeName", TypeAttributes.Class | TypeAttributes.Public, objectType); + var nestedType = new TypeDefinition(null, "NestedType", TypeAttributes.Class | TypeAttributes.NestedPublic, objectType); + declaringType.NestedTypes.Add(nestedType); + otherModule.TopLevelTypes.Add(declaringType); + + var reference = _importer.ImportType(nestedType); + + Assert.NotNull(reference.DeclaringType); + Assert.Equal(declaringType, reference.DeclaringType, Comparer); + Assert.Equal(_module, reference.Module); + Assert.Equal(_module, reference.DeclaringType.Module); + } + [Fact] public void ImportSimpleTypeFromReflectionShouldResultInTypeRef() { @@ -170,7 +191,7 @@ public void ImportMethodFromExternalModuleShouldResultInMemberRef() var result = _importer.ImportMethod(method); - Assert.Equal(method, result, _comparer); + Assert.Equal(method, result, Comparer); Assert.Same(_module, result.Module); } @@ -217,7 +238,7 @@ public void ImportGenericMethodFromReflectionShouldResultInMethodSpec() Assert.Equal(new TypeSignature[] { _module.CorLibTypeFactory.String - }, specification.Signature.TypeArguments, _comparer); + }, specification.Signature.TypeArguments, Comparer); } [Fact] @@ -231,7 +252,7 @@ public void ImportFieldFromExternalModuleShouldResultInMemberRef() var result = _importer.ImportField(field); - Assert.Equal(field, result, _comparer); + Assert.Equal(field, result, Comparer); Assert.Same(_module, result.Module); } From 5dc012371f3a53458426153c426f53db1b1a7989 Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 18:48:06 +0100 Subject: [PATCH 03/51] BUGFIX: import resolution scope instead of module for typedefs. --- src/AsmResolver.DotNet/ReferenceImporter.cs | 6 +++++- .../ReferenceImporterTest.cs | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/AsmResolver.DotNet/ReferenceImporter.cs b/src/AsmResolver.DotNet/ReferenceImporter.cs index b1c858e76..e132b2b71 100644 --- a/src/AsmResolver.DotNet/ReferenceImporter.cs +++ b/src/AsmResolver.DotNet/ReferenceImporter.cs @@ -142,7 +142,11 @@ protected virtual ITypeDefOrRef ImportType(TypeDefinition type) if (type.Module == TargetModule) return type; - return new TypeReference(TargetModule, ImportScope(type.Module!), type.Namespace, type.Name); + return new TypeReference( + TargetModule, + ImportScope(((ITypeDescriptor) type).Scope!), + type.Namespace, + type.Name); } /// diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index 1563dd71c..735ad198c 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -113,8 +113,18 @@ public void ImportNestedTypeDefinitionShouldImportParentType() otherAssembly.Modules.Add(otherModule); var objectType = otherModule.CorLibTypeFactory.Object.ToTypeDefOrRef(); - var declaringType = new TypeDefinition("SomeNamespace", "SomeName", TypeAttributes.Class | TypeAttributes.Public, objectType); - var nestedType = new TypeDefinition(null, "NestedType", TypeAttributes.Class | TypeAttributes.NestedPublic, objectType); + + var declaringType = new TypeDefinition( + "SomeNamespace", + "SomeName", + TypeAttributes.Class | TypeAttributes.Public, + objectType); + var nestedType = new TypeDefinition( + null, + "NestedType", + TypeAttributes.Class | TypeAttributes.NestedPublic, + objectType); + declaringType.NestedTypes.Add(nestedType); otherModule.TopLevelTypes.Add(declaringType); From f2d7bf6aef1c18bc9772934bdc3768d5e0e158d8 Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 19:52:05 +0100 Subject: [PATCH 04/51] Add typesig importer tests with non-imported embedded references. --- .../ReferenceImporterTest.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index be9f40fc4..7ee5a63d2 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -264,5 +264,47 @@ public void ImportFieldFromReflectionShouldResultInMemberRef() Assert.Equal(field.DeclaringType.FullName, result.DeclaringType.FullName); Assert.Equal(field.FieldType.FullName, ((FieldSignature) result.Signature).FieldType.FullName); } + + [Fact] + public void ImportTypeSigWithNonImportedEmbeddedReferenceShouldResultInNewInstance() + { + // https://github.com/Washi1337/AsmResolver/issues/268 + + var genericType = new TypeDefinition("SomeNamespace", "SomeName", TypeAttributes.Class); + genericType.GenericParameters.Add(new GenericParameter("T")); + _module.TopLevelTypes.Add(genericType); + + var instance = genericType.MakeGenericInstanceType( + new TypeDefOrRefSignature( + new TypeReference(_module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream"), false) + ); + + var imported = _importer.ImportTypeSignature(instance); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.NotSame(instance, newInstance); + Assert.Equal(_module, newInstance.Module); + Assert.Equal(_module, newInstance.TypeArguments[0].Module); + } + + [Fact] + public void ImportTypeSigWithImportedEmbeddedReferenceShouldResultInSameInstance() + { + // https://github.com/Washi1337/AsmResolver/issues/268 + + var genericType = new TypeDefinition("SomeNamespace", "SomeName", TypeAttributes.Class); + genericType.GenericParameters.Add(new GenericParameter("T")); + _module.TopLevelTypes.Add(genericType); + + var instance = genericType.MakeGenericInstanceType( + new TypeDefOrRefSignature( + new TypeReference(_module, _module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream"), false) + ); + + var imported = _importer.ImportTypeSignature(instance); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.Same(instance, newInstance); + } } } From 94d5064a8df0947a451ecc8a4e8b02403ba89f8f Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 19:56:59 +0100 Subject: [PATCH 05/51] Add IImportable, let reference importer do more thorough checks on whether a member is imported or not. --- src/AsmResolver.DotNet/AssemblyDefinition.cs | 3 +++ src/AsmResolver.DotNet/AssemblyDescriptor.cs | 7 ++++- src/AsmResolver.DotNet/AssemblyReference.cs | 3 +++ src/AsmResolver.DotNet/EventDefinition.cs | 7 +++++ src/AsmResolver.DotNet/ExportedType.cs | 7 +++-- src/AsmResolver.DotNet/FieldDefinition.cs | 7 +++++ src/AsmResolver.DotNet/IImportable.cs | 18 +++++++++++++ src/AsmResolver.DotNet/IMemberDescriptor.cs | 2 +- src/AsmResolver.DotNet/IResolutionScope.cs | 2 +- src/AsmResolver.DotNet/InvalidTypeDefOrRef.cs | 3 +++ src/AsmResolver.DotNet/MemberReference.cs | 7 +++++ src/AsmResolver.DotNet/MethodDefinition.cs | 7 +++++ src/AsmResolver.DotNet/MethodSpecification.cs | 7 +++++ src/AsmResolver.DotNet/ModuleDefinition.cs | 3 +++ src/AsmResolver.DotNet/ModuleReference.cs | 3 +++ src/AsmResolver.DotNet/PropertyDefinition.cs | 7 +++++ src/AsmResolver.DotNet/ReferenceImporter.cs | 26 +++++++++---------- .../ReflectionAssemblyDescriptor.cs | 3 +++ .../Signatures/CallingConventionSignature.cs | 5 +++- .../GenericInstanceMethodSignature.cs | 12 +++++++++ .../Signatures/LocalVariablesSignature.cs | 12 +++++++++ .../Signatures/MemberSignature.cs | 3 +++ .../Signatures/MethodSignatureBase.cs | 23 ++++++++++++++++ .../Signatures/Types/CorLibTypeSignature.cs | 3 +++ .../Types/CustomModifierTypeSignature.cs | 4 +++ .../Types/FunctionPointerTypeSignature.cs | 4 +++ .../Types/GenericInstanceTypeSignature.cs | 15 +++++++++++ .../Types/GenericParameterSignature.cs | 3 +++ .../Signatures/Types/SentinelTypeSignature.cs | 3 +++ .../Signatures/Types/TypeDefOrRefSignature.cs | 3 +++ .../Signatures/Types/TypeSignature.cs | 3 +++ .../Types/TypeSpecificationSignature.cs | 3 +++ src/AsmResolver.DotNet/TypeDefinition.cs | 3 +++ src/AsmResolver.DotNet/TypeReference.cs | 3 +++ src/AsmResolver.DotNet/TypeSpecification.cs | 3 +++ 35 files changed, 207 insertions(+), 20 deletions(-) create mode 100644 src/AsmResolver.DotNet/IImportable.cs diff --git a/src/AsmResolver.DotNet/AssemblyDefinition.cs b/src/AsmResolver.DotNet/AssemblyDefinition.cs index 220980bcb..43fe53c77 100644 --- a/src/AsmResolver.DotNet/AssemblyDefinition.cs +++ b/src/AsmResolver.DotNet/AssemblyDefinition.cs @@ -222,6 +222,9 @@ protected virtual IList GetModules() return _publicKeyToken; } + /// + public override bool IsImportedInModule(ModuleDefinition module) => ManifestModule == module; + /// public override AssemblyDefinition Resolve() => this; diff --git a/src/AsmResolver.DotNet/AssemblyDescriptor.cs b/src/AsmResolver.DotNet/AssemblyDescriptor.cs index 248812ba8..87a816029 100644 --- a/src/AsmResolver.DotNet/AssemblyDescriptor.cs +++ b/src/AsmResolver.DotNet/AssemblyDescriptor.cs @@ -2,18 +2,20 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Security.Cryptography; using System.Threading; using AsmResolver.Collections; using AsmResolver.PE.DotNet.Metadata.Tables; using AsmResolver.PE.DotNet.Metadata.Tables.Rows; +using AssemblyHashAlgorithm = AsmResolver.PE.DotNet.Metadata.Tables.Rows.AssemblyHashAlgorithm; namespace AsmResolver.DotNet { /// /// Provides a base implementation for describing a self-describing .NET assembly hosted by a common language runtime (CLR). /// - public abstract class AssemblyDescriptor : MetadataMember, IHasCustomAttribute, IFullNameProvider + public abstract class AssemblyDescriptor : MetadataMember, IHasCustomAttribute, IFullNameProvider, IImportable { private const int PublicKeyTokenLength = 8; @@ -212,6 +214,9 @@ public IList CustomAttributes /// public override string ToString() => FullName; + /// + public abstract bool IsImportedInModule(ModuleDefinition module); + /// /// Computes the token of a public key using the provided hashing algorithm. /// diff --git a/src/AsmResolver.DotNet/AssemblyReference.cs b/src/AsmResolver.DotNet/AssemblyReference.cs index b5548144e..f37630de6 100644 --- a/src/AsmResolver.DotNet/AssemblyReference.cs +++ b/src/AsmResolver.DotNet/AssemblyReference.cs @@ -147,6 +147,9 @@ public AssemblyReference(AssemblyDescriptor descriptor) /// protected virtual byte[]? GetHashValue() => null; + /// + public override bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// public override AssemblyDefinition? Resolve() => Module?.MetadataResolver.AssemblyResolver.Resolve(this); diff --git a/src/AsmResolver.DotNet/EventDefinition.cs b/src/AsmResolver.DotNet/EventDefinition.cs index 649ce3734..e333a7e5c 100644 --- a/src/AsmResolver.DotNet/EventDefinition.cs +++ b/src/AsmResolver.DotNet/EventDefinition.cs @@ -170,6 +170,13 @@ public IList CustomAttributes IMemberDefinition IMemberDescriptor.Resolve() => this; + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (EventType?.IsImportedInModule(module) ?? false); + } + /// /// Obtains the list of custom attributes assigned to the member. /// diff --git a/src/AsmResolver.DotNet/ExportedType.cs b/src/AsmResolver.DotNet/ExportedType.cs index 935a0a795..d0845621b 100644 --- a/src/AsmResolver.DotNet/ExportedType.cs +++ b/src/AsmResolver.DotNet/ExportedType.cs @@ -28,8 +28,8 @@ public class ExportedType : protected ExportedType(MetadataToken token) : base(token) { - _name = new LazyVariable(() => GetName()); - _namespace = new LazyVariable(() => GetNamespace()); + _name = new LazyVariable(GetName); + _namespace = new LazyVariable(GetNamespace); _implementation = new LazyVariable(GetImplementation); } @@ -145,6 +145,9 @@ public IList CustomAttributes /// public TypeDefinition? Resolve() => Module?.MetadataResolver.ResolveType(this); + /// + public bool IsImportedInModule(ModuleDefinition module) => Module == module; + IMemberDefinition? IMemberDescriptor.Resolve() => Resolve(); /// diff --git a/src/AsmResolver.DotNet/FieldDefinition.cs b/src/AsmResolver.DotNet/FieldDefinition.cs index 08dc3832d..585f5ef3d 100644 --- a/src/AsmResolver.DotNet/FieldDefinition.cs +++ b/src/AsmResolver.DotNet/FieldDefinition.cs @@ -386,6 +386,13 @@ public IList CustomAttributes FieldDefinition IFieldDescriptor.Resolve() => this; + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (Signature?.IsImportedInModule(module) ?? false); + } + IMemberDefinition IMemberDescriptor.Resolve() => this; /// diff --git a/src/AsmResolver.DotNet/IImportable.cs b/src/AsmResolver.DotNet/IImportable.cs new file mode 100644 index 000000000..1d6fa8875 --- /dev/null +++ b/src/AsmResolver.DotNet/IImportable.cs @@ -0,0 +1,18 @@ +namespace AsmResolver.DotNet +{ + /// + /// Represents an entity in a .NET module that can be imported using the . + /// + public interface IImportable + { + /// + /// Determines whether the descriptor of the member is fully imported in the provided module. + /// + /// The module that is supposed to import the member. + /// true if the descriptor of the member is fully imported by the module, false otherwise. + /// + /// This method verifies all references in the descriptor of the member, but does not verify the contents (e.g. a method body). + /// + bool IsImportedInModule(ModuleDefinition module); + } +} diff --git a/src/AsmResolver.DotNet/IMemberDescriptor.cs b/src/AsmResolver.DotNet/IMemberDescriptor.cs index 75cf4f91d..e837e453b 100644 --- a/src/AsmResolver.DotNet/IMemberDescriptor.cs +++ b/src/AsmResolver.DotNet/IMemberDescriptor.cs @@ -3,7 +3,7 @@ namespace AsmResolver.DotNet /// /// Provides members for describing a (reference to a) member defined in a .NET assembly. /// - public interface IMemberDescriptor : IFullNameProvider, IModuleProvider + public interface IMemberDescriptor : IFullNameProvider, IModuleProvider, IImportable { /// /// When this member is defined in a type, gets the enclosing type. diff --git a/src/AsmResolver.DotNet/IResolutionScope.cs b/src/AsmResolver.DotNet/IResolutionScope.cs index 22c397ff0..444a63298 100644 --- a/src/AsmResolver.DotNet/IResolutionScope.cs +++ b/src/AsmResolver.DotNet/IResolutionScope.cs @@ -3,7 +3,7 @@ namespace AsmResolver.DotNet /// /// Represents a member that can be referenced by a ResolutionScope coded index. /// - public interface IResolutionScope : IMetadataMember, INameProvider, IModuleProvider + public interface IResolutionScope : IMetadataMember, INameProvider, IModuleProvider, IImportable { /// /// Gets the underlying assembly that this scope defines. diff --git a/src/AsmResolver.DotNet/InvalidTypeDefOrRef.cs b/src/AsmResolver.DotNet/InvalidTypeDefOrRef.cs index 7e63115fc..a4fd0d641 100644 --- a/src/AsmResolver.DotNet/InvalidTypeDefOrRef.cs +++ b/src/AsmResolver.DotNet/InvalidTypeDefOrRef.cs @@ -73,6 +73,9 @@ public static InvalidTypeDefOrRef Get(InvalidTypeSignatureError error) return instance; } + /// + public bool IsImportedInModule(ModuleDefinition module) => false; + IMemberDefinition? IMemberDescriptor.Resolve() => null; TypeDefinition? ITypeDescriptor.Resolve() => null; diff --git a/src/AsmResolver.DotNet/MemberReference.cs b/src/AsmResolver.DotNet/MemberReference.cs index 000940b0a..8254f8a3a 100644 --- a/src/AsmResolver.DotNet/MemberReference.cs +++ b/src/AsmResolver.DotNet/MemberReference.cs @@ -153,6 +153,13 @@ public IList CustomAttributes throw new ArgumentOutOfRangeException(); } + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (Signature?.IsImportedInModule(module) ?? false); + } + FieldDefinition? IFieldDescriptor.Resolve() { if (!IsField) diff --git a/src/AsmResolver.DotNet/MethodDefinition.cs b/src/AsmResolver.DotNet/MethodDefinition.cs index e79a423a4..59b6eb989 100644 --- a/src/AsmResolver.DotNet/MethodDefinition.cs +++ b/src/AsmResolver.DotNet/MethodDefinition.cs @@ -691,6 +691,13 @@ public IList GenericParameters MethodDefinition IMethodDescriptor.Resolve() => this; + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (Signature?.IsImportedInModule(module) ?? false); + } + IMemberDefinition IMemberDescriptor.Resolve() => this; /// diff --git a/src/AsmResolver.DotNet/MethodSpecification.cs b/src/AsmResolver.DotNet/MethodSpecification.cs index 02da0eb30..430c9952e 100644 --- a/src/AsmResolver.DotNet/MethodSpecification.cs +++ b/src/AsmResolver.DotNet/MethodSpecification.cs @@ -99,6 +99,13 @@ public IList CustomAttributes /// public MethodDefinition? Resolve() => Method?.Resolve(); + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return (Method?.IsImportedInModule(module) ?? false) + && (Signature?.IsImportedInModule(module) ?? false); + } + IMemberDefinition? IMemberDescriptor.Resolve() => Resolve(); /// diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs index d6b06f18a..36b89e058 100644 --- a/src/AsmResolver.DotNet/ModuleDefinition.cs +++ b/src/AsmResolver.DotNet/ModuleDefinition.cs @@ -1104,6 +1104,9 @@ protected IAssemblyResolver CreateAssemblyResolver(IFileService fileService) /// public override string ToString() => Name ?? string.Empty; + /// + bool IImportable.IsImportedInModule(ModuleDefinition module) => this == module; + /// /// Rebuilds the .NET module to a portable executable file and writes it to the file system. /// diff --git a/src/AsmResolver.DotNet/ModuleReference.cs b/src/AsmResolver.DotNet/ModuleReference.cs index 4feacbf12..9191d9ad7 100644 --- a/src/AsmResolver.DotNet/ModuleReference.cs +++ b/src/AsmResolver.DotNet/ModuleReference.cs @@ -76,6 +76,9 @@ public IList CustomAttributes } } + /// + public bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// /// Obtains the name of the module. /// diff --git a/src/AsmResolver.DotNet/PropertyDefinition.cs b/src/AsmResolver.DotNet/PropertyDefinition.cs index 05c94c9b2..93348cedb 100644 --- a/src/AsmResolver.DotNet/PropertyDefinition.cs +++ b/src/AsmResolver.DotNet/PropertyDefinition.cs @@ -187,6 +187,13 @@ public IList CustomAttributes IMemberDefinition IMemberDescriptor.Resolve() => this; + /// + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (Signature?.IsImportedInModule(module) ?? false); + } + /// /// Obtains the name of the property definition. /// diff --git a/src/AsmResolver.DotNet/ReferenceImporter.cs b/src/AsmResolver.DotNet/ReferenceImporter.cs index b1c858e76..0d7f54673 100644 --- a/src/AsmResolver.DotNet/ReferenceImporter.cs +++ b/src/AsmResolver.DotNet/ReferenceImporter.cs @@ -47,7 +47,7 @@ public IResolutionScope ImportScope(IResolutionScope? scope) { if (scope is null) throw new ArgumentNullException(nameof(scope)); - if (scope.Module == TargetModule) + if (scope.IsImportedInModule(TargetModule)) return scope; return scope switch @@ -69,7 +69,7 @@ protected virtual AssemblyReference ImportAssembly(AssemblyDescriptor assembly) { if (assembly is null) throw new ArgumentNullException(nameof(assembly)); - if (assembly is AssemblyReference r && r.Module == TargetModule) + if (assembly is AssemblyReference r && assembly.IsImportedInModule(TargetModule)) return r; var reference = TargetModule.AssemblyReferences.FirstOrDefault(a => _comparer.Equals(a, assembly)); @@ -92,7 +92,7 @@ public virtual ModuleReference ImportModule(ModuleReference module) { if (module is null) throw new ArgumentNullException(nameof(module)); - if (module.Module == TargetModule) + if (module.IsImportedInModule(TargetModule)) return module; var reference = TargetModule.ModuleReferences.FirstOrDefault(a => _comparer.Equals(a, module)); @@ -139,7 +139,7 @@ protected virtual ITypeDefOrRef ImportType(TypeDefinition type) { AssertTypeIsValid(type); - if (type.Module == TargetModule) + if (type.IsImportedInModule(TargetModule)) return type; return new TypeReference(TargetModule, ImportScope(type.Module!), type.Namespace, type.Name); @@ -154,7 +154,7 @@ protected virtual ITypeDefOrRef ImportType(TypeReference type) { AssertTypeIsValid(type); - if (type.Module == TargetModule) + if (type.IsImportedInModule(TargetModule)) return type; return new TypeReference(TargetModule, ImportScope(type.Scope!), type.Namespace, type.Name); @@ -171,7 +171,7 @@ protected virtual ITypeDefOrRef ImportType(TypeSpecification type) if (type.Signature is null) throw new ArgumentNullException(nameof(type)); - if (type.Module == TargetModule) + if (type.IsImportedInModule(TargetModule)) return type; return new TypeSpecification(ImportTypeSignature(type.Signature)); @@ -186,7 +186,7 @@ public virtual TypeSignature ImportTypeSignature(TypeSignature type) { if (type is null) throw new ArgumentNullException(nameof(type)); - if (type.Module == TargetModule) + if (type.IsImportedInModule(TargetModule)) return type; return type.AcceptVisitor(this); @@ -212,11 +212,8 @@ public virtual ITypeDefOrRef ImportType(Type type) throw new ArgumentNullException(nameof(type)); var importedTypeSig = ImportTypeSignature(type); - if (importedTypeSig is TypeDefOrRefSignature - || importedTypeSig is CorLibTypeSignature) - { + if (importedTypeSig is TypeDefOrRefSignature or CorLibTypeSignature) return importedTypeSig.GetUnderlyingTypeDefOrRef()!; - } return new TypeSpecification(importedTypeSig); } @@ -266,6 +263,7 @@ private TypeSignature ImportArrayType(Type type) var result = new ArrayTypeSignature(baseType); for (int i = 0; i < rank; i++) result.Dimensions.Add(new ArrayDimension()); + return result; } @@ -318,7 +316,7 @@ public virtual IMethodDefOrRef ImportMethod(IMethodDefOrRef method) if (method.Signature is null) throw new ArgumentException("Cannot import a method that does not have a signature."); - if (method.Module == TargetModule) + if (method.IsImportedInModule(TargetModule)) return method; return new MemberReference( @@ -406,7 +404,7 @@ public virtual MethodSpecification ImportMethod(MethodSpecification method) if (method.DeclaringType is null) throw new ArgumentException("Cannot import a method that is not added to a type."); - if (method.Module == TargetModule) + if (method.IsImportedInModule(TargetModule)) return method; var memberRef = ImportMethod(method.Method); @@ -479,7 +477,7 @@ public virtual IFieldDescriptor ImportField(IFieldDescriptor field) if (field.Signature is null) throw new ArgumentException("Cannot import a field that does not have a signature."); - if (field.Module == TargetModule) + if (field.IsImportedInModule(TargetModule)) return field; return new MemberReference( diff --git a/src/AsmResolver.DotNet/ReflectionAssemblyDescriptor.cs b/src/AsmResolver.DotNet/ReflectionAssemblyDescriptor.cs index adf51b04e..d192bf2ba 100644 --- a/src/AsmResolver.DotNet/ReflectionAssemblyDescriptor.cs +++ b/src/AsmResolver.DotNet/ReflectionAssemblyDescriptor.cs @@ -32,6 +32,9 @@ public ReflectionAssemblyDescriptor(ModuleDefinition parentModule, AssemblyName /// protected override Utf8String? GetCulture() => _assemblyName.CultureName; + /// + public override bool IsImportedInModule(ModuleDefinition module) => false; + /// public override bool IsCorLib => Name is not null && KnownCorLibs.KnownCorLibNames.Contains(Name); diff --git a/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs b/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs index f7d33ae5c..4ed13994d 100644 --- a/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs @@ -7,7 +7,7 @@ namespace AsmResolver.DotNet.Signatures /// Provides a base for all signature that deal with a calling convention. This includes most member signatures, /// such as method and field signatures. /// - public abstract class CallingConventionSignature : ExtendableBlobSignature + public abstract class CallingConventionSignature : ExtendableBlobSignature, IImportable { private const CallingConventionAttributes SignatureTypeMask = (CallingConventionAttributes)0xF; @@ -148,5 +148,8 @@ public bool IsSentinel set => Attributes = (Attributes & ~CallingConventionAttributes.Sentinel) | (value ? CallingConventionAttributes.Sentinel : 0); } + + /// + public abstract bool IsImportedInModule(ModuleDefinition module); } } diff --git a/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs b/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs index c17695745..240bd396e 100644 --- a/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs @@ -91,6 +91,18 @@ protected override void WriteContents(BlobSerializationContext context) TypeArguments[i].Write(context); } + /// + public override bool IsImportedInModule(ModuleDefinition module) + { + for (int i = 0; i < TypeArguments.Count; i++) + { + if (!TypeArguments[i].IsImportedInModule(module)) + return false; + } + + return true; + } + /// public override string ToString() { diff --git a/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs b/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs index ccf81a2a5..e8c8de393 100644 --- a/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs @@ -68,6 +68,18 @@ public IList VariableTypes get; } + /// + public override bool IsImportedInModule(ModuleDefinition module) + { + for (int i = 0; i < VariableTypes.Count; i++) + { + if (!VariableTypes[i].IsImportedInModule(module)) + return false; + } + + return true; + } + /// protected override void WriteContents(BlobSerializationContext context) { diff --git a/src/AsmResolver.DotNet/Signatures/MemberSignature.cs b/src/AsmResolver.DotNet/Signatures/MemberSignature.cs index a34b3bdba..2d5e412d1 100644 --- a/src/AsmResolver.DotNet/Signatures/MemberSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/MemberSignature.cs @@ -27,6 +27,9 @@ protected TypeSignature MemberReturnType set; } + /// + public override bool IsImportedInModule(ModuleDefinition module) => MemberReturnType.IsImportedInModule(module); + /// public override string ToString() { diff --git a/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs b/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs index 50452b60f..4e58f029a 100644 --- a/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs +++ b/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs @@ -78,6 +78,29 @@ public IList SentinelParameterTypes get; } = new List(); + /// + public override bool IsImportedInModule(ModuleDefinition module) + { + if (!ReturnType.IsImportedInModule(module)) + return false; + + for (int i = 0; i < ParameterTypes.Count; i++) + { + var x = ParameterTypes[i]; + if (!x.IsImportedInModule(module)) + return false; + } + + for (int i = 0; i < SentinelParameterTypes.Count; i++) + { + var x = SentinelParameterTypes[i]; + if (!x.IsImportedInModule(module)) + return false; + } + + return true; + } + /// /// Initializes the and properties by reading /// the parameter count, return type and parameter fields of the signature from the provided input stream. diff --git a/src/AsmResolver.DotNet/Signatures/Types/CorLibTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/CorLibTypeSignature.cs index 69db2a00c..ae2a6974c 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/CorLibTypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/CorLibTypeSignature.cs @@ -78,6 +78,9 @@ ElementType switch return Type.Resolve(); } + /// + public override bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() { diff --git a/src/AsmResolver.DotNet/Signatures/Types/CustomModifierTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/CustomModifierTypeSignature.cs index 34baa3006..64ec085e1 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/CustomModifierTypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/CustomModifierTypeSignature.cs @@ -75,6 +75,10 @@ public override string Name TState state) => visitor.VisitCustomModifierType(this, state); + /// + public override bool IsImportedInModule(ModuleDefinition module) => + ModifierType.IsImportedInModule(module) && base.IsImportedInModule(module); + /// protected override void WriteContents(BlobSerializationContext context) { diff --git a/src/AsmResolver.DotNet/Signatures/Types/FunctionPointerTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/FunctionPointerTypeSignature.cs index d5aeb810c..ff2acc2c8 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/FunctionPointerTypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/FunctionPointerTypeSignature.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using AsmResolver.PE.DotNet.Metadata.Tables.Rows; namespace AsmResolver.DotNet.Signatures.Types @@ -48,6 +49,9 @@ public MethodSignature Signature public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() => Signature?.ReturnType?.Module?.CorLibTypeFactory.IntPtr.Type; + /// + public override bool IsImportedInModule(ModuleDefinition module) => Signature.IsImportedInModule(module); + /// protected override void WriteContents(BlobSerializationContext context) { diff --git a/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs index 6872344f2..7ed057d8b 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs @@ -108,6 +108,21 @@ public override bool IsValueType /// public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() => GenericType; + /// + public override bool IsImportedInModule(ModuleDefinition module) + { + if (!GenericType.IsImportedInModule(module)) + return false; + + for (int i = 0; i < TypeArguments.Count; i++) + { + if (!TypeArguments[i].IsImportedInModule(module)) + return false; + } + + return true; + } + /// protected override void WriteContents(BlobSerializationContext context) { diff --git a/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs index f3af9b9d8..803e056a2 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs @@ -82,6 +82,9 @@ public int Index /// public override TypeDefinition? Resolve() => null; + /// + public override bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() => null; diff --git a/src/AsmResolver.DotNet/Signatures/Types/SentinelTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/SentinelTypeSignature.cs index 79e5f7709..49e7faa18 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/SentinelTypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/SentinelTypeSignature.cs @@ -33,6 +33,9 @@ public class SentinelTypeSignature : TypeSignature /// public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() => null; + /// + public override bool IsImportedInModule(ModuleDefinition module) => true; + /// protected override void WriteContents(BlobSerializationContext context) => context.Writer.WriteByte((byte) ElementType); diff --git a/src/AsmResolver.DotNet/Signatures/Types/TypeDefOrRefSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/TypeDefOrRefSignature.cs index 0222d9b59..cab577dc4 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/TypeDefOrRefSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/TypeDefOrRefSignature.cs @@ -60,6 +60,9 @@ public override bool IsValueType /// public override TypeDefinition? Resolve() => Type.Resolve(); + /// + public override bool IsImportedInModule(ModuleDefinition module) => Type.IsImportedInModule(module); + /// public override ITypeDefOrRef ToTypeDefOrRef() => Type; diff --git a/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs index 2373fc3bf..f5419ddfe 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs @@ -376,6 +376,9 @@ internal static void WriteFieldOrPropType(BlobSerializationContext context, Type public TypeSignature InstantiateGenericTypes(GenericContext context) => AcceptVisitor(GenericTypeActivator.Instance, context); + /// + public abstract bool IsImportedInModule(ModuleDefinition module); + /// /// Visit the current type signature using the provided visitor. /// diff --git a/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs index cd0bf2d18..1fa4130e5 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs @@ -37,6 +37,9 @@ public TypeSignature BaseType public override ITypeDefOrRef? GetUnderlyingTypeDefOrRef() => BaseType.GetUnderlyingTypeDefOrRef(); + /// + public override bool IsImportedInModule(ModuleDefinition module) => BaseType.IsImportedInModule(module); + /// protected override void WriteContents(BlobSerializationContext context) { diff --git a/src/AsmResolver.DotNet/TypeDefinition.cs b/src/AsmResolver.DotNet/TypeDefinition.cs index 65852f98c..d1757a8f8 100644 --- a/src/AsmResolver.DotNet/TypeDefinition.cs +++ b/src/AsmResolver.DotNet/TypeDefinition.cs @@ -680,6 +680,9 @@ public TypeSignature ToTypeSignature() ?? new TypeDefOrRefSignature(this, IsValueType); } + /// + public bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// public bool IsAccessibleFromType(TypeDefinition type) { diff --git a/src/AsmResolver.DotNet/TypeReference.cs b/src/AsmResolver.DotNet/TypeReference.cs index 57a5fe8b6..113a8892d 100644 --- a/src/AsmResolver.DotNet/TypeReference.cs +++ b/src/AsmResolver.DotNet/TypeReference.cs @@ -136,6 +136,9 @@ public TypeSignature ToTypeSignature() ?? new TypeDefOrRefSignature(this, IsValueType); } + /// + public bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// public TypeDefinition? Resolve() => Module?.MetadataResolver.ResolveType(this); diff --git a/src/AsmResolver.DotNet/TypeSpecification.cs b/src/AsmResolver.DotNet/TypeSpecification.cs index 9d9a4713d..d268bf85a 100644 --- a/src/AsmResolver.DotNet/TypeSpecification.cs +++ b/src/AsmResolver.DotNet/TypeSpecification.cs @@ -95,6 +95,9 @@ public IList CustomAttributes public TypeSignature ToTypeSignature() => Signature ?? throw new ArgumentException("Signature embedded into the type specification is null."); + /// + public bool IsImportedInModule(ModuleDefinition module) => Signature?.IsImportedInModule(module) ?? false; + /// public TypeDefinition? Resolve() => Module?.MetadataResolver.ResolveType(this); From 78b3400aa1b9abbe50a4ca174f0c1f6d635de5ce Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 21:00:51 +0100 Subject: [PATCH 06/51] Add more type sig importing tests. --- .../ReferenceImporterTest.cs | 106 +++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index 7ee5a63d2..c469f479c 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -266,7 +266,30 @@ public void ImportFieldFromReflectionShouldResultInMemberRef() } [Fact] - public void ImportTypeSigWithNonImportedEmbeddedReferenceShouldResultInNewInstance() + public void ImportNonImportedTypeDefOrRefShouldResultInNewInstance() + { + var signature = new TypeReference(_module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream") + .ToTypeSignature(); + + var imported = _importer.ImportTypeSignature(signature); + + Assert.NotSame(signature, imported); + Assert.Equal(signature, imported, _comparer); + Assert.Equal(_module, imported.Module); + } + + [Fact] + public void ImportFullyImportedTypeDefOrRefShouldResultInSameInstance() + { + var signature = new TypeReference(_module, _module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream") + .ToTypeSignature(); + + var imported = _importer.ImportTypeSignature(signature); + Assert.Same(signature, imported); + } + + [Fact] + public void ImportGenericTypeSigWithNonImportedTypeArgumentShouldResultInNewInstance() { // https://github.com/Washi1337/AsmResolver/issues/268 @@ -288,7 +311,7 @@ public void ImportTypeSigWithNonImportedEmbeddedReferenceShouldResultInNewInstan } [Fact] - public void ImportTypeSigWithImportedEmbeddedReferenceShouldResultInSameInstance() + public void ImportFullyImportedGenericTypeSigShouldResultInSameInstance() { // https://github.com/Washi1337/AsmResolver/issues/268 @@ -306,5 +329,84 @@ public void ImportTypeSigWithImportedEmbeddedReferenceShouldResultInSameInstance var newInstance = Assert.IsAssignableFrom(imported); Assert.Same(instance, newInstance); } + + [Fact] + public void ImportCustomModifierTypeWithNonImportedModifierTypeShouldResultInNewInstance() + { + var signature = new TypeReference(_module, _dummyAssembly, "SomeNamespace", "SomeType") + .ToTypeSignature() + .MakeModifierType(new TypeReference(_dummyAssembly, "SomeNamespace", "SomeModifierType"), true); + + var imported = _importer.ImportTypeSignature(signature); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.NotSame(signature, newInstance); + Assert.Equal(_module, newInstance.Module); + Assert.Equal(_module, newInstance.ModifierType.Module); + } + + [Fact] + public void ImportFullyImportedCustomModifierTypeShouldResultInSameInstance() + { + var signature = new TypeReference(_module, _dummyAssembly, "SomeNamespace", "SomeType") + .ToTypeSignature() + .MakeModifierType(new TypeReference(_module, _dummyAssembly, "SomeNamespace", "SomeModifierType"), true); + + var imported = _importer.ImportTypeSignature(signature); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.Same(signature, newInstance); + } + + [Fact] + public void ImportFunctionPointerTypeWithNonImportedParameterShouldResultInNewInstance() + { + var signature = MethodSignature + .CreateStatic( + _module.CorLibTypeFactory.Void, + new TypeReference(_dummyAssembly, "SomeNamespace", "SomeType").ToTypeSignature()) + .MakeFunctionPointerType(); + + var imported = _importer.ImportTypeSignature(signature); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.NotSame(signature, newInstance); + Assert.Equal(signature, newInstance, _comparer); + Assert.Equal(_module, newInstance.Module); + Assert.Equal(_module, newInstance.Signature.ParameterTypes[0].Module); + } + + [Fact] + public void ImportFunctionPointerTypeWithNonImportedReturnTypeShouldResultInNewInstance() + { + var signature = MethodSignature + .CreateStatic( + new TypeReference(_dummyAssembly, "SomeNamespace", "SomeType").ToTypeSignature(), + _module.CorLibTypeFactory.Int32) + .MakeFunctionPointerType(); + + var imported = _importer.ImportTypeSignature(signature); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.NotSame(signature, newInstance); + Assert.Equal(signature, newInstance, _comparer); + Assert.Equal(_module, newInstance.Module); + Assert.Equal(_module, newInstance.Signature.ReturnType.Module); + } + + [Fact] + public void ImportFullyImportedFunctionPointerTypeShouldResultInSameInstance() + { + var signature = MethodSignature + .CreateStatic( + _module.CorLibTypeFactory.Void, + new TypeReference(_module, _dummyAssembly, "SomeNamespace", "SomeType").ToTypeSignature()) + .MakeFunctionPointerType(); + + var imported = _importer.ImportTypeSignature(signature); + + var newInstance = Assert.IsAssignableFrom(imported); + Assert.Same(signature, newInstance); + } } } From 4e86ea3d6ae951885cefbf69dae3033b3c769390 Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 21:01:17 +0100 Subject: [PATCH 07/51] BUGFIX: Let TypeSpecificationSignature.Module return the module of the base type. --- .../Signatures/Types/TypeSpecificationSignature.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs index 1fa4130e5..412964357 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/TypeSpecificationSignature.cs @@ -23,6 +23,9 @@ public TypeSignature BaseType set; } + /// + public override ModuleDefinition? Module => BaseType.Module; + /// public override string? Namespace => BaseType.Namespace; From 49d34d1ab6be0ed9b62281fd1d975b77e5ad1ee2 Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 17 Mar 2022 21:01:35 +0100 Subject: [PATCH 08/51] BUGFIX: Let SignatureComparer.Equals implement comparisons for FunctionPointerTypeSignature. --- .../SignatureComparer.TypeSignature.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/AsmResolver.DotNet/Signatures/SignatureComparer.TypeSignature.cs b/src/AsmResolver.DotNet/Signatures/SignatureComparer.TypeSignature.cs index f7afe504a..e31005637 100644 --- a/src/AsmResolver.DotNet/Signatures/SignatureComparer.TypeSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/SignatureComparer.TypeSignature.cs @@ -20,6 +20,7 @@ public partial class SignatureComparer : IEqualityComparer, IEqualityComparer, IEqualityComparer, + IEqualityComparer, IEqualityComparer>, IEqualityComparer> { @@ -59,6 +60,7 @@ public bool Equals(TypeSignature? x, TypeSignature? y) case ElementType.Boxed: return Equals(x as BoxedTypeSignature, y as BoxedTypeSignature); case ElementType.FnPtr: + return Equals(x as FunctionPointerTypeSignature, y as FunctionPointerTypeSignature); case ElementType.Internal: case ElementType.Modifier: throw new NotSupportedException(); @@ -309,6 +311,22 @@ public int GetHashCode(ArrayTypeSignature obj) } } + /// + public bool Equals(FunctionPointerTypeSignature? x, FunctionPointerTypeSignature? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + return Equals(x.Signature, y.Signature); + } + + /// + public int GetHashCode(FunctionPointerTypeSignature obj) + { + return obj.Signature.GetHashCode(); + } + /// public bool Equals(IList? x, IList? y) { From 1051ad23caea989527751b648a70dcf8620495a5 Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 18 Mar 2022 20:52:37 +0100 Subject: [PATCH 09/51] Remove excessive null-forgiving operator. --- src/AsmResolver.DotNet/ReferenceImporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/ReferenceImporter.cs b/src/AsmResolver.DotNet/ReferenceImporter.cs index e132b2b71..35636cd41 100644 --- a/src/AsmResolver.DotNet/ReferenceImporter.cs +++ b/src/AsmResolver.DotNet/ReferenceImporter.cs @@ -144,7 +144,7 @@ protected virtual ITypeDefOrRef ImportType(TypeDefinition type) return new TypeReference( TargetModule, - ImportScope(((ITypeDescriptor) type).Scope!), + ImportScope(((ITypeDescriptor) type).Scope), type.Namespace, type.Name); } From 275937dae3ef716edcdd43f602b0632201c7175e Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 18 Mar 2022 21:00:14 +0100 Subject: [PATCH 10/51] Address merge conflicts. --- test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index dfb2969cc..13b0a7bb5 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -305,7 +305,7 @@ public void ImportNonImportedTypeDefOrRefShouldResultInNewInstance() var imported = _importer.ImportTypeSignature(signature); Assert.NotSame(signature, imported); - Assert.Equal(signature, imported, _comparer); + Assert.Equal(signature, imported, Comparer); Assert.Equal(_module, imported.Module); } @@ -402,7 +402,7 @@ public void ImportFunctionPointerTypeWithNonImportedParameterShouldResultInNewIn var newInstance = Assert.IsAssignableFrom(imported); Assert.NotSame(signature, newInstance); - Assert.Equal(signature, newInstance, _comparer); + Assert.Equal(signature, newInstance, Comparer); Assert.Equal(_module, newInstance.Module); Assert.Equal(_module, newInstance.Signature.ParameterTypes[0].Module); } @@ -420,7 +420,7 @@ public void ImportFunctionPointerTypeWithNonImportedReturnTypeShouldResultInNewI var newInstance = Assert.IsAssignableFrom(imported); Assert.NotSame(signature, newInstance); - Assert.Equal(signature, newInstance, _comparer); + Assert.Equal(signature, newInstance, Comparer); Assert.Equal(_module, newInstance.Module); Assert.Equal(_module, newInstance.Signature.ReturnType.Module); } From 2ac4251c1c709f985f8a2c4b0250d372c29bb666 Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 18 Mar 2022 21:15:31 +0100 Subject: [PATCH 11/51] Clarify remarks for IsImportedInModule. --- src/AsmResolver.DotNet/IImportable.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/IImportable.cs b/src/AsmResolver.DotNet/IImportable.cs index 1d6fa8875..9fdbc2c76 100644 --- a/src/AsmResolver.DotNet/IImportable.cs +++ b/src/AsmResolver.DotNet/IImportable.cs @@ -11,7 +11,8 @@ public interface IImportable /// The module that is supposed to import the member. /// true if the descriptor of the member is fully imported by the module, false otherwise. /// - /// This method verifies all references in the descriptor of the member, but does not verify the contents (e.g. a method body). + /// This method verifies all references in the descriptor of the member only. It does not verify any additional + /// data or contents (such as a method body) associated to the member. /// bool IsImportedInModule(ModuleDefinition module); } From b09801bf1d9e4acdbcb6b26938d8ed912bc4d356 Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 18 Mar 2022 21:16:25 +0100 Subject: [PATCH 12/51] Add IImportable to IImplementation and derivatives. --- src/AsmResolver.DotNet/ExportedType.cs | 6 ++++- src/AsmResolver.DotNet/FileReference.cs | 3 +++ src/AsmResolver.DotNet/IImplementation.cs | 2 +- .../Types/GenericParameterSignature.cs | 9 ++++--- .../ReferenceImporterTest.cs | 25 +++++++++++++++++++ 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/AsmResolver.DotNet/ExportedType.cs b/src/AsmResolver.DotNet/ExportedType.cs index d0845621b..bf83bd24d 100644 --- a/src/AsmResolver.DotNet/ExportedType.cs +++ b/src/AsmResolver.DotNet/ExportedType.cs @@ -146,7 +146,11 @@ public IList CustomAttributes public TypeDefinition? Resolve() => Module?.MetadataResolver.ResolveType(this); /// - public bool IsImportedInModule(ModuleDefinition module) => Module == module; + public bool IsImportedInModule(ModuleDefinition module) + { + return Module == module + && (Implementation?.IsImportedInModule(module) ?? false); + } IMemberDefinition? IMemberDescriptor.Resolve() => Resolve(); diff --git a/src/AsmResolver.DotNet/FileReference.cs b/src/AsmResolver.DotNet/FileReference.cs index e8f78cdb0..ef1f3c225 100644 --- a/src/AsmResolver.DotNet/FileReference.cs +++ b/src/AsmResolver.DotNet/FileReference.cs @@ -120,6 +120,9 @@ public IList CustomAttributes } } + /// + public bool IsImportedInModule(ModuleDefinition module) => Module == module; + /// /// Obtains the name of the referenced file. /// diff --git a/src/AsmResolver.DotNet/IImplementation.cs b/src/AsmResolver.DotNet/IImplementation.cs index 1674e3120..7d99282d7 100644 --- a/src/AsmResolver.DotNet/IImplementation.cs +++ b/src/AsmResolver.DotNet/IImplementation.cs @@ -4,7 +4,7 @@ namespace AsmResolver.DotNet /// Represents a member that is either a reference to an external file, assembly or type, and can be referenced by /// an Implementation coded index. /// - public interface IImplementation : IFullNameProvider, IModuleProvider, IHasCustomAttribute + public interface IImplementation : IFullNameProvider, IModuleProvider, IHasCustomAttribute, IImportable { } } diff --git a/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs index 803e056a2..24f487016 100644 --- a/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs +++ b/src/AsmResolver.DotNet/Signatures/Types/GenericParameterSignature.cs @@ -9,8 +9,6 @@ namespace AsmResolver.DotNet.Signatures.Types /// public class GenericParameterSignature : TypeSignature { - private readonly IResolutionScope? _scope; - /// /// Creates a new reference to a generic parameter. /// @@ -30,7 +28,7 @@ public GenericParameterSignature(GenericParameterType parameterType, int index) /// The index of the referenced parameter. public GenericParameterSignature(ModuleDefinition module, GenericParameterType parameterType, int index) { - _scope = module; + Scope = module; ParameterType = parameterType; Index = index; } @@ -74,7 +72,10 @@ public int Index public override string? Namespace => null; /// - public override IResolutionScope? Scope => _scope; + public override IResolutionScope? Scope + { + get; + } /// public override bool IsValueType => false; diff --git a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs index 13b0a7bb5..83ec26082 100644 --- a/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs +++ b/test/AsmResolver.DotNet.Tests/ReferenceImporterTest.cs @@ -309,6 +309,20 @@ public void ImportNonImportedTypeDefOrRefShouldResultInNewInstance() Assert.Equal(_module, imported.Module); } + [Fact] + public void ImportTypeSpecWithNonImportedBaseTypeShouldResultInNewInstance() + { + var signature = new TypeReference(_module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream") + .ToTypeSignature() + .MakeSzArrayType(); + + var imported = _importer.ImportTypeSignature(signature); + var newInstance = Assert.IsAssignableFrom(imported); + Assert.NotSame(signature, newInstance); + Assert.Equal(signature, newInstance, Comparer); + Assert.Equal(_module, newInstance.BaseType.Module); + } + [Fact] public void ImportFullyImportedTypeDefOrRefShouldResultInSameInstance() { @@ -319,6 +333,17 @@ public void ImportFullyImportedTypeDefOrRefShouldResultInSameInstance() Assert.Same(signature, imported); } + [Fact] + public void ImportFullyImportedTypeSpecShouldResultInSameInstance() + { + var signature = new TypeReference(_module, _module.CorLibTypeFactory.CorLibScope, "System.IO", "Stream") + .ToTypeSignature() + .MakeSzArrayType(); + + var imported = _importer.ImportTypeSignature(signature); + Assert.Same(signature, imported); + } + [Fact] public void ImportGenericTypeSigWithNonImportedTypeArgumentShouldResultInNewInstance() { From 36dcd8b294c34db047527f74130bb1358f3a677a Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 19 Mar 2022 14:24:08 +0100 Subject: [PATCH 13/51] Initial setup for .NET bundle manifests. --- .../DotNet/Bundles/BundleFile.cs | 38 ++++++ .../DotNet/Bundles/BundleFileType.cs | 12 ++ .../DotNet/Bundles/BundleManifest.cs | 125 ++++++++++++++++++ .../DotNet/Bundles/BundleManifestFlags.cs | 11 ++ .../DotNet/Bundles/SerializedBundleFile.cs | 22 +++ .../Bundles/SerializedBundleManifest.cs | 39 ++++++ .../DotNet/Bundles/BundleManifestTest.cs | 45 +++++++ .../Properties/Resources.Designer.cs | 21 +++ .../Properties/Resources.resx | 9 ++ .../Resources/HelloWorld.SingleFile.v1.exe | Bin 0 -> 178015 bytes .../Resources/HelloWorld.SingleFile.v2.exe | Bin 0 -> 129408 bytes .../Resources/HelloWorld.SingleFile.v6.exe | Bin 0 -> 152984 bytes 12 files changed, 322 insertions(+) create mode 100644 src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs create mode 100644 src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs create mode 100644 src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs create mode 100644 src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs create mode 100644 src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs create mode 100644 src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs create mode 100644 test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs create mode 100644 test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v1.exe create mode 100644 test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v2.exe create mode 100644 test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v6.exe diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs b/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs new file mode 100644 index 000000000..0b90418f7 --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs @@ -0,0 +1,38 @@ +namespace AsmResolver.PE.DotNet.Bundles +{ + public class BundleFile + { + private readonly LazyVariable _contents; + + public BundleFile() + { + _contents = new LazyVariable(GetContents); + } + + public string RelativePath + { + get; + set; + } + + public BundleFileType Type + { + get; + set; + } + + public bool IsCompressed + { + get; + set; + } + + public ISegment Contents + { + get => _contents.Value; + set => _contents.Value = value; + } + + protected virtual ISegment? GetContents() => null; + } +} diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs b/src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs new file mode 100644 index 000000000..58ad0aead --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs @@ -0,0 +1,12 @@ +namespace AsmResolver.PE.DotNet.Bundles +{ + public enum BundleFileType + { + Unknown, + Assembly, + NativeBinary, + DepsJson, + RuntimeConfigJson, + Symbols + } +} diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs new file mode 100644 index 000000000..ad1e22fe7 --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using AsmResolver.IO; + +namespace AsmResolver.PE.DotNet.Bundles +{ + public class BundleManifest + { + private static readonly byte[] BundleSignature = { + 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, + 0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32, + 0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18, + 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae + }; + + private IList? _files; + + protected BundleManifest() + { + } + + public BundleManifest(uint version, string bundleId) + { + MajorVersion = version; + MinorVersion = 0; + BundleID = bundleId; + } + + public uint MajorVersion + { + get; + set; + } + + public uint MinorVersion + { + get; + set; + } + + public string BundleID + { + get; + set; + } + + public BundleManifestFlags Flags + { + get; + set; + } + + public IList Files + { + get + { + if (_files is null) + Interlocked.CompareExchange(ref _files, GetFiles(), null); + return _files; + } + } + + public static BundleManifest FromFile(string filePath) + { + return FromBytes(System.IO.File.ReadAllBytes(filePath)); + } + + public static BundleManifest FromBytes(byte[] data) + { + return FromDataSource(new ByteArrayDataSource(data)); + } + + public static BundleManifest FromBytes(byte[] data, ulong offset) + { + return FromDataSource(new ByteArrayDataSource(data), offset); + } + + public static BundleManifest FromDataSource(IDataSource source) + { + long address = FindBundleManifestAddress(source); + if (address == -1) + throw new BadImageFormatException("File does not contain an AppHost bundle signature."); + + return FromDataSource(source, (ulong) address); + } + + public static BundleManifest FromDataSource(IDataSource source, ulong offset) + { + var reader = new BinaryStreamReader(source, 0, 0, (uint) source.Length) + { + Offset = offset + }; + + return FromReader(reader); + } + + public static BundleManifest FromReader(BinaryStreamReader reader) => new SerializedBundleManifest(reader); + + public static long FindBundleManifestAddress(IDataSource source) + { + for (ulong i = sizeof(ulong); i < source.Length - (ulong) BundleSignature.Length; i++) + { + bool fullMatch = true; + for (int j = 0; fullMatch && j < BundleSignature.Length; j++) + { + if (source[i + (ulong) j] != BundleSignature[j]) + fullMatch = false; + } + + if (fullMatch) + { + var reader = new BinaryStreamReader(source, i - sizeof(ulong), 0, 8); + ulong address = reader.ReadUInt64(); + if (source.IsValidAddress(address)) + return (long) address; + } + } + + return -1; + } + + protected virtual IList GetFiles() => new List(); + } +} diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs b/src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs new file mode 100644 index 000000000..c40ad02cb --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace AsmResolver.PE.DotNet.Bundles +{ + [Flags] + public enum BundleManifestFlags : ulong + { + None = 0, + NetCoreApp3CompatibilityMode = 1 + } +} diff --git a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs new file mode 100644 index 000000000..a6991a9e7 --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs @@ -0,0 +1,22 @@ +using AsmResolver.IO; + +namespace AsmResolver.PE.DotNet.Bundles +{ + public class SerializedBundleFile : BundleFile + { + public SerializedBundleFile(ref BinaryStreamReader reader, uint bundleVersionFormat) + { + ulong offset = reader.ReadUInt64(); + ulong size = reader.ReadUInt64(); + + if (bundleVersionFormat >= 6) + { + ulong compressedSize = reader.ReadUInt64(); + IsCompressed = compressedSize != 0; + } + + Type = (BundleFileType) reader.ReadByte(); + RelativePath = reader.ReadBinaryFormatterString(); + } + } +} diff --git a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs new file mode 100644 index 000000000..8a8c3bdfa --- /dev/null +++ b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using AsmResolver.IO; + +namespace AsmResolver.PE.DotNet.Bundles +{ + public class SerializedBundleManifest : BundleManifest + { + private readonly uint _originalMajorVersion; + private readonly BinaryStreamReader _fileEntriesReader; + private readonly uint _originalFileCount; + + public SerializedBundleManifest(BinaryStreamReader reader) + { + MajorVersion = _originalMajorVersion = reader.ReadUInt32(); + MinorVersion = reader.ReadUInt32(); + _originalFileCount = reader.ReadUInt32(); + BundleID = reader.ReadBinaryFormatterString(); + + if (MajorVersion >= 2) + { + reader.Offset += 4 * sizeof(ulong); + Flags = (BundleManifestFlags) reader.ReadUInt64(); + } + + _fileEntriesReader = reader; + } + + protected override IList GetFiles() + { + var reader = _fileEntriesReader; + var result = new List(); + + for (int i = 0; i < _originalFileCount; i++) + result.Add(new SerializedBundleFile(ref reader, _originalMajorVersion)); + + return result; + } + } +} diff --git a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs b/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs new file mode 100644 index 000000000..73166ad9c --- /dev/null +++ b/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs @@ -0,0 +1,45 @@ +using System.Linq; +using AsmResolver.PE.DotNet.Bundles; +using Xunit; + +namespace AsmResolver.PE.Tests.DotNet.Bundles +{ + public class BundleManifestTest + { + [Fact] + public void ReadBundleManifestHeaderV1() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V1); + Assert.Equal(1u, manifest.MajorVersion); + Assert.Equal("j7LK4is5ipe1CCtiafaTb8uhSOR7JhI=", manifest.BundleID); + Assert.Equal(new[] + { + "HelloWorld.dll", "HelloWorld.deps.json", "HelloWorld.runtimeconfig.json" + }, manifest.Files.Select(f => f.RelativePath)); + } + + [Fact] + public void ReadBundleManifestHeaderV2() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V2); + Assert.Equal(2u, manifest.MajorVersion); + Assert.Equal("poUQ+RBCefcEL4xrSAXdE2I5M+5D_Pk=", manifest.BundleID); + Assert.Equal(new[] + { + "HelloWorld.dll", "HelloWorld.deps.json", "HelloWorld.runtimeconfig.json" + }, manifest.Files.Select(f => f.RelativePath)); + } + + [Fact] + public void ReadBundleManifestHeaderV6() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + Assert.Equal(6u, manifest.MajorVersion); + Assert.Equal("lc43r48XAQNxN7Cx8QQvO9JgZI5lqPA=", manifest.BundleID); + Assert.Equal(new[] + { + "HelloWorld.dll", "HelloWorld.deps.json", "HelloWorld.runtimeconfig.json" + }, manifest.Files.Select(f => f.RelativePath)); + } + } +} diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs index 388c1419d..e47a1c7c9 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs @@ -94,6 +94,27 @@ public class Resources { } } + public static byte[] HelloWorld_SingleFile_V1 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V1", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] HelloWorld_SingleFile_V2 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V2", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] HelloWorld_SingleFile_V6 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V6", resourceCulture); + return ((byte[])(obj)); + } + } + public static byte[] SimpleDll { get { object obj = ResourceManager.GetObject("SimpleDll", resourceCulture); diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.resx b/test/AsmResolver.PE.Tests/Properties/Resources.resx index e9a93ecd7..1b2a1e7be 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.resx +++ b/test/AsmResolver.PE.Tests/Properties/Resources.resx @@ -39,6 +39,15 @@ ..\Resources\HelloWorld.TablesStream.ExtraData.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\HelloWorld.SingleFile.v1.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\HelloWorld.SingleFile.v2.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\HelloWorld.SingleFile.v6.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\SimpleDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v1.exe b/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v1.exe new file mode 100644 index 0000000000000000000000000000000000000000..67e3b49a25d845f18dc2cde124c962cd763fb1ea GIT binary patch literal 178015 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

*`G9?zzxGWwke>Bu)N*0UBnxfdBvi literal 0 HcmV?d00001 diff --git a/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v6.exe b/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v6.exe new file mode 100644 index 0000000000000000000000000000000000000000..e980f978ebf60bd5b692383cc7c04efd2baaefe5 GIT binary patch literal 152984 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 YH7w;qh$$2L5xkH~;_u literal 0 HcmV?d00001 From ed38bd62458e629b00a8fde81c0f6a76d1ece058 Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 19 Mar 2022 14:58:46 +0100 Subject: [PATCH 14/51] Support for reading bundled file contents. --- .../DotNet/Bundles/BundleFile.cs | 47 ++++++++++++++++ .../DotNet/Bundles/SerializedBundleFile.cs | 12 +++- .../DotNet/Bundles/BundleFileTest.cs | 56 +++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs b/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs index 0b90418f7..a78abcad8 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs @@ -1,3 +1,8 @@ +using System; +using System.IO; +using System.IO.Compression; +using AsmResolver.IO; + namespace AsmResolver.PE.DotNet.Bundles { public class BundleFile @@ -33,6 +38,48 @@ public ISegment Contents set => _contents.Value = value; } + public bool CanRead => Contents is IReadableSegment; + protected virtual ISegment? GetContents() => null; + + public bool TryGetReader(out BinaryStreamReader reader) + { + if (Contents is IReadableSegment segment) + { + reader = segment.CreateReader(); + return true; + } + + reader = default; + return false; + } + + public byte[] GetData() => GetData(true); + + public byte[] GetData(bool decompressIfRequired) + { + if (TryGetReader(out var reader)) + { + byte[] contents = reader.ReadToEnd(); + if (decompressIfRequired && IsCompressed) + { + using var outputStream = new MemoryStream(); + + using var inputStream = new MemoryStream(contents); + using var deflate = new DeflateStream(inputStream, CompressionMode.Decompress); + { + deflate.CopyTo(outputStream); + } + + contents = outputStream.ToArray(); + } + + return contents; + } + + throw new InvalidOperationException("Contents of file is not readable."); + } + + public override string ToString() => RelativePath; } } diff --git a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs index a6991a9e7..0918d2a2f 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs +++ b/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs @@ -4,6 +4,8 @@ namespace AsmResolver.PE.DotNet.Bundles { public class SerializedBundleFile : BundleFile { + private readonly BinaryStreamReader _contentsReader; + public SerializedBundleFile(ref BinaryStreamReader reader, uint bundleVersionFormat) { ulong offset = reader.ReadUInt64(); @@ -12,11 +14,19 @@ public SerializedBundleFile(ref BinaryStreamReader reader, uint bundleVersionFor if (bundleVersionFormat >= 6) { ulong compressedSize = reader.ReadUInt64(); - IsCompressed = compressedSize != 0; + if (compressedSize != 0) + { + size = compressedSize; + IsCompressed = true; + } } Type = (BundleFileType) reader.ReadByte(); RelativePath = reader.ReadBinaryFormatterString(); + + _contentsReader = reader.ForkAbsolute(offset, (uint) size); } + + protected override ISegment GetContents() => _contentsReader.ReadSegment(_contentsReader.Length); } } diff --git a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs b/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs new file mode 100644 index 000000000..a21f2195f --- /dev/null +++ b/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Text; +using AsmResolver.PE.DotNet.Bundles; +using AsmResolver.PE.DotNet.Metadata.Strings; +using AsmResolver.PE.DotNet.Metadata.Tables; +using AsmResolver.PE.DotNet.Metadata.Tables.Rows; +using Xunit; + +namespace AsmResolver.PE.Tests.DotNet.Bundles +{ + public class BundleFileTest + { + [Fact] + public void ReadUncompressedStringContents() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + var file = manifest.Files.First(f => f.Type == BundleFileType.RuntimeConfigJson); + string contents = Encoding.UTF8.GetString(file.GetData()); + + Assert.Equal(@"{ + ""runtimeOptions"": { + ""tfm"": ""net6.0"", + ""framework"": { + ""name"": ""Microsoft.NETCore.App"", + ""version"": ""6.0.0"" + }, + ""configProperties"": { + ""System.Reflection.Metadata.MetadataUpdater.IsSupported"": false + } + } +}", contents); + } + + [Fact] + public void ReadUncompressedAssemblyContents() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + var bundleFile = manifest.Files.First(f => f.RelativePath == "HelloWorld.dll"); + + var embeddedImage = PEImage.FromBytes(bundleFile.GetData()); + var metadata = embeddedImage.DotNetDirectory!.Metadata!; + + uint nameIndex = metadata + .GetStream() + .GetTable() + .GetByRid(1) + .Name; + + string? name = metadata + .GetStream() + .GetStringByIndex(nameIndex); + + Assert.Equal("HelloWorld.dll", name); + } + } +} From 3de7eebcba1e94181dd4898c53b9cd96d2f1c08d Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Wed, 23 Mar 2022 00:09:20 -0400 Subject: [PATCH 15/51] use actual types for private readonly --- .../Builder/Metadata/Blob/BlobStreamBuffer.cs | 2 +- .../Builder/Metadata/Guid/GuidStreamBuffer.cs | 2 +- .../Builder/Metadata/UserStrings/UserStringsStreamBuffer.cs | 2 +- .../Builder/Resources/DotNetResourcesDirectoryBuffer.cs | 2 +- src/AsmResolver.DotNet/Collections/ParameterCollection.cs | 2 +- src/AsmResolver.DotNet/DefaultMetadataResolver.cs | 4 ++-- src/AsmResolver.PE.File/SerializedPEFile.cs | 2 +- src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs | 4 ++-- src/AsmResolver.PE.Win32Resources/Version/StringTable.cs | 2 +- .../Version/VersionInfoResource.cs | 2 +- src/AsmResolver.PE/DotNet/Metadata/Tables/TablesStream.cs | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/AsmResolver.DotNet/Builder/Metadata/Blob/BlobStreamBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/Blob/BlobStreamBuffer.cs index b9283f323..691afffa6 100644 --- a/src/AsmResolver.DotNet/Builder/Metadata/Blob/BlobStreamBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Metadata/Blob/BlobStreamBuffer.cs @@ -14,7 +14,7 @@ namespace AsmResolver.DotNet.Builder.Metadata.Blob public class BlobStreamBuffer : IMetadataStreamBuffer { private readonly MemoryStream _rawStream = new(); - private readonly IBinaryStreamWriter _writer; + private readonly BinaryStreamWriter _writer; private readonly Dictionary _blobs = new(ByteArrayEqualityComparer.Instance); ///

diff --git a/src/AsmResolver.DotNet/Builder/Metadata/Guid/GuidStreamBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/Guid/GuidStreamBuffer.cs index 710ff651a..aacf2ba7d 100644 --- a/src/AsmResolver.DotNet/Builder/Metadata/Guid/GuidStreamBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Metadata/Guid/GuidStreamBuffer.cs @@ -13,7 +13,7 @@ namespace AsmResolver.DotNet.Builder.Metadata.Guid public class GuidStreamBuffer : IMetadataStreamBuffer { private readonly MemoryStream _rawStream = new(); - private readonly IBinaryStreamWriter _writer; + private readonly BinaryStreamWriter _writer; private readonly Dictionary _guids = new(); /// diff --git a/src/AsmResolver.DotNet/Builder/Metadata/UserStrings/UserStringsStreamBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/UserStrings/UserStringsStreamBuffer.cs index 15df10919..c6706b3cf 100644 --- a/src/AsmResolver.DotNet/Builder/Metadata/UserStrings/UserStringsStreamBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Metadata/UserStrings/UserStringsStreamBuffer.cs @@ -14,7 +14,7 @@ namespace AsmResolver.DotNet.Builder.Metadata.UserStrings public class UserStringsStreamBuffer : IMetadataStreamBuffer { private readonly MemoryStream _rawStream = new(); - private readonly IBinaryStreamWriter _writer; + private readonly BinaryStreamWriter _writer; private readonly Dictionary _strings = new(); /// diff --git a/src/AsmResolver.DotNet/Builder/Resources/DotNetResourcesDirectoryBuffer.cs b/src/AsmResolver.DotNet/Builder/Resources/DotNetResourcesDirectoryBuffer.cs index 524b55ae2..073df1eec 100644 --- a/src/AsmResolver.DotNet/Builder/Resources/DotNetResourcesDirectoryBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Resources/DotNetResourcesDirectoryBuffer.cs @@ -12,7 +12,7 @@ namespace AsmResolver.DotNet.Builder.Resources public class DotNetResourcesDirectoryBuffer { private readonly MemoryStream _rawStream = new(); - private readonly IBinaryStreamWriter _writer; + private readonly BinaryStreamWriter _writer; private readonly Dictionary _dataOffsets = new(ByteArrayEqualityComparer.Instance); /// diff --git a/src/AsmResolver.DotNet/Collections/ParameterCollection.cs b/src/AsmResolver.DotNet/Collections/ParameterCollection.cs index 1d6639dcc..a2e8b4c5d 100644 --- a/src/AsmResolver.DotNet/Collections/ParameterCollection.cs +++ b/src/AsmResolver.DotNet/Collections/ParameterCollection.cs @@ -15,7 +15,7 @@ namespace AsmResolver.DotNet.Collections [DebuggerDisplay("Count = {" + nameof(Count) + "}")] public class ParameterCollection : IReadOnlyList { - private readonly IList _parameters = new List(); + private readonly List _parameters = new List(); private readonly MethodDefinition _owner; private bool _hasThis; diff --git a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs index 2d0031695..30bab5716 100644 --- a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs +++ b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs @@ -12,7 +12,7 @@ namespace AsmResolver.DotNet /// public class DefaultMetadataResolver : IMetadataResolver { - private readonly IDictionary _typeCache; + private readonly ConcurrentDictionary _typeCache; private readonly SignatureComparer _comparer = new() { AcceptNewerAssemblyVersionNumbers = true @@ -55,7 +55,7 @@ public IAssemblyResolver AssemblyResolver // Check if type definition has changed since last lookup. if (typeDef.IsTypeOf(type.Namespace, type.Name)) return typeDef; - _typeCache.Remove(type); + _typeCache.TryRemove(type, out _); } return null; diff --git a/src/AsmResolver.PE.File/SerializedPEFile.cs b/src/AsmResolver.PE.File/SerializedPEFile.cs index ded5c5b04..44af78a71 100644 --- a/src/AsmResolver.PE.File/SerializedPEFile.cs +++ b/src/AsmResolver.PE.File/SerializedPEFile.cs @@ -10,7 +10,7 @@ namespace AsmResolver.PE.File /// public class SerializedPEFile : PEFile { - private readonly IList _sectionHeaders; + private readonly List _sectionHeaders; private readonly BinaryStreamReader _reader; /// diff --git a/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs b/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs index d7db9fd79..9904b1a1a 100644 --- a/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs +++ b/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +12,7 @@ public class IconResource : IWin32Resource /// /// Used to keep track of icon groups. /// - private readonly IDictionary _entries = new Dictionary(); + private readonly Dictionary _entries = new Dictionary(); /// /// Obtains the icon group resources from the provided root win32 resources directory. diff --git a/src/AsmResolver.PE.Win32Resources/Version/StringTable.cs b/src/AsmResolver.PE.Win32Resources/Version/StringTable.cs index 2089b4eec..3d88a0b1a 100644 --- a/src/AsmResolver.PE.Win32Resources/Version/StringTable.cs +++ b/src/AsmResolver.PE.Win32Resources/Version/StringTable.cs @@ -122,7 +122,7 @@ public static StringTable FromReader(ref BinaryStreamReader reader) return new KeyValuePair(header.Key, value); } - private readonly IDictionary _entries = new Dictionary(); + private readonly Dictionary _entries = new Dictionary(); /// /// Creates a new string table. diff --git a/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs b/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs index 2b7334ef2..666591d7c 100644 --- a/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs +++ b/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs @@ -98,7 +98,7 @@ private static VersionTableEntry ReadNextEntry(ref BinaryStreamReader reader) } private FixedVersionInfo _fixedVersionInfo = new FixedVersionInfo(); - private readonly IDictionary _entries = new Dictionary(); + private readonly Dictionary _entries = new Dictionary(); /// public override string Key => VsVersionInfoKey; diff --git a/src/AsmResolver.PE/DotNet/Metadata/Tables/TablesStream.cs b/src/AsmResolver.PE/DotNet/Metadata/Tables/TablesStream.cs index 017bb9490..4d903de19 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/Tables/TablesStream.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/Tables/TablesStream.cs @@ -31,7 +31,7 @@ public class TablesStream : SegmentBase, IMetadataStream /// public const string UncompressedStreamName = "#Schema"; - private readonly IDictionary _indexEncoders; + private readonly Dictionary _indexEncoders; private readonly LazyVariable> _tables; private readonly LazyVariable> _layouts; From 095ac6b2720d0675919aae71de5872da006ca2dc Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 11:46:36 +0100 Subject: [PATCH 16/51] Move Bundles into AsmResolver.DotNet. --- .../Bundles/BundleFile.cs | 2 +- .../Bundles/BundleFileType.cs | 2 +- .../Bundles/BundleManifest.cs | 2 +- .../Bundles/BundleManifestFlags.cs | 2 +- .../Bundles/SerializedBundleFile.cs | 2 +- .../Bundles/SerializedBundleManifest.cs | 2 +- .../Bundles/BundleFileTest.cs | 20 ++++------------- .../Bundles/BundleManifestTest.cs | 4 ++-- .../Properties/Resources.Designer.cs | 21 ++++++++++++++++++ .../Properties/Resources.resx | 9 ++++++++ .../Resources/HelloWorld.SingleFile.v1.exe | Bin .../Resources/HelloWorld.SingleFile.v2.exe | Bin .../Resources/HelloWorld.SingleFile.v6.exe | Bin .../Properties/Resources.Designer.cs | 21 ------------------ .../Properties/Resources.resx | 9 -------- 15 files changed, 42 insertions(+), 54 deletions(-) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/BundleFile.cs (98%) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/BundleFileType.cs (80%) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/BundleManifest.cs (98%) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/BundleManifestFlags.cs (78%) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/SerializedBundleFile.cs (95%) rename src/{AsmResolver.PE/DotNet => AsmResolver.DotNet}/Bundles/SerializedBundleManifest.cs (96%) rename test/{AsmResolver.PE.Tests/DotNet => AsmResolver.DotNet.Tests}/Bundles/BundleFileTest.cs (66%) rename test/{AsmResolver.PE.Tests/DotNet => AsmResolver.DotNet.Tests}/Bundles/BundleManifestTest.cs (95%) rename test/{AsmResolver.PE.Tests => AsmResolver.DotNet.Tests}/Resources/HelloWorld.SingleFile.v1.exe (100%) rename test/{AsmResolver.PE.Tests => AsmResolver.DotNet.Tests}/Resources/HelloWorld.SingleFile.v2.exe (100%) rename test/{AsmResolver.PE.Tests => AsmResolver.DotNet.Tests}/Resources/HelloWorld.SingleFile.v6.exe (100%) diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs similarity index 98% rename from src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs rename to src/AsmResolver.DotNet/Bundles/BundleFile.cs index a78abcad8..52458f2a9 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -3,7 +3,7 @@ using System.IO.Compression; using AsmResolver.IO; -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { public class BundleFile { diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs b/src/AsmResolver.DotNet/Bundles/BundleFileType.cs similarity index 80% rename from src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs rename to src/AsmResolver.DotNet/Bundles/BundleFileType.cs index 58ad0aead..e6fc46d45 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/BundleFileType.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFileType.cs @@ -1,4 +1,4 @@ -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { public enum BundleFileType { diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs similarity index 98% rename from src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs rename to src/AsmResolver.DotNet/Bundles/BundleManifest.cs index ad1e22fe7..a360730c6 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -3,7 +3,7 @@ using System.Threading; using AsmResolver.IO; -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { public class BundleManifest { diff --git a/src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs b/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs similarity index 78% rename from src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs rename to src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs index c40ad02cb..86b2c0969 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/BundleManifestFlags.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs @@ -1,6 +1,6 @@ using System; -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { [Flags] public enum BundleManifestFlags : ulong diff --git a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs b/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs similarity index 95% rename from src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs rename to src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs index 0918d2a2f..5b995a816 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs @@ -1,6 +1,6 @@ using AsmResolver.IO; -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { public class SerializedBundleFile : BundleFile { diff --git a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs similarity index 96% rename from src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs rename to src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs index 8a8c3bdfa..40e4fcc67 100644 --- a/src/AsmResolver.PE/DotNet/Bundles/SerializedBundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using AsmResolver.IO; -namespace AsmResolver.PE.DotNet.Bundles +namespace AsmResolver.DotNet.Bundles { public class SerializedBundleManifest : BundleManifest { diff --git a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleFileTest.cs similarity index 66% rename from test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs rename to test/AsmResolver.DotNet.Tests/Bundles/BundleFileTest.cs index a21f2195f..cf0bddfb0 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleFileTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleFileTest.cs @@ -1,12 +1,12 @@ using System.Linq; using System.Text; -using AsmResolver.PE.DotNet.Bundles; +using AsmResolver.DotNet.Bundles; using AsmResolver.PE.DotNet.Metadata.Strings; using AsmResolver.PE.DotNet.Metadata.Tables; using AsmResolver.PE.DotNet.Metadata.Tables.Rows; using Xunit; -namespace AsmResolver.PE.Tests.DotNet.Bundles +namespace AsmResolver.DotNet.Tests.Bundles { public class BundleFileTest { @@ -37,20 +37,8 @@ public void ReadUncompressedAssemblyContents() var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); var bundleFile = manifest.Files.First(f => f.RelativePath == "HelloWorld.dll"); - var embeddedImage = PEImage.FromBytes(bundleFile.GetData()); - var metadata = embeddedImage.DotNetDirectory!.Metadata!; - - uint nameIndex = metadata - .GetStream() - .GetTable() - .GetByRid(1) - .Name; - - string? name = metadata - .GetStream() - .GetStringByIndex(nameIndex); - - Assert.Equal("HelloWorld.dll", name); + var embeddedImage = ModuleDefinition.FromBytes(bundleFile.GetData()); + Assert.Equal("HelloWorld.dll", embeddedImage.Name); } } } diff --git a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs similarity index 95% rename from test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs rename to test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 73166ad9c..e25c841e6 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -1,8 +1,8 @@ using System.Linq; -using AsmResolver.PE.DotNet.Bundles; +using AsmResolver.DotNet.Bundles; using Xunit; -namespace AsmResolver.PE.Tests.DotNet.Bundles +namespace AsmResolver.DotNet.Tests.Bundles { public class BundleManifestTest { diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs index 141a67ba8..e824f4b21 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs @@ -136,6 +136,27 @@ public class Resources { } } + public static byte[] HelloWorld_SingleFile_V1 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V1", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] HelloWorld_SingleFile_V2 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V2", resourceCulture); + return ((byte[])(obj)); + } + } + + public static byte[] HelloWorld_SingleFile_V6 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V6", resourceCulture); + return ((byte[])(obj)); + } + } + public static byte[] Assembly1_Forwarder { get { object obj = ResourceManager.GetObject("Assembly1_Forwarder", resourceCulture); diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx index c6ab516aa..0ff471e63 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx @@ -57,6 +57,15 @@ ..\Resources\HelloWorld.WithAttribute.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\HelloWorld.SingleFile.v1.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\HelloWorld.SingleFile.v2.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\HelloWorld.SingleFile.v6.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\Assembly1_Forwarder.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v1.exe b/test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v1.exe similarity index 100% rename from test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v1.exe rename to test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v1.exe diff --git a/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v2.exe b/test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v2.exe similarity index 100% rename from test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v2.exe rename to test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v2.exe diff --git a/test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v6.exe b/test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v6.exe similarity index 100% rename from test/AsmResolver.PE.Tests/Resources/HelloWorld.SingleFile.v6.exe rename to test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v6.exe diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs index e47a1c7c9..388c1419d 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs @@ -94,27 +94,6 @@ public class Resources { } } - public static byte[] HelloWorld_SingleFile_V1 { - get { - object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V1", resourceCulture); - return ((byte[])(obj)); - } - } - - public static byte[] HelloWorld_SingleFile_V2 { - get { - object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V2", resourceCulture); - return ((byte[])(obj)); - } - } - - public static byte[] HelloWorld_SingleFile_V6 { - get { - object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V6", resourceCulture); - return ((byte[])(obj)); - } - } - public static byte[] SimpleDll { get { object obj = ResourceManager.GetObject("SimpleDll", resourceCulture); diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.resx b/test/AsmResolver.PE.Tests/Properties/Resources.resx index 1b2a1e7be..e9a93ecd7 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.resx +++ b/test/AsmResolver.PE.Tests/Properties/Resources.resx @@ -39,15 +39,6 @@ ..\Resources\HelloWorld.TablesStream.ExtraData.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\HelloWorld.SingleFile.v1.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\HelloWorld.SingleFile.v2.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\HelloWorld.SingleFile.v6.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ..\Resources\SimpleDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 From 3f19b446ab44b687ba43dc3b3b0d529e16a9d8b2 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 12:49:20 +0100 Subject: [PATCH 17/51] Basic write support for bundles via apphost templates. --- src/AsmResolver.DotNet/Bundles/BundleFile.cs | 16 +- .../Bundles/BundleManifest.cs | 169 ++++++++++++++++-- .../Bundles/SerializedBundleManifest.cs | 7 +- .../Bundles/BundleManifestTest.cs | 103 ++++++++++- test/AsmResolver.Tests/Runners/PERunner.cs | 11 ++ 5 files changed, 289 insertions(+), 17 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs index 52458f2a9..76e4cf33f 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -1,11 +1,12 @@ using System; using System.IO; using System.IO.Compression; +using AsmResolver.Collections; using AsmResolver.IO; namespace AsmResolver.DotNet.Bundles { - public class BundleFile + public class BundleFile : IOwnedCollectionElement { private readonly LazyVariable _contents; @@ -14,6 +15,19 @@ public BundleFile() _contents = new LazyVariable(GetContents); } + public BundleManifest? ParentManifest + { + get; + private set; + } + + /// + BundleManifest? IOwnedCollectionElement.Owner + { + get => ParentManifest; + set => ParentManifest = value; + } + public string RelativePath { get; diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index a360730c6..522d798a2 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -1,19 +1,28 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; using System.Threading; +using AsmResolver.Collections; using AsmResolver.IO; namespace AsmResolver.DotNet.Bundles { public class BundleManifest { - private static readonly byte[] BundleSignature = { + private static readonly byte[] BundleSignature = + { 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, 0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32, 0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18, 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae }; + private static readonly byte[] AppBinaryPathPlaceholder = + Encoding.UTF8.GetBytes("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"); + private IList? _files; protected BundleManifest() @@ -97,29 +106,165 @@ public static BundleManifest FromDataSource(IDataSource source, ulong offset) public static BundleManifest FromReader(BinaryStreamReader reader) => new SerializedBundleManifest(reader); - public static long FindBundleManifestAddress(IDataSource source) + private static long FindInFile(IDataSource source, byte[] data) { - for (ulong i = sizeof(ulong); i < source.Length - (ulong) BundleSignature.Length; i++) + for (ulong i = sizeof(ulong); i < source.Length - (ulong) data.Length; i++) { bool fullMatch = true; - for (int j = 0; fullMatch && j < BundleSignature.Length; j++) + for (int j = 0; fullMatch && j < data.Length; j++) { - if (source[i + (ulong) j] != BundleSignature[j]) + if (source[i + (ulong) j] != data[j]) fullMatch = false; } if (fullMatch) - { - var reader = new BinaryStreamReader(source, i - sizeof(ulong), 0, 8); - ulong address = reader.ReadUInt64(); - if (source.IsValidAddress(address)) - return (long) address; - } + return (long) i; } return -1; } - protected virtual IList GetFiles() => new List(); + private static long ReadBundleManifestAddress(IDataSource source, long signatureAddress) + { + var reader = new BinaryStreamReader(source, (ulong) signatureAddress - sizeof(ulong), 0, 8); + ulong manifestAddress = reader.ReadUInt64(); + + return source.IsValidAddress(manifestAddress) + ? (long) manifestAddress + : -1; + } + + public static long FindBundleManifestAddress(IDataSource source) + { + long signatureAddress = FindInFile(source, BundleSignature); + if (signatureAddress == -1) + return -1; + + return ReadBundleManifestAddress(source, signatureAddress); + } + + protected virtual IList GetFiles() => new OwnedCollection(this); + + public void WriteUsingTemplate(string appHostTemplatePath, Stream outputStream, string appBinaryPath) + { + WriteUsingTemplate(System.IO.File.ReadAllBytes(appHostTemplatePath), outputStream, appBinaryPath, + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + && RuntimeInformation.ProcessArchitecture + == Architecture.Arm64); + } + + public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath) + { + WriteUsingTemplate(appHostTemplate, outputStream, appBinaryPath, + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + && RuntimeInformation.ProcessArchitecture + == Architecture.Arm64); + } + + public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath, bool isArm64Linux) + { + WriteUsingTemplate(appHostTemplate, new BinaryStreamWriter(outputStream), appBinaryPath, isArm64Linux); + } + + public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter writer, string appBinaryPath, bool isArm64Linux) + { + byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(appBinaryPath); + if (appBinaryPathBytes.Length > 1024) + throw new ArgumentException("Application binary path cannot exceed 1024 bytes."); + + long signatureAddress = FindInFile(new ByteArrayDataSource(appHostTemplate), BundleSignature); + if (signatureAddress == -1) + throw new ArgumentException("AppHost template does not contain the bundle signature."); + + long appBinaryPathAddress = FindInFile(new ByteArrayDataSource(appHostTemplate), AppBinaryPathPlaceholder); + if (appBinaryPathAddress == -1) + throw new ArgumentException("AppHost template does not contain the application binary path placeholder."); + + writer.WriteBytes(appHostTemplate); + writer.Offset = writer.Length; + ulong headerAddress = Write(writer, isArm64Linux); + + writer.Offset = (ulong) signatureAddress - sizeof(ulong); + writer.WriteUInt64(headerAddress); + + writer.Offset = (ulong) appBinaryPathAddress; + writer.WriteBytes(appBinaryPathBytes); + if (AppBinaryPathPlaceholder.Length > appBinaryPathBytes.Length) + writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); + } + + public ulong Write(IBinaryStreamWriter writer, bool isArm64Linux) + { + WriteFileContents(writer, isArm64Linux + ? 4096u + : 16u); + + ulong headerAddress = writer.Offset; + WriteManifestHeader(writer); + + return headerAddress; + } + + private void WriteFileContents(IBinaryStreamWriter writer, uint alignment) + { + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + + if (file.Type == BundleFileType.Assembly) + writer.Align(alignment); + + file.Contents.UpdateOffsets(writer.Offset, (uint) writer.Offset); + file.Contents.Write(writer); + } + } + + private void WriteManifestHeader(IBinaryStreamWriter writer) + { + writer.WriteUInt32(MajorVersion); + writer.WriteUInt32(MinorVersion); + writer.WriteInt32(Files.Count); + writer.WriteBinaryFormatterString(BundleID); + + if (MajorVersion >= 2) + { + WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.DepsJson)); + WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.RuntimeConfigJson)); + writer.WriteUInt64((ulong) Flags); + } + + WriteFileHeaders(writer); + } + + private void WriteFileHeaders(IBinaryStreamWriter writer) + { + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + + WriteFileOffsetSizePair(writer, file); + + if (MajorVersion >= 6) + writer.WriteUInt64(file.IsCompressed ? file.Contents.GetPhysicalSize() : 0); + + writer.WriteByte((byte) file.Type); + writer.WriteBinaryFormatterString(file.RelativePath); + } + } + + private static void WriteFileOffsetSizePair(IBinaryStreamWriter writer, BundleFile? file) + { + if (file is not null) + { + writer.WriteUInt64(file.Contents.Offset); + writer.WriteUInt64((ulong) file.GetData().Length); + } + else + { + writer.WriteUInt64(0); + writer.WriteUInt64(0); + } + } + } } diff --git a/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs index 40e4fcc67..0e67023ba 100644 --- a/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using AsmResolver.Collections; using AsmResolver.IO; namespace AsmResolver.DotNet.Bundles @@ -7,13 +8,13 @@ public class SerializedBundleManifest : BundleManifest { private readonly uint _originalMajorVersion; private readonly BinaryStreamReader _fileEntriesReader; - private readonly uint _originalFileCount; + private readonly int _originalFileCount; public SerializedBundleManifest(BinaryStreamReader reader) { MajorVersion = _originalMajorVersion = reader.ReadUInt32(); MinorVersion = reader.ReadUInt32(); - _originalFileCount = reader.ReadUInt32(); + _originalFileCount = reader.ReadInt32(); BundleID = reader.ReadBinaryFormatterString(); if (MajorVersion >= 2) @@ -28,7 +29,7 @@ public SerializedBundleManifest(BinaryStreamReader reader) protected override IList GetFiles() { var reader = _fileEntriesReader; - var result = new List(); + var result = new OwnedCollection(this); for (int i = 0; i < _originalFileCount; i++) result.Add(new SerializedBundleFile(ref reader, _originalMajorVersion)); diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index e25c841e6..ab55a5c42 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -1,11 +1,22 @@ +using System; +using System.IO; using System.Linq; +using System.Runtime.InteropServices; using AsmResolver.DotNet.Bundles; +using AsmResolver.Tests.Runners; using Xunit; namespace AsmResolver.DotNet.Tests.Bundles { - public class BundleManifestTest + public class BundleManifestTest : IClassFixture { + private readonly TemporaryDirectoryFixture _fixture; + + public BundleManifestTest(TemporaryDirectoryFixture fixture) + { + _fixture = fixture; + } + [Fact] public void ReadBundleManifestHeaderV1() { @@ -41,5 +52,95 @@ public void ReadBundleManifestHeaderV6() "HelloWorld.dll", "HelloWorld.deps.json", "HelloWorld.runtimeconfig.json" }, manifest.Files.Select(f => f.RelativePath)); } + + [SkippableFact] + public void WriteBundleManifestV1Windows() + { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + AssertReadWriteManifestWindowsPreservesOutput( + Properties.Resources.HelloWorld_SingleFile_V1, + "3.1", + "HelloWorld.dll", + $"Hello, World!{Environment.NewLine}"); + } + + [SkippableFact] + public void WriteBundleManifestV2Windows() + { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + AssertReadWriteManifestWindowsPreservesOutput( + Properties.Resources.HelloWorld_SingleFile_V2, + "5.0", + "HelloWorld.dll", + $"Hello, World!{Environment.NewLine}"); + } + + [SkippableFact] + public void WriteBundleManifestV6Windows() + { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + AssertReadWriteManifestWindowsPreservesOutput( + Properties.Resources.HelloWorld_SingleFile_V6, + "6.0", + "HelloWorld.dll", + $"Hello, World!{Environment.NewLine}"); + } + + private void AssertReadWriteManifestWindowsPreservesOutput( + byte[] inputFile, + string sdkVersion, + string fileName, + string expectedOutput) + { + var manifest = BundleManifest.FromBytes(inputFile); + + string sdkPath = Path.Combine(DotNetCorePathProvider.DefaultInstallationPath!, "sdk"); + string? sdkVersionPath = null; + foreach (string dir in Directory.GetDirectories(sdkPath)) + { + if (Path.GetFileName(dir).StartsWith(sdkVersion)) + { + sdkVersionPath = Path.Combine(dir); + break; + } + } + + if (string.IsNullOrEmpty(sdkVersionPath)) + { + throw new InvalidOperationException( + $"Could not find the apphost template for .NET SDK version {sdkVersion}. This is an indication that the test environment does not have this SDK installed."); + } + + string appHostPathTemplate = Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); + + using var stream = new MemoryStream(); + manifest.WriteUsingTemplate(appHostPathTemplate, stream, fileName); + + var newManifest = BundleManifest.FromBytes(stream.ToArray()); + AssertBundlesAreEqual(manifest, newManifest); + + string output = _fixture + .GetRunner() + .RunAndCaptureOutput(Path.ChangeExtension(fileName, ".exe"), stream.ToArray()); + Assert.Equal(expectedOutput, output); + } + + private static void AssertBundlesAreEqual(BundleManifest manifest, BundleManifest newManifest) + { + Assert.Equal(manifest.MajorVersion, newManifest.MajorVersion); + Assert.Equal(manifest.MinorVersion, newManifest.MinorVersion); + Assert.Equal(manifest.BundleID, newManifest.BundleID); + + Assert.Equal(manifest.Files.Count, newManifest.Files.Count); + for (int i = 0; i < manifest.Files.Count; i++) + { + var file = manifest.Files[i]; + var newFile = newManifest.Files[i]; + Assert.Equal(file.Type, newFile.Type); + Assert.Equal(file.RelativePath, newFile.RelativePath); + Assert.Equal(file.IsCompressed, newFile.IsCompressed); + Assert.Equal(file.GetData(), newFile.GetData()); + } + } } } diff --git a/test/AsmResolver.Tests/Runners/PERunner.cs b/test/AsmResolver.Tests/Runners/PERunner.cs index 3f5a674fb..c2e4ff405 100644 --- a/test/AsmResolver.Tests/Runners/PERunner.cs +++ b/test/AsmResolver.Tests/Runners/PERunner.cs @@ -58,6 +58,17 @@ public string Rebuild(PEFile peFile, string fileName, string testClass, string t return fullPath; } + public string RunAndCaptureOutput(string fileName, byte[] contents, string[]? arguments = null, + int timeout = 5000, + [CallerFilePath] string testClass = "File", + [CallerMemberName] string testMethod = "Test") + { + testClass = Path.GetFileNameWithoutExtension(testClass); + string testExecutablePath = GetTestExecutablePath(testClass, testMethod, fileName); + File.WriteAllBytes(testExecutablePath, contents); + return RunAndCaptureOutput(testExecutablePath, arguments, timeout); + } + public string RunAndCaptureOutput(string filePath, string[]? arguments = null, int timeout = 5000) { var info = GetStartInfo(filePath, arguments); From 9f86ff2016bef27d890d14991ed4a924ec4e4e55 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 13:50:02 +0100 Subject: [PATCH 18/51] Add compression/decompression capabilities. --- src/AsmResolver.DotNet/Bundles/BundleFile.cs | 28 +++++++++++++- .../Bundles/BundleManifest.cs | 4 +- .../Bundles/BundleManifestTest.cs | 37 +++++++++++++------ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs index 76e4cf33f..e01b3b494 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -80,7 +80,7 @@ public byte[] GetData(bool decompressIfRequired) using var outputStream = new MemoryStream(); using var inputStream = new MemoryStream(contents); - using var deflate = new DeflateStream(inputStream, CompressionMode.Decompress); + using (var deflate = new DeflateStream(inputStream, CompressionMode.Decompress)) { deflate.CopyTo(outputStream); } @@ -94,6 +94,32 @@ public byte[] GetData(bool decompressIfRequired) throw new InvalidOperationException("Contents of file is not readable."); } + public void Compress() + { + if (IsCompressed) + throw new InvalidOperationException("File is already compressed."); + + using var inputStream = new MemoryStream(GetData()); + + using var outputStream = new MemoryStream(); + using (var deflate = new DeflateStream(outputStream, CompressionLevel.Optimal)) + { + inputStream.CopyTo(deflate); + } + + Contents = new DataSegment(outputStream.ToArray()); + IsCompressed = true; + } + + public void Decompress() + { + if (!IsCompressed) + throw new InvalidOperationException("File is not compressed."); + + Contents = new DataSegment(GetData(true)); + IsCompressed = false; + } + public override string ToString() => RelativePath; } } diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index 522d798a2..9200ad5ee 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -182,7 +182,7 @@ public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter write writer.WriteBytes(appHostTemplate); writer.Offset = writer.Length; - ulong headerAddress = Write(writer, isArm64Linux); + ulong headerAddress = WriteManifest(writer, isArm64Linux); writer.Offset = (ulong) signatureAddress - sizeof(ulong); writer.WriteUInt64(headerAddress); @@ -193,7 +193,7 @@ public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter write writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); } - public ulong Write(IBinaryStreamWriter writer, bool isArm64Linux) + public ulong WriteManifest(IBinaryStreamWriter writer, bool isArm64Linux) { WriteFileContents(writer, isArm64Linux ? 4096u diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index ab55a5c42..59b429d16 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Runtime.InteropServices; using AsmResolver.DotNet.Bundles; +using AsmResolver.IO; using AsmResolver.Tests.Runners; using Xunit; @@ -57,8 +58,8 @@ public void ReadBundleManifestHeaderV6() public void WriteBundleManifestV1Windows() { Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); - AssertReadWriteManifestWindowsPreservesOutput( - Properties.Resources.HelloWorld_SingleFile_V1, + AssertWriteManifestWindowsPreservesOutput( + BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V1), "3.1", "HelloWorld.dll", $"Hello, World!{Environment.NewLine}"); @@ -68,8 +69,8 @@ public void WriteBundleManifestV1Windows() public void WriteBundleManifestV2Windows() { Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); - AssertReadWriteManifestWindowsPreservesOutput( - Properties.Resources.HelloWorld_SingleFile_V2, + AssertWriteManifestWindowsPreservesOutput( + BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V2), "5.0", "HelloWorld.dll", $"Hello, World!{Environment.NewLine}"); @@ -79,21 +80,35 @@ public void WriteBundleManifestV2Windows() public void WriteBundleManifestV6Windows() { Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); - AssertReadWriteManifestWindowsPreservesOutput( - Properties.Resources.HelloWorld_SingleFile_V6, + AssertWriteManifestWindowsPreservesOutput( + BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6), "6.0", "HelloWorld.dll", $"Hello, World!{Environment.NewLine}"); } - private void AssertReadWriteManifestWindowsPreservesOutput( - byte[] inputFile, + [SkippableFact] + public void MarkFilesAsCompressed() + { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + manifest.Files.First(f => f.RelativePath == "HelloWorld.dll").Compress(); + + using var stream = new MemoryStream(); + ulong address = manifest.WriteManifest(new BinaryStreamWriter(stream), false); + + var reader = ByteArrayDataSource.CreateReader(stream.ToArray()); + reader.Offset = address; + var newManifest = BundleManifest.FromReader(reader); + AssertBundlesAreEqual(manifest, newManifest); + } + + private void AssertWriteManifestWindowsPreservesOutput( + BundleManifest manifest, string sdkVersion, string fileName, string expectedOutput) { - var manifest = BundleManifest.FromBytes(inputFile); - string sdkPath = Path.Combine(DotNetCorePathProvider.DefaultInstallationPath!, "sdk"); string? sdkVersionPath = null; foreach (string dir in Directory.GetDirectories(sdkPath)) @@ -120,7 +135,7 @@ public void WriteBundleManifestV6Windows() AssertBundlesAreEqual(manifest, newManifest); string output = _fixture - .GetRunner() + .GetRunner() .RunAndCaptureOutput(Path.ChangeExtension(fileName, ".exe"), stream.ToArray()); Assert.Equal(expectedOutput, output); } From 7346b12241d4e0438d7e8571c947375e63d82f50 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 14:09:51 +0100 Subject: [PATCH 19/51] Add read benchmarks, improve FindInFile performance by reading blocks instead of individual bytes. --- .../Bundles/BundleManifest.cs | 24 +++++++++++++----- .../DotNetBundleBenchmark.cs | 19 ++++++++++++++ .../Properties/Resources.Designer.cs | 10 ++++++++ .../Properties/Resources.resx | 3 +++ .../Resources/HelloWorld.SingleFile.v6.exe | Bin 0 -> 152984 bytes .../Bundles/BundleManifestTest.cs | 10 ++++++-- 6 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 test/AsmResolver.Benchmarks/DotNetBundleBenchmark.cs create mode 100644 test/AsmResolver.Benchmarks/Resources/HelloWorld.SingleFile.v6.exe diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index 9200ad5ee..9ab4574fb 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -108,17 +108,27 @@ public static BundleManifest FromDataSource(IDataSource source, ulong offset) private static long FindInFile(IDataSource source, byte[] data) { - for (ulong i = sizeof(ulong); i < source.Length - (ulong) data.Length; i++) + byte[] buffer = new byte[0x1000]; + + ulong start = 0; + while (start < source.Length) { - bool fullMatch = true; - for (int j = 0; fullMatch && j < data.Length; j++) + int read = source.ReadBytes(start, buffer, 0, buffer.Length); + + for (int i = sizeof(ulong); i < read - data.Length; i++) { - if (source[i + (ulong) j] != data[j]) - fullMatch = false; + bool fullMatch = true; + for (int j = 0; fullMatch && j < data.Length; j++) + { + if (buffer[i + j] != data[j]) + fullMatch = false; + } + + if (fullMatch) + return (long) start + i; } - if (fullMatch) - return (long) i; + start += (ulong) read; } return -1; diff --git a/test/AsmResolver.Benchmarks/DotNetBundleBenchmark.cs b/test/AsmResolver.Benchmarks/DotNetBundleBenchmark.cs new file mode 100644 index 000000000..00acd4fc9 --- /dev/null +++ b/test/AsmResolver.Benchmarks/DotNetBundleBenchmark.cs @@ -0,0 +1,19 @@ +using System.IO; +using AsmResolver.DotNet.Bundles; +using BenchmarkDotNet.Attributes; + +namespace AsmResolver.Benchmarks +{ + [MemoryDiagnoser] + public class DotNetBundleBenchmark + { + private static readonly byte[] HelloWorldSingleFileV6 = Properties.Resources.HelloWorld_SingleFile_V6; + private readonly MemoryStream _outputStream = new(); + + [Benchmark] + public void ReadBundleManifestV6() + { + _ = BundleManifest.FromBytes(HelloWorldSingleFileV6); + } + } +} diff --git a/test/AsmResolver.Benchmarks/Properties/Resources.Designer.cs b/test/AsmResolver.Benchmarks/Properties/Resources.Designer.cs index 86ed39706..ee7805eca 100644 --- a/test/AsmResolver.Benchmarks/Properties/Resources.Designer.cs +++ b/test/AsmResolver.Benchmarks/Properties/Resources.Designer.cs @@ -99,5 +99,15 @@ public class Resources { return ((byte[])(obj)); } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] HelloWorld_SingleFile_V6 { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V6", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/test/AsmResolver.Benchmarks/Properties/Resources.resx b/test/AsmResolver.Benchmarks/Properties/Resources.resx index 83f78bc25..585e32796 100644 --- a/test/AsmResolver.Benchmarks/Properties/Resources.resx +++ b/test/AsmResolver.Benchmarks/Properties/Resources.resx @@ -130,4 +130,7 @@ ..\Resources\HelloWorld.ManyMethods.deflate;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\HelloWorld.SingleFile.v6.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + diff --git a/test/AsmResolver.Benchmarks/Resources/HelloWorld.SingleFile.v6.exe b/test/AsmResolver.Benchmarks/Resources/HelloWorld.SingleFile.v6.exe new file mode 100644 index 0000000000000000000000000000000000000000..e980f978ebf60bd5b692383cc7c04efd2baaefe5 GIT binary patch literal 152984 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 YH7w;qh$$2L5xkH~;_u literal 0 HcmV?d00001 diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 59b429d16..740895546 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using AsmResolver.DotNet.Bundles; using AsmResolver.IO; @@ -107,7 +108,9 @@ public void MarkFilesAsCompressed() BundleManifest manifest, string sdkVersion, string fileName, - string expectedOutput) + string expectedOutput, + [CallerFilePath] string className = "File", + [CallerMemberName] string methodName = "Method") { string sdkPath = Path.Combine(DotNetCorePathProvider.DefaultInstallationPath!, "sdk"); string? sdkVersionPath = null; @@ -136,7 +139,10 @@ public void MarkFilesAsCompressed() string output = _fixture .GetRunner() - .RunAndCaptureOutput(Path.ChangeExtension(fileName, ".exe"), stream.ToArray()); + .RunAndCaptureOutput(Path.ChangeExtension(fileName, ".exe"), stream.ToArray(), null, + 5000, + className, + methodName); Assert.Equal(expectedOutput, output); } From d9ab29d4649cc0be4a031e44463861b45f5b0100 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 14:42:46 +0100 Subject: [PATCH 20/51] Add xmldoc to bundle models. --- src/AsmResolver.DotNet/Bundles/BundleFile.cs | 60 +++++++- .../Bundles/BundleFileType.cs | 26 ++++ .../Bundles/BundleManifest.cs | 132 +++++++++++++++++- .../Bundles/BundleManifestFlags.cs | 10 ++ .../Bundles/SerializedBundleFile.cs | 10 ++ .../Bundles/SerializedBundleManifest.cs | 8 ++ 6 files changed, 242 insertions(+), 4 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs index e01b3b494..981588232 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -6,15 +6,26 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Represents a single file in a .NET bundle manifest. + /// public class BundleFile : IOwnedCollectionElement { private readonly LazyVariable _contents; - public BundleFile() + /// + /// Creates a new empty bundle file. + /// + /// The path of the file, relative to the root of the bundle. + public BundleFile(string relativePath) { + RelativePath = relativePath; _contents = new LazyVariable(GetContents); } + /// + /// Gets the parent manifest this file was added to. + /// public BundleManifest? ParentManifest { get; @@ -28,34 +39,61 @@ public BundleFile() set => ParentManifest = value; } + /// + /// Gets or sets the path to the file, relative to the root directory of the bundle. + /// public string RelativePath { get; set; } + /// + /// Gets or sets the type of the file. + /// public BundleFileType Type { get; set; } + /// + /// Gets or sets a value indicating whether the data stored in is compressed or not. + /// public bool IsCompressed { get; set; } + /// + /// Gets or sets the raw contents of the file. + /// public ISegment Contents { get => _contents.Value; set => _contents.Value = value; } + /// + /// Gets a value whether the contents of the file can be read using a . + /// public bool CanRead => Contents is IReadableSegment; + /// + /// Obtains the raw contents of the file. + /// + /// The contents. + /// + /// This method is called upon initialization of the property. + /// protected virtual ISegment? GetContents() => null; + /// + /// Attempts to create a that points to the start of the raw contents of the file. + /// + /// The reader. + /// true if the reader was constructed successfully, false otherwise. public bool TryGetReader(out BinaryStreamReader reader) { if (Contents is IReadableSegment segment) @@ -68,8 +106,17 @@ public bool TryGetReader(out BinaryStreamReader reader) return false; } + /// + /// Reads (and decompresses if necessary) the contents of the file. + /// + /// The contents. public byte[] GetData() => GetData(true); + /// + /// Reads the contents of the file. + /// + /// true if the contents should be decompressed or not when necessary. + /// The contents. public byte[] GetData(bool decompressIfRequired) { if (TryGetReader(out var reader)) @@ -94,6 +141,11 @@ public byte[] GetData(bool decompressIfRequired) throw new InvalidOperationException("Contents of file is not readable."); } + /// + /// Marks the file as compressed, compresses the file contents, and replaces the value of + /// with the result. + /// + /// Occurs when the file was already compressed. public void Compress() { if (IsCompressed) @@ -111,6 +163,11 @@ public void Compress() IsCompressed = true; } + /// + /// Marks the file as uncompressed, decompresses the file contents, and replaces the value of + /// with the result. + /// + /// Occurs when the file was already compressed. public void Decompress() { if (!IsCompressed) @@ -120,6 +177,7 @@ public void Decompress() IsCompressed = false; } + /// public override string ToString() => RelativePath; } } diff --git a/src/AsmResolver.DotNet/Bundles/BundleFileType.cs b/src/AsmResolver.DotNet/Bundles/BundleFileType.cs index e6fc46d45..8ac16b290 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFileType.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFileType.cs @@ -1,12 +1,38 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Provides members defining all possible file types that can be stored in a bundled .NET application. + /// public enum BundleFileType { + /// + /// Indicates the file type is unknown. + /// Unknown, + + /// + /// Indicates the file is a .NET assembly. + /// Assembly, + + /// + /// Indicates the file is a native binary. + /// NativeBinary, + + /// + /// Indicates the file is the deps.json file associated to a .NET assembly. + /// DepsJson, + + /// + /// Indicates the file is the runtimeconfig.json file associated to a .NET assembly. + /// RuntimeConfigJson, + + /// + /// Indicates the file contains symbols. + /// Symbols } } diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index 9ab4574fb..a57a7b894 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -10,6 +10,9 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Represents a set of bundled files embedded in a .NET application host or single-file host. + /// public class BundleManifest { private static readonly byte[] BundleSignature = @@ -25,41 +28,76 @@ public class BundleManifest private IList? _files; + /// + /// Initializes an empty bundle manifest. + /// protected BundleManifest() { + BundleID = string.Empty; } - public BundleManifest(uint version, string bundleId) + /// + /// Creates a new bundle manifest. + /// + /// The file format version. + /// The unique bundle manifest identifier. + public BundleManifest(uint majorVersionNumber, string bundleId) { - MajorVersion = version; + MajorVersion = majorVersionNumber; MinorVersion = 0; BundleID = bundleId; } + /// + /// Gets or sets the major file format version of the bundle. + /// + /// + /// Version numbers recognized by the CLR are: + /// + /// 1 for .NET Core 3.1 + /// 2 for .NET 5.0 + /// 6 for .NET 6.0 + /// + /// public uint MajorVersion { get; set; } + /// + /// Gets or sets the minor file format version of the bundle. + /// + /// + /// This value is ignored by the CLR and should be set to 0. + /// public uint MinorVersion { get; set; } + /// + /// Gets or sets the unique identifier for the bundle manifest. + /// public string BundleID { get; set; } + /// + /// Gets or sets flags associated to the bundle. + /// public BundleManifestFlags Flags { get; set; } + /// + /// Gets a collection of files stored in the bundle. + /// public IList Files { get @@ -70,21 +108,42 @@ public IList Files } } + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The path to the file to read. + /// The read manifest. public static BundleManifest FromFile(string filePath) { - return FromBytes(System.IO.File.ReadAllBytes(filePath)); + return FromBytes(File.ReadAllBytes(filePath)); } + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The raw contents of the file to read. + /// The read manifest. public static BundleManifest FromBytes(byte[] data) { return FromDataSource(new ByteArrayDataSource(data)); } + /// + /// Parses the bundle header in the provided file at the provided address. + /// + /// The raw contents of the file to read. + /// The address within the file to start reading the bundle at. + /// The read manifest. public static BundleManifest FromBytes(byte[] data, ulong offset) { return FromDataSource(new ByteArrayDataSource(data), offset); } + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The raw contents of the file to read. + /// The read manifest. public static BundleManifest FromDataSource(IDataSource source) { long address = FindBundleManifestAddress(source); @@ -94,6 +153,12 @@ public static BundleManifest FromDataSource(IDataSource source) return FromDataSource(source, (ulong) address); } + /// + /// Parses the bundle header in the provided file at the provided address. + /// + /// The raw contents of the file to read. + /// The address within the file to start reading the bundle at. + /// The read manifest. public static BundleManifest FromDataSource(IDataSource source, ulong offset) { var reader = new BinaryStreamReader(source, 0, 0, (uint) source.Length) @@ -104,10 +169,18 @@ public static BundleManifest FromDataSource(IDataSource source, ulong offset) return FromReader(reader); } + /// + /// Parses the bundle header from the provided input stream. + /// + /// The input stream pointing to the start of the bundle to read. + /// The read manifest. public static BundleManifest FromReader(BinaryStreamReader reader) => new SerializedBundleManifest(reader); private static long FindInFile(IDataSource source, byte[] data) { + // Note: For performance reasons, we read data from the data source in blocks, such that we avoid + // virtual-dispatch calls and do the searching directly on a byte array instead. + byte[] buffer = new byte[0x1000]; ulong start = 0; @@ -144,6 +217,11 @@ private static long ReadBundleManifestAddress(IDataSource source, long signature : -1; } + /// + /// Attempts to find the start of the bundle header in the provided file. + /// + /// The file to locate the bundle header in. + /// The offset, or -1 if none was found. public static long FindBundleManifestAddress(IDataSource source) { long signatureAddress = FindInFile(source, BundleSignature); @@ -153,8 +231,25 @@ public static long FindBundleManifestAddress(IDataSource source) return ReadBundleManifestAddress(source, signatureAddress); } + /// + /// Obtains the list of files stored in the bundle. + /// + /// The files + /// + /// This method is called upon initialization of the property. + /// protected virtual IList GetFiles() => new OwnedCollection(this); + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// + /// The path to the application host file template to use. By default this is stored in + /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or + /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. + /// + /// The output stream to write to. + /// The name of the file in the bundle that contains the entry point of the application. public void WriteUsingTemplate(string appHostTemplatePath, Stream outputStream, string appBinaryPath) { WriteUsingTemplate(System.IO.File.ReadAllBytes(appHostTemplatePath), outputStream, appBinaryPath, @@ -163,6 +258,12 @@ public void WriteUsingTemplate(string appHostTemplatePath, Stream outputStream, == Architecture.Arm64); } + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The application host template file to use. + /// The output stream to write to. + /// The name of the file in the bundle that contains the entry point of the application. public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath) { WriteUsingTemplate(appHostTemplate, outputStream, appBinaryPath, @@ -171,11 +272,25 @@ public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, stri == Architecture.Arm64); } + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The application host template file to use. + /// The output stream to write to. + /// The name of the file in the bundle that contains the entry point of the application. + /// true if the application host is a Linux ELF binary targeting ARM64. public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath, bool isArm64Linux) { WriteUsingTemplate(appHostTemplate, new BinaryStreamWriter(outputStream), appBinaryPath, isArm64Linux); } + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The application host template file to use. + /// The output stream to write to. + /// The name of the file in the bundle that contains the entry point of the application. + /// true if the application host is a Linux ELF binary targeting ARM64. public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter writer, string appBinaryPath, bool isArm64Linux) { byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(appBinaryPath); @@ -203,6 +318,17 @@ public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter write writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); } + /// + /// Writes the manifest to an output stream. + /// + /// The output stream to write to. + /// true if the application host is a Linux ELF binary targeting ARM64. + /// The address of the bundle header. + /// + /// This does not necessarily produce a working executable file, it only writes the contents of the entire manifest, + /// without a host application that invokes the manifest. If you want to produce a runnable executable, use one + /// of the or one of its overloads instead. + /// public ulong WriteManifest(IBinaryStreamWriter writer, bool isArm64Linux) { WriteFileContents(writer, isArm64Linux diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs b/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs index 86b2c0969..0a2a9a277 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifestFlags.cs @@ -2,10 +2,20 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Provides members defining all flags that can be assigned to a bundle manifest. + /// [Flags] public enum BundleManifestFlags : ulong { + /// + /// Indicates no flags were assigned. + /// None = 0, + + /// + /// Indicates the bundle was compiled in .NET Core 3 compatibility mode. + /// NetCoreApp3CompatibilityMode = 1 } } diff --git a/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs b/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs index 5b995a816..79581a262 100644 --- a/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/SerializedBundleFile.cs @@ -2,11 +2,20 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Represents a lazily initialized implementation of that is read from an existing file. + /// public class SerializedBundleFile : BundleFile { private readonly BinaryStreamReader _contentsReader; + /// + /// Reads a bundle file entry from the provided input stream. + /// + /// The input stream. + /// The file format version of the bundle. public SerializedBundleFile(ref BinaryStreamReader reader, uint bundleVersionFormat) + : base(string.Empty) { ulong offset = reader.ReadUInt64(); ulong size = reader.ReadUInt64(); @@ -27,6 +36,7 @@ public SerializedBundleFile(ref BinaryStreamReader reader, uint bundleVersionFor _contentsReader = reader.ForkAbsolute(offset, (uint) size); } + /// protected override ISegment GetContents() => _contentsReader.ReadSegment(_contentsReader.Length); } } diff --git a/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs index 0e67023ba..2fce34fae 100644 --- a/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/SerializedBundleManifest.cs @@ -4,12 +4,19 @@ namespace AsmResolver.DotNet.Bundles { + /// + /// Represents a lazily initialized implementation of that is read from an existing file. + /// public class SerializedBundleManifest : BundleManifest { private readonly uint _originalMajorVersion; private readonly BinaryStreamReader _fileEntriesReader; private readonly int _originalFileCount; + /// + /// Reads a bundle manifest from the provided input stream. + /// + /// The input stream. public SerializedBundleManifest(BinaryStreamReader reader) { MajorVersion = _originalMajorVersion = reader.ReadUInt32(); @@ -26,6 +33,7 @@ public SerializedBundleManifest(BinaryStreamReader reader) _fileEntriesReader = reader; } + /// protected override IList GetFiles() { var reader = _fileEntriesReader; From e4df13df02ef795a2c46b6eee83a3cdbadfddddf Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 17:34:15 +0100 Subject: [PATCH 21/51] Add convenience BundleFile constructors. --- src/AsmResolver.DotNet/Bundles/BundleFile.cs | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/AsmResolver.DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs index 981588232..84dba4101 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -23,6 +23,30 @@ public BundleFile(string relativePath) _contents = new LazyVariable(GetContents); } + /// + /// Creates a new bundle file. + /// + /// The path of the file, relative to the root of the bundle. + /// The type of the file. + /// The contents of the file. + public BundleFile(string relativePath, BundleFileType type, byte[] contents) + : this(relativePath, type, new DataSegment(contents)) + { + } + + /// + /// Creates a new empty bundle file. + /// + /// The path of the file, relative to the root of the bundle. + /// The type of the file. + /// The contents of the file. + public BundleFile(string relativePath, BundleFileType type, ISegment contents) + { + RelativePath = relativePath; + Type = type; + _contents = new LazyVariable(contents); + } + /// /// Gets the parent manifest this file was added to. /// From 303564599df3f80366b92f1dacaad4de2773072d Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 23 Mar 2022 18:25:17 +0100 Subject: [PATCH 22/51] Add documentation on bundles API. --- docs/dotnet/bundles.rst | 147 ++++++++++++++++++ docs/index.rst | 1 + .../Bundles/BundleManifest.cs | 23 +++ 3 files changed, 171 insertions(+) create mode 100644 docs/dotnet/bundles.rst diff --git a/docs/dotnet/bundles.rst b/docs/dotnet/bundles.rst new file mode 100644 index 000000000..488260461 --- /dev/null +++ b/docs/dotnet/bundles.rst @@ -0,0 +1,147 @@ +AppHost / SingleFileHost Bundles +================================ + +Since the release of .NET Core 3.1, it is possible to deploy .NET assemblies as a single binary. These files are executables that do not contain a traditional .NET metadata header, and run natively on the underlying operating system via a platform-specific application host bootstrapper. + +AsmResolver supports extracting the embedded files from these types of binaries. Additionally, given an application host template provided by the .NET SDK, AsmResolver also supports constructing new bundles as well. All relevant code is found in the following namespace: + +.. code-block:: csharp + + using AsmResolver.DotNet.Bundles; + + +Creating Bundles +---------------- + +.NET bundles are represented using the ``BundleManifest`` class. Creating new bundles can be done using any of the constructors: + +.. code-block:: csharp + + var manifest = new BundleManifest( + majorVersionNumber: 6, + bundleId: ""); + + +The major version number refers to the file format that should be used when saving the manifest. Below an overview of the values that are recognized by the CLR: + ++----------------------+----------------------------+ +| .NET Version Number | Bundle File Format Version | ++======================+============================+ +| .NET Core 3.1 | 1 | ++----------------------+----------------------------+ +| .NET 5.0 | 2 | ++----------------------+----------------------------+ +| .NET 6.0 | 6 | ++----------------------+----------------------------+ + +It is also possible to change the version number as well as the bundle ID later, since these values are exposed as mutable properties ``MajorVersion`` and ``BundleID`` + +.. code-block:: csharp + + manifest.MajorVersion = 6; + manifest.BundleID = GenerateRandomID(); + + +Reading Bundles +--------------- + +Reading and extracting existing bundle manifests from an executable can be done by using one of the ``FromXXX`` methods: + +.. code-block:: csharp + + var manifest = BundleManifest.FromFile(@"C:\Path\To\Executable.exe"); + +.. code-block:: csharp + + byte[] contents = ... + var manifest = BundleManifest.FromBytes(contents); + +.. code-block:: csharp + + IDataSource contents = ... + var manifest = BundleManifest.FromDataSource(contents); + + +Similar to the official .NET bundler and extractor, the methods above locate the bundle in the file by looking for a specific signature first. However, official implementations of the application hosting program itself actually do not verify or use this signature in any shape or form. This means that a third party can replace or remove this signature, or write their own implementation of an application host that does not adhere to this standard, and thus throw off static analysis of the file. + +AsmResolver does not provide built-in alternative heuristics for finding the right start address of the bundle header. However, it is possible to implement one yourself and provide the resulting start address in one of the overloads of the ``FromXXX`` methods: + +.. code-block:: csharp + + byte[] contents = ... + ulong bundleAddress = ... + var manifest = BundleManifest.FromBytes(contents, bundleAddress); + +.. code-block:: csharp + + IDataSource contents = ... + ulong bundleAddress = ... + var manifest = BundleManifest.FromDataSource(contents, bundleAddress); + + +Writing Bundles +--------------- + +Constructing new bundled executable files requires a template file that AsmResolver can base the final output on. This is similar how .NET compilers themselves do this as well. By default, the .NET SDK installs template binaries in either ``/sdk//AppHostTemplate`` or ``/packs/Microsoft.NETCore.App.Host.//runtimes//native``. It is then possible to use ``WriteUsingTemplate`` to construct a new binary. + +.. code-block:: csharp + + BundleManifest manifest = ... + var manifest = manifest.WriteUsingTemplate( + @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", + @"C:\User\Admin\HelloWorld.exe", + @"HelloWorld.dll"); + + +Typically on Windows, use an ```apphost.exe`` template if you want to construct a native binary that is framework dependent, and ``singlefilehost.exe`` for a fully self-contained binary. + + +Managing Files +-------------- + +Files in a bundle are represented using the ``BundleFile`` class, and are exposed by the ``BundleManifest.Files`` property. Both the class as well as the list itself is fully mutable, and thus can be used to add, remove or modify files in the bundle. + +Creating a new file can be done using the constructors: + +.. code-block:: csharp + + var newFile = new BundleFile( + relativePath: "HelloWorld.dll", + type: BundleFileType.Assembly, + contents: System.IO.File.ReadAllBytes(@"C:\Binaries\HelloWorld.dll")); + + manifest.Files.Add(newFile); + + +It is also possible to iterate over all files and inspect their contents using ``GetData``: + +.. code-block:: csharp + + foreach (var file in manifest.Files) + { + string path = file.RelativePath; + byte[] contents = file.GetData(); + + Console.WriteLine($"Extracting {path}..."); + System.IO.File.WriteAllBytes(path, contents); + } + + +Changing the contents of an existing file can be done using the ``Contents`` property. + +.. code-block:: csharp + + BundleFile file = ... + file.Contents = new DataSegment(new byte[] { 1, 2, 3, 4 }); + + +If the bundle manifest is put into a single-file host template (e.g. ``singlefilehost.exe``), then files can also be compressed or decompressed: + +.. code-block:: csharp + + file.Compress(); + // file.Contents now contains the compressed version of the data and file.IsCompressed = true + + file.Decompress(); + // file.Contents now contains the decompressed version of the data and file.IsCompressed = false + diff --git a/docs/index.rst b/docs/index.rst index 6e56f82d4..89f3b0aeb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -62,4 +62,5 @@ Table of Contents: dotnet/cloning dotnet/token-allocation dotnet/type-memory-layout + dotnet/bundles dotnet/advanced-pe-image-building.rst diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index a57a7b894..3fa82444e 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -231,6 +231,13 @@ public static long FindBundleManifestAddress(IDataSource source) return ReadBundleManifestAddress(source, signatureAddress); } + /// + /// Gets a value indicating whether the provided data source contains a conventional bundled assembly signature. + /// + /// The file to locate the bundle header in. + /// true if a bundle signature was found, false otherwise. + public static bool IsBundledAssembly(IDataSource source) => FindBundleManifestAddress(source) != -1; + /// /// Obtains the list of files stored in the bundle. /// @@ -240,6 +247,22 @@ public static long FindBundleManifestAddress(IDataSource source) /// protected virtual IList GetFiles() => new OwnedCollection(this); + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// + /// The path to the application host file template to use. By default this is stored in + /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or + /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. + /// + /// The output path to write to. + /// The name of the file in the bundle that contains the entry point of the application. + public void WriteUsingTemplate(string appHostTemplatePath, string outputPath, string appBinaryPath) + { + using var fs = File.Create(outputPath); + WriteUsingTemplate(appHostTemplatePath, fs, appBinaryPath); + } + /// /// Constructs a new application host file based on the bundle manifest. /// From bbfdddbf01e3964ef97a7e7701a96696f5a9be9d Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Sat, 26 Mar 2022 14:15:55 -0400 Subject: [PATCH 23/51] redirect object base type when member cloning --- .../Cloning/CloneContextAwareReferenceImporter.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs index 4fd836cfe..fb67345e0 100644 --- a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs +++ b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs @@ -40,5 +40,13 @@ public override IMethodDefOrRef ImportMethod(IMethodDefOrRef method) ? (IMethodDefOrRef) clonedMethod : base.ImportMethod(method); } + + /// + protected override ITypeDefOrRef ImportType(TypeReference type) + { + return type.Namespace == "System" && type.Name == nameof(System.Object) + ? _context.Module.CorLibTypeFactory.Object.Type + : base.ImportType(type); + } } -} \ No newline at end of file +} From 61a712d6e63e45536c795a313243b9f1ec3b8360 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Sun, 27 Mar 2022 01:46:12 -0400 Subject: [PATCH 24/51] use an instantiator for creating the reference importer --- .../Cloning/CloneContextAwareReferenceImporter.cs | 7 +++++-- src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs | 8 +++++--- src/AsmResolver.DotNet/Cloning/MemberCloner.cs | 8 ++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs index 4fd836cfe..235f5a277 100644 --- a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs +++ b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs @@ -5,7 +5,10 @@ namespace AsmResolver.DotNet.Cloning /// public class CloneContextAwareReferenceImporter : ReferenceImporter { - private readonly MemberCloneContext _context; + /// + /// The working space for this member cloning procedure. + /// + protected readonly MemberCloneContext _context; /// /// Creates a new instance of the class. @@ -41,4 +44,4 @@ public override IMethodDefOrRef ImportMethod(IMethodDefOrRef method) : base.ImportMethod(method); } } -} \ No newline at end of file +} diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs index 5f6fa56e9..43092c939 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs @@ -12,10 +12,12 @@ public class MemberCloneContext /// Creates a new instance of the class. /// /// The target module to copy the cloned members into. - public MemberCloneContext(ModuleDefinition module) + /// The instantiator for creating the reference importer + public MemberCloneContext(ModuleDefinition module, + Func? importerInstantiator = null) { Module = module ?? throw new ArgumentNullException(nameof(module)); - Importer = new CloneContextAwareReferenceImporter(this); + Importer = importerInstantiator?.Invoke(this) ?? new CloneContextAwareReferenceImporter(this); } /// @@ -42,4 +44,4 @@ public ReferenceImporter Importer get; } = new Dictionary(); } -} \ No newline at end of file +} diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs index eae611adb..2d1a6022b 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs @@ -17,6 +17,7 @@ namespace AsmResolver.DotNet.Cloning /// public partial class MemberCloner { + private readonly Func? _importerInstantiator; private readonly ModuleDefinition _targetModule; private readonly HashSet _typesToClone = new(); @@ -29,9 +30,12 @@ public partial class MemberCloner /// Creates a new instance of the class. /// /// The target module to copy the members into. - public MemberCloner(ModuleDefinition targetModule) + /// The instantiator for creating the reference importer + public MemberCloner(ModuleDefinition targetModule, + Func? importerInstantiator = null) { _targetModule = targetModule ?? throw new ArgumentNullException(nameof(targetModule)); + _importerInstantiator = importerInstantiator; } /// @@ -220,7 +224,7 @@ public MemberCloner Include(EventDefinition @event) /// An object representing the result of the cloning process. public MemberCloneResult Clone() { - var context = new MemberCloneContext(_targetModule); + var context = new MemberCloneContext(_targetModule, _importerInstantiator); CreateMemberStubs(context); DeepCopyMembers(context); From 4176cd86016740d9b48d8f50f47c9d589105fa14 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 10:23:50 +0200 Subject: [PATCH 25/51] Add PEFile.EofData. --- src/AsmResolver.PE.File/PEFile.cs | 36 +++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/AsmResolver.PE.File/PEFile.cs b/src/AsmResolver.PE.File/PEFile.cs index e89eac9ff..f8274652c 100644 --- a/src/AsmResolver.PE.File/PEFile.cs +++ b/src/AsmResolver.PE.File/PEFile.cs @@ -21,6 +21,7 @@ public class PEFile : IPEFile public const uint ValidPESignature = 0x4550; // "PE\0\0" private readonly LazyVariable _extraSectionData; + private readonly LazyVariable _eofData; private IList? _sections; /// @@ -43,6 +44,7 @@ public PEFile(DosHeader dosHeader, FileHeader fileHeader, OptionalHeader optiona FileHeader = fileHeader ?? throw new ArgumentNullException(nameof(fileHeader)); OptionalHeader = optionalHeader ?? throw new ArgumentNullException(nameof(optionalHeader)); _extraSectionData = new LazyVariable(GetExtraSectionData); + _eofData = new LazyVariable(GetEofData); MappingMode = PEMappingMode.Unmapped; } @@ -101,6 +103,15 @@ public PEMappingMode MappingMode set => _extraSectionData.Value = value; } + /// + /// Gets or sets the data appended to the end of the file (EoF), if available. + /// + public ISegment? EofData + { + get => _eofData.Value; + set => _eofData.Value = value; + } + /// /// Reads an unmapped PE file from the disk. /// @@ -360,7 +371,7 @@ public bool TryCreateReaderAtRva(uint rva, uint size, out BinaryStreamReader rea /// public void UpdateHeaders() { - var oldSections = Sections.Select(_ => _.CreateHeader()).ToList(); + var oldSections = Sections.Select(x => x.CreateHeader()).ToList(); FileHeader.NumberOfSections = (ushort) Sections.Count; @@ -383,6 +394,8 @@ public void UpdateHeaders() var lastSection = Sections[Sections.Count - 1]; OptionalHeader.SizeOfImage = lastSection.Rva + lastSection.GetVirtualSize().Align(OptionalHeader.SectionAlignment); + + EofData?.UpdateOffsets(lastSection.Offset + lastSection.GetPhysicalSize(), OptionalHeader.SizeOfImage); } /// @@ -474,28 +487,30 @@ public void Write(IBinaryStreamWriter writer) // NT headers writer.Offset = DosHeader.NextHeaderOffset; - writer.WriteUInt32(ValidPESignature); FileHeader.Write(writer); OptionalHeader.Write(writer); // Section headers. writer.Offset = OptionalHeader.Offset + FileHeader.SizeOfOptionalHeader; - foreach (var section in Sections) - section.CreateHeader().Write(writer); + for (int i = 0; i < Sections.Count; i++) + Sections[i].CreateHeader().Write(writer); // Data between section headers and sections. ExtraSectionData?.Write(writer); // Sections. - writer.Offset = OptionalHeader.SizeOfHeaders; - foreach (var section in Sections) + for (int i = 0; i < Sections.Count; i++) { + var section = Sections[i]; writer.Offset = section.Offset; section.Contents?.Write(writer); writer.Align(OptionalHeader.FileAlignment); } + + // EOF Data. + EofData?.Write(writer); } /// @@ -515,5 +530,14 @@ public void Write(IBinaryStreamWriter writer) /// This method is called upon the initialization of the property. /// protected virtual ISegment? GetExtraSectionData() => null; + + /// + /// Obtains any data appended to the end of the file (EoF). + /// + /// The extra data. + /// + /// This method is called upon the initialization of the property. + /// + private ISegment? GetEofData() => null; } } From 56ec9aa8a522d4bdb44ced6dcb79a4c8f558fd4f Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 10:41:58 +0200 Subject: [PATCH 26/51] Read support EofData. --- src/AsmResolver.PE.File/PEFile.cs | 2 +- src/AsmResolver.PE.File/SerializedPEFile.cs | 16 +++++++++++++++- test/AsmResolver.PE.File.Tests/PEFileTest.cs | 16 ++++++++++++++++ .../Properties/Resources.Designer.cs | 10 ++++++++++ .../Properties/Resources.resx | 3 +++ .../Resources/HelloWorld.EOF.exe | Bin 0 -> 4634 bytes 6 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 test/AsmResolver.PE.File.Tests/Resources/HelloWorld.EOF.exe diff --git a/src/AsmResolver.PE.File/PEFile.cs b/src/AsmResolver.PE.File/PEFile.cs index f8274652c..276e4aa0b 100644 --- a/src/AsmResolver.PE.File/PEFile.cs +++ b/src/AsmResolver.PE.File/PEFile.cs @@ -538,6 +538,6 @@ public void Write(IBinaryStreamWriter writer) /// /// This method is called upon the initialization of the property. /// - private ISegment? GetEofData() => null; + protected virtual ISegment? GetEofData() => null; } } diff --git a/src/AsmResolver.PE.File/SerializedPEFile.cs b/src/AsmResolver.PE.File/SerializedPEFile.cs index ded5c5b04..73a3d1e7d 100644 --- a/src/AsmResolver.PE.File/SerializedPEFile.cs +++ b/src/AsmResolver.PE.File/SerializedPEFile.cs @@ -46,7 +46,7 @@ public SerializedPEFile(in BinaryStreamReader reader, PEMappingMode mode) // Data between section headers and sections. int extraSectionDataLength = (int) (DosHeader.Offset + OptionalHeader.SizeOfHeaders - _reader.Offset); if (extraSectionDataLength != 0) - ExtraSectionData = DataSegment.FromReader(ref _reader, extraSectionDataLength); + ExtraSectionData = _reader.ReadSegment((uint) extraSectionDataLength); } /// @@ -77,5 +77,19 @@ protected override IList GetSections() return result; } + /// + protected override ISegment? GetEofData() + { + if (MappingMode != PEMappingMode.Unmapped) + return null; + + var lastSection = _sectionHeaders[_sectionHeaders.Count - 1]; + ulong offset = lastSection.PointerToRawData + lastSection.SizeOfRawData; + + var reader = _reader.ForkAbsolute(offset); + return reader.Length > 0 + ? reader.ReadSegment(reader.Length) + : null; + } } } diff --git a/test/AsmResolver.PE.File.Tests/PEFileTest.cs b/test/AsmResolver.PE.File.Tests/PEFileTest.cs index c7fe42964..ec0d0909f 100644 --- a/test/AsmResolver.PE.File.Tests/PEFileTest.cs +++ b/test/AsmResolver.PE.File.Tests/PEFileTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Text; using AsmResolver.IO; using AsmResolver.PE.File.Headers; using AsmResolver.Tests.Runners; @@ -168,5 +169,20 @@ public void SectionsInMappedBinaryShouldUseVirtualAddressesAsOffset() Assert.Equal(expected, actual); } } + + [Fact] + public void PEWithNoEofData() + { + var file = PEFile.FromBytes(Properties.Resources.HelloWorld); + Assert.Null(file.EofData); + } + + [Fact] + public void ReadEofData() + { + var file = PEFile.FromBytes(Properties.Resources.HelloWorld_EOF); + var readable = Assert.IsAssignableFrom(file.EofData); + Assert.Equal(Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"), readable.ToArray()); + } } } diff --git a/test/AsmResolver.PE.File.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.PE.File.Tests/Properties/Resources.Designer.cs index 0e74fe94c..f2f817fd5 100644 --- a/test/AsmResolver.PE.File.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.PE.File.Tests/Properties/Resources.Designer.cs @@ -80,6 +80,16 @@ public class Resources { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] HelloWorld_EOF { + get { + object obj = ResourceManager.GetObject("HelloWorld_EOF", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/test/AsmResolver.PE.File.Tests/Properties/Resources.resx b/test/AsmResolver.PE.File.Tests/Properties/Resources.resx index 293c5e462..c33ee0174 100644 --- a/test/AsmResolver.PE.File.Tests/Properties/Resources.resx +++ b/test/AsmResolver.PE.File.Tests/Properties/Resources.resx @@ -124,6 +124,9 @@ ..\Resources\HelloWorld.dump;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\HelloWorld.EOF.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\NativeMemoryDemos.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/test/AsmResolver.PE.File.Tests/Resources/HelloWorld.EOF.exe b/test/AsmResolver.PE.File.Tests/Resources/HelloWorld.EOF.exe new file mode 100644 index 0000000000000000000000000000000000000000..90549fef61c5defcf86eb24ba3a349abc4eccb0f GIT binary patch literal 4634 zcmeHK|8HEy5ufMS#&K#pQ3^_E8#db$^ot*8n6Sw|y_|A@+UQ6D+Tc2O@ zz8r7goqd2%)B;i@KtTd25zJTaM3bdOZI_2+p)%saw`Cb6j_Ig6o|vLp0qw>Y=hAx{k|WfJW!t z{;Ot&SXDi|3q~F}&~+H*^dFhde{b5*8e{wF<7V0%OOK5{z^Z%51$+X_h94*T8^*sf zo{vJuuPB!I02lP@7>8H$^bg?d*6^9t`7Fjh*!l;ir`@20ksDk$&fH0~lZk&CV{}*S z&p^!6p}`h9Rvb#kxf9J9@z_hhrY51Im zf7dXp;YY?MxCdxctBmz>6b#rO7<*|{<2k|mK1Yum!=Q_rdTQSbSjh)y(1*rOdI47L z0qmvyfc^AMz};BS@Bs~{G@RG)K@ESPp+oo4on!&;C6jhxrAd3~7~t3FLBL@;5BM$m zIp7%m0`R-^HsB2X7V!IeJ`dP^xfvlCrQ2RWgud18?!1%}i$S^O%2VViI|yB;L}#Vz z2Iqj6X(sSh;7U3dI+0v(d`VeZs#Pjh$(2(PPQ6r%BuyzLy^`A~I8o%e}1>3|x0AwNT5omCOWQ)p7OYigc|ljj1-j zX>l%u^LDhI!3r$D(PpgF{K)a7o{yZ8<2q3Xw;eK5Zb`~FR3tq!Sz{*F;}aol$oV#r zphe5^Themfl{WiJrX2-gb3W@>6+cjsW2@#=Q*rF34D&LqJGNBG>0l!qDo7lFqUF*> zsMUwR|13#-!7c?P=p0}Oyi5nd96R)8>Nh*@Uw-w-TNAH7^QRwEw=j&p9fFJ=Aba*O zIoM4AeXl)IT-!f>{Ynq0Zw&SsN!mZapG%?Zu5+PPT?+i!En8OEo5DsIY$^kC{FM-$ zG3ah{X|~Y17~f9fGs(FIDh9vWVr3mwb*;t{uF!5?BU&6WK4egTJMPF32HkKaJhK9#Cz zC7;db?0wfh&aExKn7L3{Exz1f9odt`=R4f2YJH8b< zQWdj7v?QZq+o@tux>!tnD*7@SPj@iQYPm%Dvs1^ubDWah?`iH14}bKtqfft7e@|Tb z%ZU$uQc5ZZoBtT&g0bzbSz%(%Lo-1*yCwA{)!9Kxv+QyO;CAC)5*dws3H~1u=+d=S z;1#tG+vnofREHsP6+dx{c^10dAsM5w{KhsG-(d(DQ(E@oSCV?Ed6m@mCe=YSyRIT1#A;nw(^c_`P62tA!jjM-K9ogifE< zk+rxTBCco!a4pO#@GVq#2V7tCiC*a*hph%|iXi1+zH$pqyR}Rj?}qp{P9ro~xEE3)hstCMl_VvkZwF;0^~uy~VeaUO zlu(i7mn}E&!=FNqNw+SG9g;Z=F1X~k*IN#OC%0vid9nNU7lgPpRR3!OS%auumQr`EBiR)N;mgHmJH z_{Fdw>(Ui2!^xDT=KXqbNrov=bEa&(auCLK%T+RQN-G(;g*8pnM{crxVx$!W2uzGL yPv{hX4PWpk;{SuL9{+;d`K5XPlL%NPyDZl$8_vZ`uIC5UheH+B>YH1QNB#}c`^dHc literal 0 HcmV?d00001 From 878fb587f33ad296ea9bde1c311a6f771eb3f7c9 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 10:45:33 +0200 Subject: [PATCH 27/51] EOF writer tests. --- test/AsmResolver.PE.File.Tests/PEFileTest.cs | 60 +++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/test/AsmResolver.PE.File.Tests/PEFileTest.cs b/test/AsmResolver.PE.File.Tests/PEFileTest.cs index ec0d0909f..7a1c47463 100644 --- a/test/AsmResolver.PE.File.Tests/PEFileTest.cs +++ b/test/AsmResolver.PE.File.Tests/PEFileTest.cs @@ -181,8 +181,64 @@ public void PEWithNoEofData() public void ReadEofData() { var file = PEFile.FromBytes(Properties.Resources.HelloWorld_EOF); - var readable = Assert.IsAssignableFrom(file.EofData); - Assert.Equal(Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"), readable.ToArray()); + byte[] data = Assert.IsAssignableFrom(file.EofData).ToArray(); + Assert.Equal(Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"), data); + } + + [Fact] + public void AddNewEofData() + { + byte[] expected = { 1, 2, 3, 4 }; + + var file = PEFile.FromBytes(Properties.Resources.HelloWorld); + Assert.Null(file.EofData); + file.EofData = new DataSegment(expected); + + using var stream = new MemoryStream(); + file.Write(stream); + byte[] newFileBytes = stream.ToArray(); + + Assert.Equal(expected, newFileBytes[^expected.Length..]); + + var newFile = PEFile.FromBytes(newFileBytes); + var readable = Assert.IsAssignableFrom(newFile.EofData); + Assert.Equal(expected, readable.ToArray()); + } + + [Fact] + public void ModifyExistingEofData() + { + var file = PEFile.FromBytes(Properties.Resources.HelloWorld_EOF); + byte[] data = Assert.IsAssignableFrom(file.EofData).ToArray(); + Array.Reverse(data); + file.EofData = new DataSegment(data); + + using var stream = new MemoryStream(); + file.Write(stream); + byte[] newFileBytes = stream.ToArray(); + + Assert.Equal(data, newFileBytes[^data.Length..]); + + var newFile = PEFile.FromBytes(newFileBytes); + byte[] newData = Assert.IsAssignableFrom(newFile.EofData).ToArray(); + Assert.Equal(data, newData); + } + + [Fact] + public void RemoveExistingEofData() + { + var file = PEFile.FromBytes(Properties.Resources.HelloWorld_EOF); + byte[] originalData = Assert.IsAssignableFrom(file.EofData).ToArray(); + file.EofData = null; + + using var stream = new MemoryStream(); + file.Write(stream); + byte[] newFileBytes = stream.ToArray(); + + Assert.NotEqual(originalData, newFileBytes[^originalData.Length..]); + + var newFile = PEFile.FromBytes(newFileBytes); + Assert.Null(newFile.EofData); } } } From c24c6fa44c612503f57aaaa1ee0ac923af57fdb4 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 12:02:07 +0200 Subject: [PATCH 28/51] Extract BundlerParameters from WriteUsingTemplate parameters. Update apphost win32resources and subsystem. --- .../Bundles/BundleManifest.cs | 135 +++++++----- .../Bundles/BundlerParameters.cs | 199 ++++++++++++++++++ .../Bundles/BundleManifestTest.cs | 2 +- 3 files changed, 281 insertions(+), 55 deletions(-) create mode 100644 src/AsmResolver.DotNet/Bundles/BundlerParameters.cs diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index 3fa82444e..1423ef80d 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -7,6 +7,10 @@ using System.Threading; using AsmResolver.Collections; using AsmResolver.IO; +using AsmResolver.PE; +using AsmResolver.PE.File; +using AsmResolver.PE.File.Headers; +using AsmResolver.PE.Win32Resources.Builder; namespace AsmResolver.DotNet.Bundles { @@ -250,87 +254,54 @@ public static long FindBundleManifestAddress(IDataSource source) /// /// Constructs a new application host file based on the bundle manifest. /// - /// - /// The path to the application host file template to use. By default this is stored in - /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or - /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. - /// - /// The output path to write to. - /// The name of the file in the bundle that contains the entry point of the application. - public void WriteUsingTemplate(string appHostTemplatePath, string outputPath, string appBinaryPath) + /// The path of the file to write to. + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(string outputPath, in BundlerParameters parameters) { using var fs = File.Create(outputPath); - WriteUsingTemplate(appHostTemplatePath, fs, appBinaryPath); + WriteUsingTemplate(fs, parameters); } /// /// Constructs a new application host file based on the bundle manifest. /// - /// - /// The path to the application host file template to use. By default this is stored in - /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or - /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. - /// /// The output stream to write to. - /// The name of the file in the bundle that contains the entry point of the application. - public void WriteUsingTemplate(string appHostTemplatePath, Stream outputStream, string appBinaryPath) + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(Stream outputStream, in BundlerParameters parameters) { - WriteUsingTemplate(System.IO.File.ReadAllBytes(appHostTemplatePath), outputStream, appBinaryPath, - RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - && RuntimeInformation.ProcessArchitecture - == Architecture.Arm64); + WriteUsingTemplate(new BinaryStreamWriter(outputStream), parameters); } /// /// Constructs a new application host file based on the bundle manifest. /// - /// The application host template file to use. - /// The output stream to write to. - /// The name of the file in the bundle that contains the entry point of the application. - public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath) + /// The output stream to write to. + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(IBinaryStreamWriter writer, BundlerParameters parameters) { - WriteUsingTemplate(appHostTemplate, outputStream, appBinaryPath, - RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - && RuntimeInformation.ProcessArchitecture - == Architecture.Arm64); - } + var appBinaryEntry = Files.FirstOrDefault(f => f.RelativePath == parameters.ApplicationBinaryPath); + if (appBinaryEntry is null) + throw new ArgumentException($"Application {parameters.ApplicationBinaryPath} does not exist within the bundle."); - /// - /// Constructs a new application host file based on the bundle manifest. - /// - /// The application host template file to use. - /// The output stream to write to. - /// The name of the file in the bundle that contains the entry point of the application. - /// true if the application host is a Linux ELF binary targeting ARM64. - public void WriteUsingTemplate(byte[] appHostTemplate, Stream outputStream, string appBinaryPath, bool isArm64Linux) - { - WriteUsingTemplate(appHostTemplate, new BinaryStreamWriter(outputStream), appBinaryPath, isArm64Linux); - } + if (!parameters.IsArm64Linux) + EnsureAppHostPEHeadersAreUpToDate(ref parameters); - /// - /// Constructs a new application host file based on the bundle manifest. - /// - /// The application host template file to use. - /// The output stream to write to. - /// The name of the file in the bundle that contains the entry point of the application. - /// true if the application host is a Linux ELF binary targeting ARM64. - public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter writer, string appBinaryPath, bool isArm64Linux) - { - byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(appBinaryPath); + byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(parameters.ApplicationBinaryPath); if (appBinaryPathBytes.Length > 1024) throw new ArgumentException("Application binary path cannot exceed 1024 bytes."); - long signatureAddress = FindInFile(new ByteArrayDataSource(appHostTemplate), BundleSignature); + var appHostTemplateSource = new ByteArrayDataSource(parameters.ApplicationHostTemplate); + long signatureAddress = FindInFile(appHostTemplateSource, BundleSignature); if (signatureAddress == -1) throw new ArgumentException("AppHost template does not contain the bundle signature."); - long appBinaryPathAddress = FindInFile(new ByteArrayDataSource(appHostTemplate), AppBinaryPathPlaceholder); + long appBinaryPathAddress = FindInFile(appHostTemplateSource, AppBinaryPathPlaceholder); if (appBinaryPathAddress == -1) throw new ArgumentException("AppHost template does not contain the application binary path placeholder."); - writer.WriteBytes(appHostTemplate); + writer.WriteBytes(parameters.ApplicationHostTemplate); writer.Offset = writer.Length; - ulong headerAddress = WriteManifest(writer, isArm64Linux); + ulong headerAddress = WriteManifest(writer, parameters.IsArm64Linux); writer.Offset = (ulong) signatureAddress - sizeof(ulong); writer.WriteUInt64(headerAddress); @@ -341,6 +312,62 @@ public void WriteUsingTemplate(byte[] appHostTemplate, IBinaryStreamWriter write writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); } + private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters parameters) + { + PEFile file; + try + { + file = PEFile.FromBytes(parameters.ApplicationHostTemplate); + } + catch (BadImageFormatException) + { + // Template is not a PE file. + return; + } + + bool changed = false; + + // Ensure same Windows subsystem is used (typically required for GUI applications). + if (file.OptionalHeader.SubSystem != parameters.SubSystem) + { + file.OptionalHeader.SubSystem = parameters.SubSystem; + changed = true; + } + + // If the app binary has resources (such as an icon or version info), we need to copy it into the + // AppHost template so that they are also visible from the final packed executable. + if (parameters.Resources is { } directory) + { + // Put original resource directory in a new .rsrc section. + var buffer = new ResourceDirectoryBuffer(); + buffer.AddDirectory(directory); + var rsrc = new PESection(".rsrc", SectionFlags.MemoryRead | SectionFlags.ContentInitializedData); + rsrc.Contents = buffer; + + // Find .reloc section, and insert .rsrc before it if it is present. + int sectionIndex = file.Sections.Count - 1; + for (int i = file.Sections.Count - 1; i >= 0; i--) + { + if (file.Sections[i].Name == ".reloc") + { + sectionIndex = i; + break; + } + } + + file.Sections.Insert(sectionIndex, rsrc); + changed = true; + } + + // Rebuild AppHost PE file if necessary. + if (changed) + { + using var stream = new MemoryStream(); + file.Write(stream); + parameters.ApplicationHostTemplate = stream.ToArray(); + } + } + /// /// Writes the manifest to an output stream. /// diff --git a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs new file mode 100644 index 000000000..0dc8282a6 --- /dev/null +++ b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs @@ -0,0 +1,199 @@ +using System.IO; +using AsmResolver.IO; +using AsmResolver.PE; +using AsmResolver.PE.File.Headers; +using AsmResolver.PE.Win32Resources; + +namespace AsmResolver.DotNet.Bundles +{ + /// + /// Defines parameters for the .NET application bundler. + /// + public struct BundlerParameters + { + /// + /// Initializes new bundler parameters. + /// + /// + /// The path to the application host file template to use. By default this is stored in + /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or + /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. + /// + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + public BundlerParameters(string appHostTemplatePath, string appBinaryPath) + : this(File.ReadAllBytes(appHostTemplatePath), appBinaryPath) + { + } + + /// + /// Initializes new bundler parameters. + /// + /// The application host template file to use. + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + public BundlerParameters(byte[] appHostTemplate, string appBinaryPath) + { + ApplicationHostTemplate = appHostTemplate; + ApplicationBinaryPath = appBinaryPath; + IsArm64Linux = false; + Resources = null; + SubSystem = SubSystem.WindowsCui; + } + + /// + /// Initializes new bundler parameters. + /// + /// + /// The path to the application host file template to use. By default this is stored in + /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate or + /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native. + /// + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + /// + /// The path to copy the PE headers and Win32 resources from. This is typically the original native executable + /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. + /// + public BundlerParameters(string appHostTemplatePath, string appBinaryPath, string? imagePathToCopyHeadersFrom) + : this( + File.ReadAllBytes(appHostTemplatePath), + appBinaryPath, + !string.IsNullOrEmpty(imagePathToCopyHeadersFrom) + ? PEImage.FromFile(imagePathToCopyHeadersFrom!) + : null + ) + { + } + + /// + /// Initializes new bundler parameters. + /// + /// The application host template file to use. + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + /// + /// The binary to copy the PE headers and Win32 resources from. This is typically the original native executable + /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. + /// + public BundlerParameters(byte[] appHostTemplate, string appBinaryPath, IDataSource? imageToCopyHeadersFrom) + : this( + appHostTemplate, + appBinaryPath, + imageToCopyHeadersFrom is not null + ? PEImage.FromDataSource(imageToCopyHeadersFrom) + : null + ) + { + } + + /// + /// Initializes new bundler parameters. + /// + /// The application host template file to use. + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + /// + /// The PE image to copy the headers and Win32 resources from. This is typically the original native executable + /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. + /// + public BundlerParameters(byte[] appHostTemplate, string appBinaryPath, IPEImage? imageToCopyHeadersFrom) + : this( + appHostTemplate, + appBinaryPath, + imageToCopyHeadersFrom?.SubSystem ?? SubSystem.WindowsCui, + imageToCopyHeadersFrom?.Resources + ) + { + } + + /// + /// Initializes new bundler parameters. + /// + /// The application host template file to use. + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + /// The subsystem to use in the final Windows PE binary. + /// The resources to copy into the final Windows PE binary. + public BundlerParameters( + byte[] appHostTemplate, + string appBinaryPath, + SubSystem subSystem, + IResourceDirectory? resources) + { + ApplicationHostTemplate = appHostTemplate; + ApplicationBinaryPath = appBinaryPath; + IsArm64Linux = false; + SubSystem = subSystem; + Resources = resources; + } + + /// + /// Gets or sets the template application hosting binary. + /// + /// + /// By default, the official implementations of the application host can be found in one of the following + /// installation directories: + /// + /// <DOTNET-INSTALLATION-PATH>/sdk/<version>/AppHostTemplate + /// <DOTNET-INSTALLATION-PATH>/packs/Microsoft.NETCore.App.Host.<runtime-identifier>/<version>/runtimes/<runtime-identifier>/native + /// + /// It is therefore recommended to use the contents of one of these templates to ensure compatibility. + /// + public byte[] ApplicationHostTemplate + { + get; + set; + } + + /// + /// Gets or sets the path to the binary within the bundle that contains the application's entry point. + /// + public string ApplicationBinaryPath + { + get; + set; + } + + /// + /// Gets a value indicating whether the bundled executable targets the Linux operating system on ARM64. + /// + public bool IsArm64Linux + { + get; + set; + } + + /// + /// Gets or sets the Win32 resources directory to copy into the final PE executable. + /// + /// + /// This field is ignored if is set to true, or + /// does not contain a proper PE image. + /// + public IResourceDirectory? Resources + { + get; + set; + } + + /// + /// Gets or sets the Windows subsystem the final PE executable should target. + /// + /// + /// This field is ignored if is set to true, or + /// does not contain a proper PE image. + /// + public SubSystem SubSystem + { + get; + set; + } + } +} diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 740895546..88a3da352 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -132,7 +132,7 @@ public void MarkFilesAsCompressed() string appHostPathTemplate = Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); using var stream = new MemoryStream(); - manifest.WriteUsingTemplate(appHostPathTemplate, stream, fileName); + manifest.WriteUsingTemplate(stream, new BundlerParameters(appHostPathTemplate, fileName)); var newManifest = BundleManifest.FromBytes(stream.ToArray()); AssertBundlesAreEqual(manifest, newManifest); From 31c70817d9df1d220b044b171b23b65b375cf821 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 12:27:42 +0200 Subject: [PATCH 29/51] BUGFIX: Update win32 resource data dir in final bundle PE file. --- .../Bundles/BundleManifest.cs | 9 +- .../Bundles/BundlerParameters.cs | 22 +++++ .../AsmResolver.DotNet.Tests.csproj | 1 + .../Bundles/BundleManifestTest.cs | 92 +++++++++++++++--- .../Properties/Resources.Designer.cs | 7 ++ .../Properties/Resources.resx | 3 + ...HelloWorld.SingleFile.v6.WithResources.exe | Bin 0 -> 219620 bytes 7 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v6.WithResources.exe diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index 1423ef80d..c21e6d20f 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -344,7 +344,7 @@ private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters para var rsrc = new PESection(".rsrc", SectionFlags.MemoryRead | SectionFlags.ContentInitializedData); rsrc.Contents = buffer; - // Find .reloc section, and insert .rsrc before it if it is present. + // Find .reloc section, and insert .rsrc before it if it is present. Otherwise just append to the end. int sectionIndex = file.Sections.Count - 1; for (int i = file.Sections.Count - 1; i >= 0; i--) { @@ -356,6 +356,13 @@ private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters para } file.Sections.Insert(sectionIndex, rsrc); + + // Update resource data directory va + size. + file.AlignSections(); + file.OptionalHeader.DataDirectories[(int) DataDirectoryIndex.ResourceDirectory] = new DataDirectory( + buffer.Rva, + buffer.GetPhysicalSize()); + changed = true; } diff --git a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs index 0dc8282a6..2e83c3c16 100644 --- a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs +++ b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs @@ -69,6 +69,28 @@ public BundlerParameters(string appHostTemplatePath, string appBinaryPath, strin { } + /// + /// Initializes new bundler parameters. + /// + /// The application host template file to use. + /// + /// The name of the file in the bundle that contains the entry point of the application. + /// + /// + /// The binary to copy the PE headers and Win32 resources from. This is typically the original native executable + /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. + /// + public BundlerParameters(byte[] appHostTemplate, string appBinaryPath, byte[]? imageToCopyHeadersFrom) + : this( + appHostTemplate, + appBinaryPath, + imageToCopyHeadersFrom is not null + ? PEImage.FromBytes(imageToCopyHeadersFrom) + : null + ) + { + } + /// /// Initializes new bundler parameters. /// diff --git a/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj b/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj index 30de93753..a29c5c0d5 100644 --- a/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj +++ b/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 88a3da352..2bd797187 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -5,6 +5,10 @@ using System.Runtime.InteropServices; using AsmResolver.DotNet.Bundles; using AsmResolver.IO; +using AsmResolver.PE; +using AsmResolver.PE.File; +using AsmResolver.PE.File.Headers; +using AsmResolver.PE.Win32Resources.Version; using AsmResolver.Tests.Runners; using Xunit; @@ -104,6 +108,56 @@ public void MarkFilesAsCompressed() AssertBundlesAreEqual(manifest, newManifest); } + [Theory] + [InlineData(SubSystem.WindowsCui)] + [InlineData(SubSystem.WindowsGui)] + public void WriteWithSubSystem(SubSystem subSystem) + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + string appHostTemplatePath = FindAppHostTemplate("6.0"); + + using var stream = new MemoryStream(); + manifest.WriteUsingTemplate(stream, new BundlerParameters(appHostTemplatePath, "HelloWorld.dll") + { + SubSystem = subSystem + }); + + var newFile = PEFile.FromBytes(stream.ToArray()); + Assert.Equal(subSystem, newFile.OptionalHeader.SubSystem); + } + + [Fact] + public void WriteWithWin32Resources() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6_WithResources); + string appHostTemplatePath = FindAppHostTemplate("6.0"); + + // Obtain expected version info. + var oldImage = PEImage.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6_WithResources); + var versionInfo = VersionInfoResource.FromDirectory(oldImage.Resources!)!; + + // Bundle with PE image as template for PE headers and resources. + using var stream = new MemoryStream(); + manifest.WriteUsingTemplate(stream, new BundlerParameters( + File.ReadAllBytes(appHostTemplatePath), + "HelloWorld.dll", + oldImage)); + + // Verify new file still runs as expected. + string output = _fixture + .GetRunner() + .RunAndCaptureOutput("HelloWorld.exe", stream.ToArray()); + + Assert.Equal($"Hello, World!{Environment.NewLine}", output); + + // Verify that resources were added properly. + var newImage = PEImage.FromBytes(stream.ToArray()); + Assert.NotNull(newImage.Resources); + var newVersionInfo = VersionInfoResource.FromDirectory(newImage.Resources); + Assert.NotNull(newVersionInfo); + Assert.Equal(versionInfo.FixedVersionInfo.FileVersion, newVersionInfo.FixedVersionInfo.FileVersion); + } + private void AssertWriteManifestWindowsPreservesOutput( BundleManifest manifest, string sdkVersion, @@ -111,6 +165,29 @@ public void MarkFilesAsCompressed() string expectedOutput, [CallerFilePath] string className = "File", [CallerMemberName] string methodName = "Method") + { + string appHostTemplatePath = FindAppHostTemplate(sdkVersion); + + using var stream = new MemoryStream(); + manifest.WriteUsingTemplate(stream, new BundlerParameters(appHostTemplatePath, fileName)); + + var newManifest = BundleManifest.FromBytes(stream.ToArray()); + AssertBundlesAreEqual(manifest, newManifest); + + string output = _fixture + .GetRunner() + .RunAndCaptureOutput( + Path.ChangeExtension(fileName, ".exe"), + stream.ToArray(), + null, + 5000, + className, + methodName); + + Assert.Equal(expectedOutput, output); + } + + private static string FindAppHostTemplate(string sdkVersion) { string sdkPath = Path.Combine(DotNetCorePathProvider.DefaultInstallationPath!, "sdk"); string? sdkVersionPath = null; @@ -130,20 +207,7 @@ public void MarkFilesAsCompressed() } string appHostPathTemplate = Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); - - using var stream = new MemoryStream(); - manifest.WriteUsingTemplate(stream, new BundlerParameters(appHostPathTemplate, fileName)); - - var newManifest = BundleManifest.FromBytes(stream.ToArray()); - AssertBundlesAreEqual(manifest, newManifest); - - string output = _fixture - .GetRunner() - .RunAndCaptureOutput(Path.ChangeExtension(fileName, ".exe"), stream.ToArray(), null, - 5000, - className, - methodName); - Assert.Equal(expectedOutput, output); + return appHostPathTemplate; } private static void AssertBundlesAreEqual(BundleManifest manifest, BundleManifest newManifest) diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs index e824f4b21..c2e4010ea 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.Designer.cs @@ -157,6 +157,13 @@ public class Resources { } } + public static byte[] HelloWorld_SingleFile_V6_WithResources { + get { + object obj = ResourceManager.GetObject("HelloWorld_SingleFile_V6_WithResources", resourceCulture); + return ((byte[])(obj)); + } + } + public static byte[] Assembly1_Forwarder { get { object obj = ResourceManager.GetObject("Assembly1_Forwarder", resourceCulture); diff --git a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx index 0ff471e63..5e722a4a9 100644 --- a/test/AsmResolver.DotNet.Tests/Properties/Resources.resx +++ b/test/AsmResolver.DotNet.Tests/Properties/Resources.resx @@ -66,6 +66,9 @@ ..\Resources\HelloWorld.SingleFile.v6.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\HelloWorld.SingleFile.v6.WithResources.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\Assembly1_Forwarder.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v6.WithResources.exe b/test/AsmResolver.DotNet.Tests/Resources/HelloWorld.SingleFile.v6.WithResources.exe new file mode 100644 index 0000000000000000000000000000000000000000..9da59aba9f824126a4fd9d8f3eafd4ea4d97ded8 GIT binary patch literal 219620 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 D)&5AX literal 0 HcmV?d00001 From 45e5d7db6f7ed1cd864d7c6a1104e171f1f4438a Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 12:44:08 +0200 Subject: [PATCH 30/51] Update API docs with descriptions of new BundlerParameters struct. --- docs/dotnet/bundles.rst | 32 +++++++++++++++---- .../Bundles/BundleManifestTest.cs | 7 ++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/dotnet/bundles.rst b/docs/dotnet/bundles.rst index 488260461..65cbdc774 100644 --- a/docs/dotnet/bundles.rst +++ b/docs/dotnet/bundles.rst @@ -82,18 +82,38 @@ AsmResolver does not provide built-in alternative heuristics for finding the rig Writing Bundles --------------- -Constructing new bundled executable files requires a template file that AsmResolver can base the final output on. This is similar how .NET compilers themselves do this as well. By default, the .NET SDK installs template binaries in either ``/sdk//AppHostTemplate`` or ``/packs/Microsoft.NETCore.App.Host.//runtimes//native``. It is then possible to use ``WriteUsingTemplate`` to construct a new binary. +Constructing new bundled executable files requires a template file that AsmResolver can base the final output on. This is similar how .NET compilers themselves do this as well. By default, the .NET SDK installs template binaries in one of the following directories: + +- ``/sdk//AppHostTemplate`` +- ``/packs/Microsoft.NETCore.App.Host.//runtimes//native`` + +Using this template file, it is then possible to write a new bundled executable file using ``WriteUsingTemplate``: .. code-block:: csharp BundleManifest manifest = ... - var manifest = manifest.WriteUsingTemplate( - @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", - @"C:\User\Admin\HelloWorld.exe", - @"HelloWorld.dll"); + manifest.WriteUsingTemplate( + @"C:\Path\To\Output\File.exe", + new BundlerParameters( + appHostTemplatePath: @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", + appBinaryPath: @"HelloWorld.dll")); + + +Typically on Windows, use an ```apphost.exe`` template if you want to construct a native binary that is framework dependent, and ``singlefilehost.exe`` for a fully self-contained binary. On Linux, use the ``apphost`` and ``singlefilehost`` ELF equivalents. +For bundle executable files targeting Windows, it may be required to copy over some values from the original PE file into the final bundle executable file. Usually these values include fields from the PE headers (such as the executable's sub-system target) and Win32 resources (such as application icons and version information). AsmResolver can automatically update these headers by specifying a source image in the ``BundlerParameters``: -Typically on Windows, use an ```apphost.exe`` template if you want to construct a native binary that is framework dependent, and ``singlefilehost.exe`` for a fully self-contained binary. +.. code-block:: csharp + + BundleManifest manifest = ... + manifest.WriteUsingTemplate( + @"C:\Path\To\Output\File.exe", + new BundlerParameters( + appHostTemplatePath: @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", + appBinaryPath: @"HelloWorld.dll", + imagePathToCopyHeadersFrom: @"C:\Path\To\Original\HelloWorld.exe")); + +``BundleManifest`` also defines other ```WriteUsingTemplate`` overloads taking ``byte[]``, ``IDataSource`` or ``IPEImage`` instances instead of paths. Managing Files diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 2bd797187..9ee1b23cd 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -143,6 +143,13 @@ public void WriteWithWin32Resources() "HelloWorld.dll", oldImage)); + manifest.WriteUsingTemplate( + @"C:\Path\To\Output\File.exe", + new BundlerParameters( + appHostTemplatePath: @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", + appBinaryPath: @"HelloWorld.dll", + imagePathToCopyHeadersFrom: @"C:\Path\To\HelloWorld.exe")); + // Verify new file still runs as expected. string output = _fixture .GetRunner() From 9872aacda8975bb4a67fb1b1b5b77fd622030777 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 12:48:18 +0200 Subject: [PATCH 31/51] Remove hardcoded paths in tests. --- .../Bundles/BundleManifestTest.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 9ee1b23cd..e2a1388d7 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -126,9 +126,11 @@ public void WriteWithSubSystem(SubSystem subSystem) Assert.Equal(subSystem, newFile.OptionalHeader.SubSystem); } - [Fact] + [SkippableFact] public void WriteWithWin32Resources() { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6_WithResources); string appHostTemplatePath = FindAppHostTemplate("6.0"); @@ -143,13 +145,6 @@ public void WriteWithWin32Resources() "HelloWorld.dll", oldImage)); - manifest.WriteUsingTemplate( - @"C:\Path\To\Output\File.exe", - new BundlerParameters( - appHostTemplatePath: @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\6.0.0\runtimes\win-x64\native\apphost.exe", - appBinaryPath: @"HelloWorld.dll", - imagePathToCopyHeadersFrom: @"C:\Path\To\HelloWorld.exe")); - // Verify new file still runs as expected. string output = _fixture .GetRunner() From 8d116207099d819f821ef95290e8cb63b65cf7ce Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 28 Mar 2022 13:00:26 +0200 Subject: [PATCH 32/51] Small typo fixes and removal of some compiler warnings. --- docs/dotnet/bundles.rst | 4 ++-- src/AsmResolver.DotNet/Bundles/BundleManifest.cs | 2 +- test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/dotnet/bundles.rst b/docs/dotnet/bundles.rst index 65cbdc774..e96491ae9 100644 --- a/docs/dotnet/bundles.rst +++ b/docs/dotnet/bundles.rst @@ -99,9 +99,9 @@ Using this template file, it is then possible to write a new bundled executable appBinaryPath: @"HelloWorld.dll")); -Typically on Windows, use an ```apphost.exe`` template if you want to construct a native binary that is framework dependent, and ``singlefilehost.exe`` for a fully self-contained binary. On Linux, use the ``apphost`` and ``singlefilehost`` ELF equivalents. +Typically on Windows, use an ``apphost.exe`` template if you want to construct a native binary that is framework dependent, and ``singlefilehost.exe`` for a fully self-contained binary. On Linux, use the ``apphost`` and ``singlefilehost`` ELF equivalents. -For bundle executable files targeting Windows, it may be required to copy over some values from the original PE file into the final bundle executable file. Usually these values include fields from the PE headers (such as the executable's sub-system target) and Win32 resources (such as application icons and version information). AsmResolver can automatically update these headers by specifying a source image in the ``BundlerParameters``: +For bundle executable files targeting Windows, it may be required to copy over some values from the original PE file into the final bundle executable file. Usually these values include fields from the PE headers (such as the executable's sub-system target) and Win32 resources (such as application icons and version information). AsmResolver can automatically update these headers by specifying a source image to pull this data from in the ``BundlerParameters``: .. code-block:: csharp diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index c21e6d20f..f5a957a28 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -384,7 +384,7 @@ private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters para /// /// This does not necessarily produce a working executable file, it only writes the contents of the entire manifest, /// without a host application that invokes the manifest. If you want to produce a runnable executable, use one - /// of the or one of its overloads instead. + /// of the WriteUsingTemplate methods instead. /// public ulong WriteManifest(IBinaryStreamWriter writer, bool isArm64Linux) { diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index e2a1388d7..e4852bbb6 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -208,8 +208,7 @@ private static string FindAppHostTemplate(string sdkVersion) $"Could not find the apphost template for .NET SDK version {sdkVersion}. This is an indication that the test environment does not have this SDK installed."); } - string appHostPathTemplate = Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); - return appHostPathTemplate; + return Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); } private static void AssertBundlesAreEqual(BundleManifest manifest, BundleManifest newManifest) From 45e96ce98b7cb7941ab87c67ba172f1871efdeec Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Mon, 28 Mar 2022 13:31:03 -0400 Subject: [PATCH 33/51] check that object is in a cor lib assembly --- .../Cloning/CloneContextAwareReferenceImporter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs index fb67345e0..966c32e3d 100644 --- a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs +++ b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs @@ -44,7 +44,9 @@ public override IMethodDefOrRef ImportMethod(IMethodDefOrRef method) /// protected override ITypeDefOrRef ImportType(TypeReference type) { - return type.Namespace == "System" && type.Name == nameof(System.Object) + return type.Namespace == "System" + && type.Name == nameof(System.Object) + && (type.Scope?.GetAssembly()?.IsCorLib ?? false) ? _context.Module.CorLibTypeFactory.Object.Type : base.ImportType(type); } From bc688fd43cbfddd9e010adea933a7d081fce1e60 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Mon, 28 Mar 2022 13:42:14 -0400 Subject: [PATCH 34/51] fix constructors for better binary compatibility --- src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs | 8 +++++++- src/AsmResolver.DotNet/Cloning/MemberCloner.cs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs index 43092c939..4bcf5894b 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs @@ -8,13 +8,19 @@ namespace AsmResolver.DotNet.Cloning /// public class MemberCloneContext { + /// + /// Creates a new instance of the class. + /// + /// The target module to copy the cloned members into. + public MemberCloneContext(ModuleDefinition module) : this(module, null) { } + /// /// Creates a new instance of the class. /// /// The target module to copy the cloned members into. /// The instantiator for creating the reference importer public MemberCloneContext(ModuleDefinition module, - Func? importerInstantiator = null) + Func? importerInstantiator) { Module = module ?? throw new ArgumentNullException(nameof(module)); Importer = importerInstantiator?.Invoke(this) ?? new CloneContextAwareReferenceImporter(this); diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs index 2d1a6022b..acd0d1811 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs @@ -26,13 +26,19 @@ public partial class MemberCloner private readonly HashSet _propertiesToClone = new(); private readonly HashSet _eventsToClone = new(); + /// + /// Creates a new instance of the class. + /// + /// The target module to copy the members into. + public MemberCloner(ModuleDefinition targetModule) : this(targetModule, null) { } + /// /// Creates a new instance of the class. /// /// The target module to copy the members into. /// The instantiator for creating the reference importer public MemberCloner(ModuleDefinition targetModule, - Func? importerInstantiator = null) + Func? importerInstantiator) { _targetModule = targetModule ?? throw new ArgumentNullException(nameof(targetModule)); _importerInstantiator = importerInstantiator; From 7b8d92eaf7865f26c93ce74d7df2d1215f29e149 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Mon, 28 Mar 2022 13:51:52 -0400 Subject: [PATCH 35/51] make line ending setting coorespond to code base line endings --- .editorconfig | 2 +- AsmResolver.sln | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index b1533ed3f..3c5663e27 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,7 @@ [*] charset = utf-8 -end_of_line = lf +end_of_line = crlf trim_trailing_whitespace = true insert_final_newline = true indent_style = space diff --git a/AsmResolver.sln b/AsmResolver.sln index 313cb8c0b..526ac85f6 100644 --- a/AsmResolver.sln +++ b/AsmResolver.sln @@ -71,9 +71,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TlsTest", "test\TestBinarie EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CallManagedExport", "test\TestBinaries\Native\CallManagedExport\CallManagedExport.vcxproj", "{40483E28-C703-4933-BA5B-9512EF6E6A21}" EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "HelloWorldVB", "test\TestBinaries\DotNet\HelloWorldVB\HelloWorldVB.vbproj", "{CF6A7E02-37DC-4963-AC14-76D74ADCD87A}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ClassLibraryVB", "test\TestBinaries\DotNet\ClassLibraryVB\ClassLibraryVB.vbproj", "{2D1DF5DA-7367-4490-B3F0-B996348E150B}" +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "HelloWorldVB", "test\TestBinaries\DotNet\HelloWorldVB\HelloWorldVB.vbproj", "{CF6A7E02-37DC-4963-AC14-76D74ADCD87A}" +EndProject +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "ClassLibraryVB", "test\TestBinaries\DotNet\ClassLibraryVB\ClassLibraryVB.vbproj", "{2D1DF5DA-7367-4490-B3F0-B996348E150B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{66C7E95F-0C1A-466E-988A-C84D5542458B}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + CONTRIBUTING.md = CONTRIBUTING.md + LICENSE.md = LICENSE.md + README.md = README.md + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From c0bfc4578895a4c7fbf73a40fb02abcf72776304 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Tue, 29 Mar 2022 16:54:56 -0400 Subject: [PATCH 36/51] add an ApplyMethod for PropertyDefinition and EventDefinition --- src/AsmResolver.DotNet/EventDefinition.cs | 31 +++++++++++++++----- src/AsmResolver.DotNet/PropertyDefinition.cs | 18 ++++++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/AsmResolver.DotNet/EventDefinition.cs b/src/AsmResolver.DotNet/EventDefinition.cs index e333a7e5c..c9a899e15 100644 --- a/src/AsmResolver.DotNet/EventDefinition.cs +++ b/src/AsmResolver.DotNet/EventDefinition.cs @@ -136,19 +136,19 @@ public IList Semantics } /// - /// Gets the method definition representing the add accessor of this event definition. + /// Gets the method definition representing the first add accessor of this event definition. /// public MethodDefinition? AddMethod => Semantics.FirstOrDefault(s => s.Attributes == MethodSemanticsAttributes.AddOn)?.Method; /// - /// Gets the method definition representing the remove accessor of this event definition. + /// Gets the method definition representing the first remove accessor of this event definition. /// public MethodDefinition? RemoveMethod => Semantics.FirstOrDefault(s => s.Attributes == MethodSemanticsAttributes.RemoveOn)?.Method; /// - /// Gets the method definition representing the fire accessor of this event definition. + /// Gets the method definition representing the first fire accessor of this event definition. /// public MethodDefinition? FireMethod => Semantics.FirstOrDefault(s => s.Attributes == MethodSemanticsAttributes.Fire)?.Method; @@ -164,6 +164,23 @@ public IList CustomAttributes } } + /// + /// Clear and apply these methods to the event definition. + /// + /// The method definition representing the add accessor of this event definition. + /// The method definition representing the remove accessor of this event definition. + /// The method definition representing the fire accessor of this event definition. + public void ApplyMethods(MethodDefinition? addMethod, MethodDefinition? removeMethod, MethodDefinition? fireMethod) + { + Semantics.Clear(); + if (addMethod is not null) + Semantics.Add(new MethodSemantics(addMethod, MethodSemanticsAttributes.AddOn)); + if (removeMethod is not null) + Semantics.Add(new MethodSemantics(removeMethod, MethodSemanticsAttributes.RemoveOn)); + if (fireMethod is not null) + Semantics.Add(new MethodSemantics(fireMethod, MethodSemanticsAttributes.Fire)); + } + /// public bool IsAccessibleFromType(TypeDefinition type) => Semantics.Any(s => s.Method?.IsAccessibleFromType(type) ?? false); @@ -188,7 +205,7 @@ public bool IsImportedInModule(ModuleDefinition module) new OwnedCollection(this); /// - /// Obtains the name of the property definition. + /// Obtains the name of the event definition. /// /// The name. /// @@ -197,7 +214,7 @@ public bool IsImportedInModule(ModuleDefinition module) protected virtual Utf8String? GetName() => null; /// - /// Obtains the event type of the property definition. + /// Obtains the event type of the event definition. /// /// The event type. /// @@ -206,7 +223,7 @@ public bool IsImportedInModule(ModuleDefinition module) protected virtual ITypeDefOrRef? GetEventType() => null; /// - /// Obtains the declaring type of the property definition. + /// Obtains the declaring type of the event definition. /// /// The declaring type. /// @@ -215,7 +232,7 @@ public bool IsImportedInModule(ModuleDefinition module) protected virtual TypeDefinition? GetDeclaringType() => null; /// - /// Obtains the methods associated to this property definition. + /// Obtains the methods associated to this event definition. /// /// The method semantic objects. /// diff --git a/src/AsmResolver.DotNet/PropertyDefinition.cs b/src/AsmResolver.DotNet/PropertyDefinition.cs index 93348cedb..6b6975a9c 100644 --- a/src/AsmResolver.DotNet/PropertyDefinition.cs +++ b/src/AsmResolver.DotNet/PropertyDefinition.cs @@ -170,17 +170,31 @@ public IList CustomAttributes } /// - /// Gets the method definition representing the get accessor of this property definition. + /// Gets the method definition representing the first get accessor of this property definition. /// public MethodDefinition? GetMethod => Semantics.FirstOrDefault(s => s.Attributes == MethodSemanticsAttributes.Getter)?.Method; /// - /// Gets the method definition representing the set accessor of this property definition. + /// Gets the method definition representing the first set accessor of this property definition. /// public MethodDefinition? SetMethod => Semantics.FirstOrDefault(s => s.Attributes == MethodSemanticsAttributes.Setter)?.Method; + /// + /// Clear and apply these methods to the property definition. + /// + /// The method definition representing the get accessor of this property definition. + /// The method definition representing the set accessor of this property definition. + public void ApplyMethods(MethodDefinition? getMethod, MethodDefinition? setMethod) + { + Semantics.Clear(); + if (getMethod is not null) + Semantics.Add(new MethodSemantics(getMethod, MethodSemanticsAttributes.Getter)); + if (setMethod is not null) + Semantics.Add(new MethodSemantics(setMethod, MethodSemanticsAttributes.Setter)); + } + /// public bool IsAccessibleFromType(TypeDefinition type) => Semantics.Any(s => s.Method?.IsAccessibleFromType(type) ?? false); From 51666952a00a8d4cceccd251aafbc9c0ac2662a2 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Wed, 30 Mar 2022 09:29:34 -0400 Subject: [PATCH 37/51] change name to SetSemanticMethods --- src/AsmResolver.DotNet/EventDefinition.cs | 2 +- src/AsmResolver.DotNet/PropertyDefinition.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AsmResolver.DotNet/EventDefinition.cs b/src/AsmResolver.DotNet/EventDefinition.cs index c9a899e15..f319e1270 100644 --- a/src/AsmResolver.DotNet/EventDefinition.cs +++ b/src/AsmResolver.DotNet/EventDefinition.cs @@ -170,7 +170,7 @@ public IList CustomAttributes /// The method definition representing the add accessor of this event definition. /// The method definition representing the remove accessor of this event definition. /// The method definition representing the fire accessor of this event definition. - public void ApplyMethods(MethodDefinition? addMethod, MethodDefinition? removeMethod, MethodDefinition? fireMethod) + public void SetSemanticMethods(MethodDefinition? addMethod, MethodDefinition? removeMethod, MethodDefinition? fireMethod) { Semantics.Clear(); if (addMethod is not null) diff --git a/src/AsmResolver.DotNet/PropertyDefinition.cs b/src/AsmResolver.DotNet/PropertyDefinition.cs index 6b6975a9c..3df05c38c 100644 --- a/src/AsmResolver.DotNet/PropertyDefinition.cs +++ b/src/AsmResolver.DotNet/PropertyDefinition.cs @@ -186,7 +186,7 @@ public IList CustomAttributes /// /// The method definition representing the get accessor of this property definition. /// The method definition representing the set accessor of this property definition. - public void ApplyMethods(MethodDefinition? getMethod, MethodDefinition? setMethod) + public void SetSemanticMethods(MethodDefinition? getMethod, MethodDefinition? setMethod) { Semantics.Clear(); if (getMethod is not null) From b5ac4462a109d3b98330ee61a71f19c57e467a2e Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Wed, 30 Mar 2022 09:39:14 -0400 Subject: [PATCH 38/51] name changes and context property in the cloning reference importer --- .../Cloning/CloneContextAwareReferenceImporter.cs | 10 ++++++---- src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs | 6 +++--- src/AsmResolver.DotNet/Cloning/MemberCloner.cs | 10 +++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs index 235f5a277..0382fb8a9 100644 --- a/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs +++ b/src/AsmResolver.DotNet/Cloning/CloneContextAwareReferenceImporter.cs @@ -5,10 +5,7 @@ namespace AsmResolver.DotNet.Cloning /// public class CloneContextAwareReferenceImporter : ReferenceImporter { - /// - /// The working space for this member cloning procedure. - /// - protected readonly MemberCloneContext _context; + private readonly MemberCloneContext _context; /// /// Creates a new instance of the class. @@ -20,6 +17,11 @@ public CloneContextAwareReferenceImporter(MemberCloneContext context) _context = context; } + /// + /// The working space for this member cloning procedure. + /// + protected MemberCloneContext Context => _context; + /// protected override ITypeDefOrRef ImportType(TypeDefinition type) { diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs index 4bcf5894b..78c52c8c3 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloneContext.cs @@ -18,12 +18,12 @@ public class MemberCloneContext /// Creates a new instance of the class. /// /// The target module to copy the cloned members into. - /// The instantiator for creating the reference importer + /// The factory for creating the reference importer public MemberCloneContext(ModuleDefinition module, - Func? importerInstantiator) + Func? importerFactory) { Module = module ?? throw new ArgumentNullException(nameof(module)); - Importer = importerInstantiator?.Invoke(this) ?? new CloneContextAwareReferenceImporter(this); + Importer = importerFactory?.Invoke(this) ?? new CloneContextAwareReferenceImporter(this); } /// diff --git a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs index acd0d1811..1580d1efa 100644 --- a/src/AsmResolver.DotNet/Cloning/MemberCloner.cs +++ b/src/AsmResolver.DotNet/Cloning/MemberCloner.cs @@ -17,7 +17,7 @@ namespace AsmResolver.DotNet.Cloning /// public partial class MemberCloner { - private readonly Func? _importerInstantiator; + private readonly Func? _importerFactory; private readonly ModuleDefinition _targetModule; private readonly HashSet _typesToClone = new(); @@ -36,12 +36,12 @@ public partial class MemberCloner /// Creates a new instance of the class. /// /// The target module to copy the members into. - /// The instantiator for creating the reference importer + /// The factory for creating the reference importer public MemberCloner(ModuleDefinition targetModule, - Func? importerInstantiator) + Func? importerFactory) { _targetModule = targetModule ?? throw new ArgumentNullException(nameof(targetModule)); - _importerInstantiator = importerInstantiator; + _importerFactory = importerFactory; } /// @@ -230,7 +230,7 @@ public MemberCloner Include(EventDefinition @event) /// An object representing the result of the cloning process. public MemberCloneResult Clone() { - var context = new MemberCloneContext(_targetModule, _importerInstantiator); + var context = new MemberCloneContext(_targetModule, _importerFactory); CreateMemberStubs(context); DeepCopyMembers(context); From 11f2fe1ae55b2b39690206b4c19a2f914c27eaa2 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 30 Mar 2022 21:38:15 +0200 Subject: [PATCH 39/51] Prioritize app binary path verification over updating / rebuilding the template PE file. --- src/AsmResolver.DotNet/Bundles/BundleManifest.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index f5a957a28..f5fd82f8d 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Threading; using AsmResolver.Collections; using AsmResolver.IO; -using AsmResolver.PE; using AsmResolver.PE.File; using AsmResolver.PE.File.Headers; using AsmResolver.PE.Win32Resources.Builder; @@ -283,13 +281,13 @@ public void WriteUsingTemplate(IBinaryStreamWriter writer, BundlerParameters par if (appBinaryEntry is null) throw new ArgumentException($"Application {parameters.ApplicationBinaryPath} does not exist within the bundle."); - if (!parameters.IsArm64Linux) - EnsureAppHostPEHeadersAreUpToDate(ref parameters); - byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(parameters.ApplicationBinaryPath); if (appBinaryPathBytes.Length > 1024) throw new ArgumentException("Application binary path cannot exceed 1024 bytes."); + if (!parameters.IsArm64Linux) + EnsureAppHostPEHeadersAreUpToDate(ref parameters); + var appHostTemplateSource = new ByteArrayDataSource(parameters.ApplicationHostTemplate); long signatureAddress = FindInFile(appHostTemplateSource, BundleSignature); if (signatureAddress == -1) From 59ead8c26cec188375353a4d1b22423ab4691a6e Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 30 Mar 2022 21:54:32 +0200 Subject: [PATCH 40/51] Add deterministic bundle ID generation. --- .../Bundles/BundleManifest.cs | 46 ++++++++++++++++++- .../Bundles/BundleManifestTest.cs | 43 +++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index f5fd82f8d..bd8e6f80b 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Text; using System.Threading; using AsmResolver.Collections; @@ -17,6 +18,8 @@ namespace AsmResolver.DotNet.Bundles /// public class BundleManifest { + private const int DefaultBundleIDLength = 12; + private static readonly byte[] BundleSignature = { 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, @@ -35,13 +38,22 @@ public class BundleManifest /// protected BundleManifest() { - BundleID = string.Empty; } /// /// Creates a new bundle manifest. /// /// The file format version. + public BundleManifest(uint majorVersionNumber) + { + MajorVersion = majorVersionNumber; + MinorVersion = 0; + } + + /// + /// Creates a new bundle manifest with a specific bundle identifier. + /// + /// The file format version. /// The unique bundle manifest identifier. public BundleManifest(uint majorVersionNumber, string bundleId) { @@ -82,7 +94,11 @@ public uint MinorVersion /// /// Gets or sets the unique identifier for the bundle manifest. /// - public string BundleID + /// + /// When this property is set to null, the bundle identifier will be generated upon writing the manifest + /// based on the contents of the manifest. + /// + public string? BundleID { get; set; @@ -249,6 +265,30 @@ public static long FindBundleManifestAddress(IDataSource source) /// protected virtual IList GetFiles() => new OwnedCollection(this); + /// + /// Generates a bundle identifier based on the SHA-256 hashes of all files in the manifest. + /// + /// The generated bundle identifier. + public string GenerateDeterministicBundleID() + { + using var manifestHasher = SHA256.Create(); + + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + using var fileHasher = SHA256.Create(); + byte[] fileHash = fileHasher.ComputeHash(file.GetData()); + manifestHasher.TransformBlock(fileHash, 0, fileHash.Length, fileHash, 0); + } + + manifestHasher.TransformFinalBlock(Array.Empty(), 0, 0); + byte[] manifestHash = manifestHasher.Hash; + + return Convert.ToBase64String(manifestHash) + .Substring(DefaultBundleIDLength) + .Replace('/', '_'); + } + /// /// Constructs a new application host file based on the bundle manifest. /// @@ -415,6 +455,8 @@ private void WriteManifestHeader(IBinaryStreamWriter writer) writer.WriteUInt32(MajorVersion); writer.WriteUInt32(MinorVersion); writer.WriteInt32(Files.Count); + + BundleID ??= GenerateDeterministicBundleID(); writer.WriteBinaryFormatterString(BundleID); if (MajorVersion >= 2) diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index e4852bbb6..0bed69a5a 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using AsmResolver.DotNet.Bundles; using AsmResolver.IO; using AsmResolver.PE; @@ -160,6 +161,48 @@ public void WriteWithWin32Resources() Assert.Equal(versionInfo.FixedVersionInfo.FileVersion, newVersionInfo.FixedVersionInfo.FileVersion); } + [Fact] + public void NewManifestShouldGenerateBundleIdIfUnset() + { + var manifest = new BundleManifest(6); + + manifest.Files.Add(new BundleFile("HelloWorld.dll", BundleFileType.Assembly, + Properties.Resources.HelloWorld_NetCore)); + manifest.Files.Add(new BundleFile("HelloWorld.runtimeconfig.json", BundleFileType.RuntimeConfigJson, + Encoding.UTF8.GetBytes(@"{ + ""runtimeOptions"": { + ""tfm"": ""net6.0"", + ""includedFrameworks"": [ + { + ""name"": ""Microsoft.NETCore.App"", + ""version"": ""6.0.0"" + } + ] + } +}"))); + + Assert.Null(manifest.BundleID); + + using var stream = new MemoryStream(); + manifest.WriteUsingTemplate(stream, new BundlerParameters( + FindAppHostTemplate("6.0"), + "HelloWorld.dll")); + + Assert.NotNull(manifest.BundleID); + } + + [Fact] + public void SameManifestContentsShouldResultInSameBundleID() + { + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); + + var newManifest = new BundleManifest(manifest.MajorVersion); + foreach (var file in manifest.Files) + newManifest.Files.Add(new BundleFile(file.RelativePath, file.Type, file.GetData())); + + Assert.Equal(manifest.BundleID, newManifest.GenerateDeterministicBundleID()); + } + private void AssertWriteManifestWindowsPreservesOutput( BundleManifest manifest, string sdkVersion, From 405c13da5373784707abddc38e62efedcbca9d93 Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 30 Mar 2022 21:56:49 +0200 Subject: [PATCH 41/51] Update docs on bundle ID generation. --- docs/dotnet/bundles.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/dotnet/bundles.rst b/docs/dotnet/bundles.rst index e96491ae9..670b9eb3d 100644 --- a/docs/dotnet/bundles.rst +++ b/docs/dotnet/bundles.rst @@ -17,9 +17,7 @@ Creating Bundles .. code-block:: csharp - var manifest = new BundleManifest( - majorVersionNumber: 6, - bundleId: ""); + var manifest = new BundleManifest(majorVersionNumber: 6); The major version number refers to the file format that should be used when saving the manifest. Below an overview of the values that are recognized by the CLR: @@ -34,12 +32,23 @@ The major version number refers to the file format that should be used when savi | .NET 6.0 | 6 | +----------------------+----------------------------+ +To create a new bundle with a specific bundle identifier, use the overloaded constructor + +.. code-block:: csharp + + var manifest = new BundleManifest(6, "MyBundleID"); + + It is also possible to change the version number as well as the bundle ID later, since these values are exposed as mutable properties ``MajorVersion`` and ``BundleID`` .. code-block:: csharp manifest.MajorVersion = 6; - manifest.BundleID = GenerateRandomID(); + manifest.BundleID = manifest.GenerateDeterministicBundleID(); + +.. note:: + + If ``BundleID`` is left unset (``null``), it will be automatically assigned a new one using ``GenerateDeterministicBundleID`` upon writing. Reading Bundles From c5545dc39db34add58deb522343ab35c3a339b6b Mon Sep 17 00:00:00 2001 From: Washi Date: Wed, 30 Mar 2022 22:09:36 +0200 Subject: [PATCH 42/51] Move EofData and ExtraSectionData into IPEFile interface. --- src/AsmResolver.PE.File/IPEFile.cs | 18 ++++++++++++++++++ src/AsmResolver.PE.File/PEFile.cs | 8 ++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/AsmResolver.PE.File/IPEFile.cs b/src/AsmResolver.PE.File/IPEFile.cs index 6f22ca61a..57e4e50a9 100644 --- a/src/AsmResolver.PE.File/IPEFile.cs +++ b/src/AsmResolver.PE.File/IPEFile.cs @@ -61,6 +61,24 @@ PEMappingMode MappingMode get; } + /// + /// Gets or sets the padding data in between the last section header and the first section. + /// + public ISegment? ExtraSectionData + { + get; + set; + } + + /// + /// Gets or sets the data appended to the end of the file (EoF), if available. + /// + public ISegment? EofData + { + get; + set; + } + /// /// Finds the section containing the provided virtual address. /// diff --git a/src/AsmResolver.PE.File/PEFile.cs b/src/AsmResolver.PE.File/PEFile.cs index 276e4aa0b..d1dc0f2d7 100644 --- a/src/AsmResolver.PE.File/PEFile.cs +++ b/src/AsmResolver.PE.File/PEFile.cs @@ -94,18 +94,14 @@ public PEMappingMode MappingMode protected set; } - /// - /// Gets or sets the padding data in between the last section header and the first section. - /// + /// public ISegment? ExtraSectionData { get => _extraSectionData.Value; set => _extraSectionData.Value = value; } - /// - /// Gets or sets the data appended to the end of the file (EoF), if available. - /// + /// public ISegment? EofData { get => _eofData.Value; From 2da80a30a63bed91984e602fe11ae67a5aca9cf5 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Wed, 30 Mar 2022 19:45:06 -0400 Subject: [PATCH 43/51] allow net 6 assembly trimming --- src/AsmResolver.PE.File/AsmResolver.PE.File.csproj | 1 + .../AsmResolver.PE.Win32Resources.csproj | 1 + src/AsmResolver.PE/AsmResolver.PE.csproj | 1 + src/AsmResolver/AsmResolver.csproj | 3 ++- .../DotNet/Metadata/UserStringsStreamTest.cs | 2 +- 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj b/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj index 6341887ff..5c0bfda0f 100644 --- a/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj +++ b/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj @@ -9,6 +9,7 @@ true enable net6.0;netcoreapp3.1;netstandard2.0 + true diff --git a/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj b/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj index 0baf5f6c0..219f54c0d 100644 --- a/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj +++ b/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj @@ -7,6 +7,7 @@ 1701;1702;NU5105 enable net6.0;netcoreapp3.1;netstandard2.0 + true diff --git a/src/AsmResolver.PE/AsmResolver.PE.csproj b/src/AsmResolver.PE/AsmResolver.PE.csproj index 43c3a61d5..058547040 100644 --- a/src/AsmResolver.PE/AsmResolver.PE.csproj +++ b/src/AsmResolver.PE/AsmResolver.PE.csproj @@ -8,6 +8,7 @@ 1701;1702;NU5105 enable net6.0;netcoreapp3.1;netstandard2.0 + true diff --git a/src/AsmResolver/AsmResolver.csproj b/src/AsmResolver/AsmResolver.csproj index da0e0e6cb..07dbf2281 100644 --- a/src/AsmResolver/AsmResolver.csproj +++ b/src/AsmResolver/AsmResolver.csproj @@ -3,11 +3,12 @@ AsmResolver The base library for the AsmResolver executable file inspection toolsuite. - exe pe dotnet cil inspection manipulation assembly disassembly + exe pe dotnet cil inspection manipulation assembly disassembly true 1701;1702;NU5105 enable net6.0;netcoreapp3.1;netstandard2.0 + true diff --git a/test/AsmResolver.PE.Tests/DotNet/Metadata/UserStringsStreamTest.cs b/test/AsmResolver.PE.Tests/DotNet/Metadata/UserStringsStreamTest.cs index 9b3c274ac..fb350b97a 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Metadata/UserStringsStreamTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Metadata/UserStringsStreamTest.cs @@ -22,7 +22,7 @@ private static void AssertHasString(byte[] streamData, string needle) [InlineData("")] [InlineData("ABC")] [InlineData("DEF")] - public void FindExistingString(string? value) => AssertHasString(new byte[] + public void FindExistingString(string value) => AssertHasString(new byte[] { 0x00, 0x07, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, From 28e8d230fbe8c2e1239345a1c211a6a9fd4040aa Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 2 Apr 2022 15:02:31 +0200 Subject: [PATCH 44/51] Add clarifying remarks on BundleFile.IsCompressed and Compress(). --- src/AsmResolver.DotNet/Bundles/BundleFile.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleFile.cs b/src/AsmResolver.DotNet/Bundles/BundleFile.cs index 84dba4101..958eeba16 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleFile.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleFile.cs @@ -84,6 +84,13 @@ public BundleFileType Type /// /// Gets or sets a value indicating whether the data stored in is compressed or not. /// + /// + /// The default implementation of the application host by Microsoft only supports compressing files if it is + /// a fully self-contained binary and the file is not the .deps.json nor the .runtmeconfig.json + /// file. This property does not do validation on any of these conditions. As such, if the file is supposed to be + /// compressed with any of these conditions not met, a custom application host template needs to be provided + /// upon serializing the bundle for it to be runnable. + /// public bool IsCompressed { get; @@ -170,6 +177,13 @@ public byte[] GetData(bool decompressIfRequired) /// with the result. /// /// Occurs when the file was already compressed. + /// + /// The default implementation of the application host by Microsoft only supports compressing files if it is + /// a fully self-contained binary and the file is not the .deps.json nor the .runtmeconfig.json + /// file. This method does not do validation on any of these conditions. As such, if the file is supposed to be + /// compressed with any of these conditions not met, a custom application host template needs to be provided + /// upon serializing the bundle for it to be runnable. + /// public void Compress() { if (IsCompressed) @@ -191,7 +205,7 @@ public void Compress() /// Marks the file as uncompressed, decompresses the file contents, and replaces the value of /// with the result. /// - /// Occurs when the file was already compressed. + /// Occurs when the file was not compressed. public void Decompress() { if (!IsCompressed) From e35aa59e0f8a6fd51f12401b47607314f0687919 Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 2 Apr 2022 15:13:22 +0200 Subject: [PATCH 45/51] Bump version numbers. --- Directory.Build.props | 2 +- appveyor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 09d02e0ef..648c5ce2f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,7 +7,7 @@ https://github.com/Washi1337/AsmResolver git 10 - 4.9.0 + 4.10.0 diff --git a/appveyor.yml b/appveyor.yml index 6de584d01..fe19b7d43 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ - master image: Visual Studio 2022 - version: 4.9.0-master-build.{build} + version: 4.10.0-master-build.{build} configuration: Release skip_commits: @@ -33,7 +33,7 @@ - development image: Visual Studio 2022 - version: 4.9.0-dev-build.{build} + version: 4.10.0-dev-build.{build} configuration: Release skip_commits: From 03ec8b81752f476e778a4a9812545bd98c3f5e0f Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Mon, 4 Apr 2022 17:38:04 -0400 Subject: [PATCH 46/51] add json source generation for RuntimeConfiguration --- .../Config/Json/RuntimeConfiguration.cs | 12 ++---------- .../Json/RuntimeConfigurationSerializerContext.cs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 src/AsmResolver.DotNet/Config/Json/RuntimeConfigurationSerializerContext.cs diff --git a/src/AsmResolver.DotNet/Config/Json/RuntimeConfiguration.cs b/src/AsmResolver.DotNet/Config/Json/RuntimeConfiguration.cs index 3a8ef6863..227751398 100644 --- a/src/AsmResolver.DotNet/Config/Json/RuntimeConfiguration.cs +++ b/src/AsmResolver.DotNet/Config/Json/RuntimeConfiguration.cs @@ -1,6 +1,5 @@ using System.IO; using System.Text.Json; -using System.Text.Json.Serialization; namespace AsmResolver.DotNet.Config.Json { @@ -9,13 +8,6 @@ namespace AsmResolver.DotNet.Config.Json /// public class RuntimeConfiguration { - private static readonly JsonSerializerOptions JsonSerializerOptions = new() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; - /// /// Parses runtime configuration from a JSON file. /// @@ -33,7 +25,7 @@ public class RuntimeConfiguration /// The parsed runtime configuration. public static RuntimeConfiguration? FromJson(string json) { - return JsonSerializer.Deserialize(json, JsonSerializerOptions); + return JsonSerializer.Deserialize(json, RuntimeConfigurationSerializerContext.Default.RuntimeConfiguration); } /// @@ -67,7 +59,7 @@ public RuntimeOptions RuntimeOptions /// The JSON string. public string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, RuntimeConfigurationSerializerContext.Default.RuntimeConfiguration); } /// diff --git a/src/AsmResolver.DotNet/Config/Json/RuntimeConfigurationSerializerContext.cs b/src/AsmResolver.DotNet/Config/Json/RuntimeConfigurationSerializerContext.cs new file mode 100644 index 000000000..7f77c1dc6 --- /dev/null +++ b/src/AsmResolver.DotNet/Config/Json/RuntimeConfigurationSerializerContext.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace AsmResolver.DotNet.Config.Json +{ + [JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] + [JsonSerializable(typeof(RuntimeConfiguration))] + internal partial class RuntimeConfigurationSerializerContext : JsonSerializerContext + { + } +} From af40369d5fa7ca557057785dba745ad0258fcca2 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Mon, 4 Apr 2022 17:40:32 -0400 Subject: [PATCH 47/51] add annotations for DynamicMethodHelper --- .../Code/Cil/CilMethodBody.cs | 1 + .../DynamicMethodDefinition.cs | 3 +- src/AsmResolver.DotNet/DynamicMethodHelper.cs | 3 +- .../RequiresUnreferencedCodeAttribute.cs | 34 +++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/AsmResolver.DotNet/RequiresUnreferencedCodeAttribute.cs diff --git a/src/AsmResolver.DotNet/Code/Cil/CilMethodBody.cs b/src/AsmResolver.DotNet/Code/Cil/CilMethodBody.cs index 633440c24..180e474f8 100644 --- a/src/AsmResolver.DotNet/Code/Cil/CilMethodBody.cs +++ b/src/AsmResolver.DotNet/Code/Cil/CilMethodBody.cs @@ -136,6 +136,7 @@ public bool VerifyLabelsOnBuild /// The method that owns the method body. /// The Dynamic Method/Delegate/DynamicResolver. /// The method body. + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Calls ResolveDynamicResolver")] public static CilMethodBody FromDynamicMethod(MethodDefinition method, object dynamicMethodObj) { if (!(method.Module is SerializedModuleDefinition module)) diff --git a/src/AsmResolver.DotNet/DynamicMethodDefinition.cs b/src/AsmResolver.DotNet/DynamicMethodDefinition.cs index 90e5865bf..b95d8f003 100644 --- a/src/AsmResolver.DotNet/DynamicMethodDefinition.cs +++ b/src/AsmResolver.DotNet/DynamicMethodDefinition.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using AsmResolver.DotNet.Code.Cil; using AsmResolver.DotNet.Signatures; @@ -18,6 +18,7 @@ public class DynamicMethodDefinition : MethodDefinition /// /// Target Module /// Dynamic Method / Delegate / DynamicResolver + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Calls ResolveDynamicResolver and FromDynamicMethod")] public DynamicMethodDefinition(ModuleDefinition module,object dynamicMethodObj) : base(new MetadataToken(TableIndex.Method, 0)) { diff --git a/src/AsmResolver.DotNet/DynamicMethodHelper.cs b/src/AsmResolver.DotNet/DynamicMethodHelper.cs index 7e856d135..f3cece5db 100644 --- a/src/AsmResolver.DotNet/DynamicMethodHelper.cs +++ b/src/AsmResolver.DotNet/DynamicMethodHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -81,6 +81,7 @@ private static void InterpretEHInfo(CilMethodBody methodBody, ReferenceImporter } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Calls GetTypes")] public static object ResolveDynamicResolver(object dynamicMethodObj) { //Convert dynamicMethodObj to DynamicResolver diff --git a/src/AsmResolver.DotNet/RequiresUnreferencedCodeAttribute.cs b/src/AsmResolver.DotNet/RequiresUnreferencedCodeAttribute.cs new file mode 100644 index 000000000..c5fd0fea6 --- /dev/null +++ b/src/AsmResolver.DotNet/RequiresUnreferencedCodeAttribute.cs @@ -0,0 +1,34 @@ +#if !NET6_0_OR_GREATER +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that the specified method requires dynamic access to code that is not + /// referenced statically, for example, through System.Reflection. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)] + internal sealed class RequiresUnreferencedCodeAttribute : Attribute + { + /// + /// Gets a message that contains information about the usage of unreferenced code. + /// + public string Message { get; } + + /// + /// Gets or sets an optional URL that contains more information about the method, + /// why it requires unreferenced code, and what options a consumer has to deal with + /// it. + /// + public string? Url { get; set; } + + /// + /// Initializes a new instance of the System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute + /// class with the specified message. + /// + /// A message that contains information about the usage of unreferenced code. + public RequiresUnreferencedCodeAttribute(string message) + { + Message = message; + } + } +} +#endif From 891af44cfa89a2a031ab6f88394635b78b5fdde2 Mon Sep 17 00:00:00 2001 From: Washi Date: Thu, 7 Apr 2022 20:23:56 +0200 Subject: [PATCH 48/51] Add discord server link. --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index db28f348a..31582ebfe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ AsmResolver =========== - [![Master branch build status](https://img.shields.io/appveyor/ci/Washi1337/AsmResolver/master.svg)](https://ci.appveyor.com/project/Washi1337/asmresolver/branch/master) [![Nuget feed](https://img.shields.io/nuget/v/AsmResolver.svg)](https://www.nuget.org/packages/AsmResolver/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Documentation Status](https://readthedocs.org/projects/asmresolver/badge/?version=latest)](https://asmresolver.readthedocs.io/en/latest/?badge=latest) + [![Master branch build status](https://img.shields.io/appveyor/ci/Washi1337/AsmResolver/master.svg)](https://ci.appveyor.com/project/Washi1337/asmresolver/branch/master) + [![Nuget feed](https://img.shields.io/nuget/v/AsmResolver.svg)](https://www.nuget.org/packages/AsmResolver/) + [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + [![Documentation Status](https://readthedocs.org/projects/asmresolver/badge/?version=latest)](https://asmresolver.readthedocs.io/en/latest/?badge=latest) + [![Discord](https://img.shields.io/discord/961647807591243796.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/Y7DTBkbhJJ) AsmResolver is a PE inspection library allowing .NET programmers to read, modify and write executable files. This includes .NET as well as native images. The library exposes high-level representations of the PE, while still allowing the user to access low-level structures. @@ -53,6 +57,12 @@ Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on general workflow and code style. +Found a bug or have questions? +------------------------------ +Please use the [issue tracker](https://github.com/Washi1337/AsmResolver/issues). Try to be as descriptive as possible. + +You can also join the [Discord](https://discord.gg/Y7DTBkbhJJ) to engage more directly with the community. + Acknowledgements ---------------- @@ -60,12 +70,7 @@ AsmResolver started out as a hobby project, but has grown into a community proje - Special thanks to all the people who contributed [directly with code commits](https://github.com/Washi1337/AsmResolver/graphs/contributors). -- Another big thank you to all the people that suggested new features, provided feedback on the API design, have done extensive testing, and/or reported bugs on the [issue board](https://github.com/Washi1337/AsmResolver/issues), by e-mail, or through DMs. +- Another big thank you to all the people that suggested new features, provided feedback on the API design, have done extensive testing, and/or reported bugs on the [issue board](https://github.com/Washi1337/AsmResolver/issues), by e-mail, or through DMs. If you feel you have been under-represented in these acknowledgements, feel free to contact me. - -Found a bug or have questions? ------------------------------- -Please use the [issue tracker](https://github.com/Washi1337/AsmResolver/issues). Try to be as descriptive as possible. - From 32f8ae737144a5c6fd18ac33257b9daaceee60de Mon Sep 17 00:00:00 2001 From: Washi Date: Fri, 8 Apr 2022 20:31:39 +0200 Subject: [PATCH 49/51] Surpress null warning on using Hash property after call TransformFinalBlock. --- .../Bundles/BundleManifest.cs | 1006 ++++++++--------- 1 file changed, 503 insertions(+), 503 deletions(-) diff --git a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs index bd8e6f80b..2acc2a57b 100644 --- a/src/AsmResolver.DotNet/Bundles/BundleManifest.cs +++ b/src/AsmResolver.DotNet/Bundles/BundleManifest.cs @@ -1,503 +1,503 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using AsmResolver.Collections; -using AsmResolver.IO; -using AsmResolver.PE.File; -using AsmResolver.PE.File.Headers; -using AsmResolver.PE.Win32Resources.Builder; - -namespace AsmResolver.DotNet.Bundles -{ - /// - /// Represents a set of bundled files embedded in a .NET application host or single-file host. - /// - public class BundleManifest - { - private const int DefaultBundleIDLength = 12; - - private static readonly byte[] BundleSignature = - { - 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, - 0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32, - 0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18, - 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae - }; - - private static readonly byte[] AppBinaryPathPlaceholder = - Encoding.UTF8.GetBytes("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"); - - private IList? _files; - - /// - /// Initializes an empty bundle manifest. - /// - protected BundleManifest() - { - } - - /// - /// Creates a new bundle manifest. - /// - /// The file format version. - public BundleManifest(uint majorVersionNumber) - { - MajorVersion = majorVersionNumber; - MinorVersion = 0; - } - - /// - /// Creates a new bundle manifest with a specific bundle identifier. - /// - /// The file format version. - /// The unique bundle manifest identifier. - public BundleManifest(uint majorVersionNumber, string bundleId) - { - MajorVersion = majorVersionNumber; - MinorVersion = 0; - BundleID = bundleId; - } - - /// - /// Gets or sets the major file format version of the bundle. - /// - /// - /// Version numbers recognized by the CLR are: - /// - /// 1 for .NET Core 3.1 - /// 2 for .NET 5.0 - /// 6 for .NET 6.0 - /// - /// - public uint MajorVersion - { - get; - set; - } - - /// - /// Gets or sets the minor file format version of the bundle. - /// - /// - /// This value is ignored by the CLR and should be set to 0. - /// - public uint MinorVersion - { - get; - set; - } - - /// - /// Gets or sets the unique identifier for the bundle manifest. - /// - /// - /// When this property is set to null, the bundle identifier will be generated upon writing the manifest - /// based on the contents of the manifest. - /// - public string? BundleID - { - get; - set; - } - - /// - /// Gets or sets flags associated to the bundle. - /// - public BundleManifestFlags Flags - { - get; - set; - } - - /// - /// Gets a collection of files stored in the bundle. - /// - public IList Files - { - get - { - if (_files is null) - Interlocked.CompareExchange(ref _files, GetFiles(), null); - return _files; - } - } - - /// - /// Attempts to automatically locate and parse the bundle header in the provided file. - /// - /// The path to the file to read. - /// The read manifest. - public static BundleManifest FromFile(string filePath) - { - return FromBytes(File.ReadAllBytes(filePath)); - } - - /// - /// Attempts to automatically locate and parse the bundle header in the provided file. - /// - /// The raw contents of the file to read. - /// The read manifest. - public static BundleManifest FromBytes(byte[] data) - { - return FromDataSource(new ByteArrayDataSource(data)); - } - - /// - /// Parses the bundle header in the provided file at the provided address. - /// - /// The raw contents of the file to read. - /// The address within the file to start reading the bundle at. - /// The read manifest. - public static BundleManifest FromBytes(byte[] data, ulong offset) - { - return FromDataSource(new ByteArrayDataSource(data), offset); - } - - /// - /// Attempts to automatically locate and parse the bundle header in the provided file. - /// - /// The raw contents of the file to read. - /// The read manifest. - public static BundleManifest FromDataSource(IDataSource source) - { - long address = FindBundleManifestAddress(source); - if (address == -1) - throw new BadImageFormatException("File does not contain an AppHost bundle signature."); - - return FromDataSource(source, (ulong) address); - } - - /// - /// Parses the bundle header in the provided file at the provided address. - /// - /// The raw contents of the file to read. - /// The address within the file to start reading the bundle at. - /// The read manifest. - public static BundleManifest FromDataSource(IDataSource source, ulong offset) - { - var reader = new BinaryStreamReader(source, 0, 0, (uint) source.Length) - { - Offset = offset - }; - - return FromReader(reader); - } - - /// - /// Parses the bundle header from the provided input stream. - /// - /// The input stream pointing to the start of the bundle to read. - /// The read manifest. - public static BundleManifest FromReader(BinaryStreamReader reader) => new SerializedBundleManifest(reader); - - private static long FindInFile(IDataSource source, byte[] data) - { - // Note: For performance reasons, we read data from the data source in blocks, such that we avoid - // virtual-dispatch calls and do the searching directly on a byte array instead. - - byte[] buffer = new byte[0x1000]; - - ulong start = 0; - while (start < source.Length) - { - int read = source.ReadBytes(start, buffer, 0, buffer.Length); - - for (int i = sizeof(ulong); i < read - data.Length; i++) - { - bool fullMatch = true; - for (int j = 0; fullMatch && j < data.Length; j++) - { - if (buffer[i + j] != data[j]) - fullMatch = false; - } - - if (fullMatch) - return (long) start + i; - } - - start += (ulong) read; - } - - return -1; - } - - private static long ReadBundleManifestAddress(IDataSource source, long signatureAddress) - { - var reader = new BinaryStreamReader(source, (ulong) signatureAddress - sizeof(ulong), 0, 8); - ulong manifestAddress = reader.ReadUInt64(); - - return source.IsValidAddress(manifestAddress) - ? (long) manifestAddress - : -1; - } - - /// - /// Attempts to find the start of the bundle header in the provided file. - /// - /// The file to locate the bundle header in. - /// The offset, or -1 if none was found. - public static long FindBundleManifestAddress(IDataSource source) - { - long signatureAddress = FindInFile(source, BundleSignature); - if (signatureAddress == -1) - return -1; - - return ReadBundleManifestAddress(source, signatureAddress); - } - - /// - /// Gets a value indicating whether the provided data source contains a conventional bundled assembly signature. - /// - /// The file to locate the bundle header in. - /// true if a bundle signature was found, false otherwise. - public static bool IsBundledAssembly(IDataSource source) => FindBundleManifestAddress(source) != -1; - - /// - /// Obtains the list of files stored in the bundle. - /// - /// The files - /// - /// This method is called upon initialization of the property. - /// - protected virtual IList GetFiles() => new OwnedCollection(this); - - /// - /// Generates a bundle identifier based on the SHA-256 hashes of all files in the manifest. - /// - /// The generated bundle identifier. - public string GenerateDeterministicBundleID() - { - using var manifestHasher = SHA256.Create(); - - for (int i = 0; i < Files.Count; i++) - { - var file = Files[i]; - using var fileHasher = SHA256.Create(); - byte[] fileHash = fileHasher.ComputeHash(file.GetData()); - manifestHasher.TransformBlock(fileHash, 0, fileHash.Length, fileHash, 0); - } - - manifestHasher.TransformFinalBlock(Array.Empty(), 0, 0); - byte[] manifestHash = manifestHasher.Hash; - - return Convert.ToBase64String(manifestHash) - .Substring(DefaultBundleIDLength) - .Replace('/', '_'); - } - - /// - /// Constructs a new application host file based on the bundle manifest. - /// - /// The path of the file to write to. - /// The parameters to use for bundling all files into a single executable. - public void WriteUsingTemplate(string outputPath, in BundlerParameters parameters) - { - using var fs = File.Create(outputPath); - WriteUsingTemplate(fs, parameters); - } - - /// - /// Constructs a new application host file based on the bundle manifest. - /// - /// The output stream to write to. - /// The parameters to use for bundling all files into a single executable. - public void WriteUsingTemplate(Stream outputStream, in BundlerParameters parameters) - { - WriteUsingTemplate(new BinaryStreamWriter(outputStream), parameters); - } - - /// - /// Constructs a new application host file based on the bundle manifest. - /// - /// The output stream to write to. - /// The parameters to use for bundling all files into a single executable. - public void WriteUsingTemplate(IBinaryStreamWriter writer, BundlerParameters parameters) - { - var appBinaryEntry = Files.FirstOrDefault(f => f.RelativePath == parameters.ApplicationBinaryPath); - if (appBinaryEntry is null) - throw new ArgumentException($"Application {parameters.ApplicationBinaryPath} does not exist within the bundle."); - - byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(parameters.ApplicationBinaryPath); - if (appBinaryPathBytes.Length > 1024) - throw new ArgumentException("Application binary path cannot exceed 1024 bytes."); - - if (!parameters.IsArm64Linux) - EnsureAppHostPEHeadersAreUpToDate(ref parameters); - - var appHostTemplateSource = new ByteArrayDataSource(parameters.ApplicationHostTemplate); - long signatureAddress = FindInFile(appHostTemplateSource, BundleSignature); - if (signatureAddress == -1) - throw new ArgumentException("AppHost template does not contain the bundle signature."); - - long appBinaryPathAddress = FindInFile(appHostTemplateSource, AppBinaryPathPlaceholder); - if (appBinaryPathAddress == -1) - throw new ArgumentException("AppHost template does not contain the application binary path placeholder."); - - writer.WriteBytes(parameters.ApplicationHostTemplate); - writer.Offset = writer.Length; - ulong headerAddress = WriteManifest(writer, parameters.IsArm64Linux); - - writer.Offset = (ulong) signatureAddress - sizeof(ulong); - writer.WriteUInt64(headerAddress); - - writer.Offset = (ulong) appBinaryPathAddress; - writer.WriteBytes(appBinaryPathBytes); - if (AppBinaryPathPlaceholder.Length > appBinaryPathBytes.Length) - writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); - } - - private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters parameters) - { - PEFile file; - try - { - file = PEFile.FromBytes(parameters.ApplicationHostTemplate); - } - catch (BadImageFormatException) - { - // Template is not a PE file. - return; - } - - bool changed = false; - - // Ensure same Windows subsystem is used (typically required for GUI applications). - if (file.OptionalHeader.SubSystem != parameters.SubSystem) - { - file.OptionalHeader.SubSystem = parameters.SubSystem; - changed = true; - } - - // If the app binary has resources (such as an icon or version info), we need to copy it into the - // AppHost template so that they are also visible from the final packed executable. - if (parameters.Resources is { } directory) - { - // Put original resource directory in a new .rsrc section. - var buffer = new ResourceDirectoryBuffer(); - buffer.AddDirectory(directory); - var rsrc = new PESection(".rsrc", SectionFlags.MemoryRead | SectionFlags.ContentInitializedData); - rsrc.Contents = buffer; - - // Find .reloc section, and insert .rsrc before it if it is present. Otherwise just append to the end. - int sectionIndex = file.Sections.Count - 1; - for (int i = file.Sections.Count - 1; i >= 0; i--) - { - if (file.Sections[i].Name == ".reloc") - { - sectionIndex = i; - break; - } - } - - file.Sections.Insert(sectionIndex, rsrc); - - // Update resource data directory va + size. - file.AlignSections(); - file.OptionalHeader.DataDirectories[(int) DataDirectoryIndex.ResourceDirectory] = new DataDirectory( - buffer.Rva, - buffer.GetPhysicalSize()); - - changed = true; - } - - // Rebuild AppHost PE file if necessary. - if (changed) - { - using var stream = new MemoryStream(); - file.Write(stream); - parameters.ApplicationHostTemplate = stream.ToArray(); - } - } - - /// - /// Writes the manifest to an output stream. - /// - /// The output stream to write to. - /// true if the application host is a Linux ELF binary targeting ARM64. - /// The address of the bundle header. - /// - /// This does not necessarily produce a working executable file, it only writes the contents of the entire manifest, - /// without a host application that invokes the manifest. If you want to produce a runnable executable, use one - /// of the WriteUsingTemplate methods instead. - /// - public ulong WriteManifest(IBinaryStreamWriter writer, bool isArm64Linux) - { - WriteFileContents(writer, isArm64Linux - ? 4096u - : 16u); - - ulong headerAddress = writer.Offset; - WriteManifestHeader(writer); - - return headerAddress; - } - - private void WriteFileContents(IBinaryStreamWriter writer, uint alignment) - { - for (int i = 0; i < Files.Count; i++) - { - var file = Files[i]; - - if (file.Type == BundleFileType.Assembly) - writer.Align(alignment); - - file.Contents.UpdateOffsets(writer.Offset, (uint) writer.Offset); - file.Contents.Write(writer); - } - } - - private void WriteManifestHeader(IBinaryStreamWriter writer) - { - writer.WriteUInt32(MajorVersion); - writer.WriteUInt32(MinorVersion); - writer.WriteInt32(Files.Count); - - BundleID ??= GenerateDeterministicBundleID(); - writer.WriteBinaryFormatterString(BundleID); - - if (MajorVersion >= 2) - { - WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.DepsJson)); - WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.RuntimeConfigJson)); - writer.WriteUInt64((ulong) Flags); - } - - WriteFileHeaders(writer); - } - - private void WriteFileHeaders(IBinaryStreamWriter writer) - { - for (int i = 0; i < Files.Count; i++) - { - var file = Files[i]; - - WriteFileOffsetSizePair(writer, file); - - if (MajorVersion >= 6) - writer.WriteUInt64(file.IsCompressed ? file.Contents.GetPhysicalSize() : 0); - - writer.WriteByte((byte) file.Type); - writer.WriteBinaryFormatterString(file.RelativePath); - } - } - - private static void WriteFileOffsetSizePair(IBinaryStreamWriter writer, BundleFile? file) - { - if (file is not null) - { - writer.WriteUInt64(file.Contents.Offset); - writer.WriteUInt64((ulong) file.GetData().Length); - } - else - { - writer.WriteUInt64(0); - writer.WriteUInt64(0); - } - } - - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using AsmResolver.Collections; +using AsmResolver.IO; +using AsmResolver.PE.File; +using AsmResolver.PE.File.Headers; +using AsmResolver.PE.Win32Resources.Builder; + +namespace AsmResolver.DotNet.Bundles +{ + /// + /// Represents a set of bundled files embedded in a .NET application host or single-file host. + /// + public class BundleManifest + { + private const int DefaultBundleIDLength = 12; + + private static readonly byte[] BundleSignature = + { + 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, + 0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32, + 0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18, + 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae + }; + + private static readonly byte[] AppBinaryPathPlaceholder = + Encoding.UTF8.GetBytes("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"); + + private IList? _files; + + /// + /// Initializes an empty bundle manifest. + /// + protected BundleManifest() + { + } + + /// + /// Creates a new bundle manifest. + /// + /// The file format version. + public BundleManifest(uint majorVersionNumber) + { + MajorVersion = majorVersionNumber; + MinorVersion = 0; + } + + /// + /// Creates a new bundle manifest with a specific bundle identifier. + /// + /// The file format version. + /// The unique bundle manifest identifier. + public BundleManifest(uint majorVersionNumber, string bundleId) + { + MajorVersion = majorVersionNumber; + MinorVersion = 0; + BundleID = bundleId; + } + + /// + /// Gets or sets the major file format version of the bundle. + /// + /// + /// Version numbers recognized by the CLR are: + /// + /// 1 for .NET Core 3.1 + /// 2 for .NET 5.0 + /// 6 for .NET 6.0 + /// + /// + public uint MajorVersion + { + get; + set; + } + + /// + /// Gets or sets the minor file format version of the bundle. + /// + /// + /// This value is ignored by the CLR and should be set to 0. + /// + public uint MinorVersion + { + get; + set; + } + + /// + /// Gets or sets the unique identifier for the bundle manifest. + /// + /// + /// When this property is set to null, the bundle identifier will be generated upon writing the manifest + /// based on the contents of the manifest. + /// + public string? BundleID + { + get; + set; + } + + /// + /// Gets or sets flags associated to the bundle. + /// + public BundleManifestFlags Flags + { + get; + set; + } + + /// + /// Gets a collection of files stored in the bundle. + /// + public IList Files + { + get + { + if (_files is null) + Interlocked.CompareExchange(ref _files, GetFiles(), null); + return _files; + } + } + + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The path to the file to read. + /// The read manifest. + public static BundleManifest FromFile(string filePath) + { + return FromBytes(File.ReadAllBytes(filePath)); + } + + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The raw contents of the file to read. + /// The read manifest. + public static BundleManifest FromBytes(byte[] data) + { + return FromDataSource(new ByteArrayDataSource(data)); + } + + /// + /// Parses the bundle header in the provided file at the provided address. + /// + /// The raw contents of the file to read. + /// The address within the file to start reading the bundle at. + /// The read manifest. + public static BundleManifest FromBytes(byte[] data, ulong offset) + { + return FromDataSource(new ByteArrayDataSource(data), offset); + } + + /// + /// Attempts to automatically locate and parse the bundle header in the provided file. + /// + /// The raw contents of the file to read. + /// The read manifest. + public static BundleManifest FromDataSource(IDataSource source) + { + long address = FindBundleManifestAddress(source); + if (address == -1) + throw new BadImageFormatException("File does not contain an AppHost bundle signature."); + + return FromDataSource(source, (ulong) address); + } + + /// + /// Parses the bundle header in the provided file at the provided address. + /// + /// The raw contents of the file to read. + /// The address within the file to start reading the bundle at. + /// The read manifest. + public static BundleManifest FromDataSource(IDataSource source, ulong offset) + { + var reader = new BinaryStreamReader(source, 0, 0, (uint) source.Length) + { + Offset = offset + }; + + return FromReader(reader); + } + + /// + /// Parses the bundle header from the provided input stream. + /// + /// The input stream pointing to the start of the bundle to read. + /// The read manifest. + public static BundleManifest FromReader(BinaryStreamReader reader) => new SerializedBundleManifest(reader); + + private static long FindInFile(IDataSource source, byte[] data) + { + // Note: For performance reasons, we read data from the data source in blocks, such that we avoid + // virtual-dispatch calls and do the searching directly on a byte array instead. + + byte[] buffer = new byte[0x1000]; + + ulong start = 0; + while (start < source.Length) + { + int read = source.ReadBytes(start, buffer, 0, buffer.Length); + + for (int i = sizeof(ulong); i < read - data.Length; i++) + { + bool fullMatch = true; + for (int j = 0; fullMatch && j < data.Length; j++) + { + if (buffer[i + j] != data[j]) + fullMatch = false; + } + + if (fullMatch) + return (long) start + i; + } + + start += (ulong) read; + } + + return -1; + } + + private static long ReadBundleManifestAddress(IDataSource source, long signatureAddress) + { + var reader = new BinaryStreamReader(source, (ulong) signatureAddress - sizeof(ulong), 0, 8); + ulong manifestAddress = reader.ReadUInt64(); + + return source.IsValidAddress(manifestAddress) + ? (long) manifestAddress + : -1; + } + + /// + /// Attempts to find the start of the bundle header in the provided file. + /// + /// The file to locate the bundle header in. + /// The offset, or -1 if none was found. + public static long FindBundleManifestAddress(IDataSource source) + { + long signatureAddress = FindInFile(source, BundleSignature); + if (signatureAddress == -1) + return -1; + + return ReadBundleManifestAddress(source, signatureAddress); + } + + /// + /// Gets a value indicating whether the provided data source contains a conventional bundled assembly signature. + /// + /// The file to locate the bundle header in. + /// true if a bundle signature was found, false otherwise. + public static bool IsBundledAssembly(IDataSource source) => FindBundleManifestAddress(source) != -1; + + /// + /// Obtains the list of files stored in the bundle. + /// + /// The files + /// + /// This method is called upon initialization of the property. + /// + protected virtual IList GetFiles() => new OwnedCollection(this); + + /// + /// Generates a bundle identifier based on the SHA-256 hashes of all files in the manifest. + /// + /// The generated bundle identifier. + public string GenerateDeterministicBundleID() + { + using var manifestHasher = SHA256.Create(); + + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + using var fileHasher = SHA256.Create(); + byte[] fileHash = fileHasher.ComputeHash(file.GetData()); + manifestHasher.TransformBlock(fileHash, 0, fileHash.Length, fileHash, 0); + } + + manifestHasher.TransformFinalBlock(Array.Empty(), 0, 0); + byte[] manifestHash = manifestHasher.Hash!; + + return Convert.ToBase64String(manifestHash) + .Substring(DefaultBundleIDLength) + .Replace('/', '_'); + } + + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The path of the file to write to. + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(string outputPath, in BundlerParameters parameters) + { + using var fs = File.Create(outputPath); + WriteUsingTemplate(fs, parameters); + } + + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The output stream to write to. + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(Stream outputStream, in BundlerParameters parameters) + { + WriteUsingTemplate(new BinaryStreamWriter(outputStream), parameters); + } + + /// + /// Constructs a new application host file based on the bundle manifest. + /// + /// The output stream to write to. + /// The parameters to use for bundling all files into a single executable. + public void WriteUsingTemplate(IBinaryStreamWriter writer, BundlerParameters parameters) + { + var appBinaryEntry = Files.FirstOrDefault(f => f.RelativePath == parameters.ApplicationBinaryPath); + if (appBinaryEntry is null) + throw new ArgumentException($"Application {parameters.ApplicationBinaryPath} does not exist within the bundle."); + + byte[] appBinaryPathBytes = Encoding.UTF8.GetBytes(parameters.ApplicationBinaryPath); + if (appBinaryPathBytes.Length > 1024) + throw new ArgumentException("Application binary path cannot exceed 1024 bytes."); + + if (!parameters.IsArm64Linux) + EnsureAppHostPEHeadersAreUpToDate(ref parameters); + + var appHostTemplateSource = new ByteArrayDataSource(parameters.ApplicationHostTemplate); + long signatureAddress = FindInFile(appHostTemplateSource, BundleSignature); + if (signatureAddress == -1) + throw new ArgumentException("AppHost template does not contain the bundle signature."); + + long appBinaryPathAddress = FindInFile(appHostTemplateSource, AppBinaryPathPlaceholder); + if (appBinaryPathAddress == -1) + throw new ArgumentException("AppHost template does not contain the application binary path placeholder."); + + writer.WriteBytes(parameters.ApplicationHostTemplate); + writer.Offset = writer.Length; + ulong headerAddress = WriteManifest(writer, parameters.IsArm64Linux); + + writer.Offset = (ulong) signatureAddress - sizeof(ulong); + writer.WriteUInt64(headerAddress); + + writer.Offset = (ulong) appBinaryPathAddress; + writer.WriteBytes(appBinaryPathBytes); + if (AppBinaryPathPlaceholder.Length > appBinaryPathBytes.Length) + writer.WriteZeroes(AppBinaryPathPlaceholder.Length - appBinaryPathBytes.Length); + } + + private static void EnsureAppHostPEHeadersAreUpToDate(ref BundlerParameters parameters) + { + PEFile file; + try + { + file = PEFile.FromBytes(parameters.ApplicationHostTemplate); + } + catch (BadImageFormatException) + { + // Template is not a PE file. + return; + } + + bool changed = false; + + // Ensure same Windows subsystem is used (typically required for GUI applications). + if (file.OptionalHeader.SubSystem != parameters.SubSystem) + { + file.OptionalHeader.SubSystem = parameters.SubSystem; + changed = true; + } + + // If the app binary has resources (such as an icon or version info), we need to copy it into the + // AppHost template so that they are also visible from the final packed executable. + if (parameters.Resources is { } directory) + { + // Put original resource directory in a new .rsrc section. + var buffer = new ResourceDirectoryBuffer(); + buffer.AddDirectory(directory); + var rsrc = new PESection(".rsrc", SectionFlags.MemoryRead | SectionFlags.ContentInitializedData); + rsrc.Contents = buffer; + + // Find .reloc section, and insert .rsrc before it if it is present. Otherwise just append to the end. + int sectionIndex = file.Sections.Count - 1; + for (int i = file.Sections.Count - 1; i >= 0; i--) + { + if (file.Sections[i].Name == ".reloc") + { + sectionIndex = i; + break; + } + } + + file.Sections.Insert(sectionIndex, rsrc); + + // Update resource data directory va + size. + file.AlignSections(); + file.OptionalHeader.DataDirectories[(int) DataDirectoryIndex.ResourceDirectory] = new DataDirectory( + buffer.Rva, + buffer.GetPhysicalSize()); + + changed = true; + } + + // Rebuild AppHost PE file if necessary. + if (changed) + { + using var stream = new MemoryStream(); + file.Write(stream); + parameters.ApplicationHostTemplate = stream.ToArray(); + } + } + + /// + /// Writes the manifest to an output stream. + /// + /// The output stream to write to. + /// true if the application host is a Linux ELF binary targeting ARM64. + /// The address of the bundle header. + /// + /// This does not necessarily produce a working executable file, it only writes the contents of the entire manifest, + /// without a host application that invokes the manifest. If you want to produce a runnable executable, use one + /// of the WriteUsingTemplate methods instead. + /// + public ulong WriteManifest(IBinaryStreamWriter writer, bool isArm64Linux) + { + WriteFileContents(writer, isArm64Linux + ? 4096u + : 16u); + + ulong headerAddress = writer.Offset; + WriteManifestHeader(writer); + + return headerAddress; + } + + private void WriteFileContents(IBinaryStreamWriter writer, uint alignment) + { + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + + if (file.Type == BundleFileType.Assembly) + writer.Align(alignment); + + file.Contents.UpdateOffsets(writer.Offset, (uint) writer.Offset); + file.Contents.Write(writer); + } + } + + private void WriteManifestHeader(IBinaryStreamWriter writer) + { + writer.WriteUInt32(MajorVersion); + writer.WriteUInt32(MinorVersion); + writer.WriteInt32(Files.Count); + + BundleID ??= GenerateDeterministicBundleID(); + writer.WriteBinaryFormatterString(BundleID); + + if (MajorVersion >= 2) + { + WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.DepsJson)); + WriteFileOffsetSizePair(writer, Files.FirstOrDefault(f => f.Type == BundleFileType.RuntimeConfigJson)); + writer.WriteUInt64((ulong) Flags); + } + + WriteFileHeaders(writer); + } + + private void WriteFileHeaders(IBinaryStreamWriter writer) + { + for (int i = 0; i < Files.Count; i++) + { + var file = Files[i]; + + WriteFileOffsetSizePair(writer, file); + + if (MajorVersion >= 6) + writer.WriteUInt64(file.IsCompressed ? file.Contents.GetPhysicalSize() : 0); + + writer.WriteByte((byte) file.Type); + writer.WriteBinaryFormatterString(file.RelativePath); + } + } + + private static void WriteFileOffsetSizePair(IBinaryStreamWriter writer, BundleFile? file) + { + if (file is not null) + { + writer.WriteUInt64(file.Contents.Offset); + writer.WriteUInt64((ulong) file.GetData().Length); + } + else + { + writer.WriteUInt64(0); + writer.WriteUInt64(0); + } + } + + } +} From 788c6b3fb7c12047f3dcacf851df723da4a4b182 Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 9 Apr 2022 13:56:32 +0200 Subject: [PATCH 50/51] Add check for apphost file existence. --- .../Bundles/BundleManifestTest.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index 0bed69a5a..423509378 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -109,11 +109,13 @@ public void MarkFilesAsCompressed() AssertBundlesAreEqual(manifest, newManifest); } - [Theory] + [SkippableTheory()] [InlineData(SubSystem.WindowsCui)] [InlineData(SubSystem.WindowsGui)] public void WriteWithSubSystem(SubSystem subSystem) { + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + var manifest = BundleManifest.FromBytes(Properties.Resources.HelloWorld_SingleFile_V6); string appHostTemplatePath = FindAppHostTemplate("6.0"); @@ -251,7 +253,18 @@ private static string FindAppHostTemplate(string sdkVersion) $"Could not find the apphost template for .NET SDK version {sdkVersion}. This is an indication that the test environment does not have this SDK installed."); } - return Path.Combine(sdkVersionPath, "AppHostTemplate", "apphost.exe"); + string fileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? "apphost.exe" + : "apphost"; + + string finalPath = Path.Combine(sdkVersionPath, "AppHostTemplate", fileName); + if (!File.Exists(finalPath)) + { + throw new InvalidOperationException( + $"Could not find the apphost template for .NET SDK version {sdkVersion}. This is an indication that the test environment does not have this SDK installed."); + } + + return finalPath; } private static void AssertBundlesAreEqual(BundleManifest manifest, BundleManifest newManifest) From fb3516a097021a559c3c6127cba3342e6fd1ec37 Mon Sep 17 00:00:00 2001 From: Washi Date: Sat, 9 Apr 2022 13:57:30 +0200 Subject: [PATCH 51/51] BUGFIX: Do not include 'shared' in default UNIX dotnet installation paths. Add default macOS dotnet installation folder. --- src/AsmResolver.DotNet/DotNetCorePathProvider.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/AsmResolver.DotNet/DotNetCorePathProvider.cs b/src/AsmResolver.DotNet/DotNetCorePathProvider.cs index 63c7cd756..c01e99357 100644 --- a/src/AsmResolver.DotNet/DotNetCorePathProvider.cs +++ b/src/AsmResolver.DotNet/DotNetCorePathProvider.cs @@ -13,8 +13,9 @@ namespace AsmResolver.DotNet public class DotNetCorePathProvider { private static readonly string[] DefaultDotNetUnixPaths = { - "/usr/share/dotnet/shared", - "/opt/dotnet/shared/" + "/usr/share/dotnet/", + "/usr/local/share/dotnet/", + "/opt/dotnet/" }; private static readonly Regex NetCoreRuntimePattern = new(@"\.NET( Core)? \d+\.\d+\.\d+"); @@ -23,7 +24,7 @@ public class DotNetCorePathProvider static DotNetCorePathProvider() { DefaultInstallationPath = FindDotNetPath(); - Default = new(); + Default = new DotNetCorePathProvider(); } /// @@ -153,8 +154,12 @@ public bool HasRuntimeInstalled(string runtimeName, Version runtimeVersion) private void DetectInstalledRuntimes(string installationDirectory) { installationDirectory = Path.Combine(installationDirectory, "shared"); + if (!Directory.Exists(installationDirectory)) + return; + foreach (string directory in Directory.EnumerateDirectories(installationDirectory)) _installedRuntimes.Add(new DotNetInstallationInfo(directory)); + _installedRuntimes.Sort(); }