簡體   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