19

我先给你一些背景知识,为什么我要问这个问题:

我目前在一个受到严格监管的行业工作,因此我们的代码由官方测试机构仔细检查。这些测试机构希望能够构建代码并生成每次都完全相同的 .exe 或 .dll(显然无需更改任何代码!)。他们检查他们创建的可执行文件的 MD5 和 SHA1 以确保这一点。

到目前为止,我主要使用 C++ 进行编码,其中(经过一些项目设置调整)我设法让项目以一致的方式重建为相同的 MD5/SHA1。我现在在一个项目中使用 C#,并且在重建后很难让 MD5 匹配。我知道文件的 PE 头中有“时间戳”,它们已被清除为 0。我还知道 .exe 有一个 GUID,它再次被清除为 00 00 00 ...等等。但是文件仍然不匹配。

我正在使用 CFF Explorer 查看和编辑 PE 标头以删除时间和日期戳。使用二进制比较工具后,.exe 中只有 2 个不同的字节块(都非常小)。

不一致的块之一出现*Project*\obj\Release\xxx.pdb一些二进制代码之前,它以 ASCII 格式详细说明了文件的路径。

编辑:现在已知这是 *.pdb 文件的 GUID,但是我仍然不知道是否可以修改它而不会导致任何错误!?

另一个块出现在看起来是函数名称的中间,即。(典型部分)AssemblyName.GetName.Version.get_Version.System.IO.Ports.SerialPort.Parity.Byte.<PrivateImplementationDetails>{

然后是不同的代码块:

4A134ACE-D6A0-461B-A47C-3A4232D90816

其次是:

"}.ValueType.__StaticArrayInitTypeSize=7.$$method0x60000ab-1.RuntimeFieldHandle.InitializeArray`... 等等。

任何想法或建议都将受到欢迎!

4

6 回答 6

5

更新:Roslyn 似乎有一个/feature:deterministic用于可重现构建的编译器标志,尽管它还不是 100% 工作


您应该能够通过禁用 PDB 生成来摆脱调试 GUID。如果没有,将 GUID 设置为零就可以了 - 只有调试器会查看该部分(您将无法再调试程序集,但它应该仍然可以正常运行)。

PrivateImplementationDetails 有点困难 - 这些是编译器为某些语言构造(数组初始化器、使用字符串的 switch 语句等)生成的内部帮助器类。因为它们只在内部使用,所以类名并不重要,所以你可以给它们分配一个运行编号。

我会通过查看#Strings 元数据流并将所有形式为“<PrivateImplementationDetails>{GUID}”的字符串替换为“<PrivateImplementationDetails>{running number, padded to the same length as a GUID}”来做到这一点。

#Strings 元数据流只是元数据使用的字符串列表,以 UTF-8 编码并由 \0 分隔;因此,一旦您知道#Strings 流在可执行文件中的位置,查找和替换名称应该很容易。

不幸的是,包含此信息的“元数据流标头”完全隐藏在文件格式中。您必须从 NT Optional Header 开始,找到指向 CLI Runtime Header 的指针,使用 PE 节表将其解析为文件位置(它是 RVA,但您需要文件内的位置),然后转到元数据根并读取流标头。

于 2009-09-23T21:30:31.853 回答
2

我不确定这一点,但只是一个想法:您是否使用任何匿名类型,编译器可能会在幕后为其生成名称,每次编译器运行时可能会有所不同?只是我想到的一种可能性。可能是乔恩·斯基特的一个;-)

更新:您也许还可以使用 Reflector插件进行比较和反汇编。

于 2009-09-15T10:41:02.593 回答
2

关于 PDB GUID 问题,如果您指定不应在编译发布版本时生成 PDB,二进制文件是否仍包含 PDB 的文件系统 GUID?

要禁用 PDB 生成:

  1. 在解决方案资源管理器中右键单击您的项目,然后选择属性。
  2. 从左侧的菜单中,选择构建。
  3. 确保配置选择是发布(您仍然需要一个 PDB 进行调试)。
  4. 点击右下角的高级按钮。
  5. 在输出/调试信息下,选择无。

如果您从控制台构建,请使用 /debug- 获得相同的结果。

于 2009-09-22T17:02:55.450 回答
0

看看这个问题的答案。特别是在第三个提供的外部链接上。

编辑:

我实际上想要链接到这篇文章。

于 2009-09-15T10:45:02.773 回答
0

您说经过一些项目调整后,您能够让 C++ 应用程序可重复编译为相同的 SHA1/MD5 值。我和你在同一条船上,在一个需要重复重建完全相同的可执行文件的第三方测试实验室的行业中。

在研究如何在 VS2005 中实现这一点时,我在这里看到了你的帖子。您能否分享您为使 C++ 应用程序始终构建为相同的 SHA1/MD5 值而进行的项目调整?这对我自己以及任何其他有此要求的人都有很大帮助。

于 2010-03-17T19:35:39.130 回答
0

使用 ildasm.exe 完全反汇编这两个程序并比较 IL。然后,您可以使用基于文本的方法“清理”代码并(可以预见地)再次重新编译它。

于 2013-11-19T06:46:48.573 回答