파일에서 바이트 시퀀스가 ​​발생하는 횟수를 어떻게 계산할 수 있습니까? 하는지 알고 싶습니다 . 지금은 grep을

내가 가지고있는 파일 내에서 특정 바이트 시퀀스가 ​​몇 번 발생하는지 계산하고 싶습니다. 예를 들어, \0xdeadbeef실행 파일 내 에서 숫자 가 몇 번이나 발생 하는지 알고 싶습니다 . 지금은 grep을 사용하여 수행하고 있습니다.

#/usr/bin/fish
grep -c \Xef\Xbe\Xad\Xde my_executable_file

(내 CPU는 리틀 엔디안이기 때문에 바이트는 역순으로 기록됩니다)

그러나 접근 방식에는 두 가지 문제가 있습니다.

  • \Xnn이스케이프 시퀀스는 물고기 쉘에서 작동합니다.
  • grep은 실제로 내 마법 번호를 포함하는 줄 수를 계산합니다. 패턴이 같은 줄에서 두 번 발생하면 한 번만 계산됩니다.

이러한 문제를 해결하는 방법이 있습니까? 이 하나의 라이너를 Bash 쉘에서 실행하고 패턴이 파일 내에서 발생하는 횟수를 정확하게 계산하려면 어떻게해야합니까?



답변

이것은 요청 된 한 줄짜리 솔루션입니다 ( “프로세스 대체”가있는 최근 쉘).

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

아래는 솔루션의 각 부분에 대한 자세한 설명입니다.

16 진수의 바이트 값 :

첫 번째 문제는 해결하기 쉽습니다.

이 \ Xnn 이스케이프 시퀀스는 생선 껍질에서만 작동합니다.

상단 X을 하단으로 변경하고 xprintf (대부분의 쉘)를 사용하십시오.

$ printf -- '\xef\xbe\xad\xde'

또는 사용하십시오 :

$ /usr/bin/printf -- '\xef\xbe\xad\xde'

‘\ x’표현을 구현하지 않기로 선택한 쉘의 경우.

물론 16 진수를 8 진수로 변환하면 거의 모든 쉘에서 작동합니다.

$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'

여기서 “$ sh”는 (합리적인) 쉘입니다. 그러나 올바르게 인용하는 것은 매우 어렵습니다.

이진 파일.

가장 강력한 솔루션은 파일과 바이트 시퀀스 (둘 다)를 (new line) 0x0A또는 (null byte) 와 같은 홀수 문자 값에 문제가없는 인코딩으로 변환하는 것 0x00입니다. 둘 다 “텍스트 파일”을 처리하도록 설계된 도구를 사용하여 올바르게 관리하기가 매우 어렵습니다.

base64와 같은 변환은 유효한 것으로 보이지만 모든 입력 바이트가 mod 24 (비트) 위치의 첫 번째, 두 번째 또는 세 번째 바이트인지에 따라 최대 3 개의 출력 표현을 가질 수있는 문제를 나타냅니다.

$ echo "abc" | base64
YWJjCg==

$ echo "-abc" | base64
LWFiYwo=

$ echo "--abc" | base64
LS1hYmMK

$ echo "---abc" | base64        # Note that YWJj repeats.
LS0tYWJjCg==

16 진 변환

따라서 가장 강력한 변환은 간단한 HEX 표현과 같이 각 바이트 경계에서 시작하는 변환이어야합니다.
이 도구 중 하나를 사용하여 파일의 16 진 표현으로 파일을 얻을 수 있습니다.

$ 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

이 경우 검색 할 바이트 시퀀스는 이미 16 진입니다.
:

$ 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 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


답변

GNU grep-P(perl-regexp) 플래그로

LC_ALL=C grep -oaP '\xef\xbe\xad\xde' file | wc -l

LC_ALL=C바이트 grep순서를 문자로 해석하려고하는 멀티 바이트 로케일의 문제점을 피하는 것입니다.

-a이진 파일을 텍스트 파일과 동등한 것으로 취급합니다 (정상적인 동작 대신, grep하나 이상의 일치 여부 만 인쇄)


답변

PERLIO=:raw perl -nE '$c++ while m/\xef\xbe\xad\xde/g; END{say $c}' file

어떤 취급 이진 입력 파일 (들) (줄 바꿈 또는 인코딩 없음 번역을 참조 perlrun 다음 입력 파일 (들) 지정된 진수의 모든 일치에 대한 카운터를 증가 인쇄되지 않는 이상 루프 (또는 어떤 형태 참조) perlre를 ) .


답변

GNU awk를 사용하면 다음을 수행 할 수 있습니다.

LC_ALL=C awk -v 'RS=\xef\xbe\xad\xde' 'END{print NR - (NR && RT == "")}'

바이트 중 하나가 ERE 연산자 인 경우 (with \\) 를 통해 이스케이프해야합니다 . 마찬가지로 0x2e이는이 .로 입력해야 \\.하거나 \\\x2e. 그 외에는 0과 0xa를 포함한 임의의 바이트 값으로 작동해야합니다.

NR-1몇 가지 특별한 경우가 있기 때문에 간단하지 않습니다 .

  • 입력이 비어 있으면 NR은 0이고 NR-1은 -1을 나타냅니다.
  • 레코드 구분 기호에서 입력이 끝나면 그 후에 빈 레코드가 작성되지 않습니다. 우리는로 테스트합니다 RT=="".

또한 최악의 경우 (파일에 검색어가 포함되어 있지 않은 경우 파일이 전체 메모리에로드 됨)주의하십시오.


답변

가장 간단한 번역은 다음과 같습니다.

$ 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'는 AS ANSI는 인용 부호 bash는 (원래 ksh93기능, 지금 지원 zsh, bash, mksh, FreeBSD의 sh) 물고기의 버전 \Xef및 사용 grep -o ... | wc -l인스턴스를 계산. grep -o각 일치 항목을 별도의 줄에 출력합니다. 이 -a플래그는 grep이 텍스트 파일에서와 동일한 방식으로 이진 파일에서 작동하도록합니다. -F고정 문자열 용이므로 정규 표현식 연산자를 이스케이프 처리 할 필요가 없습니다.

귀하의 fish경우 와 마찬가지로 , 검색 할 시퀀스에 바이트 0 또는 0xa (ASCII의 줄 바꿈)가 포함되어 있으면이 방법을 사용할 수 없습니다.


답변

파이썬의 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")"