Altera determinados bytes em muitos arquivos

3

Eu preciso de um grande número de arquivos .png danificados para testar meu projeto. Para esse fim, eu preciso definir todos os bytes do 0x054-th para o 0xa00-th para 0.

.png arquivos contêm pedaços com checksums, eu quero alterar o pedaço de dados de imagem (IDAT) , sem atualizar a soma de verificação. Além disso, quero danificar muitos bytes, de modo que uma área visível (preta) apareça ao exibir a imagem (desde que o programa de visualização ignore a incompatibilidade de soma de verificação).

Aqui está o que eu tenho até agora:

#!/bin/sh

# This script reads all .png or .PNG files in the current folder,
# sets all bytes at offsets [0x054, 0xa00] to 0
# and overwrites the files back.

temp_file_ascii=outfile.txt
temp_file_bin=outfile.png
target_dir=.
start_bytes=0x054
stop_bytes=0xa00
len_bytes=$stop_bytes-$start_bytes

for file in $(find "$target_dir" -name "*.png")         #TODO: -name "*.PNG")
do
    # Copy first part of the file unchanged.
    xxd -p -s $start_bytes "$file" > $temp_file_ascii

    # Create some zero bytes, followed by 'a',
    # because I don't know how to add just zeroes.
    echo "$len_bytes: 41" | xxd -r >> $temp_file_ascii

    # Copy the rest of the input file.
    # ??

    mv outfile.png "$file"
done

EDIT: o script finalizado, usando a resposta aceita:

#!/bin/sh

if [ "$#" != 3 ]
then
    echo "Usage: "
    echo "break_png.sh <target_dir> <start_offset> <num_zeroed_bytes>"
    exit
fi

for file in $(find "$1" -name "*.png")
do
    dd if=/dev/zero of=$file bs=1 seek=$(($2)) count=$(($3)) conv=notrunc
done
    
por Vorac 01.03.2016 / 10:34

2 respostas

7

Você pode fazer algo muito mais simples com dd :

dd if=/dev/zero \
   of="$your_target_file" \
   bs=1 \
   seek="$((start_offset))" \
   count="$((num_zeros))" \
   conv=notrunc

Com $start_offset sendo o início do intervalo de bytes a zero (baseado em zero, como para apagar do n th byte, use n-1) e $num_zeros o comprimento desse intervalo. O $((...)) cuidará da conversão de hexadecimal em decimal.

(Outros testes que você pode executar seriam definir if a /dev/urandom em vez de /dev/zero ou substituir as somas de verificação por dados aleatórios também.)

    
por 01.03.2016 / 10:48
2

com ksh93 :

 PATH=/opt/ast/bin:$PATH find "$targetdir" -name '*.png' -type f -exec ksh93 -c '
   for file do
      head -c "$((0xa00 - 0x54 + 1))" < /dev/zero 1<> "$file" >#((0x54 - 1))
   done' ksh {} +

>#((...)) sendo o operador de pesquisa em ksh93 . Isso é relativamente eficiente, pois executa o menor número possível de ksh93 e todos os comandos são integrados.

Com versões recentes de zsh :

find "$targetdir" -name '*.png' -type f -exec zsh -c '
  zmodload zsh/system
  z=${(pl:0xa00-0x54+1::
 PATH=/opt/ast/bin:$PATH find "$targetdir" -name '*.png' -type f -exec ksh93 -c '
   for file do
      head -c "$((0xa00 - 0x54 + 1))" < /dev/zero 1<> "$file" >#((0x54 - 1))
   done' ksh {} +
:)} for file do {sysseek -u1 0x54-1 && print -rn $z} 1<> $file done' zsh {} +

Eles alteram o 0x54th para 0xa00th bytes (2477 bytes). Parece que você realmente quer mudar o 0x55th para 0xa00th embora. Se for esse o caso, basta remover os + 1 s e - 1 s nos códigos acima.

    
por 01.03.2016 / 11:31