用 dd 修补二进制文件

Amz*_*aro 32 patch dd history

我已经多次阅读了这句话(下面),最近一次在这里,并且一直对如何dd用于修补任何东西感到困惑,更不用说编译器了:

30 年前,我在学校使用的 Unix 系统在 RAM 和磁盘空间方面非常有限。特别是/usr/tmp文件系统非常小,当有人试图编译一个大程序时会导致问题。当然,无论如何,学生都不应该编写“大型程序”;大型程序通常是从“某处”复制的源代码。我们中的许多人复制/usr/bin/cc/home/<myname>/cc,并用于dd修补二进制文件以使用/tmp代替/usr/tmp,后者更大。当然,这只会让问题变得更糟——这些副本占用的磁盘空间在那些日子里确实很重要,现在/tmp经常被填满,甚至阻止其他用户编辑他们的文件。在他们发现发生了什么之后,系统管理员做了一个chmod go-r /bin/* /usr/bin/* 它“修复”了问题,并删除了我们所有的 C 编译器副本。

(强调我的)

dd手册页只字未提修补和不认为它可能是重新定意要做到这一点呢。

二进制文件真的可以打补丁dd吗?这有什么历史意义吗?

Mic*_*mer 79

让我们试试吧。这是一个简单的 C 程序:

#include <stdio.h>
int main(int argc, char **argv) {
    puts("/usr/tmp");
}
Run Code Online (Sandbox Code Playgroud)

我们将其构建为test

$ cc -o test test.c
Run Code Online (Sandbox Code Playgroud)

如果我们运行它,它会打印“/usr/tmp”。

让我们找出“ /usr/tmp”在二进制文件中的位置:

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp
Run Code Online (Sandbox Code Playgroud)

-t d 将十进制的偏移量打印到它找到的每个字符串的文件中。

现在让我们制作一个只有“ /tmp\0”的临时文件:

$ printf "/tmp\x00" > tmp
Run Code Online (Sandbox Code Playgroud)

所以现在我们有了二进制文件,我们知道要更改的字符串在哪里,并且我们有一个包含替换字符串的文件。

现在我们可以使用dd

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc
Run Code Online (Sandbox Code Playgroud)

这从tmp(我们的“ /tmp\0”文件)读取数据,将其写入我们的二进制文件,使用 1 个字节的输出块大小,在写入任何内容之前跳到我们之前找到的偏移量,并且在完成时明确不截断文件。

我们可以运行打过补丁的可执行文件:

$ ./test
/tmp
Run Code Online (Sandbox Code Playgroud)

程序打印出的字符串文字已经改变,所以它现在包含“ /tmp\0tmp\0”,但是字符串函数一旦看到第一个空字节就会停止。这种修补只允许使字符串更短或相同的长度,而不是更长,但它足以满足这些目的。

所以我们不仅可以使用 修补东西dd,我们刚刚完成了它。

  • 这太棒了……我强烈希望我在生产环境中永远不会遇到!过去我曾使用过类似的方法将序列号转换为微控制器的十六进制图像,不过这太容易了。 (3认同)
  • @ParthianShot - `sed` 对这种事情*不* - 你不能像使用 `dd` 那样明确和精确地限制 `sed` 的读/写缓冲区 - 这就是它的全部原因一开始就被用于这个。使用 `dd`,您可以任意放置任意数量的任意字节。这也不能说是`sed`。如果在这里像手术刀一样使用 `dd`,你会像使用破坏球一样使用 `sed`。 (2认同)

fro*_*utz 9

这取决于您所说的“修补二进制文件”是什么意思。

dd有时使用更改二进制文件。当然dd, .

例如,我有一个包含一些 PNG 数据的二进制文件。使用binwalk找到的偏移量,dd将其解压(通常binwalk还提取的东西,但我的副本是越野车),编辑它gimp,确保编辑的文件大小相同或比原来的更小的(改变偏移是不是你可以很容易做到),然后使用dd将更改后的图像放回原位。

$ binwalk thebinary
[…]
4194643    0x400153     PNG image, 800 x 160, 8-bit/color RGB, non-interlaced
[…]
$ dd if=nickel bs=1 skip=4194641 count=2 conv=swab | od -i
21869 # file size in this case - depends on the binary format
$ dd if=thebinary bs=1 skip=4194643 count=21869 of=theimage.png
$ gimp theimage.png
$ pngcrush myimage.png myimage.crush.png
# make sure myimage.crush.png is smaller than the original
$ dd if=myimage.crush.png of=thebinary bs=1 seek=4194643 conv=notrunc
Run Code Online (Sandbox Code Playgroud)

有时我也希望替换二进制文件中的字符串(例如路径或变量名)。虽然这也可以使用 完成dd,但使用sed. 您只需要确保您替换的字符串与原始字符串的长度相同,这样您就不会最终更改偏移量。

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary
Run Code Online (Sandbox Code Playgroud)

或者拿起@MichaelHomer 的例子,其中添加了一个 0 字节:

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test
Run Code Online (Sandbox Code Playgroud)

当然,您必须在之后验证它是否确实有效。