นี่คือโซลูชันแบบหนึ่งซับขอ (สำหรับเชลล์ล่าสุดที่มี "การทดแทนกระบวนการ"):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
หากไม่มี "การทดแทนกระบวนการ" <(…)
ให้ใช้ grep เป็นตัวกรอง:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
ด้านล่างนี้เป็นคำอธิบายโดยละเอียดของแต่ละส่วนของโซลูชัน
ค่าไบต์จากตัวเลขฐานสิบหก:
ปัญหาแรกของคุณแก้ไขได้ง่าย:
ลำดับการหลบหนี \ Xnn เหล่านั้นใช้ได้เฉพาะในเปลือกปลา
เปลี่ยนด้านบน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
หรือ (null 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"
แต่มันสามารถเปลี่ยนได้ ตัวอย่างของ hex-bin-hex ไปกลับดังนี้:
$ 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 313132323131323231313232313132323131323231313232313132323131323231313232 313132320a
บัฟเฟอร์
มีข้อกังวลว่า grep จะบัฟเฟอร์ไฟล์ทั้งหมดและถ้าไฟล์มีขนาดใหญ่ให้สร้างภาระหนักสำหรับคอมพิวเตอร์ สำหรับสิ่งนั้นเราอาจใช้วิธีการแก้ปัญหาแบบไม่บุบสลาย:
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
grep -o