【问题标题】:How to check if a binary file is contained inside another binary from the Linux command line?如何从 Linux 命令行检查二进制文件是否包含在另一个二进制文件中?
【发布时间】:2021-01-11 21:22:49
【问题描述】:

基本上我想要一个“将二进制字符串作为模式的多行 grep”。

例如:

printf '\x00\x01\n\x02\x03' > big.bin
printf '\x01\n\x02' > small.bin
printf '\x00\n\x02' > small2.bin

那么以下应该成立:

  • small.bin 包含在 big.bin
  • small2.bin 不包含在 big.bin

我不想将文件转换为带有xxd 的 ASCII 十六进制表示,如图所示,例如at:https://unix.stackexchange.com/questions/217936/equivalent-command-to-grep-binary-files 因为那感觉很浪费。

理想情况下,该工具应处理无法放入内存的大文件。

请注意,以下尝试不起作用。

grep -f 匹配不应该的位置,因为它必须拆分换行符:

grep -F -f small.bin big.bin
# Correct: Binary file big.bin matches
grep -F -f small2.bin big.bin
# Wrong: Binary file big.bin matches

$(cat) 中的 Shell 替换失败,因为它是 impossible to handle null characters in Bash AFAIK,所以字符串只会在第一个 0 处被截断,我相信:

grep -F "$(cat small.bin)" big.bin
# Correct: Binary file big.bin matches
grep -F "$(cat small2.bin)" big.bin
# Wrong: Binary file big.bin matches

已在How can i check if binary file's content is found in other binary file? 提出了一个 C 问题,但是否可以使用任何广泛可用的 CLI(希望是 POSIX 或 GNU coreutils)工具?

值得注意的是,实现诸如Boyer-Moore 之类的非朴素算法并非易事。

我可以按如下方式破解一个正常工作的 Python one 班轮,但它不适用于不适合内存的文件:

grepbin() ( python -c 'import sys;sys.exit(not open(sys.argv[1]).read() in open(sys.argv[2]).read())' "$1" "$2" )
grepbin small.bin big.bin && echo 1
grepbin small2.bin big.bin && echo 2

我还可以在 GitHub 上找到以下两个工具:

但它们似乎不太支持从文件中获取模式,您在命令行上将输入提供为十六进制 ASCII。我可以使用:

bgrep $(xxd -p small.bin | tr -d '\n') big.bin

因为使用xxd 转换小文件并不重要,但这并不是很好。

无论如何,如果我要实现该功能,我很可能会将其用于上面的 Rust 库。

bgrep 也在:How does bgrep work?

在 Ubuntu 20.10 上测试。

【问题讨论】:

  • rep -f matches where it shouldn't because it must be splitting newlines: 并且它正在解析正则表达式。 grep "$(cat small.bin)" 不仅零字节失败。 grep 需要一个正则表达式。请注意,您的is it possible with any widely available CLI 正在“寻求工具推荐”的垃圾箱中。
  • @KamilCuk true,为非正则表达式添加了-F。如果它关闭,我会在其他地方发布,通常的程序。
  • "$(cat file-with-nulls)" 正在为失败做好准备,因为 NUL 不能存储在 C 字符串中,并且 bash 中的所有字符串都是 NUL 分隔的 C 字符串。就此而言,如果grep 使用能够包含 NUL 文字的字符串,我会感到非常惊讶——不,很惊讶。
  • ...构建一个 Python 代码版本会是一个更合理的开始,该版本执行窗口以逐步搜索文件(obvs.,需要围绕块边界进行一些特殊情况处理;但只要可以强制执行最大大小,这些似乎都不是特别棘手)。
  • grep 将整个正则表达式模式加载到内存中。我认为没有一种工具可以在二进制文件中搜索二进制字节流(不是字节缓冲区......)。如果小文件适合内存并且大文件很大,您可以编写一个简单的 C 程序来读取小文件,将其大小用作块大小,从大文件中读取块,并尝试使用memmem().

标签: bash grep posix gnu-coreutils


【解决方案1】:

如何通过 Linux 命令行检查一个二进制文件是否包含在另一个二进制文件中?

非常 POSIX 可移植的方法是使用 od 转换为十六进制,然后使用 grep 检查子字符串,以及介于两者之间的一些 sed 脚本。

通常的正常便携方式是使用xxd而不是od

xxd -p small.bin | tr -d '[ \n]' > small.bin2
xxd -p big.bin | tr -d '[ \n]' > big.bin2
grep -F -f small.bin2 big.bin2

dockeralpinebusybox 上测试效果很好。

但是:

我不想用 xxd 将文件转换为 ASCII 十六进制表示,如图所示

那么你不能在 shell 中处理二进制文件。选择另一种语言。 Shell 是专门为解析漂亮的人类可读字符串而创建的 - 对于其他任何内容,它都非常令人不快,对于零字节的文件,xxd 是您首先输入的内容。

我可以按如下方式构建一个可以工作的 Python one liner,

awk 也是 POSIX 并且随处可用 - 我相信更精通awk 的人可能会来编写您的 python 脚本的精确 1:1,但是:

但它不适用于不适合内存的文件:

所以写一个不同的算法,不会那样做。

总的来说,当给出不使用xxd(或od)将零字节二进制文件转换为十六进制表示的约束时:

是否可以使用任何广泛可用的 CLI(希望是 POSIX 或 GNU coreutils)工具?

没有。为此编写您自己的程序。也可以写成perl,有时候在没有python的机器上也可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-10
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    相关资源
    最近更新 更多