说我已经生成了以下二进制文件:
# 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
并说,我想0x00使用类似grep的语法查找全零()的位置。
0x00
到目前为止,我能做的最好的事情是:
$ hexdump -v -e "1/1 \" %02x\n\"" mydata.bin | grep -n '00' 1: 00 2: 00 3: 00 4: 00 9: 00 12: 00
但是,这会将原始二进制文件中的每个字节隐式转换为多字节ASCII表示形式,并可以对其进行grep操作;不完全是优化的主要示例:)
grep
是否有类似grepLinux 的二进制文件?也可能支持某种类似于正则表达式的语法,但也支持字节“字符”的东西-也就是说,我可以编写类似“ a(\x00*)b”的东西,并在字节“ a”之间匹配字节0的“零个或多个”出现( 97)和“ b”(98)?
a(\x00*)b
编辑:上下文是我正在一个驱动程序上,我捕获8位数据;数据出了点问题,可能是千字节到兆字节,我想检查特定的签名及其出现的位置。( 到目前为止,我正在使用千字节片段,因此优化并不是那么重要-但是,如果我开始在兆字节长捕获中遇到一些错误,并且需要分析这些错误,我想我想进行一些优化:)。 特别是,我希望可以在其中“ grep”一个字节作为字符- hexdump强迫我按字节搜索字符串)
hexdump
EDIT2:相同的问题,不同的论坛:) grepping二进制文件中的字节序列
EDIT3:多亏了@tchrist的回答,这也是一个“抓紧”和匹配并显示结果的示例( 尽管与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)
要将匹配的数据每个分组为一个字节(两个十六进制字符),则需要为匹配的字符串中存在的多个字节指定“ H2 H2 H2 …”;因为我的比赛’ .....\0\0\0\xCC\0\0\0.....‘覆盖了17个字节,所以我可以"H2"x17在Perl中写’ ‘。这些“ H2”中的每一个都将返回一个单独的变量(如列表中所示),因此join还需要用于在它们之间添加空格-最终:
.....\0\0\0\xCC\0\0\0.....
"H2"x17
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
好吧..实际上Perl是非常好的“二进制grepping”工具,我必须承认:)只要一个人正确地学习语法:)
这是较短的单线版本:
% perl -ln0e 'print tell' < inputfile
这是一个稍长的单线:
% perl -e '($/,$\) = ("\0","\n"); print tell while <STDIN>' < inputfile
连接这两个单行代码的方法是通过取消编译第一个程序的程序:
% perl -MO=Deparse,-p -ln0e 'print tell' BEGIN { $/ = "\000"; $\ = "\n"; } LINE: while (defined(($_ = <ARGV>))) { chomp($_); print(tell); }
如果您想将其放在文件中,而不是从命令行调用它,那么这里是一个更明确的版本:
#!/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(); }
这是很长的版本:
#!/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);
顺便说一句,要创建测试输入文件,我没有使用过长的Python大型脚本;我只是使用了这个简单的Perl单行代码:
% perl -e 'print 0.0.0.0.2.4.6.8.0.1.3.0.5.20' > inputfile
您会发现,完成相同的工作,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);
尽管这也可行:
print chr for @values;
一样
print map { chr } @values;
尽管对于那些喜欢所有严谨,细心和全部的人来说,这可能是您所看到的更多:
#!/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);
Perl支持多种处理方式,因此您可以选择最习惯的一种方式。如果这是我计划作为学校或工作项目检查的内容,那么我肯定会选择更长,更仔细的版本- 如果我使用的是单行代码,或者至少在shell脚本中添加注释。
您可以在自己的系统上找到Perl的文档。只需输入
% man perl % man perlrun % man perlvar % man perlfunc
等在您的shell提示下。如果要在网上使用漂亮的版本,请从http://perldoc.perl.org获取perl,perlrun,perlvar和perlfunc的联机帮助页。