Как вывести часть двоичного файла - PullRequest
10 голосов
/ 26 февраля 2012

У меня есть двоичный файл, и я хочу извлечь его часть, начиная с известной строки байтов (т.е. FF D8 FF D0) и заканчивая известной строкой байтов (AF FF D9)

В прошлом я использовал dd, чтобы вырезать часть двоичного файла из начала / конца, но эта команда, похоже, не поддерживает то, что я спрашиваю.

Какой инструмент на терминале может сделать это?

Ответы [ 6 ]

7 голосов
/ 26 февраля 2012

Найдите начальную / конечную позицию, затем извлеките диапазон.

$ 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
3 голосов
/ 28 февраля 2012

В одном канале:

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, чтобы выбрать необходимую часть файла.Как только 1-й шаблон найден, awk печатает байты до тех пор, пока 2-й шаблон не будет найден и завершен.

Случай, когда 1-й шаблон найден, но 2-й не найден, должен учитываться.Это делается в части END скрипта awk, которая возвращает ненулевой статус выхода.Это ловит bash ${PIPESTATUS[1]}, где я решил удалить новый файл.

Обратите внимание, что пустой файл также означает, что ничего не было найдено.

2 голосов
/ 27 февраля 2012

Это должно работать со стандартными инструментами (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}

Примечание: В приведенном выше сценарии используется временныйфайл, чтобы предотвратить двоичное> шестнадцатеричное преобразование дважды.Пространственно-временной компромисс состоит в том, чтобы передать результат xxd непосредственно в два grep.Однострочник также возможен за счет ясности.

Можно также использовать tee и именованный канал, чтобы избежать необходимости сохранять временный файл и преобразовывать выходные данные дважды, но я не уверен в этомбудет быстрее (xxd быстр) и, конечно, будет сложнее писать.

1 голос
/ 28 февраля 2012

Другое решение в 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

1-й sed печатает от ff d8 ff d0 до конца файла. Обратите внимание, что вам нужно N в -e '1{N;N;N}' столько, сколько есть байтов в вашем 1-м паттерне минус один .

2-й sed печатает от начала файла до aa ff d9. Еще раз обратите внимание, что вам нужно столько N в -e '1{N;N}', сколько есть байтов во втором шаблоне минус один .

Опять же, необходим тест, чтобы проверить, найден ли второй шаблон, и удалите файл, если его нет.

Обратите внимание, что команда Q является расширением GNU до sed. Если у вас его нет, вам нужно удалить оставшуюся часть файла, как только будет найден шаблон (в цикле, подобном 1-му sed, но не печатать файл), и проверить после преобразования в шестнадцатеричный формат в двоичный, что конец new_file заканчивается с узором Райт.

1 голос
/ 28 февраля 2012

Вариант решения 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
1 голос
/ 26 февраля 2012

См. эту ссылку , чтобы узнать, как сделать двоичный файл grep. Получив начальное и конечное смещение, вы сможете набрать dd, чтобы получить то, что вам нужно.

...