Вам нужно 'ldd busybox' и скопировать общие библиотеки, на которые он ссылается, в chroot. Используйте 'cp -L src dst' на libs, потому что они обычно упрощены.
Это запрошенное однострочное решение (для последних оболочек, которые имеют «подстановку процесса»):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Если «подстановка процесса» <(…)
недоступна, просто используйте grep как filter:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Ниже приводится подробное описание каждой части решения.
Первую проблему легко решить:
Эти escape-последовательности \ Xnn работают только в оболочке Fish.
Измените верхний X
на нижний x
и используйте printf (для большинства оболочек):
$ printf -- '\xef\xbe\xad\xde'
Или используйте:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Для тех оболочек, которые предпочитают не реализовывать представление '\ x'.
Конечно, преобразование шестнадцатеричного числа в восьмеричное будет работать (почти) в любой оболочке:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Где «$ sh» - любая (разумная) оболочка. Но правильно процитировать его довольно сложно.
Наиболее надежным решением является преобразование файла и последовательности байтов (обоих) в некоторую кодировку, которая не имеет проблем с нечетными значениями символов, например (новая строка) 0x0A
или (нулевой байт) 0x00
. И тем и другим довольно сложно правильно управлять с помощью инструментов, разработанных и адаптированных для обработки «текстовых файлов».
Преобразование, подобное base64, может показаться допустимым, но оно представляет проблему, заключающуюся в том, что каждый входной байт может иметь до трех выходных представлений в зависимости от того, является ли он первым, вторым или третьим байтом позиции mod 24 (биты).
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Вот почему наиболее надежным преобразованием должно быть преобразование, которое начинается на границе каждого байта, как в простом HEX-представлении.
Мы можем получить файл с шестнадцатеричным представлением файла любым из следующих инструментов:
$ od -vAn -tx1 infile.bin | tr -d '\n' > infile.hex
$ hexdump -v -e '/1 "%02x "' infile.bin > infile.hex
$ xxd -c1 -p infile.bin | tr '\n' ' ' > infile.hex
Последовательность байтов для поиска в данном случае уже шестнадцатеричная.
:
$ var="ef be ad de"
Но это также может быть преобразовано. Пример передачи шестнадцатеричного-двоичного-шестнадцатеричного цикла туда и обратно:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
Строка поиска может быть установлена из двоичного представления. Любой из трех представленных выше вариантов od, hexdump или xxd эквивалентен. Просто убедитесь, что вы включили пробелы, чтобы обеспечить совпадение на границах байтов (сдвиг на полубайты не разрешен):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Если двоичный файл выглядит следующим образом:
$ cat infile.bin | xxd
00000000: 5468 6973 2069 7320 efbe adde 2061 2074 This is .... a t
00000010: 6573 7420 0aef bead de0a 6f66 2069 6e70 est ......of inp
00000020: 7574 200a dead beef 0a66 726f 6d20 6120 ut ......from a
00000030: 6269 0a6e 6172 7920 6669 6c65 2e0a 3131 bi.nary file..11
00000040: 3232 3131 3232 3131 3232 3131 3232 3131 2211221122112211
00000050: 3232 3131 3232 3131 3232 3131 3232 3131 2211221122112211
00000060: 3232 0a
Затем простой поиск с помощью grep выдаст список совпадающих последовательностей:
$ grep -o "$a" infile.hex | wc -l
2
Все это можно выполнить в одной строке:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Например, для поиска 11221122
в том же файле потребуются следующие два шага:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
Чтобы "увидеть" совпадения:
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232
$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
… 0a 3131323231313232313132323131323231313232313132323131323231313232 313132320a
Есть опасения, что grep будет буферизовать весь файл, и, если файл большой, создаст большой . Для этого мы можем использовать небуферизованное решение sed:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -ue 's/\('"$a"'\)/\n\1\n/g' |
sed -n '/^'"$a"'$/p' |
wc -l
Первый sed не буферизован ( -u
) и используется только для вставки двух новых строк в поток для каждой соответствующей строки. Второй sed
будет печатать только (короткие) совпадающие строки. Wc -l подсчитает совпадающие строки.
Это приведет к буферизации только некоторых коротких строк. Соответствующая строка (строки) во втором sed. Это должно быть довольно мало используемых ресурсов.
Или, что несколько сложнее для понимания, но та же идея в одном sed:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
wc -l
PERLIO=:raw perl -nE '$c++ while m/\xef\xbe\xad\xde/g; END{say $c}' file
Который рассматривает входной файл(ы) как двоичный (без перевода для linefeeds или кодировок, см. perlrun), затем циклирует входной файл(ы), не печатая приращение счетчика для всех совпадений заданного шестигранника (или любой другой формы, см. perlre).
Самый простой перевод, который я вижу:
$ echo $'\xef\xbe\xad\xde' > hugohex
$ echo $'\xef\xbe\xad\xde\xef\xbe\xad\xde' >> hugohex
$ grep -F -a -o -e $'\xef\xbe\xad\xde' hugohex|wc -l
3
Где я использовал $ '\ xef'
как bash-цитирование ANSI (первоначально ksh93
, теперь поддерживается zsh
, bash
, mksh
, FreeBSD sh
) версией Fish \ Xef
и использовал grep -o ... | wc -l
для подсчета экземпляров. grep -o
выводит каждое совпадение в отдельной строке. Флаг -a
заставляет grep вести себя с двоичными файлами так же, как с текстовыми файлами. -F
предназначен для фиксированных строк, поэтому вам не нужно экранировать операторы регулярных выражений.
Как и в случае с fish
, вы не можете использовать этот подход, хотя если последовательность, которую нужно искать, включает байты 0 или 0xa (новая строка в ASCII).
С флагом GNU grep
-P
(perl-regexp)
LC_ALL=C grep -oaP '\xef\xbe\xad\xde' file | wc -l
LC_ALL = C
, чтобы избежать проблем в многобайтовых локали, где grep
в противном случае попытался бы интерпретировать последовательности байтов как символы.
-a
обрабатывает двоичные файлы, эквивалентные текстовым файлам (вместо обычного поведения, когда grep
только выводит, есть ли хотя бы одно совпадение или нет)
Вы можете использовать метод Python bytes.count
, чтобы получить общее количество неперекрывающихся подстрок в байтовой строке.
python -c "print(open('./myexecutable', 'rb').read().count(b'\xef\xbe\xad\xde'))"
Этот однострочный файл загружает в память весь файл, поэтому он не самый эффективный, но работает и более разборчив, чем Perl; D
tr "$(printf \\0xef)\n" \\n\\0 < infile |
grep -c "^$(printf "\0xbe\0xad\0xde")"
С помощью GNU awk
вы можете:
LC_ALL=C awk -v 'RS=\xef\xbe\xad\xde' 'END{print NR - (NR && RT == "")}'
Если какой-либо из байтов является операторами ERE, их нужно экранировать (с помощью \\
). Как 0x2e
, то есть .
необходимо ввести как \\.
или \ x2e
. Помимо этого, он должен работать с произвольными байтовыми значениями, включая 0 и 0xa.
Обратите внимание, что это не так просто, как просто NR-1
, потому что есть несколько особых случаев:
RT == ""
. Также обратите внимание, что в худшем случае (если файл не содержит поискового запроса) файл будет загружен в память целиком).
Я думаю, вы можете использовать Perl, попробуйте:
perl -0777ne 'CORE::say STDOUT s/\xef\xbe\xad\xde//g' file_name
Команда замены s
дает количество сделанных замен, -0777 означает не рассматривать новую строку как специальный символ,e
-выполнить команду, say
напечатать то, что идет дальше, затем напечатать символ новой строки, n
Не до конца разобрался, но без -из документации не работает:
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed -n or awk: LINE: while (<>) { ... # your program goes here }