Editando fluxos binários contendo bytes '\ x00'

8

Usando apenas ferramentas shell, como um fluxo binário contendo NULLs (caracteres 0x00) pode ser editado, mantendo os caracteres 0x00 no fluxo de saída?

A edição precisa substituir um caractere em uma posição especificada por outro caractere (no exemplo a seguir, pelo caractere '|'), como:

dd ibs=1 skip=$offset count=$reglen status=none if=$ARQ |
        sed 's/./\|/2' |
        sed 's/./\|/5' #| more replacements....

Mas o sed está removendo todos os caracteres '\ 0x00' antes da substituição.

EDIT - Demonstração de comportamento sed no meu ambiente usando o teste @George Vasiliou:

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | od -t x1
0000000 6c 69 6e 65 41 00 6c 69 6e 65 42 00 6c 69 6e 65
0000020 43 00
0000022

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | sed 's/./|/5' | od -t x1
0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43
0000017

Meu ambiente é um AIX 7.1 e o sed que existe não é a versão gnu.

Luciano
fonte

Respostas:

10

sedé um utilitário de texto . Funciona com linhas de texto (sequências de caracteres não NUL (não bytes) de comprimento limitado, delimitadas por um caractere de nova linha).

Se você deseja alterar o e o byte de uma sequência de bytes, ele não funcionará por vários motivos:

  • sedtrabalha em texto. Se a entrada contiver caracteres NUL, não terminar em um caractere de nova linha, tiver mais de LINE_MAX bytes entre dois caracteres de nova linha, conter seqüências de bytes que não formam caracteres válidos, dependendo da sedimplementação, não funcionará em todos. (observe que o GNU sednão possui muitas dessas limitações).
  • mesmo que essa entrada binária forme um texto válido, .corresponda a caracteres, não a bytes, portanto, pode corresponder a mais de um byte.
  • porque o código sed é executado para todas as linhas da entrada, isso mudaria o segundo e o quinto caractere de cada linha, não a entrada inteira.

Para tratar a entrada como matrizes arbitrárias de bytes (sem a limitação de bytes NUL ou limitações de comprimento), convém usar perl:

 dd.... | perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}'

Exemplo:

$ printf 'a\0b\0cd' |
>   perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' |
>   od -Ax -tx1 -tc
000000  61  7c  62  00  7c  64
         a   |   b  \0   |   d
000006

Ou você pode usar uma representação de texto intermediária, como vimo xxdassistente de:

dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r

xxd -pfornece um despejo hexadecimal com 60 caracteres por linha por padrão. Acima, estamos substituindo o segundo e o quinto hexágono de 2 dígitos da primeira linha por 7c, o número para ASCII |.

Stéphane Chazelas
fonte
Obrigado. Eu estava criando uma solução alternativa usando o xxd. Ótimo ! Ambas as soluções funcionaram no AIX.
Luciano
1

Você tem certeza ? com um teste simples, isso não parece acontecer no meu caso (gnu sed 4.2.2)

$ echo -e "lineA\nlineB\nlineC"
lineA
lineB
lineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0'
lineAlineBlineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5'
line|lineBlineC
# Verification if the nulls are still there:
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5' |tr '\0' '\n'                                                                                                
line|
lineB
lineC

Com mais testes, o nulo será perdido se você substituir o sexto caractere em meus testes (posição nula):

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/6' |tr '\0' '\n'
lineA|lineB 
lineC

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/7' |tr '\0' '\n'
lineA
|ineB           
lineC 
George Vasiliou
fonte
@Luciano See update
George Vasiliou
Veja minha edição
Luciano
@Luciano, eu também tentei com sed --posix que acc aos meus desativa manuais todas as extensões GNU, mas ainda bytes nulos estão presentes ....
George Vasiliou
Eu tentei sed no Linux, e sim parece estar funcionando. Mas preciso fazê-lo funcionar no AIX.
Luciano
1
@ Luciano, claro, eu posso entender isso ... Infelizmente não tenho o AIX para ajudá-lo, e até onde eu sei, parece que não há AIX Shells on-line para brincar ... Tenho certeza que a resposta de O Sr. Chazelas irá ajudá-lo.
George Vasiliou
0

Tente bbe - sed clone para fluxos binários: https://sourceforge.net/projects/bbe/

user280267
fonte
Você poderia adicionar alguns detalhes de suporte, como como o usuário em seu ambiente AIX pode usá-lo? Além disso, nota que a questão diz "Usar apenas ferramentas de shell", para que eles possam ser impedidos de compilação / instalação de ferramentas adicionais,
Jeff Schaller
Tem certeza de que está vinculando à ferramenta certa? Seu link foi para um projeto "Criptografia baseada em bloco, também conhecido como 2Bx4Bx2B", atualizado pela última vez em 2013
Ale