From: Adam Shelly Date: 2008-01-31T04:39:21+09:00 Subject: Re: Newbie: working with binary files/extract png from a binary file On 1/30/08, Joel VanderWerf wrote: > Jim wrote: > > Hello, > > > > I am reverse engineering a binary file that has an embedded PNG image > > in it. I opened the file in a hex editor and found the png header > > information, but how to use Ruby to extract the PNG to it's own file? > > Do you know the absolute starting position of the embedded PNG? You can find it: fp = File.new("has_embedded_png.dat","rb") m= /\211PNG/.match(fp.read) raise "no PNG" if !m fp.seek(m.begin(0)) > > If the end_pos has to be determined by reading a field, then this will > take a little tinkering. I assume PNG has a length field somewhere? So > you'll have to extract that (using String#unpack, perhaps) and chop off > that many bytes from the start of the png_data string. > There's no total length field, just a series of 'chunks' each with its own length. Luckily, the 'IEND' chunk is always last, so you can just extract chunks until you get to that one: def extract_chunk(input, output) lenword = input.read(4) length = lenword.unpack('N')[0] type = input.read(4) data = length>0 ? input.read(length) : "" crc = input.read(4) return nil if length<0 || !(('A'..'z')===type[0,1]) #return nil if validate_crc(type+data, crc) output.write lenword output.write type output.write data output.write crc return type end def extract_png(input, output) hdr = input.read(8) raise "Not a PNG File" if hdr[0,4]!= "\211PNG" raise "file not in binary mode" if hdr[4,4]!="\r\n\032\n" output.write(hdr) loop do chunk_type = extract_chunk(input,output) p chunk_type break if chunk_type.nil? || chunk_type == 'IEND' end end ofp = File.new("out.png","wb") extract_png(fp,ofp) -Adam