Đây là giải pháp một lớp lót được yêu cầu (đối với các shell gần đây có "thay thế quá trình"):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Nếu không có "thay thế quy trình" <(…)
, chỉ cần sử dụng grep làm bộ lọc:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Dưới đây là mô tả chi tiết của từng phần của giải pháp.
Giá trị byte từ số hex:
Vấn đề đầu tiên của bạn rất dễ giải quyết:
Các chuỗi thoát \ Xnn chỉ hoạt động trong vỏ cá.
Thay đổi phần trên X
thành phần dưới x
và sử dụng printf (đối với hầu hết các shell):
$ printf -- '\xef\xbe\xad\xde'
Hoặc dùng:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Đối với những shell đó chọn không triển khai biểu diễn '\ x'.
Tất nhiên, dịch hex sang bát phân sẽ hoạt động trên (gần như) bất kỳ shell nào:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Trong đó "$ sh" là bất kỳ vỏ (hợp lý) nào. Nhưng nó là khá khó khăn để giữ cho nó được trích dẫn chính xác.
Tệp nhị phân.
Giải pháp mạnh mẽ nhất là chuyển đổi tệp và chuỗi byte (cả hai) thành một số mã hóa không có vấn đề với các giá trị ký tự lẻ như (dòng mới) 0x0A
hoặc (byte byte) 0x00
. Cả hai đều khá khó để quản lý chính xác với các công cụ được thiết kế và điều chỉnh để xử lý "tệp văn bản".
Một phép biến đổi như base64 có vẻ hợp lệ, nhưng nó thể hiện một vấn đề là mỗi byte đầu vào có thể có tối đa ba biểu diễn đầu ra tùy thuộc vào đó là byte thứ nhất, thứ hai hay thứ ba của vị trí mod 24 (bit).
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Biến đổi hex.
Đó là lý do tại sao phép biến đổi mạnh nhất phải là một phép bắt đầu trên mỗi ranh giới byte, giống như biểu diễn HEX đơn giản.
Chúng tôi có thể nhận được một tệp có biểu diễn hex của tệp bằng bất kỳ công cụ nào trong số này:
$ 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
Chuỗi byte để tìm kiếm đã ở dạng hex trong trường hợp này.
:
$ var="ef be ad de"
Nhưng nó cũng có thể được chuyển đổi. Một ví dụ về hex-bin-hex khứ hồi sau:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
Chuỗi tìm kiếm có thể được đặt từ biểu diễn nhị phân. Bất kỳ tùy chọn nào trong ba tùy chọn được trình bày ở trên od, hexdump hoặc xxd đều tương đương. Chỉ cần đảm bảo bao gồm các khoảng trắng để đảm bảo khớp trên ranh giới byte (không cho phép dịch chuyển nibble):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Nếu tệp nhị phân trông như thế này:
$ 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
Sau đó, một tìm kiếm grep đơn giản sẽ đưa ra danh sách các chuỗi phù hợp:
$ grep -o "$a" infile.hex | wc -l
2
Một đường thẳng?
Tất cả có thể được thực hiện trong một dòng:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Ví dụ: tìm kiếm 11221122
trong cùng một tệp sẽ cần hai bước sau:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
Để "xem" các trận đấu:
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232
$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
Cẩu 0a 3131323231313232313132323131323231313232313132323131323231313232 313132320a
Bộ đệm
Có một lo ngại rằng grep sẽ đệm toàn bộ tệp và nếu tệp lớn, sẽ tạo ra tải nặng cho máy tính. Vì vậy, chúng tôi có thể sử dụng một giải pháp sed không có bộ đệm:
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 tiên không có bộ đệm ( -u
) và chỉ được sử dụng để thêm hai dòng mới trên luồng trên mỗi chuỗi khớp. Thứ hai sed
sẽ chỉ in các dòng phù hợp (ngắn). Wc -l sẽ đếm các dòng khớp.
Điều này sẽ chỉ đệm một số dòng ngắn. Chuỗi phù hợp (s) trong sed thứ hai. Điều này nên khá thấp trong tài nguyên được sử dụng.
Hoặc, hơi phức tạp hơn để hiểu, nhưng cùng một ý tưởng trong một 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