Linux上的二进制grep?

sda*_*aau 28 linux binary grep

假设我生成了以下二进制文件:

# generate file:
python -c 'import sys;[sys.stdout.write(chr(i)) for i in (0,0,0,0,2,4,6,8,0,1,3,0,5,20)]' > mydata.bin

# get file size in bytes
stat -c '%s' mydata.bin

# 14
Run Code Online (Sandbox Code Playgroud)

并说,我想0x00使用类似grep的语法找到所有零()的位置.

 

到目前为止,我能做的最好的事情是:

$ hexdump -v -e "1/1 \" %02x\n\"" mydata.bin | grep -n '00'

1: 00
2: 00
3: 00
4: 00
9: 00
12: 00
Run Code Online (Sandbox Code Playgroud)

但是,这会隐式地将原始二进制文件中的每个字节转换为多字节ASCII表示,并在其上grep运行; 不完全是优化的主要例子:)

是否有类似grepLinux 的二进制文件?也可能是支持正则表达式语法的东西,也支持字节"字符" - 也就是说,我可以a(\x00*)b在'a'之间编写类似' '并匹配'零或更多'字节0的出现'(' 97)和'b'(98)?

编辑:上下文是我正在研究一个驱动程序,我捕获8位数据; 数据中出现问题,可能是千字节到兆字节,我想检查特定的签名及其出现的位置.(到目前为止,我正在使用千字节片段,所以优化并不重要 - 但如果我开始在兆字节长的捕获中得到一些错误,我需要分析那些,我的猜测是我想要更优化的东西:).特别是,我想要一些东西,我可以"grep"一个字节作为一个字符 - hexdump迫使我每个字节搜索字符串)

EDIT2:同样的问题,不同的论坛:) 通过二进制文件grepping一个字节序列

EDIT3:感谢@tchrist的回答,这里也是'grepping'和匹配,并显示结果的例子(虽然与OP的问题不完全相同):

$ perl -ln0777e 'print unpack("H*",$1), "\n", pos() while /(.....\0\0\0\xCC\0\0\0.....)/g' /path/to/myfile.bin

ca000000cb000000cc000000cd000000ce     # Matched data (hex)
66357                                  # Offset (dec)
Run Code Online (Sandbox Code Playgroud)

为了将匹配的数据分组为每个字节(两个十六进制字符),需要指定"H2 H2 H2 ...",匹配字符串中有多少字节; 因为我的匹配' .....\0\0\0\xCC\0\0\0.....'涵盖17个字节,我可以"H2"x17在Perl中写' '.这些"H2"中的每一个都将返回一个单独的变量(如列表中所示),因此join还需要使用它们在它们之间添加空格 - 最终:

$ perl -ln0777e 'print join(" ", unpack("H2 "x17,$1)), "\n", pos() while /(.....\0\0\0\xCC\0\0\0.....)/g' /path/to/myfile.bin

ca 00 00 00 cb 00 00 00 cc 00 00 00 cd 00 00 00 ce
66357
Run Code Online (Sandbox Code Playgroud)

嗯..确实Perl是非常好的'二进制grepping'工具,我必须承认:)只要一个人学习正确的语法:)

Fr0*_*0sT 45

这似乎对我有用:

grep --only-matching --byte-offset --binary --text --perl-regexp "<\x-hex pattern>" <file>
Run Code Online (Sandbox Code Playgroud)

简写:

grep -obUaP "<\x-hex pattern>" <file>
Run Code Online (Sandbox Code Playgroud)

例:

grep -obUaP "\x01\x02" /bin/grep
Run Code Online (Sandbox Code Playgroud)

输出(Cygwin二进制):

153: <\x01\x02>
33210: <\x01\x02>
53453: <\x01\x02>
Run Code Online (Sandbox Code Playgroud)

所以你可以再次grep这个来提取偏移量.但是别忘了再次使用二进制模式.

  • @fuzzyTew我设法通过设置`LANG = C`(之前的LANG = pt_BR.UTF-8,也许grep试图解释我的字节流中的unicode字符)来使它工作. (7认同)
  • 对于我来说,这似乎不适用于大于0x7f的二进制字符.Grep只是不匹配. (3认同)
  • 有点晚了,但是多亏了这个 - 真的需要一个`grep`用二进制做偏移的例子; 干杯! (2认同)

Dav*_*ean 19

其他人似乎同样感到沮丧,并编写了自己的工具(或至少类似的东西):bgrep.


tch*_*ist 14

单线输入

这是较短的单行版本:

% perl -ln0e 'print tell' < inputfile
Run Code Online (Sandbox Code Playgroud)

这是一个稍长的单行:

% perl -e '($/,$\) = ("\0","\n"); print tell while <STDIN>' < inputfile
Run Code Online (Sandbox Code Playgroud)

连接这两个单行的方法是通过重新编译第一个程序:

% perl -MO=Deparse,-p -ln0e 'print tell'
BEGIN { $/ = "\000"; $\ = "\n"; }
LINE: while (defined(($_ = <ARGV>))) {
    chomp($_);
    print(tell);
}
Run Code Online (Sandbox Code Playgroud)

程序输入

如果你想把它放在一个文件而不是从命令行调用它,这里有一个更明确的版本:

#!/usr/bin/env perl

use English qw[ -no_match_vars ];

$RS  = "\0";    # input  separator for readline, chomp
$ORS = "\n";    # output separator for print

while (<STDIN>) {
    print tell();
}
Run Code Online (Sandbox Code Playgroud)

这是真正的长版本:

#!/usr/bin/env perl

use strict;
use autodie;  # for perl5.10 or better
use warnings qw[ FATAL all  ];

use IO::Handle;

IO::Handle->input_record_separator("\0");
IO::Handle->output_record_separator("\n");

binmode(STDIN);   # just in case

while (my $null_terminated = readline(STDIN)) {
    # this just *past* the null we just read:
    my $seek_offset = tell(STDIN);
    print STDOUT $seek_offset;  

}

close(STDIN);
close(STDOUT);
Run Code Online (Sandbox Code Playgroud)

单列输出

顺便说一下,为了创建测试输入文件,我没有使用你庞大的Python脚本; 我刚用这个简单的Perl单线程:

% perl -e 'print 0.0.0.0.2.4.6.8.0.1.3.0.5.20' > inputfile
Run Code Online (Sandbox Code Playgroud)

你会发现Perl经常比Python做2-3倍做同样的工作.而且你不必在清晰度上妥协; 什么可以更简单,上面的单线?

程序输出

我知道我知道.如果您还不熟悉该语言,可能会更清楚:

#!/usr/bin/env perl
@values = (
    0,  0,  0,  0,  2,
    4,  6,  8,  0,  1,
    3,  0,  5, 20,
);
print pack("C*", @values);
Run Code Online (Sandbox Code Playgroud)

虽然这也有效:

print chr for @values;
Run Code Online (Sandbox Code Playgroud)

同样如此

print map { chr } @values;
Run Code Online (Sandbox Code Playgroud)

虽然对于那些喜欢一切都严谨和谨慎的人来说,这可能会更像你所看到的:

#!/usr/bin/env perl

use strict;
use warnings qw[ FATAL all ];
use autodie;

binmode(STDOUT);

my @octet_list = (
    0,  0,  0,  0,  2,
    4,  6,  8,  0,  1,
    3,  0,  5, 20,
);

my $binary = pack("C*", @octet_list);
print STDOUT $binary;

close(STDOUT); 
Run Code Online (Sandbox Code Playgroud)

TMTOWTDI

Perl支持多种方式来做事情,以便您可以选择最适合自己的方式.如果这是我计划作为学校或工作项目检查的内容,我肯定会选择更长,更谨慎的版本 - 或者至少在shell脚本中添加注释,如果我使用的是单行内容.

您可以在自己的系统上找到Perl的文档.只需输入

% man perl
% man perlrun
% man perlvar
% man perlfunc
Run Code Online (Sandbox Code Playgroud)

在你的shell提示符下等.如果你想在网上找到漂亮的版本,http://perldoc.perl.org获取perl,perlrun,perlvarperlfunc的联机帮助页.


hdo*_*rio 10

BBE程序是sed的二进制文件编辑器状.见文档.

bbe示例:

bbe -b "/\x00\x00\xCC\x00\x00\x00/:17" -s -e "F d" -e "p h" -e "A \n" mydata.bin

11:x00 x00 xcc x00 x00 x00 xcd x00 x00 x00 xce
Run Code Online (Sandbox Code Playgroud)

说明

-b search pattern between //. each 2 byte begin with \x (hexa notation).
   -b works like this /pattern/:length (in byte) after matched pattern
-s similar to 'grep -o' suppress unmatched output 
-e similar to 'sed -e' give commands
-e 'F d' display offsets before each result here: '11:'
-e 'p h' print results in hexadecimal notation
-e 'A \n' append end-of-line to each result
Run Code Online (Sandbox Code Playgroud)

您也可以将其传输到sed以获得更清晰的输出:

bbe -b "/\x00\x00\xCC\x00\x00\x00/:17" -s -e "F d" -e "p h" -e "A \n" mydata.bin | sed -e 's/x//g'

11:00 00 cc 00 00 00 cd 00 00 00 ce
Run Code Online (Sandbox Code Playgroud)

使用来自EDIT3的Perl的解决方案为我提供了大文件的"内存不足"错误.

bgrep也存在同样的问题.

bbe唯一的缺点是我不知道如何打印匹配模式之前的上下文.


Omn*_*bat 8

仅使用grep解决直接问题的一种方法是创建包含单个空字节的文件.之后,grep -abo -f null_byte_file target_file将产生以下输出.

0:
1:
2:
3:
8:
11:

那当然是"-b"所要求的每个字节偏移量,后跟"-o"请求的空字节

我是第一个提倡perl的人,但在这种情况下,没有必要引入大家庭.