gpt4 book ai didi

.net - 如何判断两个 .NET DLL 是否相同?

转载 作者:行者123 更新时间:2023-12-04 01:48:10 36 4
gpt4 key购买 nike

我有一个 DLL 的源代码,我有一个它的编译版本在某处。

如果我编译源代码,它将与已经编译的版本具有不同的日期。

我如何判断它们是否实际上相同并且只是在不同时间编译?

最佳答案

要比较两个 .dll 文件,您可以使用 ildasm 或任何其他工具来获取 IL 代码。
我在 dll 文件中创建了一个嵌入 ildasm 的示例,以便您可以在每台机器上使用它。当我们反汇编一个程序集时,我们检查执行程序集文件夹中是否存在 ildasm.exe 文件,如果不存在,则从我们的 dll 文件中提取该文件。
使用 ildasm 文件,我们获取 IL 代码并将其保存到一个临时文件中。
然后我们需要删除以下三行:

MVID - 正如我之前写的,这是每次构建时生成的唯一 GUID

图像库(图像库告诉我们程序将被 Windows 加载器加载到内存中的哪个位置。) - 这对于每个构建也是不同的

时间日期戳 - ildasm 运行的时间和日期

所以我们读取临时文件内容,使用正则表达式删除这些行,然后将文件内容保存到同一个文件中。
这是反汇编程序类:

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace FileHasher
{
public class Disassembler
{
public static Regex regexMVID = new Regex("//\\s*MVID\\:\\s*\\{[a-zA-Z0-9\\-]+\\}", RegexOptions.Multiline | RegexOptions.Compiled);
public static Regex regexImageBase = new Regex("//\\s*Image\\s+base\\:\\s0x[0-9A-Fa-f]*", RegexOptions.Multiline | RegexOptions.Compiled);
public static Regex regexTimeStamp = new Regex("//\\s*Time-date\\s+stamp\\:\\s*0x[0-9A-Fa-f]*", RegexOptions.Multiline | RegexOptions.Compiled);

private static readonly Lazy<Assembly> currentAssembly = new Lazy<Assembly>(() =>
{
return MethodBase.GetCurrentMethod().DeclaringType.Assembly;
});

private static readonly Lazy<string> executingAssemblyPath = new Lazy<string>(() =>
{
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
});

private static readonly Lazy<string> currentAssemblyFolder = new Lazy<string>(() =>
{
return Path.GetDirectoryName(currentAssembly.Value.Location);
});

private static readonly Lazy<string[]> arrResources = new Lazy<string[]>(() =>
{
return currentAssembly.Value.GetManifestResourceNames();
});

private const string ildasmArguments = "/all /text \"{0}\"";

public static string ILDasmFileLocation
{
get
{
return Path.Combine(executingAssemblyPath.Value, "ildasm.exe");
}
}

static Disassembler()
{
//extract the ildasm file to the executing assembly location
ExtractFileToLocation("ildasm.exe", ILDasmFileLocation);
}

/// <summary>
/// Saves the file from embedded resource to a given location.
/// </summary>
/// <param name="embeddedResourceName">Name of the embedded resource.</param>
/// <param name="fileName">Name of the file.</param>
protected static void SaveFileFromEmbeddedResource(string embeddedResourceName, string fileName)
{
if (File.Exists(fileName))
{
//the file already exists, we can add deletion here if we want to change the version of the 7zip
return;
}
FileInfo fileInfoOutputFile = new FileInfo(fileName);

using (FileStream streamToOutputFile = fileInfoOutputFile.OpenWrite())
using (Stream streamToResourceFile = currentAssembly.Value.GetManifestResourceStream(embeddedResourceName))
{
const int size = 4096;
byte[] bytes = new byte[4096];
int numBytes;
while ((numBytes = streamToResourceFile.Read(bytes, 0, size)) > 0)
{
streamToOutputFile.Write(bytes, 0, numBytes);
}

streamToOutputFile.Close();
streamToResourceFile.Close();
}
}

/// <summary>
/// Searches the embedded resource and extracts it to the given location.
/// </summary>
/// <param name="fileNameInDll">The file name in DLL.</param>
/// <param name="outFileName">Name of the out file.</param>
protected static void ExtractFileToLocation(string fileNameInDll, string outFileName)
{
string resourcePath = arrResources.Value.Where(resource => resource.EndsWith(fileNameInDll, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if (resourcePath == null)
{
throw new Exception(string.Format("Cannot find {0} in the embedded resources of {1}", fileNameInDll, currentAssembly.Value.FullName));
}
SaveFileFromEmbeddedResource(resourcePath, outFileName);
}

public static string GetDisassembledFile(string assemblyFilePath)
{
if (!File.Exists(assemblyFilePath))
{
throw new InvalidOperationException(string.Format("The file {0} does not exist!", assemblyFilePath));
}

string tempFileName = Path.GetTempFileName();
var startInfo = new ProcessStartInfo(ILDasmFileLocation, string.Format(ildasmArguments, assemblyFilePath));
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;

using (var process = System.Diagnostics.Process.Start(startInfo))
{
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

if (process.ExitCode > 0)
{
throw new InvalidOperationException(
string.Format("Generating IL code for file {0} failed with exit code - {1}. Log: {2}",
assemblyFilePath, process.ExitCode, output));
}

File.WriteAllText(tempFileName, output);
}

RemoveUnnededRows(tempFileName);
return tempFileName;
}

private static void RemoveUnnededRows(string fileName)
{
string fileContent = File.ReadAllText(fileName);
//remove MVID
fileContent = regexMVID.Replace(fileContent, string.Empty);
//remove Image Base
fileContent = regexImageBase.Replace(fileContent, string.Empty);
//remove Time Stamp
fileContent = regexTimeStamp.Replace(fileContent, string.Empty);
File.WriteAllText(fileName, fileContent);
}

public static string DisassembleFile(string assemblyFilePath)
{
string disassembledFile = GetDisassembledFile(assemblyFilePath);
try
{
return File.ReadAllText(disassembledFile);
}
finally
{
if (File.Exists(disassembledFile))
{
File.Delete(disassembledFile);
}
}
}
}
}

现在您可以比较这两个 IL 代码的内容。另一种选择是生成这些文件的哈希码并进行比较。 Hese 是一个 HashCalculator 类:
使用系统;
使用 System.IO;
使用 System.Reflection;
namespace FileHasher
{
public class HashCalculator
{
public string FileName { get; private set; }

public HashCalculator(string fileName)
{
this.FileName = fileName;
}

public string CalculateFileHash()
{
if (Path.GetExtension(this.FileName).Equals(".dll", System.StringComparison.InvariantCultureIgnoreCase)
|| Path.GetExtension(this.FileName).Equals(".exe", System.StringComparison.InvariantCultureIgnoreCase))
{
return GetAssemblyFileHash();
}
else
{
return GetFileHash();
}
}

private string GetFileHash()
{
return CalculateHashFromStream(File.OpenRead(this.FileName));
}

private string GetAssemblyFileHash()
{
string tempFileName = null;
try
{
//try to open the assembly to check if this is a .NET one
var assembly = Assembly.LoadFile(this.FileName);
tempFileName = Disassembler.GetDisassembledFile(this.FileName);
return CalculateHashFromStream(File.OpenRead(tempFileName));
}
catch(BadImageFormatException)
{
return GetFileHash();
}
finally
{
if (File.Exists(tempFileName))
{
File.Delete(tempFileName);
}
}
}

private string CalculateHashFromStream(Stream stream)
{
using (var readerSource = new System.IO.BufferedStream(stream, 1200000))
{
using (var md51 = new System.Security.Cryptography.MD5CryptoServiceProvider())
{
md51.ComputeHash(readerSource);
return Convert.ToBase64String(md51.Hash);
}
}
}
}
}

您可以在我的博客上找到完整的应用程序源代码 - Compare two dll files programmatically

关于.net - 如何判断两个 .NET DLL 是否相同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2735643/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com