使用 dd 修补二进制文件

使用 dd 修补二进制文件

我已经多次阅读这句话(如下),最近一次这里,并且我一直对如何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?这有什么历史意义吗?

答案1

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

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

我们将把它构建成test

$ cc -o test test.c

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

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

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp

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

现在让我们创建一个只包含“ /tmp\0”的临时文件:

$ printf "/tmp\x00" > tmp

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

现在我们可以使用dd

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc

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

我们可以运行修补后的可执行文件:

$ ./test
/tmp

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

所以我们不仅可以使用 来修补东西dd,而且我们已经完成了。

答案2

这取决于“修补二进制文件”的含义。

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

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

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary

或者选择 @MichaelHomer 的示例,其中添加了 0 字节:

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test

当然,你必须事后验证它是否真的有效。

答案3

是的,可以使用 dd 修补二进制文件。

要使用来自 stdin 的数据修补文件:

dd of=file.bin bs=1 count=2 conv=notrunc

然后输入要修补的(文本)数据。即使在提示时输入超过 2 个字符,上述内容也仅修补 2 个字节(从文件开头)。
要修补文件中间,请通过提供文件数据的位置(地址)seek来开始修补。例如。

dd of=file.out bs=1 count=2 seek=2 conv=notrunc

或者

echo "<address: data>" | xxd -r - file.out

如果修补不可打印的字符,请使用要修补的数据创建一个二进制临时文件。例如。

dd if=file.in of=file.out bs=1 count=2 seek=2 conv=notrunc

或者

xxd -r hexoffsets.in file.out

或在标准输入上提供带有偏移量的十六进制数据

echo "<address: hex-data>" | xxd -r - file.out

定义:
patch的意思是把hexdump转换成二进制(来自xxd manpage)

在 Ubuntu 16.04.7 上测试

相关内容