Skip to content

Instantly share code, notes, and snippets.

@nikotan
Forked from sugyan/dbfile.pl
Created April 22, 2011 12:00
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 nikotan/936522 to your computer and use it in GitHub Desktop.
Save nikotan/936522 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
use strict;
use warnings;
use File::HomeDir;
use Path::Class qw(dir);
use DBI;
my $home = File::HomeDir->my_home;
my @dirs = sort {
$b->stat->mtime <=> $a->stat->mtime
} dir("$home/Library/Application Support/MobileSync/Backup")->children;
my $dir = $dirs[0];
if( index($dirs[0]->stringify, '.') >= 0 ){
$dir = $dirs[1];
}
my $mbdb = process_mbdb_file($dir->file('Manifest.mbdb'));
my $mbdx = process_mbdx_file($dir->file('Manifest.mbdx'));
my $dbfile;
for my $key (keys %{ $mbdb }) {
$dbfile = $dir->file($mbdx->{$mbdb->{$key}{start_offset}})->stringify;
}
die unless $dbfile;
print "dbfile: $dbfile\n";
my $dbh = DBI->connect("dbi:SQLite:dbname=".$dbfile);
my $sql =
"select datetime(strftime('%s',datetime('2001-01-01'))+round(Timestamp),'unixepoch','localtime'),".
"MAC,Latitude,Longitude from WifiLocation order by Timestamp desc limit 1000;";
my $sth = $dbh->prepare($sql);
$sth->execute;
while(my @row = $sth->fetchrow_array){
print $row[0]."|".$row[1]."|".$row[2]."|".$row[3]."\n";
}
$dbh->disconnect;
sub process_mbdb_file {
my ($mbdb) = @_;
my $fh = $mbdb->openr;
$fh->binmode;
my $buffer;
$fh->read($buffer, 4);
die if $buffer ne 'mbdb';
$fh->read($buffer, 2);
my $offset = 6;
my $data = +{};
while ($offset < $mbdb->stat->size) {
my $fileinfo = +{};
$fileinfo->{start_offset} = $offset;
$fileinfo->{domain} = getstring($fh, \$offset);
$fileinfo->{filename} = getstring($fh, \$offset);
$fileinfo->{linktarget} = getstring($fh, \$offset);
$fileinfo->{datahash} = getstring($fh, \$offset);
$fileinfo->{unknown1} = getstring($fh, \$offset);
$fileinfo->{mode} = getint($fh, 2, \$offset);
$fileinfo->{unknown2} = getint($fh, 4, \$offset);
$fileinfo->{unknown3} = getint($fh, 4, \$offset);
$fileinfo->{userid} = getint($fh, 4, \$offset);
$fileinfo->{groupid} = getint($fh, 4, \$offset);
$fileinfo->{mtime} = getint($fh, 4, \$offset);
$fileinfo->{atime} = getint($fh, 4, \$offset);
$fileinfo->{ctime} = getint($fh, 4, \$offset);
$fileinfo->{filelen} = getint($fh, 8, \$offset);
$fileinfo->{flag} = getint($fh, 1, \$offset);
$fileinfo->{numprops} = getint($fh, 1, \$offset);
$fileinfo->{properties} = +{};
for (1 .. $fileinfo->{numprops}) {
my $key = getstring($fh, \$offset);
my $value = getstring($fh, \$offset);
$fileinfo->{properties}{$key} = $value;
}
# 必要なのはこれが含まれているものだけ
if ($fileinfo->{filename} eq 'Library/Caches/locationd/consolidated.db') {
$data->{$fileinfo->{start_offset}} = $fileinfo;
}
};
return $data;
}
sub process_mbdx_file {
my ($mbdx) = @_;
my $fh = $mbdx->openr;
$fh->binmode;
my $buffer;
$fh->read($buffer, 4);
die if $buffer ne 'mbdx';
$fh->read($buffer, 2);
my $offset = 6;
my $filecount = getint($fh, 4, \$offset);
my $data = +{};
while ($offset < $mbdx->stat->size) {
$fh->read($buffer, 20);
$offset += 20;
my $file_id = unpack("H*", $buffer);
my $mbdb_offset = getint($fh, 4, \$offset);
my $mode = getint($fh, 2, \$offset);
$data->{$mbdb_offset + 6} = $file_id;
}
return $data;
}
sub getint {
my ($fh, $size, $offset) = @_;
$fh->read(my $buffer, $size);
$$offset += $size;
return oct('0x' . unpack("H*", $buffer));
}
sub getstring {
my ($fh, $offset) = @_;
my $buffer;
$fh->read($buffer, 2);
$$offset += 2;
my $unpacked = unpack('H*', $buffer);
return '' if $unpacked eq 'ffff';
my $length = oct("0x${unpacked}");
$fh->read($buffer, $length);
$$offset += $length;
return $buffer;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment