Grep

如何使用萬用字元 grep 十六進制模式?

  • September 21, 2021

我正在嘗試在文件中查找十六進制模式的偏移量。這適用於一個特定的值:

$ grep -obUaP -m1 "\x00\x50\x53\x46\x01\x01\x00\x00\x34\x01\x00\x00" file.bin
3088:PSF4

但是,此模式包含一些會更改的字節,因此我需要在我的 grep 中包含萬用字元。我不知道該怎麼做。到目前為止,這是我嘗試過的所有內容:

  • \x.., \x., ..,我能想到的每一個相似的形式都不匹配
  • \x[0-9][0-9]不匹配
  • \x.*不匹配
  • just .*(ie., \x00.*\x01)確實匹配,但它是貪婪的並且比模式匹配更多

可能忽略了一些愚蠢的事情,但我在這裡撞到了一堵牆。

如何在十六進制中指定萬用字元,或者至少在使用 grep 和 perl-regex 搜尋十六進制時如何?

grep -P '\xAB'不尋找十六進製字元。沒有像十六進製字元這樣的東西。\xAB是 PCRE語法,用於匹配以十六進製表示的程式碼點值為 0xAB(十進制為 171)的字元。

這裡的程式碼點是使用 UTF-8 的語言環境中的Unicode程式碼點和使用單字節字元集的語言環境中的字節值(GNUgrep -P不支持 UTF-8 以外的多字節字元集)。

因此\xAB將匹配 UTF-8 語言環境中的 U+00AB 字元 («)(該字元在 2 個字節上編碼:0xc2 和 0xab)和單字節語言環境中的 0xAB 字節(例如,它Ћ表示使用 iso8859-5 字元集的語言環境)。

如果你想匹配字節值,你應該確保語言環境使用單字節字元集,C語言環境可能是你最好的選擇。

LC_ALL=C grep -P '\xAB'

匹配 0xAB (171) 字節,無論它在任何字元集中表示什麼字元。

同樣,要匹配任何單個字節,您可以使用.(假設 C 語言環境或任何每個字元集單個字節的本地)。

要匹配一個範圍內的字節值,正如@Angle115 已經說過的那樣:([\x01-\x45]這裡是字節值 1 到 0x45 / 69)

但請記住,grep匹配文本行¹ 的**內容,因此它永遠不會找到作為行分隔符的換行符,並且無論語言環境如何,始終具有值 0x0A²(十進制為 10)。

因此LC_ALL=C grep -P '\x23.\xab'將匹配 3 個字節的序列,第一個字節的值為 0x23,第二個字節的值為除 0xA 之外的任何值,第三個字節的值為 0xAB。

為了能夠搜尋具有任意值(包括 0xA)的字節,您需要將整個輸入視為一個整體,而不是像這樣一次處理一行或以 nul 分隔的記錄grep

為此,您可以將pcregrep-M(multiline) 選項與(?s)標誌一起使用(換行不被 特殊處理.)或perl與它的 slurp 模式一起使用:

LC_ALL=C pcregrep --file-offsets -Ma '(?s)\x23.\xab' < file

pcregrep沒有-b選項,--file-offsets列印偏移量和長度可能是最接近的)。

perl -l -0777 -ne 'print "$-[0]:$_" while /\x23.\xab/gs' < file

或者:

perl -l -0777 -ne 'print $-[0] if /\x23.\xab/s' < file

只列印第一個匹配的字節偏移量。

perl將整個文件載入到記憶體中,pcregrep但內部限制可能會阻止您處理 0xA 字節相距很遠的文件。


¹ 或 NUL 分隔的記錄與--null/-z

¹ 在基於 ASCII 的系統上。我什至不知道 libpcre 是否曾經移植到 EBCDIC 系統,我懷疑現在很多人會遇到其中的一些。

引用自:https://unix.stackexchange.com/questions/669359