我该如何创建二进制补丁?

79

如何为二进制文件创建补丁是最好的方法?

我希望用户能够简单地应用它(一个简单的 patch 应用程序会很好)。在文件上运行diff只会给出 Binary files [...] differ

9个回答

68

请查看 bsdiffbspatch (网站, 手册页, 论文, GitHub 分支)。

安装此工具:

  • Windows:下载并提取此软件包。您还需要在PATH中拥有bzip2.exe 的副本;从这里下载
  • macOS:安装 Homebrew 并使用它来安装 bsdiff
  • Linux:使用您的软件包管理器来安装 bsdiff

2
相当老的源代码。使用现代的Visual Studio编译并不容易——在VS 2009中可以工作,但是在更新的版本中会出现错误。此外,它只支持32位——这对于内存消耗来说是一个真正的问题(请参见其他答案)。我不确定仅仅使用x64编译是否能解决这个问题——我转向了.NET端口,请参见其他答案。 - Philm
1
bsdiffcourgette是针对可执行二进制文件进行优化的;找到了一些非官方Windows二进制文件,但它们并没有成功运行。 - Vlastimil Ovčáčík
在Windows上,已经使用Cygwin和apt-cyg,这些软件包也存在于那里,可以轻松安装和执行! - Pysis
请注意,补丁文件不可读,这正是我所需要的。 - user18619318
@user18619318:由于二进制文件根据定义不可读,你期望这样的补丁文件会是什么样子呢? - Heinzi
@heinzi 对于文本差异,也是一样的。需要有某种提示,告诉我在文件1中的X字节位置上存在A、B、C,但在文件2中不存在;而在位置Y上,文件2中存在四个字节,但在文件1中不存在,并显示它们的值。 - Thorbjørn Andersen - UFST

32

Courgette是Google Chrome团队开发的二进制可执行文件最有效的补丁工具。

引用他们的数据:

以下是开发通道上最近一次190.1 -> 190.4更新的大小:

  • 完整更新:10,385,920字节
  • bsdiff更新:704,512字节
  • Courgette更新:78,848字节

这里是构建它的说明。这是一个2018年Windows二进制文件,由Mehrdad提供。


18
这份文件提到:“我们编写了一个新的差异算法,它更了解我们正在推送的数据类型——包含已编译可执行文件的大型文件。” 暗示着该算法在处理其他二进制文件时可能效果不如预期甚至可能无法正常工作。 - James
2
谢谢你提供的链接。但是在Windows下编译它确实是一个真实的故事。它首先安装了整个开发者系统,例如Git、Python等。也许它可以工作,但在我的机器上,获取使用了一些被保护的端口并失败了。有人知道二进制下载链接吗? - Philm
2
@James Courgette是bsdiff的真正继承者。从文档中可以看出,Courgette diff = bsdiff(concat(original, guess), update)。通过一个合理的bdiff算法,你可以得到len(bdiff(concat(original,guess),update)) < len(bdiff(original,update))+C,其中小常数C很小。将C设置为10是一个安全的选择。也许有人可以计算出bsdiffC值。请注意,如果给定的bdiff算法保证对于任何原始值、随机值和更新值,都有len(bdiff(concat(original,random),update)) <= len(bdiff(original,update)),那么C==1。 - Tino
1
与bsdiff的输出不同,Courgette的输出已经被压缩(使用bzip2),你可以进一步通过像gzip或lzma这样的工具对其进行压缩以减小文件大小。 - MultiplyByZer0

27

xdelta (网站, GitHub) 是另一个选择。它似乎更加时新,但除此之外我不知道它与其他工具如 bsdiff 相比如何。

用法:

  • 创建补丁: xdelta -e -s old_file new_file delta_file
  • 应用补丁: xdelta -d -s old_file delta_file decoded_new_file

安装方式:

  • Windows: 下载 官方二进制文件
  • Chocolatey: choco install xdelta3
  • Homebrew: brew install xdelta
  • Linux: 在您的包管理器中可用作 xdeltaxdelta3

Windows二进制文件:官方xdelta3非官方xdelta - Vlastimil Ovčáčík
这简直节省了我数小时的时间。我需要测试一个1.1GB的exe自解压安装程序的特定构建版本。通过VPN复制需要2.5个小时。我已经有了3个月前发布的不同版本...按照您的说明,生成的补丁(幸运的是)只有18MB - 猜测只有微小的更改。在远程系统上应用了补丁。对新修补后的exe执行各种校验和,在两个系统上匹配。有很多方法可能行不通,但在我的情况下完美地奏效了! - Ryan
我刚刚尝试了 xdelta,它有不同的命令行命令。就像这样:xdelta delta old_file new_file delta_filexdelta patch delta_file old_file decoded_new_file - Mariusz Pawelski
甲虫(Scarab)由Alexey Baskokov构建,基于XDelta添加目录差异。https://github.com/loyso/Scarab - Steve F

9
对于小型、简单的补丁,最好使用-a(或--text)选项告诉diff将文件视为文本。就我所知,更复杂的二进制差异只有在减小补丁大小时才有用。
$ man diff | grep -B1 "as text"
       -a, --text
              treat all files as text
$ diff old new
Binary files old and new differ
$ diff -a old new > old.patch
$ patch < old.patch old
patching file old
$ diff old new
$

如果文件大小相同且补丁只修改了几个字节,则可以使用通常与操作系统一起安装的xxd。以下内容将每个文件转换为具有每行一个字节的十六进制表示形式,然后对文件进行差异比较以创建紧凑的补丁,最后应用该补丁。
$ xxd -c1 old > old.hex
$ xxd -c1 new > new.hex
$ diff -u old.hex new.hex | grep "^+" | grep -v "^++" | sed "s/^+//" > old.hexpatch
$ xxd -c1 -r old.hexpatch old
$ diff old new
$

对于支持进程替换的shell,例如bash和zsh,有一种更简单的方法可用:
$ comm -13 <(xxd -c1 old) <(xxd -c1 new) > old.hexpatch 
$ xxd -c1 -r old.hexpatch old
$ diff old new
$

在这里,comm -13 删除仅出现在第一个输入中以及出现在两个输入中的行,仅保留第二个输入独有的行。


1
我非常喜欢xxd提供的纯文本补丁选项。然而,默认情况下,GNU diff似乎会在行前加上<>;为了让它在行前加上+-,我不得不使用diff -u,例如:diff -u old.hex new.hex | grep "^+" | grep -v "^++" | sed "s/^+//" > old.hexpatch - bmaupin
1
另外,这里有一个一行代码,可以创建补丁而不需要中间文件:comm -13 <(xxd -c1 old) <(xxd -c1 new) > old.hexpatch - bmaupin
@bmaupin 谢谢!我已经加入了这两个修复。我一直使用 diff 的 -ur 参数,忘记了默认格式。 - cjfp

6

现代端口:非常有用的.NET端口,用于bsdiff/bspatch:

https://github.com/LogosBible/bsdiff.net

这是我的个人选择。

我进行了测试,它是所有链接中唯一一个可以直接编译的(例如,使用Visual Studio,如Visual Studio 2013)。(其他地方的C++源码有点过时,并且需要至少对其进行一些修补,并且只支持32位,这会设置真正的内存(diff源文件大小)限制。这是这个C++代码bsdiff的端口,甚至测试补丁结果是否与原始代码相同。)

更进一步的想法:使用.NET 4.5甚至可以摆脱此处的依赖项#Zip库。

我没有测量它是否比C++代码稍微慢一些,但对我来说它很好用,(bsdiff:90 MB文件需要1-2分钟),对我来说时间紧迫的只有bspatch,而不是bsdiff。

我不确定一个x64机器的整个内存是否被使用,但我认为是这样的。x64可用构建("Any CPU")至少可以工作。我试过使用100 MB文件。

-此外:引用的Google项目“Courgette”可能是最好的选择,如果你的主要目标是可执行文件。但是构建它需要工作(对于至少适用于Windows的措施),而对于二进制文件,它也仅使用纯bsdiff/bspatch,就我所理解的文档而言。


2

HDiffPatch可以在Windows、macOS、Linux和Android上运行。

它支持二进制文件或目录之间的差异;

创建补丁:hdiffz [-m|-s-64] [-c-lzma2] old_path new_path out_delta_file

应用补丁:hpatchz old_path delta_file out_new_path

安装:

从最新版本下载,或下载源代码并make

Jojos Binary Diff是另一个很好的二进制差异算法;


当前版本有一个需要注意的地方:它允许您多次应用相同的补丁,即在应用之前没有crc检查。我曾经因此意外损坏了一些文件,因为hdiffs也可以添加字节,而不仅仅是替换。sfx功能非常好...但是不能记录文件的名称,所以您仍然需要一些额外的脚本来存储这些名称(至少在对单个文件进行差异比较时,而不是目录)。 - Fizz
hdiffz 尝试添加:-D -C-md5 @Fizz - undefined

1

https://github.com/reproteq/DiffPatchWpf DiffPatchWpf是一个简单的二进制补丁制作工具。

比较两个二进制文件并将它们之间的差异保存在新文件patch.txt中。

快速、轻松地在另一个二进制文件中应用补丁。

现在您可以快速、轻松地将差异应用于另一个二进制文件。

示例:

1- 加载Aori.bin文件。

2- 加载Amod.bin文件。

3- 比较并保存Aori-patch.txt文件。

4- 加载Bori.bin文件。

5- 加载Aori-patch.txt文件。

6- 应用补丁并保存Bori-patched.bin文件。

alt标签

https://youtu.be/EpyuF4t5MWk

微软Visual Studio社区版2019

版本16.7.7

.NET Framework,版本=v4.7.2

已在Windows 10 x64位上进行测试


1

使用 -a,diff 和 git-diff 可以将二进制文件作为文本处理。

使用 --binary,git-diff 还可以生成二进制文件的 ASCII 编码,适合粘贴到电子邮件中。


-7

假设您知道文件的结构,您可以使用C/C++程序逐字节修改它:

http://msdn.microsoft.com/en-us/library/c565h7xx(VS.71).aspx

只需读取旧文件,并将其修改为所需的新文件。

不要忘记在文件中包含文件格式版本号,以便您知道如何读取任何给定版本的文件格式。


6
这个解决方案太疯狂了。当已经有“sed”可以满足你的所有需求时,还使用C / C ++是不必要的。或者,如果你喜欢使用工业级便携式编程语言,“perl”是最好的选择。如果我要编写路由器固件,当然我会选择C或C ++,但diff? - Parthian Shot
这个链接是什么?是指Visual Studio 2003的安装程序吗?该链接会进行重定向。 - Peter Mortensen
1
这本质上是一个仅包含链接的回答。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接