Bash는 변수에 16진수 값 0x00을 저장할 수 없습니다.

Bash는 변수에 16진수 값 0x00을 저장할 수 없습니다.

dd로 몇 가지 트릭을 시도하고 있습니다. 나는 "header"라는 변수에 16진수 값을 저장하여 dd로 파이프할 수 있다고 생각했습니다.

변수가 없는 첫 번째 단계는 다음과 같습니다.

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

그 후 나는 이것을 시도했습니다 :

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

보시다시피 변수의 \x00값을 잃어버렸습니다 $header. 이 행동에 대한 설명이 있는 사람이 있나요? 이것이 나를 미치게 만든다.

답변1

Bash는 종결자를 위해 널 바이트를 예약하는 C 스타일 문자열을 사용하기 때문에 문자열에 널 바이트를 저장할 수 없습니다. 따라서 Bash가 중간에 저장할 필요 없이 null 바이트가 포함된 시퀀스를 간단히 파이프하도록 스크립트를 다시 작성해야 합니다. 예를 들어 다음과 같이 할 수 있습니다.

printf "\x36\xc9\xda\x00\xb4" | hd

그런데, 다른 많은 간단한 작업에는 echoBash를 사용할 수 있습니다 .printf

또는 링크 대신 임시 파일을 사용할 수 있습니다.

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

물론 파일이 /tmp/mysequence이미 존재할 수도 있다는 문제가 있습니다. 이제 임시 파일을 생성하고 해당 경로를 문자열로 저장해야 합니다.

또는 프로세스 대체를 사용하여 이를 방지할 수 있습니다.

hd <(printf "\x36\xc9\xda\x00\xb4")

연산자는 첫 번째 인수로 받을 <(command)파일 시스템에 명명된 파이프를 생성합니다 . 파이프를 열고 읽습니다.commandhd거의다른 파일과 같습니다. 여기에서 자세한 내용을 읽을 수 있습니다.https://unix.stackexchange.com/a/17117/136742.

답변2

zsh변수에 NUL 문자를 저장할 수 있는 유일한 셸을 사용할 수 있습니다 . 문자는 $IFSin 의 기본값 에 있는 경우도 있습니다 zsh.

nul=$'\0'

또는:

nul=$'\x0'

또는

nul=$'\u0000'

또는

nul=$(printf '\0')

그러나 인수나 환경 변수와 같은 변수는 다음 명령에 전달할 수 없습니다.처형된인수와 환경 변수는 execve()시스템 호출에 전달되는 NUL로 구분된 문자열이기 때문입니다(셸이 아닌 시스템 API의 제한 사항). 그러나 에서는 zshNUL 바이트를 함수나 내장 명령에 대한 인수로 전달할 수 있습니다.

echo $'\0' # works
/bin/echo $'\0' # doesn't

답변3

Bash는 내부적으로 C 문자열을 사용하며 널 바이트를 저장할 수 없습니다. 다음과 같이 임시 파일에 값을 저장합니다.

    zHex=$(mktemp --tmpdir "$(basename "$0")-XXXX")
    trap "rm -f ${zHex@Q}" EXIT

이제 변수 zHex에는 고유한 파일 이름이 포함됩니다. $zHex가 참조하는 파일은 수동으로 삭제할 수 있지만 어떤 이유로든 프로그램이 종료되면 자동으로 삭제됩니다.

그런 다음 변수를 다음과 같이 사용하십시오.

    echo -ne "\x36\xc9\xda\x00\xb4" > "$zHex"
    hd "$zHex"

null 바이트가 있는 값은 변수에 저장되지 않습니다. 대신 변수를 사용하여 파일 이름을 저장합니다. 다른 파일과 마찬가지로 이 파일에는 널 바이트가 포함될 수 있으며 계속해서 사용할 수 있습니다. 파일 자체는 물리적으로 디스크에 기록되지 않을 가능성이 높습니다.

트랩을 사용하면 bash는 자동으로 파일을 삭제하므로 미친 쓰레기 배열을 생성하지 않는 한 수동으로 삭제하는 것에 대해 걱정할 필요가 없습니다. 이 기술은 RAM 버퍼링으로 인해 매우 빠릅니다.

답변4

캐리지 리턴이 파일 이름의 일부일 수 있으므로 null로 끝나는 목록을 사용하는 것을 좋아합니다. 그러나 Bash는 문자열을 단순한 C 문자열로 저장하는데, 여기서 널 바이트는 문자열 종결자이므로 문자열 자체의 일부가 될 수 없기 때문에 bash에는 널 바이트가 있는 문자열을 저장할 수 없습니다.

이 문제를 해결하기 위해 각 요소 뒤에 null 바이트가 있다고 가정하는 문자열 배열을 만들었습니다. 목록 자체에는 분명히 null 바이트가 포함되어 있습니다. null 바이트가 포함된 값을 이렇게 배열로 저장하는데...

    readarray -d $'\0' zArray < <(null_terminated_list_maker)

그러면 다음과 같이 null 바이트를 사용하여 값을 재현할 수 있습니다.

    [[ "${zArray[*]}" ]] && printf '%s\0' "${zArray[@]}"

이러한 방식으로 bash 배열을 사용하여 null 바이트를 포함하는 모든 값을 저장할 수 있습니다.

목적 [[ "${zArray[*]}" ]]은 배열에 값이 있는지 확인하는 것입니다(빈 문자열은 값입니다). 이 테스트는 이와 같이 빈 배열을 printf에 전달하면 printf가 잘못된 null 바이트를 인쇄하는 문제를 해결합니다. 아무 것도 인쇄하면 안 됩니다.

완전히 임의의 데이터를 표현할 때 다음과 같은 질문이 있습니다. 입력이 실제로 null 바이트로 끝나나요? 널바이트로 종료되거나 종료되지 않을 수 있는 데이터를 처리하려면 이 메소드를 확장해야 합니다.

관련 정보