Skip to content

Instantly share code, notes, and snippets.

@anthonyclays
Created April 19, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anthonyclays/97c743fba9c58d3c3599 to your computer and use it in GitHub Desktop.
Save anthonyclays/97c743fba9c58d3c3599 to your computer and use it in GitHub Desktop.
#!/usr/bin/env julia
using CRC
# crc computing function
const handler = crc(CRC_32)
# offsets of IDAT chunks (points to 'I' byte)
const offsets = [114,131197,262278,393361,524445,655526,786609,917691,1048775,1179858,1188429]
# correct crcs. No 0x0a in those so we can assume they're correct ;)
const crcs = [0xf55a745d, 0x06e15ebf, 0xa0bdc18a, 0xadefb326, 0x09c557f7,
0x0848d2c4, 0x295c44c9, 0xa4afc965, 0x2fad0fb3, 0x7ec18f9e,]
# Number of missing bytes / chunk
const missing_bytes = [1, 3, 1, 0, 3, 1, 2, 0, 1, 0,]
# bytes I don't care about
const start_bytes = [0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,0x00,0x00,0x03,0xc0,0x00,0x00,0x02,0x58,0x08,0x02,0x00,0x00,0x00,0x22,0xf6,0x18,0x56,0x00,0x00,0x00,0x03,0x73,0x42,0x49,0x54,0x08,0x08,0x08,0xdb,0xe1,0x4f,0xe0,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x15,0xfd,0x00,0x00,0x15,0xfd,0x01,0xcd,0x70,0x51,0x61,0x00,0x00,0x00,0x1c,0x74,0x45,0x58,0x74,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x00,0x41,0x64,0x6f,0x62,0x65,0x20,0x46,0x69,0x72,0x65,0x77,0x6f,0x72,0x6b,0x73,0x20,0x43,0x53,0x36,0xe8,0xbc,0xb2,0x8c,] # already fixed
const end_bytes = [0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,]
function handle_chunk(chunk, checksum, missing, starti=1)
if missing == 0
checksum_correct = (handler(chunk) == checksum)
checksum_correct && println("Found matching checksum!")
return checksum_correct, chunk
end
found, i = find_next_0a(chunk, starti)
while found
# insert 0x0d
insert!(chunk, i, 0x0d)
is_correct, chunk = handle_chunk(chunk, checksum, missing-1, i+2) # skip 0x0d0a
if is_correct
print("Found location of 0x0d #$missing: at $i, around (")
show(chunk[i-4:i+4])
println(')')
# chunk found, return
return true, chunk
end
# delete 0x0d
chunk = copy(chunk)
deleteat!(chunk, i)
found, i = find_next_0a(chunk, i+1) # skip current 0x0a
end # while found
# nothing found, return
false, chunk
end
function main()
# read chunks
bs = open(readbytes, "Downloads/corrupt.png")
chunks = Vector{Uint8}[]
for i in 1:10
chunk = bs[offsets[i]:offsets[i+1]-9]
push!(chunks, chunk)
end
# fix chunks
for (chunki, chunk) in enumerate(chunks)
println("Fixing chunk $(chunki)...")
is_correct, chunk = handle_chunk(chunk, crcs[chunki], missing_bytes[chunki], 1)
@assert is_correct
println(length(chunk))
chunks[chunki] = chunk
end
# write chunks
write_to_file(chunks)
end
# utils
function find_next_0a(bs, i)
while i <= length(bs)
bs[i] == 0x0a && return (true, i)
i += 1
end
(false, i) # not found
end
function write_to_file(chunks)
f = open("Downloads/corrupt_fixed.png", "w")
map(b -> write(f, b), start_bytes)
for (chunki, chunk) in enumerate(chunks)
# write chunk length
chunklength = (chunki == 10) ? [0x00, 0x00, 0x21, 0x6f] : [0x00, 0x02, 0x00, 0x00]
map(b -> write(f, b), chunklength)
# Write chunk type and chunk data
map(b -> write(f, b), chunk)
# write checksum
map(b -> write(f, b), ntoh(crcs[chunki])) # ntoh to change endianness
end
map(b -> write(f, b), end_bytes)
flush(f)
close(f)
end
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment