繁体   English   中英

如何解密加密的Apple iTunes iPhone备份?

[英]How to decrypt an encrypted Apple iTunes iPhone backup?

我被许多不幸的iPhone用户请求帮助他们从iTunes备份中恢复数据。 这些在未加密时很容易,但不是在加密时,无论密码是否已知。

因此,我试图找出加密时mddata和mdinfo文件上使用的加密方案。 否则,我没有读取这些文件的问题,并且已经构建了一些强大的C#库。 (如果你能够提供帮助,我不在乎你使用哪种语言。这是我在这之后的原则!)

Apple“iPhone OS企业部署指南”指出“通过在iTunes的设备摘要窗格中选择加密iPhone备份选项,可以以加密格式存储设备备份。文件使用带有256位密钥的AES128进行加密。关键是安全地存放在iPhone钥匙串中。“

这是一个非常好的线索,这里有关于iPhone AES / Rijndael互操作性的 Stackoverflow的一些很好的信息,表明可以使用128和CBC模式的密钥。

除了任何其他混淆之外,还需要密钥和初始化向量(IV)/盐。

人们可能会认为关键是操纵“备份密码”,用户被提示通过iTunes输入并传递给“ AppleMobileBackup.exe ”,以CBC规定的方式填充。 但是,考虑到对iPhone钥匙串的引用,我想知道“备份密码”是否可能不会用作X509证书或对称私钥的密码,并且证书或私钥本身可能会被用作密钥。 AES和iTunes加密/解密过程是对称的。)

IV是另一回事,它可能是一些事情。 也许它是硬编码到iTunes或设备本身的密钥之一。

虽然Apple上面的评论表明该设备的钥匙链上有钥匙,但我认为这并不重要。 device, which suggests all information relevant to the decryption is present in the backup and iTunes configuration, and that anything solely on the device is irrelevant and replacable in this context. 可以将加密的备份恢复到设备,这表明与解密相关的所有信息都存在于备份和iTunes配置中,并且仅在设备上的任何内容都是无关紧要的,并且在此上下文中可以替换。 所以关键在哪里?

我在Windows机器上列出了下面的路径,但无论我们使用哪种操作系统,它都非常多。

“\\ appdata \\ Roaming \\ Apple Computer \\ iTunes \\ itunesprefs.xml”包含一个带有“Keychain”dict条目的PList。 “\\ programdata \\ apple \\ Lockdown \\ 09037027da8f4bdefdea97d706703ca034c88bab.plist”包含带有“DeviceCertificate”,“HostCertificate”和“RootCertificate”的PList,所有这些看起来都是有效的X509证书。 同一个文件似乎也包含非对称密钥“RootPrivateKey”和“HostPrivateKey”(我的阅读建议这些可能是PKCS#7-enveloped)。 此外,在每个备份中,Manifest.plist文件中都有“AuthSignature”和“AuthData”值,尽管这些值似乎在每个文件逐步备份时轮换,表明它们不是一个有用的键,除非真的有什么东西相关的工作正在进行中。

有很多误导性的东西表明从加密备份中获取数据很容易。 它不是,据我所知,它还没有完成。 绕过或禁用备份加密完全是另一回事,而不是我想做的事情。

这不是关于黑客攻击iPhone或类似的东西。 我在这里的所有内容都是从加密的iTunes备份中提取数据(照片,联系人等)的方法,因为我可以解密。 我已经尝试了各种各样的排列信息,我已经在上面提到了这些信息,但却无处可去。 我很欣赏我可能错过的任何想法或技巧。

安全研究人员Jean-BaptisteBédrune和Jean Sigwald 在2011年阿姆斯特丹的Hack-in-the-box中 介绍了如何做到这一点

从那时起,Apple发布了一份关于密钥和算法的更多细节的iOS安全白皮书 ,以及Charlie Miller等人。 已经发布了iOS黑客手册 ,它以一种操作方式涵盖了一些相同的基础。 当iOS 10首次问世时,苹果公司最初没有公布备份格式的变化,但是各种各样的人对这种格式的变化进行了逆向设计

加密备份很棒

加密iPhone备份的好处在于它们包含的WiFi密码不是常规的未加密备份。 正如iOS安全白皮书中所讨论的,加密备份被认为更“安全”,因此Apple认为可以在其中包含更多敏感信息。

一个重要的警告:显然,解密你的iOS设备的备份会删除它的加密。 为了保护您的隐私和安全, 您应该只在具有全盘加密的计算机上运行这些脚本。 虽然安全专家可以编写保护内存中密钥的软件,例如通过使用VirtualLock()SecureZeroMemory()等功能,但这些Python脚本会将您的加密密钥和密码存储在字符串中作为垃圾 -由Python收集。 这意味着你的密钥和密码会在RAM中存在一段时间,从那里它们会泄漏到你的交换文件中,然后泄漏到磁盘上,攻击者可以在那里恢复它们。 这完全违背了加密备份的要点。

如何解密备份:理论上

iOS安全白皮书比我更好地解释了每个文件密钥,保护类,保护类密钥和密钥包的基本概念。 如果您还不熟悉这些,请花几分钟时间阅读相关部分。

现在您知道iOS中的每个文件都使用自己的随机每文件加密密钥加密,属于保护类,并且每个文件加密密钥存储在文件系统元数据中,包含在保护类密钥中。

要解密:

  1. 解码存储在Manifest.plistBackupKeyBag条目中的BackupKeyBag 白皮书中给出了该结构的高级概述。 iPhone Wiki描述了二进制格式:一个4字节的字符串类型字段,一个4字节的大端字段长度字段,然后是值本身。

    重要的值是PBKDF2 ITERSALT ,双保护盐DPSL和迭代计数DPIC ,然后对于每个保护CLSWPKY包装密钥。

  2. 使用备份密码使用正确的PBKDF2盐和迭代次数导出32字节密钥。 首先使用带有DPSLDPIC的SHA256轮,然后使用带有ITERSALT的SHA1轮。

    根据RFC 3394打开每个包装的密钥。

  3. 从拉动4个字节的防护等级和更长的密钥解密清单数据库ManifestKeyManifest.plist ,并展开它。 您现在拥有一个包含所有文件元数据的SQLite数据库。

  4. 对于每个感兴趣的文件,通过在Files.file数据库列中查找包含EncryptionKeyProtectionClass条目的二进制plist,获取类加密的每文件加密密钥和保护类代码。 在使用之前,从EncryptionKey剥离初始的四字节长度标记。

    然后,通过使用使用备份密码解包的类密钥解包来派生最终解密密钥。 然后使用AES在CBC模式下使用零IV解密文件。

如何解密备份:在实践中

首先,您需要一些库依赖项。 如果您使用自制软件安装的Python 2.7或3.7在Mac上,则可以使用以下命令安装依赖项:

CFLAGS="-I$(brew --prefix)/opt/openssl/include" \
LDFLAGS="-L$(brew --prefix)/opt/openssl/lib" \    
    pip install biplist fastpbkdf2 pycrypto

在可运行的源代码表单中,以下是如何从加密的iPhone备份解密单个首选项文件:

#!/usr/bin/env python3.7
# coding: UTF-8

from __future__ import print_function
from __future__ import division

import argparse
import getpass
import os.path
import pprint
import random
import shutil
import sqlite3
import string
import struct
import tempfile
from binascii import hexlify

import Crypto.Cipher.AES # https://www.dlitz.net/software/pycrypto/
import biplist
import fastpbkdf2
from biplist import InvalidPlistException


def main():
    ## Parse options
    parser = argparse.ArgumentParser()
    parser.add_argument('--backup-directory', dest='backup_directory',
                    default='testdata/encrypted')
    parser.add_argument('--password-pipe', dest='password_pipe',
                        help="""\
Keeps password from being visible in system process list.
Typical use: --password-pipe=<(echo -n foo)
""")
    parser.add_argument('--no-anonymize-output', dest='anonymize',
                        action='store_false')
    args = parser.parse_args()
    global ANONYMIZE_OUTPUT
    ANONYMIZE_OUTPUT = args.anonymize
    if ANONYMIZE_OUTPUT:
        print('Warning: All output keys are FAKE to protect your privacy')

    manifest_file = os.path.join(args.backup_directory, 'Manifest.plist')
    with open(manifest_file, 'rb') as infile:
        manifest_plist = biplist.readPlist(infile)
    keybag = Keybag(manifest_plist['BackupKeyBag'])
    # the actual keys are unknown, but the wrapped keys are known
    keybag.printClassKeys()

    if args.password_pipe:
        password = readpipe(args.password_pipe)
        if password.endswith(b'\n'):
            password = password[:-1]
    else:
        password = getpass.getpass('Backup password: ').encode('utf-8')

    ## Unlock keybag with password
    if not keybag.unlockWithPasscode(password):
        raise Exception('Could not unlock keybag; bad password?')
    # now the keys are known too
    keybag.printClassKeys()

    ## Decrypt metadata DB
    manifest_key = manifest_plist['ManifestKey'][4:]
    with open(os.path.join(args.backup_directory, 'Manifest.db'), 'rb') as db:
        encrypted_db = db.read()

    manifest_class = struct.unpack('<l', manifest_plist['ManifestKey'][:4])[0]
    key = keybag.unwrapKeyForClass(manifest_class, manifest_key)
    decrypted_data = AESdecryptCBC(encrypted_db, key)

    temp_dir = tempfile.mkdtemp()
    try:
        # Does anyone know how to get Python’s SQLite module to open some
        # bytes in memory as a database?
        db_filename = os.path.join(temp_dir, 'db.sqlite3')
        with open(db_filename, 'wb') as db_file:
            db_file.write(decrypted_data)
        conn = sqlite3.connect(db_filename)
        conn.row_factory = sqlite3.Row
        c = conn.cursor()
        # c.execute("select * from Files limit 1");
        # r = c.fetchone()
        c.execute("""
            SELECT fileID, domain, relativePath, file
            FROM Files
            WHERE relativePath LIKE 'Media/PhotoData/MISC/DCIM_APPLE.plist'
            ORDER BY domain, relativePath""")
        results = c.fetchall()
    finally:
        shutil.rmtree(temp_dir)

    for item in results:
        fileID, domain, relativePath, file_bplist = item

        plist = biplist.readPlistFromString(file_bplist)
        file_data = plist['$objects'][plist['$top']['root'].integer]
        size = file_data['Size']

        protection_class = file_data['ProtectionClass']
        encryption_key = plist['$objects'][
            file_data['EncryptionKey'].integer]['NS.data'][4:]

        backup_filename = os.path.join(args.backup_directory,
                                    fileID[:2], fileID)
        with open(backup_filename, 'rb') as infile:
            data = infile.read()
            key = keybag.unwrapKeyForClass(protection_class, encryption_key)
            # truncate to actual length, as encryption may introduce padding
            decrypted_data = AESdecryptCBC(data, key)[:size]

        print('== decrypted data:')
        print(wrap(decrypted_data))
        print()

        print('== pretty-printed plist')
        pprint.pprint(biplist.readPlistFromString(decrypted_data))

##
# this section is mostly copied from parts of iphone-dataprotection
# http://code.google.com/p/iphone-dataprotection/

CLASSKEY_TAGS = [b"CLAS",b"WRAP",b"WPKY", b"KTYP", b"PBKY"]  #UUID
KEYBAG_TYPES = ["System", "Backup", "Escrow", "OTA (icloud)"]
KEY_TYPES = ["AES", "Curve25519"]
PROTECTION_CLASSES={
    1:"NSFileProtectionComplete",
    2:"NSFileProtectionCompleteUnlessOpen",
    3:"NSFileProtectionCompleteUntilFirstUserAuthentication",
    4:"NSFileProtectionNone",
    5:"NSFileProtectionRecovery?",

    6: "kSecAttrAccessibleWhenUnlocked",
    7: "kSecAttrAccessibleAfterFirstUnlock",
    8: "kSecAttrAccessibleAlways",
    9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly",
    10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly",
    11: "kSecAttrAccessibleAlwaysThisDeviceOnly"
}
WRAP_DEVICE = 1
WRAP_PASSCODE = 2

class Keybag(object):
    def __init__(self, data):
        self.type = None
        self.uuid = None
        self.wrap = None
        self.deviceKey = None
        self.attrs = {}
        self.classKeys = {}
        self.KeyBagKeys = None #DATASIGN blob
        self.parseBinaryBlob(data)

    def parseBinaryBlob(self, data):
        currentClassKey = None

        for tag, data in loopTLVBlocks(data):
            if len(data) == 4:
                data = struct.unpack(">L", data)[0]
            if tag == b"TYPE":
                self.type = data
                if self.type > 3:
                    print("FAIL: keybag type > 3 : %d" % self.type)
            elif tag == b"UUID" and self.uuid is None:
                self.uuid = data
            elif tag == b"WRAP" and self.wrap is None:
                self.wrap = data
            elif tag == b"UUID":
                if currentClassKey:
                    self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey
                currentClassKey = {b"UUID": data}
            elif tag in CLASSKEY_TAGS:
                currentClassKey[tag] = data
            else:
                self.attrs[tag] = data
        if currentClassKey:
            self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey

    def unlockWithPasscode(self, passcode):
        passcode1 = fastpbkdf2.pbkdf2_hmac('sha256', passcode,
                                        self.attrs[b"DPSL"],
                                        self.attrs[b"DPIC"], 32)
        passcode_key = fastpbkdf2.pbkdf2_hmac('sha1', passcode1,
                                            self.attrs[b"SALT"],
                                            self.attrs[b"ITER"], 32)
        print('== Passcode key')
        print(anonymize(hexlify(passcode_key)))
        for classkey in self.classKeys.values():
            if b"WPKY" not in classkey:
                continue
            k = classkey[b"WPKY"]
            if classkey[b"WRAP"] & WRAP_PASSCODE:
                k = AESUnwrap(passcode_key, classkey[b"WPKY"])
                if not k:
                    return False
                classkey[b"KEY"] = k
        return True

    def unwrapKeyForClass(self, protection_class, persistent_key):
        ck = self.classKeys[protection_class][b"KEY"]
        if len(persistent_key) != 0x28:
            raise Exception("Invalid key length")
        return AESUnwrap(ck, persistent_key)

    def printClassKeys(self):
        print("== Keybag")
        print("Keybag type: %s keybag (%d)" % (KEYBAG_TYPES[self.type], self.type))
        print("Keybag version: %d" % self.attrs[b"VERS"])
        print("Keybag UUID: %s" % anonymize(hexlify(self.uuid)))
        print("-"*209)
        print("".join(["Class".ljust(53),
                    "WRAP".ljust(5),
                    "Type".ljust(11),
                    "Key".ljust(65),
                    "WPKY".ljust(65),
                    "Public key"]))
        print("-"*208)
        for k, ck in self.classKeys.items():
            if k == 6:print("")

            print("".join(
                [PROTECTION_CLASSES.get(k).ljust(53),
                str(ck.get(b"WRAP","")).ljust(5),
                KEY_TYPES[ck.get(b"KTYP",0)].ljust(11),
                anonymize(hexlify(ck.get(b"KEY", b""))).ljust(65),
                anonymize(hexlify(ck.get(b"WPKY", b""))).ljust(65),
            ]))
        print()

def loopTLVBlocks(blob):
    i = 0
    while i + 8 <= len(blob):
        tag = blob[i:i+4]
        length = struct.unpack(">L",blob[i+4:i+8])[0]
        data = blob[i+8:i+8+length]
        yield (tag,data)
        i += 8 + length

def unpack64bit(s):
    return struct.unpack(">Q",s)[0]
def pack64bit(s):
    return struct.pack(">Q",s)

def AESUnwrap(kek, wrapped):
    C = []
    for i in range(len(wrapped)//8):
        C.append(unpack64bit(wrapped[i*8:i*8+8]))
    n = len(C) - 1
    R = [0] * (n+1)
    A = C[0]

    for i in range(1,n+1):
        R[i] = C[i]

    for j in reversed(range(0,6)):
        for i in reversed(range(1,n+1)):
            todec = pack64bit(A ^ (n*j+i))
            todec += pack64bit(R[i])
            B = Crypto.Cipher.AES.new(kek).decrypt(todec)
            A = unpack64bit(B[:8])
            R[i] = unpack64bit(B[8:])

    if A != 0xa6a6a6a6a6a6a6a6:
        return None
    res = b"".join(map(pack64bit, R[1:]))
    return res

ZEROIV = "\x00"*16
def AESdecryptCBC(data, key, iv=ZEROIV, padding=False):
    if len(data) % 16:
        print("AESdecryptCBC: data length not /16, truncating")
        data = data[0:(len(data)/16) * 16]
    data = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CBC, iv).decrypt(data)
    if padding:
        return removePadding(16, data)
    return data

##
# here are some utility functions, one making sure I don’t leak my
# secret keys when posting the output on Stack Exchange

anon_random = random.Random(0)
memo = {}
def anonymize(s):
    if type(s) == str:
        s = s.encode('utf-8')
    global anon_random, memo
    if ANONYMIZE_OUTPUT:
        if s in memo:
            return memo[s]
        possible_alphabets = [
            string.digits,
            string.digits + 'abcdef',
            string.ascii_letters,
            "".join(chr(x) for x in range(0, 256)),
        ]
        for a in possible_alphabets:
            if all((chr(c) if type(c) == int else c) in a for c in s):
                alphabet = a
                break
        ret = "".join([anon_random.choice(alphabet) for i in range(len(s))])
        memo[s] = ret
        return ret
    else:
        return s

def wrap(s, width=78):
    "Return a width-wrapped repr(s)-like string without breaking on \’s"
    s = repr(s)
    quote = s[0]
    s = s[1:-1]
    ret = []
    while len(s):
        i = s.rfind('\\', 0, width)
        if i <= width - 4: # "\x??" is four characters
            i = width
        ret.append(s[:i])
        s = s[i:]
    return '\n'.join("%s%s%s" % (quote, line ,quote) for line in ret)

def readpipe(path):
    if stat.S_ISFIFO(os.stat(path).st_mode):
        with open(path, 'rb') as pipe:
            return pipe.read()
    else:
        raise Exception("Not a pipe: {!r}".format(path))

if __name__ == '__main__':
    main()

然后打印此输出:

Warning: All output keys are FAKE to protect your privacy
== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES                                                                         4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES                                                                         09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES                                                                         e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES                                                                         902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES                                                                         a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES                                                                         09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES                                                                         0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES                                                                         b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES                                                                         417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES                                                                         b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES                                                                         9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== Passcode key
ee34f5bb635830d698074b1e3e268059c590973b0f1138f1954a2a4e1069e612

== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES        64e8fc94a7b670b0a9c4a385ff395fe9ba5ee5b0d9f5a5c9f0202ef7fdcb386f 4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES        22a218c9c446fbf88f3ccdc2ae95f869c308faaa7b3e4fe17b78cbf2eeaf4ec9 09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES        1004c6ca6e07d2b507809503180edf5efc4a9640227ac0d08baf5918d34b44ef e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES        2e809a0cd1a73725a788d5d1657d8fd150b0e360460cb5d105eca9c60c365152 902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES        9a078d710dcd4a1d5f70ea4062822ea3e9f7ea034233e7e290e06cf0d80c19ca a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES        606e5328816af66736a69dfe5097305cf1e0b06d6eb92569f48e5acac3f294a4 09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES        6a4b5292661bac882338d5ebb51fd6de585befb4ef5f8ffda209be8ba3af1b96 0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES        c0ed717947ce8d1de2dde893b6026e9ee1958771d7a7282dd2116f84312c2dd2 b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES        80d8c7be8d5103d437f8519356c3eb7e562c687a5e656cfd747532f71668ff99 417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES        a875a15e3ff901351c5306019e3b30ed123e6c66c949bdaa91fb4b9a69a3811e b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES        1e7756695d337e0b06c764734a9ef8148af20dcc7a636ccfea8b2eb96a9e9373 9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== decrypted data:
'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD '
'PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist versi'
'on="1.0">\n<dict>\n\t<key>DCIMLastDirectoryNumber</key>\n\t<integer>100</integ'
'er>\n\t<key>DCIMLastFileNumber</key>\n\t<integer>3</integer>\n</dict>\n</plist'
'>\n'

== pretty-printed plist
{'DCIMLastDirectoryNumber': 100, 'DCIMLastFileNumber': 3}

额外的功劳

Bédrune和Sigwald发布的iphone-dataprotection代码可以从备份中解密钥匙串 ,包括保存的wifi和网站密码等有趣的东西:

$ python iphone-dataprotection/python_scripts/keychain_tool.py ...

--------------------------------------------------------------------------------------
|                              Passwords                                             |
--------------------------------------------------------------------------------------
|Service           |Account          |Data           |Access group  |Protection class|
--------------------------------------------------------------------------------------
|AirPort           |Ed’s Coffee Shop |<3FrenchRoast  |apple         |AfterFirstUnlock|
...

该代码不再适用于使用最新iOS的手机备份,但有一些golang 端口一直保持最新,允许访问钥匙串

对不起,但它甚至可能更复杂,涉及到pbkdf2,甚至是它的变体。 收听WWDC 2010会议#209,主要讨论iOS 4中的安全措施,但也简要提到了备份的单独加密以及它们的相关性。

你可以非常肯定,在不知道密码的情况下,你无法解密它,即使是蛮力。

我们假设你想尝试让知道密码的人获得他们备份的数据。

我担心在iTunes中查看实际代码无法找出使用哪些算法。

回到牛顿时代,我不得不解密程序中的数据,并且能够直接调用其解密函数(当然知道密码),而不需要甚至低估其算法。 不幸的是,它不再那么容易了。

我确信周围有熟练的人可以对iTunes代码进行逆向工程 - 你只需让他们感兴趣。

理论上,Apple的算法应该以一种方式设计,使得数据对任何知道确切加密方法的攻击者来说仍然是安全的(即通过蛮力方法几乎不可破解)。 在WWDC会议209中,他们深入了解了他们为实现这一目标所做的工作。 如果您告诉他们您的良好意愿,也许您可​​以直接从Apple的安全团队获得答案。 毕竟,即使他们应该知道混淆的安全性也不是很有效。 试试他们的安全邮件列表。 即使他们没有回应,也许在列表上默默地有人会回应一些帮助。

祝好运!

没有尝试过,但是Elcomsoft发布了他们声称能够解密备份的产品,用于取证。 也许不像自己设计解决方案那么酷,但它可能会更快。

http://www.elcomsoft.com/eppb.html

您应该获取Erica Sadun的mdhelper命令行实用程序( OS X二进制文件源代码 )的副本。 它支持列出和提取iPhone / iPod Touch备份的内容,包括地址簿和SMS数据库,以及其他应用程序元数据和设置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM