바이너리 파일에서 null로 끝나는 문자열을 읽는 방법

바이너리 파일에서 null로 끝나는 문자열을 읽는 방법

FF값으로 가득 찬 이진 파일이 있습니다 . 초반에 많이 채워놨어요 \000. 그런 다음 \000일종의 오프셋을 얻기 위해 시작 부분을 10으로 채운 다음 더 짧은 문자열을 썼습니다.\000

나는 이것을 사용했습니다 printf:

printf \000\000\000\000\000\000\000\000\000\000MAC_ADDRESS=12:34:56:78:90,PCB_MAIN_ID=m/SF-1V/MAIN/0.0,PCB_PIGGY1_ID=n/SF-1V/PS/0.0,CSL_HW_VARIANT=D\000' > eeprom

파일의 16진수 덤프를 표시하면 다음과 같습니다.

여기에 이미지 설명을 입력하세요.

이제 이 문자열을 읽는 방법을 알고 싶습니다. MY_STR=${eeprom:OFFSET}( 는 파일 이름)을 사용할 수 eeprom있으며 문자열뿐만 아니라 내가 원하지 않는 나머지 파일도 제공합니다. 처음 발견되면 어떻게 중지합니까 \000?

  • MY_STR=${eeprom:OFFSET:LENGTH}문자열의 길이를 알 수 없으므로 사용할 수 없습니다 .
  • 또 다른 사항 - 어떻게 다시 채울 수 있나요 FF?
  • 사용 sh(비지박스)

편집하다

input몇 가지 작은 예를 만들려고 합니다... 다음 값을 가진 파일이 있습니다 (뒤에 xxd -c 1 input):

0000000: 68  h
0000001: 65  e
0000002: 6c  l
0000003: 6c  l
0000004: 6f  o
0000005: 2c  ,
0000006: 20
0000007: 00  .
0000008: 69  i
0000009: 74  t
000000a: 27  '
000000b: 73  s
000000c: 20
000000d: 6d  m
000000e: 65  e
000000f: 2c  ,
0000010: 00  .

이 스크립트가 있습니다 s.sh.

BUF=""
for c in $(xxd -p input); do
    if [ "${c}" != 00 ]; then
        BUF="$BUFc";
    else
        break;
    fi
done

echo $BUF

"hello"가 울릴 것으로 예상했지만 아무것도 인쇄되지 않습니다.

답변1

옵션 1: 직접 변수 할당

걱정되는 것이 널 바이트뿐이라면 선호하는 표준 방법을 사용하여 파일의 데이터를 변수로 직접 읽을 수 있어야 합니다. 즉, 널 바이트를 무시하고 파일에서 데이터를 읽을 수 있어야 합니다. . 다음은 cat명령 및 명령 대체를 사용하는 예 입니다 .

$ data="$(cat eeprom)"
$ echo "${data}"
MAC_ADDRESS=12:34:56:78:90,PCB_MAIN_ID=m/SF-1V/MAIN/0.0,PCB_PIGGY1_ID=n/SF-1V/PS/0.0,CSL_HW_VARIANT=D

이것은 BusyBox Docker 컨테이너에서 저에게 효과적이었습니다.

해결 방법 2: xxdand for루프 사용

더 많은 제어를 원할 경우 xxd바이트를 16진수 문자열로 변환을 사용하고 해당 문자열을 반복할 수 있습니다. 그런 다음 이러한 문자열을 반복할 때 원하는 논리를 적용할 수 있습니다. 예를 들어 초기 null 값을 명시적으로 건너뛰고 일부 중단 조건에 도달할 때까지 나머지 데이터를 인쇄할 수 있습니다.

다음 스크립트는 유효한 문자(ASCII 32~127)의 "허용 목록"을 지정하고, 다른 문자의 하위 시퀀스를 구분 기호로 처리하고, 유효한 하위 문자열을 모두 추출합니다.

#!/bin/sh
# get_hex_substrings.sh

# Get the path to the data-file as a command-line argument
datafile="$1"

# Keep track of state using environment variables
inside_padding_block="true"
inside_bad_block="false"

# NOTE: The '-p' flag is for "plain" output (no additional formatting)
# and the '-c 1' option specifies that the representation of each byte
# will be printed on a separate line
for h in $(xxd -p -c 1 "${datafile}"); do

    # Convert the hex character to standard decimal
    d="$((0x${h}))"

    # Case where we're still inside the initial padding block
    if [ "${inside_padding_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_padding_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're passed the initial padding, but inside another
    # block of non-printable characters
    elif [ "${inside_bad_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_bad_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're inside of a substring that we want to extract
    else
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            printf '\x'"${h}";
        else
            inside_bad_block="true";
            echo
        fi
    fi
done

if [ "${inside_bad_block}" == "false" ]; then
    echo
fi

\x00이제 하위 문자열을 구분하는 하위 시퀀스 합계를 사용하여 샘플 파일을 생성하여 이를 테스트할 수 있습니다 \xff.

printf '\x00\x00\x00string1\xff\xff\xffstring2\x00\x00\x00string3\x00\x00\x00' > data.hex

다음은 스크립트를 실행할 때 얻는 출력입니다.

$ sh get_hex_substrings.sh data.hex
string1
string2
string3

해결 방법 3: trcut명령 사용

널 바이트를 처리하기 위해 tr및 명령을 사용해 볼 수도 있습니다 . cut다음은 인접한 널 문자를 압착/접고 이를 개행 문자로 변환하여 널 종료 문자열 목록에서 첫 번째 널 종료 문자열을 추출하는 예입니다.

$ printf '\000\000\000string1\000\000\000string2\000\000\000string3\000\000\000' > file.dat
$ tr -s '\000' '\n' < file.dat | cut -d$'\n' -f2
string1

관련 정보