我经常用来grep -ao ...word file.bin
查找文本内容(“单词”)及其前面的几个字符;提醒一句:
-a, --text
Process a binary file as if it were text; this is equivalent to the --binary-files=text option.
-o, --only-matching
Print only the matched (non-empty) parts of a matching line, with each such part on a separate
output line.
正确的;所以刚才,我意识到它的行为是这样的:我尝试首先查找字符串war
及其前面的一个字符:
$ grep -ao .war myfile.zip
/war
9war
$war
ʆwar
好的,所以我在这里得到了 4 次点击。现在,如果我想查找字符串war
及其前面的两个字符:
$ grep -ao ..war myfile.zip
>$war
那么,现在,由于某种原因,我只得到一个结果?!
我的猜测是,在三个缺失的情况下,“前面两个字符”的值是 0x00(C 字符串的结尾),因此grep
不会输出该匹配项 - 否则我仍然期望 4 个结果(除非之前的第一个匹配项位于文件开头,否则我会得到 3 个结果)。
我可以以某种方式说服grep
简单地“忽略”匹配中的空字节(或用点或其他东西替换它们)并仍然打印可能包含它们的匹配吗?如果没有grep
,还有其他工具可以做到这一点吗?
答案1
您的方法至少存在两个(最好是三个)问题。
即使使用非标准-o
,也是grep
基于行的,因为它会找到o
每行上所有与输出匹配的内容,行是由换行符分隔的字符序列(在基于 ASCII 的系统上值为 10 / 0x0a 的字节)。
所以:
grep -o ..war
只会返回war
2 之后的实例人物(不是字节,这是这里的三个问题之一)除了换行符。
例如,在类似 的输入中<0x0a>Xwar
,0x0a 字节分隔上一行,下一行Xwar
从 之前只有一个字符的位置开始war
。
在 UTF-8 语言环境中,在类似 的输入上<0xff><0xc3><0xa9>war
,两个字节<0xc3><0xa9>
形成é
字符,但前面的 0xff 字节无效,因此无法形成字符。
grep
一般来说,仅适用于文本,因此根据grep
实现的不同,使用 NUL 字符或过长的行或不以换行符结尾的输入可能会给工作带来麻烦。
然后,在 中xxwarwar
,grep -o
会找到xxwar
,但之后继续搜索更多匹配项,因此不会找到arwar
。
这些问题可以通过使用以下方法来解决perl
:
perl -l -0777 -ne 'print "$1$2" while m{(?<=(..))(war)}sg'
我们发现实例war
前面有任何 2 个字节(不是用户区域设置中的字符),对这些前面的字节使用后向运算符,以免消耗输入。使用-0777
,它将记录分隔符设置为不可能的事情,我们处理整个输入,而不是输入中的每一行。
答案2
另一种方法是将二进制转换为十六进制并匹配:
hexdump -v -e '/1 "%02X" " "' file.bin | grep -o ".. .. $(printf "war" | hexdump -v -e '/1 "%02X" " "')"
对于字符串之前要匹配的..
每个字节,您都需要一个。.
缺点是它比 grep 或 perl 的直接匹配慢,并且不会像warwar
perl 解决方案那样在连续模式中找到后续匹配
结果将打印为十六进制值。如果您想将结果打印为字符串,请像这样将字节转换回来
hexdump -v -e '/1 "%02X" " "' file.bin | \
grep -o ".. .. $(printf "war" | hexdump -v -e '/1 "%02X" " "')" | \
xargs -d '\n' -n 1 bash -c '<<<"$1" xxd -r -p -; echo' bash
但请注意\n
,\r
字符串之前的 和许多其他控制字符会弄乱输出
您还可以通过不在每个字节后打印空格来加快搜索速度,但需要注意的是,由于十六进制字符串在字节中间匹配,可能会出现误报。这样你就可以匹配..
而不是..
每个.
hexdump -v -e '/1 "%02X" ""' file.bin | \
grep -o "....$(printf "war" | hexdump -v -e '/1 "%02X" ""')" | \
xargs -d '\n' -n 1 bash -c '<<<"$1" xxd -r -p -; echo' bash