Como reverter o conteúdo do arquivo binário?


11

Eu estava resolvendo um desafio em que encontrei um arquivo de dados sem extensão. O filecomando mostra que é a data file (application/octet-stream). O hdcomando mostra o GNP. na última linha. Portanto, se eu reverter esse arquivo, obterei o arquivo no formato .PNG , procurei em todos os lugares, mas não encontrei uma solução explicando como reverter o conteúdo de um arquivo binário.

Respostas:


11

Com xxd(de vim) e tac(do GNU coreutils, também tail -rem alguns sistemas):

< file.gnp xxd -p -c1 | tac | xxd -p -r > file.png

Existe alguma maneira de combinar isso com vi.stackexchange.com/a/2237/10649 ? Eu tentei todos os tipos de combinações sem sorte :(
Iulian Onofrei

Esta não é uma solução, porque espelhará todo o arquivo.
Philippe Delteil

@ PhilippeDelteil, espelhar todo o arquivo foi o que o OP está pedindo aqui? O que mais você gostaria que fizesse?
Stéphane Chazelas 29/11/19

4

In zsh(o único shell que pode lidar internamente com dados binários (a menos que você queira considerar a abordagem de codificação base64 do ksh93 )):

zmodload zsh/mapfile
(LC_ALL=C; printf %s ${(s::Oa)mapfile[file.gnp]} > file.png)
  • LC_ALL=C: caracteres são bytes
  • $mapfile[file.gnp]: conteúdo do file.gnparquivo
  • s::: divida a sequência em seus constituintes de bytes
  • Oa: Order reverso no array subscrito nessa matriz

1
zshnão é o único shell que pode lidar com dados binários.
precisa saber é

2

Aqui está uma maneira de reverter um arquivo binário usando ksh93. Deixei o código "frouxo" para facilitar a compreensão.

#!/bin/ksh93

typeset -b byte

redirect 3< image.gpj || exit 1

eof=$(3<#((EOF)))

read -r -u 3 -N 1 byte
printf "%B" byte > image.jpg
3<#((CUR - 1))

while (( $(3<#) > 0 ))
do
    read -r -u 3 -N 1 byte
    printf "%B" byte >> image.jpg
    3<#((CUR - 2))
done

read -r -u 3 -N 1 byte
printf "%B" byte >> image.jpg

redirect 3<&- || echo 'cannot close FD 3'

exit 0

legais. Até agora, essa é a única resposta que não envolve armazenar o arquivo inteiro na memória. No entanto, é extremamente ineficiente, pois faz várias chamadas do sistema para cada byte do arquivo (e conversões de / para base64), portanto, não seria adequado para arquivos que também não cabem na memória. Na minha máquina, ele processa arquivos a cerca de 10KB / s
Stéphane Chazelas

Observe que o primeiro readacima não deve ler nada, como é feito no final do arquivo.
Stéphane Chazelas

Tentando entender por que era tão lento, tentei executá-lo stracee ksh93parece estar se comportando de maneira estranha, onde ele procura por todo o lugar no arquivo e lê grandes quantidades na época. Talvez uma variante do github.com/att/ast/issues/15
Stéphane Chazelas

@ StéphaneChazelas. Não há mistério sobre por que é relativamente lento. Dentro do loop, ele precisa procurar para trás cada vez que lê um byte. Isso pode ser facilmente reduzido significativamente por um fator de 20 ou mais, lendo e escrevendo mais de um byte por vez. O lado de gravação das coisas também pode ser otimizado. Muitas outras técnicas estão disponíveis para acelerar ainda mais as coisas. Vou deixar esse exercício com você.
precisa saber é

Experimente straceo script para ver o que quero dizer. ksh93lê os arquivos milhares de vezes. Por exemplo, antes de ler o primeiro byte, ele procura 64KiB no final do arquivo, lê 64KiB, depois procura antes do último byte e lê 1 byte e faz algo semelhante para cada byte. Observe que o que você pode fazer com essas cadeias codificadas em base64 é limitado; portanto, se você ler mais de um byte por vez, será mais difícil extrair os bytes individuais disso.
Stéphane Chazelas

2

Com perl:

perl -0777pe '$_=reverse $_'  [input_file]

Teste de performance:

dd if=/dev/urandom of=/tmp/a bs=1M count=1
LC_ALL=C tac -rs $'.\\|\n' /tmp/a > /tmp/r

time perl -0777pe '$_=reverse $_' /tmp/a         | diff -q - /tmp/r
time xxd -p -c1 /tmp/a | tac | xxd -p -r         | diff -q - /tmp/r
time perl -0777 -F -ape '$_=reverse@F' /tmp/a    | diff -q - /tmp/r
time LC_ALL=C tac -rs $'.\\|\n' /tmp/a           | diff -q - /tmp/r

Resultado:

  • Testado localmente: minha solução é a mais rápida, perl -0777 -Fa mais lenta.
  • Testado em Experimente online! : minha solução é a mais rápida, xxda mais lenta.

Nota: o tempo diffdeve ser o mesmo para todas as soluções, pois a saída deve ser a mesma.


1
Eu apaguei o meu perl. Eu não tinha percebido na época que reversepoderia reverter as cordas também, portanto, fazer essa divisão não fazia muito sentido e sua versão é muito melhor.
Stéphane Chazelas

1

Eu tentei o seguinte:

tac -rs '.' input.gnp > output.png

A idéia é forçar 'tac' usando qualquer caractere como separador. Eu tentei isso em um arquivo binário e parecia funcionar, mas qualquer confirmação seria apreciada.

A principal vantagem é que ele não carrega o arquivo na memória.


Não funciona para mim (aqui no GNU tac8.28) quando a entrada contém caracteres de nova linha. printf '1\n2' | tac -rs . | od -vAn -tcsaídas em \n 2 1vez de 2 \n 1. Você também precisaria LC_ALL=Cou .poderia corresponder a caracteres de vários bytes.
Stéphane Chazelas

4
LC_ALL=C tac -rs $'.\\|\n'parece funcionar embora.
Stéphane Chazelas
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.