From a345ff5b7072df1832427a54e9e3e5ec1a65e098 Mon Sep 17 00:00:00 2001 From: Daniel Crenna Date: Sun, 1 Sep 2019 18:54:56 -0400 Subject: [PATCH] implement build independent hash per https://groups.google.com/forum/#!topic/mono-cecil/AGq0LfBdqjo --- Mono.Cecil.PE/Image.cs | 2 ++ Mono.Cecil.PE/ImageReader.cs | 4 +++- Mono.Cecil/AssemblyReader.cs | 1 + Mono.Cecil/ModuleDefinition.cs | 26 ++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Mono.Cecil.PE/Image.cs b/Mono.Cecil.PE/Image.cs index 109206187..1e8253cc1 100644 --- a/Mono.Cecil.PE/Image.cs +++ b/Mono.Cecil.PE/Image.cs @@ -23,6 +23,7 @@ sealed class Image : IDisposable { public Disposable Stream; public string FileName; + public int FileChecksumPosition; public ModuleKind Kind; public string RuntimeVersion; @@ -40,6 +41,7 @@ sealed class Image : IDisposable { public uint EntryPointToken; public uint Timestamp; + public int TimestampPosition; public ModuleAttributes Attributes; public DataDirectory Win32Resources; diff --git a/Mono.Cecil.PE/ImageReader.cs b/Mono.Cecil.PE/ImageReader.cs index 9731ba90b..cd1c36a03 100644 --- a/Mono.Cecil.PE/ImageReader.cs +++ b/Mono.Cecil.PE/ImageReader.cs @@ -72,6 +72,7 @@ void ReadImage () ushort sections = ReadUInt16 (); // TimeDateStamp 4 + image.TimestampPosition = (int)BaseStream.Position; image.Timestamp = ReadUInt32 (); // PointerToSymbolTable 4 // NumberOfSymbols 4 @@ -130,7 +131,7 @@ void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics) // ImageBase 4 || 8 // SectionAlignment 4 - // FileAlignement 4 + // FileAlignment 4 // OSMajor 2 // OSMinor 2 // UserMajor 2 @@ -147,6 +148,7 @@ void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics) // HeaderSize 4 // FileChecksum 4 Advance (16); + image.FileChecksumPosition = (int)(BaseStream.Position - 4); // SubSystem 2 subsystem = ReadUInt16 (); diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index 1728338c6..6377306e5 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -593,6 +593,7 @@ public ModuleDefinition Populate (ModuleDefinition module) Advance (2); // Generation module.Name = ReadString (); + module.MvidPosition = position; module.Mvid = ReadGuid (); return module; diff --git a/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/ModuleDefinition.cs index 707a1358f..4f62d5c3a 100644 --- a/Mono.Cecil/ModuleDefinition.cs +++ b/Mono.Cecil/ModuleDefinition.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Security.Cryptography; using System.Threading; using SR = System.Reflection; @@ -252,6 +253,7 @@ public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider ModuleAttributes attributes; ModuleCharacteristics characteristics; Guid mvid; + internal int MvidPosition; internal ushort linker_version = 8; internal ushort subsystem_major = 4; @@ -1159,6 +1161,30 @@ public void Write (Stream stream, WriterParameters parameters) } } + public static class ModuleDefinitionExtensions { + + // See: https://groups.google.com/forum/#!topic/mono-cecil/AGq0LfBdqjo + public static byte [] GetBuildIndependentHash (this ModuleDefinition moduleDefinition, HashAlgorithm hashAlgorithm) + { + var buffer = File.ReadAllBytes (moduleDefinition.Image.FileName); + + // Overwrite parts of the assembly file content byte array (only in memory of course) + // that change on every build with an empty byte array, and thus make it comparable + + Buffer.BlockCopy (new byte [sizeof (uint)], 0, buffer, moduleDefinition.Image.TimestampPosition, sizeof(uint)); + Buffer.BlockCopy (new byte [sizeof (uint)], 0, buffer, moduleDefinition.Image.FileChecksumPosition, sizeof(uint)); + Buffer.BlockCopy (new byte [moduleDefinition.Image.GuidHeap.IndexSize], 0, buffer, moduleDefinition.MvidPosition, moduleDefinition.Image.GuidHeap.IndexSize); + + return hashAlgorithm.ComputeHash (buffer); + } + + internal static byte [] GetBuildDependentHash (this ModuleDefinition moduleDefinition, HashAlgorithm hashAlgorithm) + { + var buffer = File.ReadAllBytes (moduleDefinition.Image.FileName); + return hashAlgorithm.ComputeHash (buffer); + } + } + static partial class Mixin { public enum Argument {