![更改许多文件中的某些字节](https://linux22.com/image/84643/%E6%9B%B4%E6%94%B9%E8%AE%B8%E5%A4%9A%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E6%9F%90%E4%BA%9B%E5%AD%97%E8%8A%82.png)
我需要大量损坏的.png
文件来测试我的项目。为此,我需要将从第 0x054 到第 0xa00 的所有字节设置为 0。
.png
文件包含带有校验和的块,我想更改图像数据块(IDAT),而不更新校验和。此外,我想损坏大量字节,以便在显示图像时出现可见(黑色)区域(假设查看程序忽略校验和不匹配)。
这是我到目前为止所得到的:
#!/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
编辑:完成的脚本,使用接受的答案:
#!/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
答案1
你可以用以下方法做一些更简单的事情dd
:
dd if=/dev/zero \
of="$your_target_file" \
bs=1 \
seek="$((start_offset))" \
count="$((num_zeros))" \
conv=notrunc
作为$start_offset
要清零的字节范围的开始(从零开始,如从第 n 个字节开始擦除,使用 n-1),以及$num_zeros
该范围的长度。将$((...))
负责将十六进制转换为十进制。
(您可以运行的其他测试是设置if
为/dev/urandom
而不是/dev/zero
,或者也用随机数据覆盖校验和。)
答案2
和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 {} +
>#((...))
是 中的查找运算符ksh93
。这是相对高效的,因为它运行尽可能少的 ksh93 并且所有命令都是内置的。
使用最新版本zsh
:
find "$targetdir" -name '*.png' -type f -exec zsh -c '
zmodload zsh/system
z=${(pl:0xa00-0x54+1::\0:)}
for file do
{sysseek -u1 0x54-1 && print -rn $z} 1<> $file
done' zsh {} +
它们将第 0x54 个字节更改为第 0xa00 个字节(2477 个字节)。看起来你实际上想将第 0x55 个更改为第 0xa00 个。如果是这种情况,只需删除上面代码中的+ 1
s 和s 即可。- 1