gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 18:08:38 27 4
gpt4 key购买 nike

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

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

Apple“iPhone OS 企业部署指南”指出“设备备份可以通过选择加密 iPhone 以加密格式存储
iTunes 设备摘要 Pane 中的备份选项。文件使用 AES128 和 256 位 key 加密。 key 安全地存储在 iPhone 钥匙串(keychain)中。”

这是一个很好的线索,在 iPhone 上的 Stackoverflow 上有一些很好的信息 AES/Rijndael interoperability建议可以使用 128 的 key 大小和 CBC 模式。

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

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

IV 是另一回事,它可能是几件事。也许它是 key 之一hard-coded进入 iTunes,或进入 devices themselves .

尽管 Apple 上面的评论表明 key 存在于设备的钥匙串(keychain)上,但我认为这并不重要。人们可以将加密的备份恢复到不同的设备,这表明与解密相关的所有信息都存在于备份和 iTunes 配置中,并且在这种情况下,仅在设备上的任何内容都无关紧要且可替换。那么关键在哪里呢?

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

“\appdata\Roaming\Apple Computer\iTunes\itunesprefs.xml”包含一个带有“Keychain”字典条目的 PList。 “\programdata\apple\Lockdown\09037027da8f4bdefdea97d706703ca034c88bab.plist”包含一个带有“DeviceCertificate”、“HostCertificate”和“RootCertificate”的PList,所有这些似乎都是有效的X509证书。同一个文件似乎还包含非对称 key “RootPrivateKey”和“HostPrivateKey”(我的阅读表明这些可能是 PKCS #7 封装的)。此外,在每个备份中,Manifest.plist 文件中都有“AuthSignature”和“AuthData”值,尽管这些值似乎随着每个文件的增量备份而轮换,表明它们作为 key 不是那么有用,除非真的相当涉及正在做。

有很多误导性的东西表明从加密备份中获取数据很容易。事实并非如此,据我所知,它还没有完成。 Bypassing or disabling备份加密完全是另一回事,这不是我想要做的。

这不是要破解 iPhone 或类似的东西。我所追求的只是一种从加密的 iTunes 备份中提取数据(照片、联系人等)的方法,就像我可以使用未加密的备份一样。我已经尝试使用上面列出的信息进行各种排列,但一无所获。我很感激我可能错过的任何想法或技术。

最佳答案

安全研究人员 Jean-Baptiste Bédrune 和 Jean Sigwald presented howto do thisHack-in-the-box Amsterdam 2011 .

此后,Apple 发布了 iOS Security Whitepaper
有关 key 和算法的更多详细信息,以及 Charlie Miller 等人。有
发布了 iOS Hacker’s Handbook ,其中涵盖了一些相同的
以操作方法为基础。当 iOS 10 首次出现时,发生了一些变化
到苹果一开始没有宣传的备份格式,但是各种
reverse-engineered the format changes .

加密备份很棒

加密的 iPhone 备份的伟大之处在于它们包含的东西
像不在常规未加密备份中的 WiFi 密码。作为
iOS Security Whitepaper 中讨论, 加密备份
被认为更“安全”,因此 Apple 认为可以包含更多
其中的敏感信息。

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

如何解密备份:理论上

iOS Security Whitepaper解释基本概念
每个文件的 key 、保护等级、保护等级 key 和 key 包
比我能做的更好。如果你还不熟悉这些,请拿一些
分钟阅读相关部分。

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

解密:

  • 解码存储在 BackupKeyBag 中的 key 包进入Manifest.plist .此结构的高级概述在
    whitepaper . iPhone Wiki
    描述二进制格式:一个4字节的字符串类型字段,一个4字节的
    大端长度字段,然后是值本身。

    重要的值是 PBKDF2 ITERSALT ,双
    保护盐DPSL和迭代次数 DPIC ,然后对于每个
    保护CLS , WPKY包裹的 key 。
  • 使用备份密码使用正确的 PBKDF2 派生出一个 32 字节的 key
    盐和迭代次数。首先使用带有 DPSL 的 SHA256 轮和DPIC ,然后是 ITER 的 SHA1 回合和 SALT .

    解开每个包裹的 key
    RFC 3394 .
  • 通过从 ManifestKey 中提取 4 字节保护类和更长的 key 来解密 list 数据库。在 Manifest.plist ,并展开它。你现在有一个
    包含所有文件元数据的 SQLite 数据库。
  • 对于每个感兴趣的文件,获取类加密的每个文件加密
    查看 Files.file 中的 key 和保护类代码数据库
    包含 EncryptionKey 的二进制 plist 的列和ProtectionClass条目。剥离初始四字节长度的标签EncryptionKey使用前。

    然后,通过用类解开它来导出最终的解密 key
    用备份密码解包的 key 。然后解密文件
    在 CBC 模式下使用 AES,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}

    额外学分

    iphone-dataprotection code由 Bédrune 和 Sigwald 发布可以
    从备份中解 key 匙串,包括保存的 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 ports一直保持最新状态
    允许访问 keychain .

    关于iphone - 如何解密加密的 Apple iTunes iPhone 备份?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1498342/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com