Exemple #1
0
        public static MBFileRecord[] ReadMBDB(string BackupPath, bool dump, bool checks)
        {
            try
            {
                MBFileRecord[] files;
                MBFileRecord   rec       = new MBFileRecord();
                byte[]         signature = new byte[6];             // buffer signature
                byte[]         buf       = new byte[26];            // buffer for .mbdx record
                StringBuilder  sb        = new StringBuilder(40);   // stringbuilder for the Key
                byte[]         data      = new byte[40];            // buffer for the fixed part of .mbdb record

                System.DateTime unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);


                // open the index
                FileStream mbdx = new FileStream(Path.Combine(BackupPath, "Manifest.mbdx"), FileMode.Open, FileAccess.Read);

                // skip signature
                mbdx.Read(signature, 0, 6);
                if (BitConverter.ToString(signature, 0) != "6D-62-64-78-02-00")     // "mbdx\2\0"
                {
                    throw new Exception("bad .mbdx file");
                }


                // open the database
                FileStream mbdb = new FileStream(Path.Combine(BackupPath, "Manifest.mbdb"), FileMode.Open, FileAccess.Read);

                // skip signature
                mbdb.Read(signature, 0, 6);
                if (BitConverter.ToString(signature, 0) != "6D-62-64-62-05-00")     // "mbdb\5\0"
                {
                    throw new Exception("bad .mbdb file");
                }

                // number of records in .mbdx
                if (mbdx.Read(buf, 0, 4) != 4)
                {
                    throw new Exception("altered .mbdx file");
                }
                int records = BigEndianBitConverter.ToInt32(buf, 0);
                files = new MBFileRecord[records];

                // loop through the records
                for (int i = 0; i < records; ++i)
                {
                    // get the fixed size .mbdx record
                    if (mbdx.Read(buf, 0, 26) != 26)
                    {
                        break;
                    }

                    // convert key to text, it's the filename in the backup directory
                    // in previous versions of iTunes, it was the file part of .mddata/.mdinfo
                    sb.Clear();
                    for (int j = 0; j < 20; ++j)
                    {
                        byte b = buf[j];
                        sb.Append(toHexLow(b >> 4));
                        sb.Append(toHexLow(b & 15));
                    }

                    rec.key    = sb.ToString();
                    rec.offset = BigEndianBitConverter.ToInt32(buf, 20);
                    rec.Mode   = BigEndianBitConverter.ToUInt16(buf, 24);


                    // read the record in the .mbdb
                    mbdb.Seek(6 + rec.offset, SeekOrigin.Begin);

                    rec.Domain     = getS(mbdb);
                    rec.Path       = getS(mbdb);
                    rec.LinkTarget = getS(mbdb);
                    rec.DataHash   = getD(mbdb);
                    rec.alwaysNA   = getD(mbdb);

                    mbdb.Read(data, 0, 40);

                    rec.data = toHex(data, 2, 4, 4, 4, 4, 4, 4, 4, 8, 1, 1);

                    //rec.ModeBis = BigEndianBitConverter.ToUInt16(data, 0);
                    rec.alwaysZero = BigEndianBitConverter.ToInt32(data, 2);
                    rec.unknown    = BigEndianBitConverter.ToInt32(data, 6);
                    rec.UserId     = BigEndianBitConverter.ToInt32(data, 10);   // or maybe GroupId (don't care...)
                    rec.GroupId    = BigEndianBitConverter.ToInt32(data, 14);   // or maybe UserId

                    rec.aTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 18));
                    rec.bTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 22));
                    rec.cTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 26));

                    rec.FileLength = BigEndianBitConverter.ToInt64(data, 30);

                    rec.flag          = data[38];
                    rec.PropertyCount = data[39];

                    rec.Properties = new MBFileRecord.Property[rec.PropertyCount];
                    for (int j = 0; j < rec.PropertyCount; ++j)
                    {
                        rec.Properties[j].Name  = getS(mbdb);
                        rec.Properties[j].Value = getD(mbdb);
                    }

                    files[i] = rec;


                    // debug print
                    if (dump)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("record {0} (mbdb offset {1})", i, rec.offset + 6);

                        Console.WriteLine("  key    {0}", rec.key);
                        Console.WriteLine("  domain {0}", rec.Domain);
                        Console.WriteLine("  path   {0}", rec.Path);
                        if (rec.LinkTarget != "n/a")
                        {
                            Console.WriteLine("  target {0}", rec.LinkTarget);
                        }
                        if (rec.DataHash != "n/a")
                        {
                            Console.WriteLine("  hash   {0}", rec.DataHash);
                        }
                        if (rec.alwaysNA != "n/a")
                        {
                            Console.WriteLine("  unk3   {0}", rec.alwaysNA);
                        }

                        string l = "?";
                        switch ((rec.Mode & 0xF000) >> 12)
                        {
                        case 0xA: l = "link"; break;

                        case 0x4: l = "dir"; break;

                        case 0x8: l = "file"; break;
                        }
                        Console.WriteLine("  mode   {1} ({0})", rec.Mode & 0xFFF, l);

                        Console.WriteLine("  time   {0}", rec.aTime);

                        // length is unsignificant if link or dir
                        if ((rec.Mode & 0xF000) == 0x8000)
                        {
                            Console.WriteLine("  length {0}", rec.FileLength);
                        }

                        Console.WriteLine("  data   {0}", rec.data);
                        for (int j = 0; j < rec.PropertyCount; ++j)
                        {
                            Console.WriteLine("  pn[{0}]  {1}", j, rec.Properties[j].Name);
                            Console.WriteLine("  pv[{0}]  {1}", j, rec.Properties[j].Value);
                        }
                    }


                    // some assertions...
                    if (checks)
                    {
                        //Debug.Assert(rec.Mode == rec.ModeBis);
                        Debug.Assert(rec.alwaysZero == 0);
                        if (rec.LinkTarget != "n/a")
                        {
                            Debug.Assert((rec.Mode & 0xF000) == 0xA000);
                        }
                        if (rec.DataHash != "n/a")
                        {
                            Debug.Assert(rec.DataHash.Length == 40);
                        }
                        Debug.Assert(rec.alwaysNA == "n/a");
                        if (rec.Domain.StartsWith("AppDomain-"))
                        {
                            Debug.Assert(rec.GroupId == 501 && rec.UserId == 501);
                        }
                        if (rec.FileLength != 0)
                        {
                            Debug.Assert((rec.Mode & 0xF000) == 0x8000);
                        }
                        if ((rec.Mode & 0xF000) == 0x8000)
                        {
                            Debug.Assert(rec.flag != 0);
                        }
                        if ((rec.Mode & 0xF000) == 0xA000)
                        {
                            Debug.Assert(rec.flag == 0 && rec.FileLength == 0);
                        }
                        if ((rec.Mode & 0xF000) == 0x4000)
                        {
                            Debug.Assert(rec.flag == 0 && rec.FileLength == 0);
                        }
                    }
                }

                return(files);
            }
            catch (Exception e)
            {
                Console.WriteLine("exception: {0}", e.Message);
            }

            return(null);
        }
Exemple #2
0
        public static List <MBFileRecord> ReadMBDB(string BackupPath)
        {
            try
            {
                List <MBFileRecord> files;
                byte[]                    signature = new byte[6];           // buffer signature
                byte[]                    buf       = new byte[26];          // buffer for .mbdx record
                StringBuilder             sb        = new StringBuilder(40); // stringbuilder for the Key
                byte[]                    data      = new byte[40];          // buffer for the fixed part of .mbdb record
                SHA1CryptoServiceProvider hasher    = new SHA1CryptoServiceProvider();

                System.DateTime unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);


                // open the database
                FileStream mbdb = new FileStream(Path.Combine(BackupPath, "Manifest.mbdb"), FileMode.Open, FileAccess.Read);

                // skip signature
                mbdb.Read(signature, 0, 6);
                if (BitConverter.ToString(signature, 0) != "6D-62-64-62-05-00")     // "mbdb\5\0"
                {
                    throw new Exception("bad .mbdb file");
                }

                files = new List <MBFileRecord>();

                // loop through the records
                for (int i = 0; mbdb.Position < mbdb.Length; ++i)
                {
                    MBFileRecord rec = new MBFileRecord();

                    rec.Domain     = getS(mbdb);
                    rec.Path       = getS(mbdb);
                    rec.LinkTarget = getS(mbdb);
                    rec.DataHash   = getD(mbdb);
                    rec.alwaysNull = getD(mbdb);

                    mbdb.Read(data, 0, 40);

                    rec.data = toHex(data, 2, 4, 4, 4, 4, 4, 4, 4, 8, 1, 1);

                    rec.Mode       = BigEndianBitConverter.ToUInt16(data, 0);
                    rec.alwaysZero = BigEndianBitConverter.ToInt32(data, 2);
                    rec.inode      = BigEndianBitConverter.ToUInt32(data, 6);
                    rec.UserId     = BigEndianBitConverter.ToUInt32(data, 10);  // or maybe GroupId (don't care...)
                    rec.GroupId    = BigEndianBitConverter.ToUInt32(data, 14);  // or maybe UserId

                    rec.aTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 18));
                    rec.bTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 22));
                    rec.cTime = unixEpoch.AddSeconds(BigEndianBitConverter.ToUInt32(data, 26));

                    rec.FileLength = BigEndianBitConverter.ToInt64(data, 30);

                    rec.flag          = data[38];
                    rec.PropertyCount = data[39];

                    rec.Properties = new MBFileRecord.Property[rec.PropertyCount];
                    for (int j = 0; j < rec.PropertyCount; ++j)
                    {
                        rec.Properties[j].Name  = getS(mbdb);
                        rec.Properties[j].Value = getD(mbdb);
                    }

                    StringBuilder fileName = new StringBuilder();
                    byte[]        fb       = hasher.ComputeHash(ASCIIEncoding.UTF8.GetBytes(rec.Domain + "-" + rec.Path));
                    for (int k = 0; k < fb.Length; k++)
                    {
                        fileName.Append(fb[k].ToString("x2"));
                    }

                    rec.key = fileName.ToString();

                    files.Add(rec);
                }

                return(files);
            }
            catch (Exception e)
            {
                Console.WriteLine("exception: {0}", e.Message);
            }

            return(null);
        }