我有二进制文件并希望从已知字节字符串(即FF D8 FF D0)开始并以已知字节字符串(AF FF D9)结束提取部分内容
过去我曾使用dd
从开始/结束中删除部分二进制文件,但此命令似乎不支持我的要求。
终端上的哪个工具可以做到这一点?
答案 0 :(得分:7)
找到开始/结束位置,然后提取范围。
$ xxd -g0 input.bin | grep -im1 FFD8FFD0 | awk -F: '{print $1}'
0000cb0
$ ^FFD8FFD0^AFFFD9^
0009590
$ dd ibs=1 count=$((0x9590-0xcb0+1)) skip=$((0xcb0)) if=input.bin of=output.bin
答案 1 :(得分:3)
在一个管道中:
xxd -c1 -p file |
awk -v b="ffd8ffd0" -v e="aaffd9" '
found == 1 {
print $0
str = str $0
if (str == e) {found = 0; exit}
if (length(str) == length(e)) str = substr(str, 3)}
found == 0 {
str = str $0
if (str == b) {found = 1; print str; str = ""}
if (length(str) == length(b)) str = substr(str, 3)}
END{ exit found }' |
xxd -r -p > new_file
test ${PIPESTATUS[1]} -eq 0 || rm new_file
我们的想法是在两个awk
之间使用xxd
来选择所需文件的一部分。找到第一个模式后,awk
将打印字节,直到找到第二个模式并退出。
必须考虑找到第一个图案但不是第二个图案的情况。它在END
脚本的awk
部分完成,返回非零退出状态。这是由bash
的{{1}}抓住的,我决定删除新文件。
请注意,空文件也意味着没有找到任何内容。
答案 2 :(得分:2)
这应该适用于标准工具(xxd,tr,grep,awk,dd)。这正确地处理了“跨行的模式分割”问题,也寻找仅在字节偏移(不是半字节)处对齐的模式。
file=<yourfile>
outfile=<youroutputfile>
startpattern="ff d8 ff d0"
endpattern="af ff d9"
xxd -g0 -c1 -ps ${file} | tr '\n' ' ' > ${file}.hex
start=$((($(grep -bo "${startpattern}" ${file}.hex\
| head -1 | awk -F: '{print $1}')-1)/3))
len=$((($(grep -bo "${endpattern}" ${file}.hex\
| head -1 | awk -F: '{print $1}')-1)/3-${start}))
dd ibs=1 count=${len} skip=${start} if=${file} of=${outfile}
注意:上面的脚本使用临时文件来防止二进制&gt;十六进制转换两次。空格/时间权衡是将xxd
的结果直接导入两个grep
。单线也是可能的,但代价是清晰。
还可以使用tee
和命名管道来防止必须存储临时文件并将输出转换两次,但我不确定它会更快(xxd很快)并且写入肯定更复杂
答案 3 :(得分:1)
请参阅this link了解二进制grep的方法。获得开始和结束偏移后,您应该能够dd
获得所需内容。
答案 4 :(得分:1)
awk
解决方案的变体,假设您的二进制文件一旦用十六进制转换为空格,就会适合内存:
xxd -c1 -p file |
tr "\n" " " |
sed -n -e 's/.*\(ff d8 ff d0.*aa ff d9\).*/\1/p' |
xxd -r -p > new_file
答案 5 :(得分:1)
sed
中的另一个解决方案,但使用的内存较少:
xxd -c1 -p file |
sed -n -e '1{N;N;N}' -e '/ff\nd8\nff\nd0/{:begin;p;s/.*//;n;bbegin}' -e 'N;D' |
sed -n -e '1{N;N}' -e '/aa\nff\nd9/{p;Q1}' -e 'P;N;D' |
xxd -r -p > new_file
test ${PIPESTATUS[2]} -eq 1 || rm new_file
第一个sed
从ff d8 ff d0
打印到文件末尾。请注意,N
中-e '1{N;N;N}'
需要sed
,因为第一种模式中的字节数少于一个。
第二个aa ff d9
从文件开头打印到N
。请再次注意,-e '1{N;N}'
中Q
需要sed
,因为第二种模式中有字节少一个。
同样,需要进行测试以检查是否找到第二个模式,如果不是,则删除该文件。
请注意,sed
命令是{{1}}的GNU扩展。如果你没有它,你需要在找到模式后丢弃文件的其余部分(在第1 {{1}}之类的循环中,但不打印文件),并在十六进制到二进制转换后检查new_file以wright模式结束。