Jest to wymagane rozwiązanie jednowierszowe (dla najnowszych powłok, które mają „podstawianie procesów”):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Jeśli nie <(…)
jest dostępne „podstawienie procesu” , użyj grep jako filtru:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Poniżej znajduje się szczegółowy opis każdej części rozwiązania.
Wartości bajtów z liczb szesnastkowych:
Twój pierwszy problem jest łatwy do rozwiązania:
Te sekwencje specjalne \ Xnn działają tylko w skorupkach ryb.
Zmień górną X
na dolną x
i użyj printf (dla większości powłok):
$ printf -- '\xef\xbe\xad\xde'
Albo użyj:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Dla tych powłok, które zdecydują się nie implementować reprezentacji „\ x”.
Oczywiście, przełożenie hex na ósemkowe będzie działać na (prawie) dowolnej powłoce:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Gdzie „$ sh” jest dowolną (rozsądną) powłoką. Ale trudno jest poprawnie go podać.
Pliki binarne.
Najbardziej niezawodnym rozwiązaniem jest transformacja pliku i sekwencji bajtów (oba) na kodowanie, które nie ma problemów z nieparzystymi wartościami znaków, takimi jak (nowa linia) 0x0A
lub (bajt zerowy) 0x00
. Oba są dość trudne do prawidłowego zarządzania za pomocą narzędzi zaprojektowanych i przystosowanych do przetwarzania „plików tekstowych”.
Transformacja taka jak base64 może wydawać się poprawna, ale przedstawia problem polegający na tym, że każdy bajt wejściowy może mieć maksymalnie trzy reprezentacje wyjściowe, w zależności od tego, czy jest to pierwszy, drugi czy trzeci bajt pozycji mod 24 (bitów).
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Przekształcenie heksadecymalne.
Właśnie dlatego najbardziej niezawodną transformacją powinna być taka, która rozpoczyna się na każdej granicy bajtów, podobnie jak prosta reprezentacja HEX.
Możemy uzyskać plik z reprezentacją szesnastkową pliku za pomocą dowolnego z tych narzędzi:
$ 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
W tym przypadku sekwencja bajtów do przeszukiwania jest już szesnastkowa.
:
$ var="ef be ad de"
Ale można go również przekształcić. Oto przykład szesnastkowego pojemnika szesnastkowego w obie strony:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
Wyszukiwany ciąg może być ustawiony z reprezentacji binarnej. Każda z trzech opcji przedstawionych powyżej od, hexdump lub xxd są równoważne. Pamiętaj tylko, aby uwzględnić spacje, aby upewnić się, że dopasowanie znajduje się na granicach bajtów (niedozwolone jest przesunięcie końcówki):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Jeśli plik binarny wygląda następująco:
$ 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
Następnie proste wyszukiwanie grep wyświetli listę pasujących sekwencji:
$ grep -o "$a" infile.hex | wc -l
2
Jedna linia?
Wszystko to można wykonać w jednym wierszu:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Na przykład wyszukiwanie 11221122
w tym samym pliku wymaga dwóch następujących kroków:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
Aby „zobaczyć” dopasowania:
$ 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
Buforowanie
Istnieje obawa, że grep zbuforuje cały plik, a jeśli plik jest duży, spowoduje duże obciążenie komputera. W tym celu możemy użyć niebuforowanego rozwiązania 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
Pierwszy sed jest niebuforowany (-u
) i służy tylko do wstrzykiwania dwóch nowych wierszy do strumienia na pasujący ciąg. Drugi sed
wydrukuje tylko (krótkie) pasujące linie. Wc -l policzy pasujące linie.
Spowoduje to buforowanie tylko niektórych krótkich linii. Pasujące łańcuchy w drugim sed. Powinno to być dość niskie w wykorzystywanych zasobach.
Lub nieco bardziej skomplikowany do zrozumienia, ale ten sam pomysł w jednym sed:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
wc -l
grep -o