#!/usr/bin/perl -w use strict; # This file clumsily extracts the DB's hidden in the iPhone backup files # Usage: perl -w bkupextract.pl /Users/flip/Library/Application\ Support/MobileSync/Backup/*/* # Added support for decoding photo files to Mr. Flip's original script # Tom Saxton, http://www.idleloop.com/ my %seen; foreach my $filename (@ARGV) { # Slurp File Contents open(FILE, "<$filename") or die "Can't open $filename: $!"; my $data = do {local $/; binmode FILE; }; close(FILE); # skip non-SQLite Files my $outfilename; my $type; my $dataOut = $data; # identify the file and use it to name the output and trim the data if ($data =~ m|SQLite|) { my $type = ($data =~ m!([^/]*?)\.(sqlitedb|db)!) ? $1 : 'unknown'; $seen{$type}++; my $outfilename = sprintf "%s_%02d.db", $type, $seen{$type}; # dump the part between "SQLite format 3" and end # FIXME -- is there cruft at end? I don't know the SQLite format. Maybe you do? $dataOut =~ s/^(.*?SQLite format 3)/SQLite format 3/; } elsif ($data =~ m|JFIF|) { $type = 'jpeg'; # This is a kludge: I just look for the three bytes that start the header for the two embedded images # but those three bytes could appear with the data stream not at a record boundary. # The right way to do it is to parse the records, but this was good enough to recover my lost photos. $dataOut =~ /(\xff\xd8....JFIF.+)(\xff\xdb\x00.+)(\xff\xdb\x00.+)/s or die "can't find JFIF bits" or die 'can\'t parse JPEG file'; $dataOut = $1 . $3; $outfilename = $data =~ m|DCIM/100APPLE/(.*\.JPG)| ? $1 : "unknown.jpg"; } else { $type = "unknown"; $outfilename = "unknown.foo"; } # Helpful progress report printf STDERR "%-60s (%s) to %-25s\n", $filename, $type, $outfilename; open(OUTFILE, ">$outfilename") or die "Can't open $outfilename: $!"; binmode OUTFILE; print OUTFILE $dataOut; close(OUTFILE); }