├── .gitignore ├── .hgignore ├── A5 Tools ├── kernel_patcher ├── kernel_patcher.c └── tfp0.plist ├── CREDITS.txt ├── README.md ├── Useful Apps for NIX └── keychainviewer0.3.deb ├── Useful Apps for Windows ├── hfsexplorer-0_21-setup.exe └── iphonebackupbrowser-r38.zip ├── build_ramdisk.sh ├── dump_data_partition.sh ├── emf_decrypter ├── CMakeLists.txt ├── LICENSE ├── README.txt ├── common │ ├── CMakeLists.txt │ ├── abstractfile.c │ └── base64.c ├── emf │ ├── CMakeLists.txt │ ├── emf.h │ ├── emf_decrypter.c │ └── emf_init.c ├── hfs │ ├── CMakeLists.txt │ ├── btree.c │ ├── catalog.c │ ├── extents.c │ ├── fastunicodecompare.c │ ├── flatfile.c │ ├── hfs.c │ ├── hfscompress.c │ ├── hfslib.c │ ├── rawfile.c │ ├── utility.c │ ├── volume.c │ └── xattr.c └── includes │ ├── abstractfile.h │ ├── common.h │ ├── dmg │ ├── dmg.h │ ├── dmgfile.h │ ├── dmglib.h │ └── filevault.h │ └── hfs │ ├── hfscompress.h │ ├── hfslib.h │ └── hfsplus.h ├── img3fs ├── Makefile ├── README └── img3fs.c ├── python_scripts ├── README.txt ├── backup_tool.py ├── backups │ ├── __init__.py │ ├── backup3.py │ └── backup4.py ├── crypto │ ├── PBKDF2.py │ ├── __init__.py │ ├── aes.py │ ├── aeswrap.py │ ├── curve25519.py │ └── gcm.py ├── demo_backup_keychain.py ├── demo_bruteforce.py ├── demo_escrow.py ├── emf_decrypter.py ├── emf_undelete.py ├── firmware │ ├── __init__.py │ ├── img2.py │ ├── img3.py │ └── scfg.py ├── hfs │ ├── __init__.py │ ├── btree.py │ ├── emf.py │ ├── hfs.py │ ├── journal.py │ └── structs.py ├── ios_examiner.py ├── kernel_patcher.py ├── keychain │ ├── __init__.py │ ├── keychain.py │ ├── keychain3.py │ ├── keychain4.py │ ├── managedconfiguration.py │ └── store.py ├── keychain_tool.py ├── keystore │ ├── __init__.py │ ├── effaceable.py │ └── keybag.py ├── nand │ ├── __init__.py │ ├── carver.py │ ├── image.py │ ├── legacyftl.py │ ├── nand.py │ ├── partition_tables.py │ ├── remote.py │ ├── structs.py │ ├── vfl.py │ ├── vsvfl.py │ └── yaftl.py ├── usbmux │ ├── __init__.py │ └── usbmux.py ├── util │ ├── __init__.py │ ├── asciitables.py │ ├── bdev.py │ ├── bplist.py │ ├── bruteforce.py │ ├── cert.py │ ├── lzss.py │ ├── ramdiskclient.py │ └── tlv.py └── windows_redsn0w_keys.py ├── ramdisk_tools ├── AppleEffaceableStorage.c ├── AppleEffaceableStorage.h ├── AppleKeyStore.c ├── AppleKeyStore.h ├── AppleKeyStore_kdf.c ├── IOAESAccelerator.c ├── IOAESAccelerator.h ├── IOKit.c ├── IOKit.h ├── IOUSBDeviceControllerLib.h ├── Makefile ├── bsdcrypto │ ├── key_wrap.c │ ├── key_wrap.h │ ├── pbkdf2.c │ ├── pbkdf2.h │ ├── rijndael.c │ ├── rijndael.h │ ├── sha1.c │ └── sha1.h ├── device_info.c ├── device_info.h ├── device_infos.c ├── dump_data_partition.sh ├── image.c ├── image.h ├── ioflash │ ├── ioflash.c │ ├── ioflash.h │ ├── ioflash_kernel.c │ └── ioflashstoragekit.c ├── kernel_patcher.c ├── keychain_dump ├── keystore_device.xml ├── plist_server.c ├── plist_server.h ├── registry.c ├── registry.h ├── remote_functions.c ├── remote_functions.h ├── restored_external.c ├── scripts │ └── mount_partitions.sh ├── shsh_dump.c ├── systemkb_bruteforce.c ├── tfp0.plist ├── util.c └── util.h ├── tcprelay.sh └── usbmuxd-python-client ├── relay.bat ├── tcprelay.py └── usbmux.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | # use glob syntax. 2 | syntax: glob 3 | 4 | *.o 5 | *.pyc 6 | *.dmg 7 | *.ipsw 8 | 9 | -------------------------------------------------------------------------------- /A5 Tools/kernel_patcher: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/A5 Tools/kernel_patcher -------------------------------------------------------------------------------- /A5 Tools/kernel_patcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | mach_port_t kernel_task=0; 9 | 10 | kern_return_t write_kernel(mach_port_t p, void* addr, uint32_t value) 11 | { 12 | kern_return_t r = vm_write(p, (vm_address_t)addr, (vm_address_t)&value, sizeof(value )); 13 | if (r) 14 | fprintf(stderr, "vm_write into kernel_task failed\n"); 15 | else 16 | fprintf(stderr, "vm_write into kernel_task OK\n"); 17 | return r; 18 | } 19 | 20 | int main(int argc, char** argv) 21 | { 22 | kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task); 23 | 24 | if( r != 0) 25 | { 26 | fprintf(stderr, "task_for_pid returned %x : missing tfp0 kernel patch or wrong entitlements\n", r); 27 | return 0; 28 | } 29 | uint32_t i; 30 | pointer_t buf; 31 | unsigned int sz; 32 | 33 | vm_address_t addr = 0x80002000; 34 | 35 | while( addr < (0x80002000 + 0xA00000)) 36 | { 37 | vm_read(kernel_task, addr, 2048, &buf, &sz); 38 | if( buf == NULL || sz == 0) 39 | continue; 40 | uint8_t* p = (uint8_t*) buf; 41 | 42 | for(i=0; i < sz; i++) 43 | { 44 | //"IOAESAccelerator enable UID" : (h("67 D0 40 F6"), h("00 20 40 F6")), 45 | if (*((uint32_t*)&p[i]) == 0xF640d067) 46 | { 47 | fprintf(stderr, "Found IOAESAccelerator UID ptr at %x\n", (uint32_t) addr + i); 48 | write_kernel(kernel_task, (void*) (addr + i), (uint32_t) 0xF6402000); 49 | return 0; 50 | } 51 | } 52 | addr += 2048; 53 | } 54 | fprintf(stderr, "Kernel patching failed\n"); 55 | return -1; 56 | } 57 | -------------------------------------------------------------------------------- /A5 Tools/tfp0.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | run-unsigned-code 8 | 9 | task_for_pid-allow 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /CREDITS.txt: -------------------------------------------------------------------------------- 1 | comex 2 | chronic dev team 3 | idroid/openiboot team 4 | iphone dev team 5 | Jonathan Zdziarski 6 | msftguy 7 | planetbeing 8 | eyerise team -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Welcome 2 | 3 | Visit the [wiki](https://github.com/Eyerise/iOS-DataProtection-ToolKit/wiki) to know how to use this ToolKit -------------------------------------------------------------------------------- /Useful Apps for NIX/keychainviewer0.3.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/Useful Apps for NIX/keychainviewer0.3.deb -------------------------------------------------------------------------------- /Useful Apps for Windows/hfsexplorer-0_21-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/Useful Apps for Windows/hfsexplorer-0_21-setup.exe -------------------------------------------------------------------------------- /Useful Apps for Windows/iphonebackupbrowser-r38.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/Useful Apps for Windows/iphonebackupbrowser-r38.zip -------------------------------------------------------------------------------- /build_ramdisk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #set +e 4 | #set -o errexit 5 | 6 | if [ $# -lt 4 ] 7 | then 8 | echo "Syntax: $0 IPSW RAMDISK KEY IV CUSTOMRAMDISK" 9 | echo "python_scripts/kernel_patcher.py can generate a shell script with the correct parameters" 10 | exit 11 | fi 12 | 13 | if [ ! -f ramdisk_tools/restored_external ] 14 | then 15 | echo "ramdisk_tools/restored_external not found, check compilation output for errors" 16 | exit -1 17 | fi 18 | 19 | IPSW=$1 20 | RAMDISK=$2 21 | KEY=$3 22 | IV=$4 23 | CUSTOMRAMDISK=$5 24 | if [ "$CUSTOMRAMDISK" == "" ]; then 25 | CUSTOMRAMDISK="myramdisk.dmg" 26 | fi 27 | IMG3FS="./img3fs/img3fs" 28 | IMG3MNT="/tmp/img3" 29 | 30 | if [ ! -f $IMG3FS ]; then 31 | echo "img3fs is missing, install osxfuse and run make -C img3fs/" 32 | exit -1 33 | fi 34 | 35 | if [ ! -f ssh.tar.gz ]; then 36 | echo "Downloading ssh.tar.gz from googlecode" 37 | curl -O http://iphone-dataprotection.googlecode.com/files/ssh.tar.gz 38 | fi 39 | 40 | unzip $IPSW $RAMDISK 41 | 42 | if [ -d "/Volumes/ramdisk" ]; then 43 | hdiutil eject /Volumes/ramdisk 44 | umount $IMG3MNT 45 | fi 46 | 47 | mkdir -p $IMG3MNT 48 | 49 | $IMG3FS -key $KEY -iv $IV $IMG3MNT $RAMDISK 50 | 51 | hdiutil attach -owners off $IMG3MNT/DATA.dmg 52 | 53 | #remove baseband files to free space 54 | rm -rf /Volumes/ramdisk/usr/local/standalone/firmware/* 55 | rm -rf /Volumes/ramdisk/usr/share/progressui/ 56 | #dont replace existing files, replacing launchctl on armv6 ramdisks makes it fail somehow 57 | tar -C /Volumes/ramdisk/ -xzkP < ssh.tar.gz 58 | rm /Volumes/ramdisk/bin/vdir 59 | rm /Volumes/ramdisk/bin/egrep 60 | rm /Volumes/ramdisk/bin/grep 61 | 62 | #rm /Volumes/ramdisk/usr/local/bin/restored_external 63 | cp ramdisk_tools/restored_external /Volumes/ramdisk/usr/local/bin 64 | 65 | cp ramdisk_tools/bruteforce ramdisk_tools/device_infos /Volumes/ramdisk/var/root 66 | cp ramdisk_tools/scripts/* /Volumes/ramdisk/var/root 67 | cp ramdisk_tools/ioflashstoragekit /Volumes/ramdisk/var/root 68 | 69 | #if present, copy ssh public key to ramdisk 70 | if [ -f ~/.ssh/id_rsa.pub ]; then 71 | mkdir /Volumes/ramdisk/var/root/.ssh 72 | cp ~/.ssh/id_rsa.pub /Volumes/ramdisk/var/root/.ssh/authorized_keys 73 | fi 74 | 75 | hdiutil eject /Volumes/ramdisk 76 | umount $IMG3MNT 77 | 78 | mv $RAMDISK $CUSTOMRAMDISK 79 | 80 | #echo "$CUSTOMRAMDISK created" 81 | 82 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /emf_decrypter/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(common abstractfile.c base64.c) 2 | 3 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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; -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /python_scripts/README.txt: -------------------------------------------------------------------------------- 1 | Dependencies 2 | pycrypto (https://www.dlitz.net/software/pycrypto/) 3 | construct (http://construct.wikispaces.com/) -------------------------------------------------------------------------------- /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/backups/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/python_scripts/backups/__init__.py -------------------------------------------------------------------------------- /python_scripts/backups/backup3.py: -------------------------------------------------------------------------------- 1 | from crypto.PBKDF2 import PBKDF2 2 | from crypto.aes import AESdecryptCBC 3 | from util import read_file, write_file, makedirs, readPlist 4 | from util.bplist import BPlistReader 5 | import hashlib 6 | import struct 7 | import glob 8 | import sys 9 | import os 10 | 11 | """ 12 | decrypt iOS 3 backup blob (metadata and file contents) 13 | """ 14 | 15 | def decrypt_blob(blob, auth_key): 16 | len = struct.unpack(">H", blob[0:2])[0] 17 | if len != 66: 18 | print "blob len != 66" 19 | magic = struct.unpack(">H", blob[2:4])[0] 20 | if magic != 0x0100: 21 | print "magic != 0x0100" 22 | iv = blob[4:20] 23 | 24 | blob_key = AESdecryptCBC(blob[20:68], auth_key)[:32] 25 | 26 | return AESdecryptCBC(blob[68:], blob_key, iv) 27 | 28 | def decrypt_backup3(backupfolder, outputfolder, passphrase): 29 | auth_key = None 30 | manifest = readPlist(backupfolder + "/Manifest.plist") 31 | 32 | if manifest["IsEncrypted"]: 33 | manifest_data = manifest["Data"].data 34 | 35 | authdata = manifest["AuthData"].data 36 | 37 | pkbdf_salt = authdata[:8] 38 | iv = authdata[8:24] 39 | key = PBKDF2(passphrase,pkbdf_salt,iterations=2000).read(32) 40 | 41 | data = AESdecryptCBC(authdata[24:], key, iv) 42 | auth_key = data[:32] 43 | 44 | if hashlib.sha1(auth_key).digest() != data[32:52]: 45 | print "wrong auth key (hash mismatch) => wrong passphrase" 46 | return 47 | 48 | print "Passphrase seems OK" 49 | 50 | for mdinfo_name in glob.glob(backupfolder + "/*.mdinfo"): 51 | 52 | mddata_name = mdinfo_name[:-7] + ".mddata" 53 | mdinfo = readPlist(mdinfo_name) 54 | metadata = mdinfo["Metadata"].data 55 | if mdinfo["IsEncrypted"]: 56 | metadata = decrypt_blob(mdinfo["Metadata"], auth_key) 57 | metadata = BPlistReader.plistWithString(metadata) 58 | 59 | print metadata["Path"] 60 | 61 | filedata = read_file(mddata_name) 62 | if mdinfo["IsEncrypted"]: 63 | filedata = decrypt_blob(filedata, auth_key) 64 | 65 | filename = metadata["Path"] 66 | makedirs(outputfolder + "/" + os.path.dirname(filename)) 67 | write_file(outputfolder + "/" + filename, filedata) 68 | -------------------------------------------------------------------------------- /python_scripts/backups/backup4.py: -------------------------------------------------------------------------------- 1 | from crypto.aes import AESdecryptCBC 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 | file_data = AESdecryptCBC(file_data, key) 160 | padding = file_data[record.size:] 161 | if len(padding) > 16 or padding != chr(len(padding)) * len(padding): 162 | warn("Incorrect padding for file %s" % record.path) 163 | file_data = file_data[:record.size] 164 | return file_data 165 | 166 | -------------------------------------------------------------------------------- /python_scripts/crypto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/python_scripts/crypto/__init__.py -------------------------------------------------------------------------------- /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 | 21 | def AESencryptCBC(data, key, iv=ZEROIV, padding=False): 22 | if len(data) % 16: 23 | print "AESdecryptCBC: data length not /16, truncating" 24 | data = data[0:(len(data)/16) * 16] 25 | data = AES.new(key, AES.MODE_CBC, iv).encrypt(data) 26 | return data 27 | -------------------------------------------------------------------------------- /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 39 | 40 | def AESwrap(kek, data): 41 | A = 0xa6a6a6a6a6a6a6a6 42 | R = [0] 43 | for i in xrange(len(data)/8): 44 | R.append(unpack64bit(data[i*8:i*8+8])) 45 | n = len(R) - 1 46 | 47 | for j in xrange(0,6): 48 | for i in xrange(1,n+1): 49 | B = AES.new(kek).encrypt(pack64bit(A) + pack64bit(R[i])) 50 | A = unpack64bit(B[:8]) ^ (n*j+i) 51 | R[i] = unpack64bit(B[8:]) 52 | 53 | res = pack64bit(A) + "".join(map(pack64bit, R[1:])) 54 | return res 55 | 56 | if __name__ == "__main__": 57 | #format (kek, data, expected_ciphertext) 58 | test_vectors = [ 59 | ("000102030405060708090A0B0C0D0E0F", "00112233445566778899AABBCCDDEEFF", "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5"), 60 | ("000102030405060708090A0B0C0D0E0F1011121314151617", "00112233445566778899AABBCCDDEEFF", "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D"), 61 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF", "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7"), 62 | ("000102030405060708090A0B0C0D0E0F1011121314151617", "00112233445566778899AABBCCDDEEFF0001020304050607", "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2"), 63 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF0001020304050607", "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1"), 64 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21") 65 | ] 66 | for kek, data, expected in test_vectors: 67 | ciphertext = AESwrap(kek.decode("hex"), data.decode("hex")) 68 | assert ciphertext == expected.decode("hex") 69 | assert AESUnwrap(kek.decode("hex"), ciphertext) == data.decode("hex") 70 | print "All tests OK !" 71 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 7 | def gcm_rightshift(vec): 8 | for x in range(15, 0, -1): 9 | c = vec[x] >> 1 10 | c |= (vec[x-1] << 7) & 0x80 11 | vec[x] = c 12 | vec[0] >>= 1 13 | return vec 14 | 15 | def gcm_gf_mult(a, b): 16 | mask = [ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 ] 17 | poly = [ 0x00, 0xe1 ] 18 | 19 | Z = [0] * 16 20 | V = [c for c in a] 21 | 22 | for x in range(128): 23 | if b[x >> 3] & mask[x & 7]: 24 | Z = [V[y] ^ Z[y] for y in range(16)] 25 | bit = V[15] & 1 26 | V = gcm_rightshift(V) 27 | V[0] ^= poly[bit] 28 | return Z 29 | 30 | def ghash(h, auth_data, data): 31 | u = (16 - len(data)) % 16 32 | v = (16 - len(auth_data)) % 16 33 | 34 | x = auth_data + chr(0) * v + data + chr(0) * u 35 | x += pack('>QQ', len(auth_data) * 8, len(data) * 8) 36 | 37 | y = [0] * 16 38 | vec_h = [ord(c) for c in h] 39 | 40 | for i in range(0, len(x), 16): 41 | block = [ord(c) for c in x[i:i+16]] 42 | y = [y[j] ^ block[j] for j in range(16)] 43 | y = gcm_gf_mult(y, vec_h) 44 | 45 | return ''.join(chr(c) for c in y) 46 | 47 | def inc32(block): 48 | counter, = unpack('>L', block[12:]) 49 | counter += 1 50 | return block[:12] + pack('>L', counter) 51 | 52 | def gctr(k, icb, plaintext): 53 | y = '' 54 | if len(plaintext) == 0: 55 | return y 56 | 57 | aes = AES.new(k) 58 | cb = icb 59 | 60 | for i in range(0, len(plaintext), aes.block_size): 61 | cb = inc32(cb) 62 | encrypted = aes.encrypt(cb) 63 | plaintext_block = plaintext[i:i+aes.block_size] 64 | y += strxor.strxor(plaintext_block, encrypted[:len(plaintext_block)]) 65 | 66 | return y 67 | 68 | def gcm_decrypt(k, iv, encrypted, auth_data, tag): 69 | aes = AES.new(k) 70 | h = aes.encrypt(chr(0) * aes.block_size) 71 | 72 | if len(iv) == 12: 73 | y0 = iv + "\x00\x00\x00\x01" 74 | else: 75 | y0 = ghash(h, '', iv) 76 | 77 | decrypted = gctr(k, y0, encrypted) 78 | s = ghash(h, auth_data, encrypted) 79 | 80 | t = aes.encrypt(y0) 81 | T = strxor.strxor(s, t) 82 | if T != tag: 83 | raise ValueError('Decrypted data is invalid') 84 | else: 85 | return decrypted 86 | 87 | def gcm_encrypt(k, iv, plaintext, auth_data): 88 | aes = AES.new(k) 89 | h = aes.encrypt(chr(0) * aes.block_size) 90 | 91 | if len(iv) == 12: 92 | y0 = iv + "\x00\x00\x00\x01" 93 | else: 94 | y0 = ghash(h, '', iv) 95 | 96 | encrypted = gctr(k, y0, plaintext) 97 | s = ghash(h, auth_data, encrypted) 98 | 99 | t = aes.encrypt(y0) 100 | T = strxor.strxor(s, t) 101 | return (encrypted, T) 102 | 103 | def main(): 104 | #http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf 105 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 106 | p = '' 107 | a = 'D609B1F056637A0D46DF998D88E5222AB2C2846512153524C0895E8108000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233340001'.decode("hex") 108 | iv = '12153524C0895E81B2C28465'.decode("hex") 109 | c, t = gcm_encrypt(k, iv, '', a) 110 | assert c == "" 111 | assert t == "f09478a9b09007d06f46e9b6a1da25dd".decode("hex") 112 | 113 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 114 | p = '08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A0002'.decode("hex") 115 | a = 'D609B1F056637A0D46DF998D88E52E00B2C2846512153524C0895E81'.decode("hex") 116 | iv = '12153524C0895E81B2C28465'.decode("hex") 117 | c, t = gcm_encrypt(k, iv, p, a) 118 | assert c == '701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D'.decode("hex") 119 | assert t == '4F8D55E7D3F06FD5A13C0C29B9D5B880'.decode("hex") 120 | 121 | key = "91bfb6cbcff07b93a4c68bbfe99ac63b713f0627025c0fb1ffc5b0812dc284f8".decode("hex") 122 | data = "020000000B00000028000000DE44D22E96B1966BAEF4CBEA8675871D40BA669401BD4EBB52AF9C025134187E70549012058456BF0EC0FA1F8FF9F822AC4312AB2141FA712E6D1482358EAC1421A1BFFA81EF38BD0BF2E52675D665EFE3C534E188F575774FAA92E74345575E370B9982661FAE8BD9243B7AD7D2105B275424C0CA1145B9D43AFF04F2747E40D62EC60563960D62A894BE66F267B14D75C0572BE60CC9B339D440FCB418D4F729BBF15C14E0D3A43E4A8B44523D8B3B0F3E7DF85AA67A707EE19CB893277D2392234D7DBC17DA4A0BD7F166189FC54C16C20D287E20FD2FB11BD2CE09ADBDABB95124CD4BFE219E34D3C80E69570A5A506555D7094916C5D75E0065F1796F556EDF0DAA1AA758E0C85AE3951BD363F26B1D43F6CBAEE12D97AD3B60CFA89C1C76BB29F2B54BE31B6CE166F4860C5E5DA92588EF53AA946DF159E60E6F05009D12FB1E37".decode("hex") 123 | ciphertext = data[12+40:-16] 124 | tag = data[-16:] 125 | print repr(gcm_decrypt(key, '', ciphertext, '', tag)) 126 | 127 | 128 | if __name__ == '__main__': 129 | main() 130 | -------------------------------------------------------------------------------- /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/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 | print "Enter passcode or leave blank for bruteforce:" 46 | z = raw_input() 47 | res = client.getPasscodeKey(systembag["KeyBagKeys"].data, z) 48 | if kb.unlockWithPasscodeKey(res.get("passcodeKey").decode("hex")): 49 | print "Passcode \"%s\" OK" % z 50 | di.update(res) 51 | keybags[kbuuid].update(res) 52 | di.save() 53 | keychain_blob = client.downloadFile("/mnt2/Keychains/keychain-2.db") 54 | write_file("keychain-2.db", keychain_blob) 55 | print "Downloaded keychain database, use keychain_tool.py to decrypt secrets" 56 | return 57 | if z != "": 58 | print "Wrong passcode, trying to bruteforce !" 59 | if checkPasscodeComplexity(client) == 0: 60 | print "Trying all 4-digits passcodes..." 61 | bf = client.bruteforceKeyBag(systembag["KeyBagKeys"].data) 62 | if bf: 63 | di.update(bf) 64 | keybags[kbuuid].update(bf) 65 | print bf 66 | print kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")) 67 | kb.printClassKeys() 68 | di["classKeys"] = kb.getClearClassKeysDict() 69 | di.save() 70 | else: 71 | print "Complex passcode used !" 72 | return 73 | 74 | #keychain_blob = client.downloadFile("/private/var/Keychains/keychain-2.db") 75 | keychain_blob = client.downloadFile("/mnt2/Keychains/keychain-2.db") 76 | write_file("keychain-2.db", keychain_blob) 77 | print "Downloaded keychain database, use keychain_tool.py to decrypt secrets" 78 | 79 | bf_system() 80 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /python_scripts/emf_decrypter.py: -------------------------------------------------------------------------------- 1 | from optparse import OptionParser 2 | from hfs.emf import EMFVolume 3 | from util.bdev import FileBlockDevice 4 | import plistlib 5 | 6 | def main(): 7 | parser = OptionParser(usage="emf_decrypter.py disk_image.bin") 8 | parser.add_option("-w", "--nowrite", dest="write", action="store_false", default=True, 9 | help="disable modifications of input file, for testing") 10 | (options, args) = parser.parse_args() 11 | if len(args) < 1: 12 | parser.print_help() 13 | return 14 | device_infos = None 15 | if len(args) >= 2: device_infos = plistlib.readPlist(args[1]) 16 | 17 | p = FileBlockDevice(args[0], 0, options.write) 18 | v = EMFVolume(p, device_infos) 19 | if not v.keybag.unlocked: 20 | print "Keybag locked, protected files won't be decrypted, continue anyway ?" 21 | if raw_input() == "n": 22 | return 23 | if options.write: 24 | print "WARNING ! This tool will modify the hfs image and possibly wreck it if something goes wrong !" 25 | print "Make sure to backup the image before proceeding" 26 | print "You can use the --nowrite option to do a dry run instead" 27 | else: 28 | print "Test mode : the input file will not be modified" 29 | print "Press a key to continue or CTRL-C to abort" 30 | raw_input() 31 | v.decryptAllFiles() 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /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 | from util.bdev import FileBlockDevice 6 | 7 | if __name__ == "__main__": 8 | if len(sys.argv) < 2: 9 | print "Usage: emf_undelete.py disk_image.bin" 10 | sys.exit(0) 11 | filename = sys.argv[1] 12 | volume = EMFVolume(FileBlockDevice(filename), None) 13 | dirname = os.path.dirname(filename) 14 | if dirname == "": 15 | dirname = "." 16 | outdir = dirname + "/" + volume.volumeID().encode("hex") + "_" + os.path.basename(filename) 17 | carveokdir = outdir + "/undelete/" 18 | carvenokdir = outdir + "/junk/" 19 | try: 20 | os.makedirs(carveokdir) 21 | os.makedirs(carvenokdir) 22 | except: 23 | pass 24 | 25 | do_emf_carving(volume, carveokdir, carvenokdir) 26 | -------------------------------------------------------------------------------- /python_scripts/firmware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/python_scripts/firmware/__init__.py -------------------------------------------------------------------------------- /python_scripts/firmware/img2.py: -------------------------------------------------------------------------------- 1 | from construct.core import Struct 2 | from construct.macros import * 3 | 4 | IMG2 = Struct("IMG2", 5 | String("magic",4), 6 | ULInt32("block_size"), 7 | ULInt32("images_offset"), 8 | ULInt32("images_block"), 9 | ULInt32("images_length"), 10 | Padding(0x1C), 11 | ULInt32("crc32"), 12 | ) -------------------------------------------------------------------------------- /python_scripts/firmware/scfg.py: -------------------------------------------------------------------------------- 1 | from construct.core import Struct 2 | from construct.macros import * 3 | from construct import RepeatUntil, OneOf 4 | from util import hexdump 5 | 6 | SCFGItem = Struct("SCFGItem", 7 | String("tag", 4), 8 | String("data", 16, padchar="\x00") 9 | ) 10 | 11 | SCFG = Struct("SCFG", 12 | OneOf(String("magic", 4), ["gfCS"]), 13 | ULInt32("length"), 14 | ULInt32("unk1"), 15 | ULInt32("unk2"), 16 | ULInt32("unk3"), 17 | ULInt32("unk4") 18 | ) 19 | 20 | def parse_SCFG(data): 21 | res = {} 22 | scfg = SCFG.parse(data) 23 | assert scfg.length > 0x18 24 | for i in Array((scfg.length - 0x18) / 20, SCFGItem).parse(data[0x18:scfg.length]): 25 | if i.tag != "\xFF\xFF\xFF\xFF": 26 | res[str(i.tag)[::-1]] = str(i.data) 27 | return res 28 | -------------------------------------------------------------------------------- /python_scripts/hfs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/python_scripts/hfs/__init__.py -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /python_scripts/keychain/keychain3.py: -------------------------------------------------------------------------------- 1 | from keychain import Keychain 2 | from crypto.aes import AESdecryptCBC, AESencryptCBC 3 | import hashlib 4 | 5 | class Keychain3(Keychain): 6 | def __init__(self, filename, key835=None): 7 | Keychain.__init__(self, filename) 8 | self.key835 = key835 9 | 10 | def decrypt_data(self, data): 11 | if data == None: 12 | return "" 13 | data = str(data) 14 | 15 | if not self.key835: 16 | print "Key 835 not availaible" 17 | return "" 18 | 19 | data = AESdecryptCBC(data[16:], self.key835, data[:16], padding=True) 20 | 21 | #data_column = iv + AES128_K835(iv, data + sha1(data)) 22 | if hashlib.sha1(data[:-20]).digest() != data[-20:]: 23 | print "data field hash mismatch : bad key ?" 24 | return "ERROR decrypting data : bad key ?" 25 | 26 | return data[:-20] 27 | 28 | def change_key835(self, newkey): 29 | tables = {"genp": "SELECT rowid, data FROM genp", 30 | "inet": "SELECT rowid, data FROM inet", 31 | "cert": "SELECT rowid, data FROM cert", 32 | "keys": "SELECT rowid, data FROM keys"} 33 | 34 | for t in tables.keys(): 35 | for row in self.conn.execute(tables[t]): 36 | rowid = row["rowid"] 37 | data = str(row["data"]) 38 | iv = data[:16] 39 | data = AESdecryptCBC(data[16:], self.key835, iv) 40 | data = AESencryptCBC(data, newkey, iv) 41 | data = iv + data 42 | data = buffer(data) 43 | self.conn.execute("UPDATE %s SET data=? WHERE rowid=?" % t, (data, rowid)) 44 | self.conn.commit() -------------------------------------------------------------------------------- /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 | print "Keychain object created with locked keybag, some items won't be decrypted" 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 {"clas": clas, "rowid": row["rowid"]} 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 | dict["clas"] = clas 53 | return dict 54 | row["clas"] = clas 55 | return Keychain.decrypt_item(self, row) 56 | 57 | def decrypt_data(self, data): 58 | data = self.decrypt_blob(data) 59 | if type(data) == dict: 60 | return data["v_Data"].data 61 | return data 62 | 63 | def decrypt_blob(self, blob): 64 | if blob == None: 65 | return "" 66 | 67 | if len(blob) < 48: 68 | print "keychain blob length must be >= 48" 69 | return 70 | 71 | version, clas = struct.unpack(" gpt.current_lba 94 | check = gpt.crc 95 | gpt.crc = 0 96 | actual = crc32(GPT_header.build(gpt)) 97 | if actual != check: 98 | print "GPT crc check fail %d vs %d" % (actual, check) 99 | return None 100 | return gpt 101 | 102 | def parse_lwvm(data, pageSize): 103 | try: 104 | hdr = LWVM_header.parse(data) 105 | if hdr.type != LWVM_MAGIC: 106 | print "LwVM magic mismatch" 107 | return 108 | tocheck = data[:44] + "\x00\x00\x00\x00" + data[48:0x1000] 109 | check = crc32(tocheck) & 0xffffffff 110 | if check != hdr.crc32: 111 | return None 112 | print "LwVM header CRC OK" 113 | partitions = hdr.LWVM_partitionRecord[:hdr.numPartitions] 114 | deviceSize=0 115 | #XXX: HAAAAAAAX 116 | for s in [8, 16, 32, 64, 128]: 117 | if hdr.mediaSize < (s* 1024*1024*1024): 118 | deviceSize = s 119 | break 120 | for i in xrange(len(hdr.chunks)): 121 | if hdr.chunks[i] == 0x0: 122 | lba0 = (i * deviceSize*1024*1024) / pageSize 123 | partitions[0].first_lba = lba0 124 | partitions[0].last_lba = lba0 + (partitions[0].end - partitions[0].begin) / pageSize 125 | elif hdr.chunks[i] == 0x1000: 126 | lbad = (i * deviceSize*1024*1024) / pageSize 127 | partitions[1].first_lba = lbad 128 | partitions[1].last_lba = lbad + (partitions[1].end - partitions[1].begin) / pageSize 129 | return partitions 130 | except: 131 | return None 132 | 133 | -------------------------------------------------------------------------------- /python_scripts/nand/remote.py: -------------------------------------------------------------------------------- 1 | from progressbar import ProgressBar 2 | from usbmux import usbmux 3 | from util import hexdump, sizeof_fmt 4 | import datetime 5 | import hashlib 6 | import struct 7 | import os 8 | 9 | CMD_DUMP = 0 10 | CMD_PROXY = 1 11 | kIOFlashStorageOptionRawPageIO = 0x002 12 | kIOFlashStorageOptionBootPageIO = 0x100 13 | 14 | class IOFlashStorageKitClient(object): 15 | def __init__(self, udid=None, host="localhost", port=2000): 16 | self.host = host 17 | self.port = port 18 | self.connect(udid) 19 | 20 | def connect(self, udid=None): 21 | mux = usbmux.USBMux() 22 | mux.process(1.0) 23 | if not mux.devices: 24 | print "Waiting for iOS device" 25 | while not mux.devices: 26 | mux.process(1.0) 27 | if not mux.devices: 28 | print "No device found" 29 | return 30 | dev = mux.devices[0] 31 | try: 32 | self.s = mux.connect(dev, self.port) 33 | except: 34 | raise Exception("Connexion to device %s port %d failed" % (dev.serial, self.port)) 35 | 36 | def send_command(self, cmd): 37 | return self.s.send(struct.pack("= 1099511627776: 70 | terabytes = bytes / 1099511627776 71 | size = '%.2fT' % terabytes 72 | elif bytes >= 1073741824: 73 | gigabytes = bytes / 1073741824 74 | size = '%.2fG' % gigabytes 75 | elif bytes >= 1048576: 76 | megabytes = bytes / 1048576 77 | size = '%.2fM' % megabytes 78 | elif bytes >= 1024: 79 | kilobytes = bytes / 1024 80 | size = '%.2fK' % kilobytes 81 | else: 82 | size = '%.2fb' % bytes 83 | return size 84 | 85 | def xor_strings(a,b): 86 | r="" 87 | for i in xrange(len(a)): 88 | r+= chr(ord(a[i])^ord(b[i])) 89 | return r 90 | 91 | hex = lambda data: " ".join("%02X" % ord(i) for i in data) 92 | ascii = lambda data: "".join(c if 31 < ord(c) < 127 else "." for c in data) 93 | 94 | def hexdump(d): 95 | for i in xrange(0,len(d),16): 96 | data = d[i:i+16] 97 | print "%08X | %s | %s" % (i, hex(data).ljust(47), ascii(data)) 98 | 99 | def search_plist(directory, matchDict): 100 | for p in map(os.path.normpath, glob.glob(directory + "/*.plist")): 101 | try: 102 | d = plistlib.readPlist(p) 103 | ok = True 104 | for k,v in matchDict.items(): 105 | if d.get(k) != v: 106 | ok = False 107 | break 108 | if ok: 109 | print "Using plist file %s" % p 110 | return d 111 | except: 112 | continue 113 | 114 | def save_pickle(filename,data): 115 | f = gzip.open(filename,"wb") 116 | cPickle.dump(data, f, cPickle.HIGHEST_PROTOCOL) 117 | f.close() 118 | 119 | def load_pickle(filename): 120 | f = gzip.open(filename,"rb") 121 | data = cPickle.load(f) 122 | f.close() 123 | return data 124 | -------------------------------------------------------------------------------- /python_scripts/util/asciitables.py: -------------------------------------------------------------------------------- 1 | 2 | def print_table(title, headers, rows): 3 | widths = [] 4 | 5 | for i in xrange(len(headers)): 6 | z = map(len, [str(row[i]) for row in rows]) 7 | z.append(len(headers[i])) 8 | widths.append(max(z)) 9 | 10 | width = sum(widths) + len(headers) + 1 11 | print "-"* width 12 | print "|" + title.center(width-2) + "|" 13 | print "-"* width 14 | hline = "|" 15 | for i in xrange(len(headers)): 16 | hline += headers[i].ljust(widths[i]) + "|" 17 | print hline 18 | 19 | print "-"* width 20 | for row in rows: 21 | line = "|" 22 | for i in xrange(len(row)): 23 | line += str(row[i]).ljust(widths[i]) + "|" 24 | print line 25 | 26 | if len(rows) == 0: 27 | print "|" + "No entries".center(width-2) + "|" 28 | print "-"* width 29 | print "" 30 | -------------------------------------------------------------------------------- /python_scripts/util/bdev.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from util import sizeof_fmt, hexdump 4 | from progressbar import ProgressBar 5 | from crypto.aes import AESdecryptCBC, AESencryptCBC 6 | 7 | class FileBlockDevice(object): 8 | def __init__(self, filename, offset=0, write=False): 9 | flag = os.O_RDONLY if not write else os.O_RDWR 10 | if sys.platform == 'win32': 11 | flag = flag | os.O_BINARY 12 | self.filename = filename 13 | self.fd = os.open(filename, flag) 14 | self.offset = offset 15 | self.writeFlag = write 16 | self.size = os.path.getsize(filename) 17 | self.setBlockSize(8192) 18 | 19 | def setBlockSize(self, bs): 20 | self.blockSize = bs 21 | self.nBlocks = self.size / bs 22 | 23 | def readBlock(self, blockNum): 24 | os.lseek(self.fd, self.offset + self.blockSize * blockNum, os.SEEK_SET) 25 | return os.read(self.fd, self.blockSize) 26 | 27 | def write(self, offset, data): 28 | if self.writeFlag: #fail silently for testing 29 | os.lseek(self.fd, self.offset + offset, os.SEEK_SET) 30 | return os.write(self.fd, data) 31 | 32 | def writeBlock(self, lba, block): 33 | return self.write(lba*self.blockSize, block) 34 | 35 | class FTLBlockDevice(object): 36 | def __init__(self, nand, first_lba, last_lba, defaultKey=None): 37 | self.nand = nand 38 | self.pageSize = nand.pageSize 39 | self.blockSize = 0 #not used 40 | self.key = defaultKey 41 | self.lbaoffset = first_lba 42 | self.last_lba = last_lba 43 | self.setBlockSize(self.pageSize) 44 | 45 | def setBlockSize(self, bs): 46 | self.blockSize = bs 47 | self.lbasPerPage = self.pageSize / bs 48 | self.lbaToLpnFactor = bs / (self.pageSize+0.0) 49 | self.pagesPerLBA = bs / self.pageSize 50 | if bs > self.pageSize: 51 | pass#raise Exception("FTLBlockDevice lba-size > pageSize not handled") 52 | 53 | def readBlock(self, blockNum): 54 | #if (self.lbaoffset + blockNum / self.lbasPerPage) > self.last_lba: 55 | # print "readBlock past last lba", blockNum 56 | # print "readBlock past last lba", blockNum 57 | # return "\x00" * self.blockSize 58 | lpn = int(self.lbaoffset + blockNum * self.lbaToLpnFactor) 59 | d = self.nand.readLPN(lpn, self.key) 60 | for i in xrange(1, self.pagesPerLBA): 61 | d += self.nand.readLPN(lpn + i, self.key) 62 | if self.lbasPerPage: 63 | zz = blockNum % self.lbasPerPage 64 | return d[zz*self.blockSize:(zz+1)*self.blockSize] 65 | return d 66 | 67 | def write(self, offset, data): 68 | raise Exception("FTLBlockDevice write method not implemented") 69 | 70 | def writeBlock(self, lba, block): 71 | raise Exception("FTLBlockDevice writeBlock method not implemented") 72 | 73 | def dumpToFile(self, outputfilename): 74 | hs = sizeof_fmt((self.last_lba - self.lbaoffset) * self.pageSize) 75 | print "Dumping partition to %s (%s)" % (outputfilename, hs) 76 | flags = os.O_CREAT | os.O_RDWR 77 | if sys.platform == "win32": 78 | flags |= os.O_BINARY 79 | fd=os.open(outputfilename, flags) 80 | 81 | pbar = ProgressBar(self.last_lba - self.lbaoffset - 1) 82 | pbar.start() 83 | for i in xrange(self.lbaoffset, self.last_lba): 84 | pbar.update(i-self.lbaoffset) 85 | d = self.nand.readLPN(i, self.key) 86 | if i == self.lbaoffset and d[0x400:0x402] != "HX": 87 | print "FAIL? Not HFS partition or wrong key" 88 | os.write(fd, d) 89 | pbar.finish() 90 | os.close(fd) 91 | 92 | class IMG3BlockDevice(object): 93 | def __init__(self, filename, key, iv, write=False): 94 | flag = os.O_RDONLY if not write else os.O_RDWR 95 | if sys.platform == 'win32': 96 | flag = flag | os.O_BINARY 97 | self.filename = filename 98 | self.fd = os.open(filename, flag) 99 | self.writeFlag = write 100 | d = os.read(self.fd, 8192) 101 | if d[:4] != "3gmI": 102 | raise Exception("IMG3BlockDevice bad magic %s" % d[:4]) 103 | if d[0x34:0x38] != "ATAD": 104 | raise Exception("Fu") 105 | self.encrypted = True 106 | self.key = key 107 | self.iv0 = iv 108 | self.offset = 0x40 109 | self.size = os.path.getsize(filename) 110 | self.setBlockSize(8192) 111 | 112 | def setBlockSize(self, bs): 113 | self.blockSize = bs 114 | self.nBlocks = self.size / bs 115 | self.ivs = {0: self.iv0} 116 | 117 | def getIVforBlock(self, blockNum): 118 | #read last 16 bytes of previous block to get IV 119 | if not self.ivs.has_key(blockNum): 120 | os.lseek(self.fd, self.offset + self.blockSize * blockNum - 16, os.SEEK_SET) 121 | self.ivs[blockNum] = os.read(self.fd, 16) 122 | return self.ivs[blockNum] 123 | 124 | def readBlock(self, blockNum): 125 | os.lseek(self.fd, self.offset + self.blockSize * blockNum, os.SEEK_SET) 126 | data = os.read(self.fd, self.blockSize) 127 | if self.encrypted: 128 | data = AESdecryptCBC(data, self.key, self.getIVforBlock(blockNum)) 129 | return data 130 | 131 | def _write(self, offset, data): 132 | if self.writeFlag: #fail silently for testing 133 | os.lseek(self.fd, self.offset + offset, os.SEEK_SET) 134 | return os.write(self.fd, data) 135 | 136 | def writeBlock(self, lba, data): 137 | if self.encrypted: 138 | data = AESencryptCBC(data, self.key, self.getIVforBlock(lba)) 139 | return self._write(lba*self.blockSize, data) 140 | -------------------------------------------------------------------------------- /python_scripts/util/bruteforce.py: -------------------------------------------------------------------------------- 1 | from keystore.keybag import Keybag 2 | from keystore.effaceable import EffaceableLockers 3 | from util.ramdiskclient import RamdiskToolClient 4 | import plistlib 5 | 6 | COMPLEXITY={ 7 | 0: "4 digits", 8 | 1: "n digits", 9 | 2: "n alphanum" 10 | } 11 | 12 | def checkPasscodeComplexity(data_volume): 13 | pl = data_volume.readFile("/mobile/Library/ConfigurationProfiles/UserSettings.plist", returnString=True) 14 | if not pl: 15 | print "Failed to read UserSettings.plist, assuming simple passcode" 16 | return 0 17 | pl = plistlib.readPlistFromString(pl) 18 | #print "passcodeKeyboardComplexity :", pl["restrictedValue"]["passcodeKeyboardComplexity"] 19 | value = pl["restrictedValue"]["passcodeKeyboardComplexity"]["value"] 20 | print "passcodeKeyboardComplexity %d => %s" % (value, COMPLEXITY.get(value)) 21 | return pl["restrictedValue"]["passcodeKeyboardComplexity"]["value"] 22 | 23 | def loadKeybagFromVolume(volume, device_infos): 24 | systembag = volume.readFile("/keybags/systembag.kb", returnString=True) 25 | if not systembag or not systembag.startswith("bplist"): 26 | print "FAIL: could not read /keybags/systembag.kb from data partition" 27 | return False 28 | lockers = EffaceableLockers(device_infos["lockers"].data) 29 | bag1key = lockers.get("BAG1")[-32:] 30 | keybag = Keybag.createWithSystemkbfile(systembag, bag1key, device_infos.get("key835", "").decode("hex")) 31 | keybag.setDKey(device_infos) 32 | if device_infos.has_key("passcodeKey"): 33 | keybag.unlockWithPasscodeKey(device_infos.get("passcodeKey").decode("hex")) 34 | return keybag 35 | 36 | def bruteforcePasscode(device_infos, data_volume): 37 | if device_infos.has_key("passcode"): 38 | print "Passcode already found, no bruteforce required" 39 | return False 40 | kb = data_volume.keybag 41 | if not kb: 42 | return False 43 | 44 | rd = RamdiskToolClient.get() 45 | if rd.device_infos.udid != device_infos.udid: 46 | print "Wrong device connected" 47 | return 48 | 49 | print "Enter passcode or leave blank for bruteforce:" 50 | z = raw_input() 51 | bf = rd.getPasscodeKey(kb.KeyBagKeys, z) 52 | if kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")): 53 | print "Passcode \"%s\" OK" % z 54 | else: 55 | if z != "": 56 | print "Wrong passcode, trying to bruteforce !" 57 | if checkPasscodeComplexity(data_volume) != 0: 58 | print "Complex passcode used, not bruteforcing" 59 | return False 60 | 61 | bf = rd.bruteforceKeyBag(kb.KeyBagKeys) 62 | if bf and kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")): 63 | print "Bruteforce successful, passcode : %s" % bf["passcode"] 64 | print "Passcode key : %s" % bf.get("passcodeKey") 65 | if kb.unlocked: 66 | device_infos.update(bf) 67 | device_infos["classKeys"] = kb.getClearClassKeysDict() 68 | device_infos["KeyBagKeys"] = plistlib.Data(kb.KeyBagKeys) 69 | return True 70 | return False 71 | -------------------------------------------------------------------------------- /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) 11 | 12 | def CERT_DER_to_PEM(data): 13 | a = ["-----BEGIN CERTIFICATE-----"] 14 | a.extend(chunks(base64.b64encode(data),64)) 15 | a.append("-----END CERTIFICATE-----") 16 | return "\n".join(a) -------------------------------------------------------------------------------- /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/util/ramdiskclient.py: -------------------------------------------------------------------------------- 1 | import plistlib 2 | import struct 3 | import socket 4 | from datetime import datetime 5 | from progressbar import ProgressBar, Percentage, Bar, SimpleProgress, ETA 6 | from usbmux import usbmux 7 | from util import sizeof_fmt 8 | 9 | kIOAESAcceleratorEncrypt = 0 10 | kIOAESAcceleratorDecrypt = 1 11 | 12 | kIOAESAcceleratorGIDMask = 0x3E8 13 | kIOAESAcceleratorUIDMask = 0x7D0 14 | 15 | 16 | class DeviceInfo(dict): 17 | @staticmethod 18 | def create(dict): 19 | try: 20 | assert dict.has_key("dataVolumeUUID") 21 | filename = "%s.plist" % dict.get("dataVolumeUUID") 22 | return DeviceInfo(plistlib.readPlist(filename)) 23 | except: 24 | return DeviceInfo(dict) 25 | 26 | def save(self): 27 | filename = "%s.plist" % self.get("dataVolumeUUID", "unk") 28 | plistlib.writePlist(self, filename) 29 | 30 | #stop doing magic stuff 31 | #def __del__(self): 32 | # self.save() 33 | 34 | class RamdiskToolClient(object): 35 | instance = None 36 | @staticmethod 37 | def get(): 38 | if not RamdiskToolClient.instance: 39 | RamdiskToolClient.instance = RamdiskToolClient() 40 | return RamdiskToolClient.instance 41 | 42 | def __init__(self, udid=None, host="localhost", port=1999): 43 | self.host = host 44 | self.port = port 45 | self.device_infos = {} 46 | self.s = None 47 | self.connect(udid) 48 | self.getDeviceInfos() 49 | 50 | def close(self): 51 | if self.s: 52 | self.s.close() 53 | self.s = None 54 | 55 | def connect(self, udid=None): 56 | mux = usbmux.USBMux() 57 | mux.process(1.0) 58 | if not mux.devices: 59 | print "Waiting for iOS device" 60 | while not mux.devices: 61 | mux.process(1.0) 62 | if not mux.devices: 63 | print "No device found" 64 | return 65 | dev = mux.devices[0] 66 | print "Connecting to device : " + dev.serial 67 | try: 68 | self.s = mux.connect(dev, self.port) 69 | except: 70 | raise Exception("Connexion to device port %d failed" % self.port) 71 | 72 | def getDeviceInfos(self): 73 | self.device_infos = self.send_req({"Request":"DeviceInfo"}) 74 | keys = self.grabDeviceKeys() 75 | if keys: 76 | self.device_infos.update(keys) 77 | return DeviceInfo.create(self.device_infos) 78 | 79 | def downloadFile(self, path): 80 | res = self.send_req({"Request": "DownloadFile", 81 | "Path": path}) 82 | if type(res) == plistlib._InternalDict and res.has_key("Data"): 83 | return res["Data"].data 84 | 85 | def getSystemKeyBag(self): 86 | return self.send_req({"Request":"GetSystemKeyBag"}) 87 | 88 | def bruteforceKeyBag(self, KeyBagKeys): 89 | return self.send_req({"Request":"BruteforceSystemKeyBag", 90 | "KeyBagKeys": plistlib.Data(KeyBagKeys)}) 91 | 92 | def getEscrowRecord(self, hostID): 93 | return self.send_req({"Request":"GetEscrowRecord", 94 | "HostID": hostID}) 95 | 96 | def getPasscodeKey(self, keybagkeys, passcode): 97 | return self.send_req({"Request":"KeyBagGetPasscodeKey", 98 | "KeyBagKeys": plistlib.Data(keybagkeys), 99 | "passcode": passcode}) 100 | 101 | def send_msg(self, dict): 102 | plist = plistlib.writePlistToString(dict) 103 | data = struct.pack("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/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 | -------------------------------------------------------------------------------- /ramdisk_tools/AppleEffaceableStorage.c: -------------------------------------------------------------------------------- 1 | #include 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/IOAESAccelerator.c: -------------------------------------------------------------------------------- 1 | /** 2 | https://github.com/planetbeing/xpwn/blob/master/crypto/aes.c 3 | **/ 4 | #include 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 | //see com.apple.driver.AppleCDMA 18 | typedef struct 19 | { 20 | uint32_t key_id; 21 | uint32_t hw_key_id; 22 | uint8_t nonce_to_encrypt_with_hw_key[16]; 23 | uint8_t* value; 24 | } device_key_descriptor; 25 | 26 | #define NUM_DEVICE_KEYS 4 27 | device_key_descriptor ios_device_keys[NUM_DEVICE_KEYS]= { 28 | {0x835, kIOAESAcceleratorUIDMask, {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, NULL}, 29 | {0x899, kIOAESAcceleratorUIDMask, {0xD1, 0xE8, 0xFC, 0xB5, 0x39, 0x37, 0xBF, 0x8D, 0xEF, 0xC7, 0x4C, 0xD1, 0xD0, 0xF1, 0xD4, 0xB0}, NULL}, 30 | {0x89B, kIOAESAcceleratorUIDMask, {0x18, 0x3E, 0x99, 0x67, 0x6B, 0xB0, 0x3C, 0x54, 0x6F, 0xA4, 0x68, 0xF5, 0x1C, 0x0C, 0xBD, 0x49}, NULL}, 31 | {0x89A, kIOAESAcceleratorUIDMask, {0xDB, 0x1F, 0x5B, 0x33, 0x60, 0x6C, 0x5F, 0x1C, 0x19, 0x34, 0xAA, 0x66, 0x58, 0x9C, 0x06, 0x61}, NULL}, 32 | }; 33 | 34 | void aes_init() 35 | { 36 | conn = IOKit_getConnect("IOAESAccelerator"); 37 | } 38 | 39 | io_connect_t IOAESAccelerator_getIOconnect() 40 | { 41 | pthread_once(&once_control, aes_init); 42 | return conn; 43 | } 44 | 45 | 46 | int doAES(void* inbuf, void *outbuf, uint32_t size, uint32_t keyMask, void* key, void* iv, int mode, int bits) { 47 | IOReturn ret; 48 | IOAESStruct in; 49 | 50 | pthread_once(&once_control, aes_init); 51 | 52 | in.mode = mode; 53 | in.bits = bits; 54 | in.inbuf = inbuf; 55 | in.outbuf = outbuf; 56 | in.size = size; 57 | in.mask = keyMask; 58 | 59 | memset(in.keybuf, 0, sizeof(in.keybuf)); 60 | 61 | if(key) 62 | memcpy(in.keybuf, key, in.bits / 8); 63 | 64 | if(iv) 65 | memcpy(in.iv, iv, 16); 66 | else 67 | memset(in.iv, 0, 16); 68 | 69 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 70 | if(ret == kIOReturnBadArgument) { 71 | IOAESStructSize = IOAESStruct_sizeold; 72 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 73 | } 74 | 75 | if(iv) 76 | memcpy(iv, in.iv, 16); 77 | 78 | return ret; 79 | } 80 | 81 | IOReturn doAES_wrapper(void* thisxxx, int mode, void* iv, void* outbuf, void *inbuf, uint32_t size, uint32_t keyMask) 82 | { 83 | int x = doAES(inbuf, outbuf, size, keyMask, NULL, iv, mode, 128); 84 | return !x; 85 | } 86 | 87 | int patch_IOAESAccelerator(); 88 | 89 | int AES_UID_Encrypt(void* input2, void* output, size_t len) 90 | { 91 | IOAESStruct in; 92 | IOReturn ret; 93 | static int triedToPatchKernelAlready = 0; 94 | unsigned char* input = valloc(16); 95 | 96 | memcpy(input, input2, 16); 97 | 98 | pthread_once(&once_control, aes_init); 99 | 100 | in.mode = kIOAESAcceleratorEncrypt; 101 | in.mask = kIOAESAcceleratorUIDMask; 102 | in.bits = 128; 103 | in.inbuf = input; 104 | in.outbuf = output; 105 | in.size = len; 106 | 107 | memset(in.keybuf, 0, sizeof(in.keybuf)); 108 | memset(in.iv, 0, 16); 109 | 110 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 111 | if(ret == kIOReturnBadArgument) { 112 | IOAESStructSize = IOAESStruct_sizeold; 113 | ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize); 114 | } 115 | 116 | if(ret == kIOReturnNotPrivileged && !triedToPatchKernelAlready) { 117 | triedToPatchKernelAlready = 1; 118 | fprintf(stderr, "Trying to patch IOAESAccelerator kernel extension to allow UID key usage\n"); 119 | patch_IOAESAccelerator(); 120 | ret = AES_UID_Encrypt(input2, output, len); 121 | } 122 | if(ret != kIOReturnSuccess) { 123 | fprintf(stderr, "IOAESAccelerator returned: %x\n", ret); 124 | } 125 | return ret; 126 | } 127 | 128 | uint8_t* IOAES_get_device_key(uint32_t id) 129 | { 130 | static uint8_t nullkey[16] = {0}; 131 | int i; 132 | for(i=0; i < NUM_DEVICE_KEYS; i++) 133 | { 134 | if (ios_device_keys[i].key_id != id) 135 | continue; 136 | if (ios_device_keys[i].value != NULL) 137 | return ios_device_keys[i].value; 138 | 139 | ios_device_keys[i].value = (uint8_t*) valloc(16); //on ARMv6 devices stuff needs to be aligned 140 | memcpy(ios_device_keys[i].value, ios_device_keys[i].nonce_to_encrypt_with_hw_key, 16); 141 | AES_UID_Encrypt(ios_device_keys[i].value, ios_device_keys[i].value, 16); 142 | return ios_device_keys[i].value; 143 | } 144 | return nullkey; 145 | 146 | } 147 | uint8_t* IOAES_key835() 148 | { 149 | return IOAES_get_device_key(0x835); 150 | } 151 | 152 | uint8_t* IOAES_key89B() 153 | { 154 | return IOAES_get_device_key(0x89B); 155 | } 156 | 157 | uint8_t* IOAES_key89A() 158 | { 159 | return IOAES_get_device_key(0x89A); 160 | } -------------------------------------------------------------------------------- /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_key89A(); 35 | uint8_t* IOAES_key89B(); 36 | 37 | -------------------------------------------------------------------------------- /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/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); -------------------------------------------------------------------------------- /ramdisk_tools/Makefile: -------------------------------------------------------------------------------- 1 | SDKVER?=5.1 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 | HGVERSION:= $(shell hg parents --template '{node|short}' || echo "unknown") 5 | CFLAGS=-Wall -isysroot $(SDK) -DHGVERSION="\"${HGVERSION}\"" 6 | CFLAGS_IOKIT=$(CFLAGS) -framework IOKit -framework CoreFoundation -framework Security -O3 -I. 7 | 8 | all: IOKit IOUSBDeviceControllerLib.h device_infos restored_external bruteforce ioflashstoragekit 9 | 10 | IOUSBDeviceControllerLib.h: 11 | curl -o IOUSBDeviceControllerLib.h http://www.opensource.apple.com/source/IOKitUser/IOKitUser-502/usb_device.subproj/IOUSBDeviceControllerLib.h?txt 12 | 13 | IOKit: 14 | ln -s /System/Library/Frameworks/IOKit.framework/Versions/Current/Headers IOKit 15 | 16 | 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 ioflash/ioflash.c kernel_patcher.c 17 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 18 | ldid -Stfp0.plist $@ 19 | 20 | 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 ioflash/ioflash.c kernel_patcher.c 21 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 22 | ldid -Skeystore_device.xml $@ 23 | 24 | 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 ioflash/ioflash.c kernel_patcher.c 25 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 26 | ldid -Skeystore_device.xml $@ 27 | 28 | ioflashstoragekit: ioflash/ioflash.c ioflash/ioflash_kernel.c ioflash/ioflashstoragekit.c util.c 29 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 30 | ldid -Stfp0.plist $@ 31 | 32 | kernel_patcher: kernel_patcher.c 33 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 34 | ldid -Stfp0.plist $@ 35 | 36 | shsh_dump: ioflash/ioflash.c ioflash/ioflash_kernel.c shsh_dump.c util.c 37 | $(CC) $(CFLAGS_IOKIT) -o $@ $^ 38 | ldid -Stfp0.plist $@ 39 | 40 | clean: 41 | rm -f bruteforce restored_external device_infos ioflashstoragekit shsh_dump 42 | 43 | rebuild: clean all 44 | -------------------------------------------------------------------------------- /ramdisk_tools/bsdcrypto/key_wrap.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: key_wrap.c,v 1.3 2011/01/11 15:42:05 deraadt 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 | * 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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 "device_info.h" 10 | #include "registry.h" 11 | #include "util.h" 12 | #include "ioflash/ioflash.h" 13 | 14 | uint8_t lockers[960]={0}; 15 | uint8_t lwvm[80]={0}; 16 | 17 | CFDictionaryRef device_info(int socket, CFDictionaryRef request) 18 | { 19 | uint8_t dkey[40]={0}; 20 | uint8_t emf[36]={0}; 21 | size_t bootargs_len = 255; 22 | char bootargs[256]={0}; 23 | 24 | struct HFSInfos hfsinfos={0}; 25 | 26 | CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 27 | 0, 28 | &kCFTypeDictionaryKeyCallBacks, 29 | &kCFTypeDictionaryValueCallBacks); 30 | 31 | get_device_infos(out); 32 | 33 | CFMutableDictionaryRef nand = FSDGetInfo(0); 34 | if (nand != NULL) 35 | CFDictionaryAddValue(out, CFSTR("nand"), nand); 36 | 37 | getHFSInfos(&hfsinfos); 38 | 39 | uint8_t* key835 = IOAES_key835(); 40 | uint8_t* key89A = IOAES_key89A(); 41 | uint8_t* key89B = IOAES_key89B(); 42 | 43 | if (!AppleEffaceableStorage__getBytes(lockers, 960)) 44 | { 45 | CFDataRef lockersData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, lockers, 960, kCFAllocatorNull); 46 | CFDictionaryAddValue(out, CFSTR("lockers"), lockersData); 47 | CFRelease(lockersData); 48 | 49 | if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_DKEY, lockers, 960, dkey, 40)) 50 | { 51 | aes_key_wrap_ctx ctx; 52 | 53 | aes_key_wrap_set_key(&ctx, key835, 16); 54 | 55 | if(aes_key_unwrap(&ctx, dkey, dkey, 32/8)) 56 | printf("FAIL unwrapping DKey with key 0x835\n"); 57 | } 58 | if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_EMF, lockers, 960, emf, 36)) 59 | { 60 | doAES(&emf[4], &emf[4], 32, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128); 61 | } 62 | else if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_LWVM, lockers, 960, lwvm, 0x50)) 63 | { 64 | doAES(lwvm, lwvm, 0x50, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128); 65 | memcpy(&emf[4], &lwvm[32+16], 32); 66 | } 67 | } 68 | 69 | CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &hfsinfos.dataVolumeOffset); 70 | CFDictionaryAddValue(out, CFSTR("dataVolumeOffset"), n); 71 | CFRelease(n); 72 | addHexaString(out, CFSTR("dataVolumeUUID"), (uint8_t*) &hfsinfos.volumeUUID, 8); 73 | addHexaString(out, CFSTR("key835"), key835, 16); 74 | addHexaString(out, CFSTR("key89A"), key89A, 16); 75 | addHexaString(out, CFSTR("key89B"), key89B, 16); 76 | addHexaString(out, CFSTR("EMF"), &emf[4], 32); 77 | addHexaString(out, CFSTR("DKey"), dkey, 32); 78 | 79 | sysctlbyname("kern.bootargs", bootargs, &bootargs_len, NULL, 0); 80 | if (bootargs_len > 1) 81 | { 82 | CFStringRef bootargsString = CFStringCreateWithBytes(kCFAllocatorDefault, bootargs, bootargs_len - 1, kCFStringEncodingASCII, 0); 83 | CFDictionaryAddValue(out, CFSTR("kern.bootargs"), bootargsString); 84 | CFRelease(bootargsString); 85 | } 86 | 87 | CFDictionaryAddValue(out, CFSTR("ramdisk revision"), CFSTR(HGVERSION)); 88 | CFDictionaryAddValue(out, CFSTR("ramdisk compile time"), CFSTR(__DATE__ " " __TIME__ )); 89 | 90 | return out; 91 | } 92 | -------------------------------------------------------------------------------- /ramdisk_tools/device_info.h: -------------------------------------------------------------------------------- 1 | #ifndef HGVERSION 2 | #define HGVERSION "unknown" 3 | #endif 4 | 5 | CFDictionaryRef device_info(int socket, CFDictionaryRef request); 6 | -------------------------------------------------------------------------------- /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 | writePlistToStdout(out); 34 | /*CFStringRef plistFileName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@.plist"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID"))); 35 | 36 | CFStringRef printString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Writing results to %@\n"), plistFileName); 37 | CFShow(printString); 38 | CFRelease(printString); 39 | 40 | saveResults(plistFileName, out); 41 | CFRelease(plistFileName);*/ 42 | CFRelease(out); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /ramdisk_tools/dump_data_partition.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat /dev/rdisk0s2s1 | netcat -l -p 1234 4 | -------------------------------------------------------------------------------- /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/image.h: -------------------------------------------------------------------------------- 1 | int drawImage(const char* pngFileName); 2 | -------------------------------------------------------------------------------- /ramdisk_tools/ioflash/ioflash.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define kIOFlashStorageOptionBootPageIO 0x100 4 | #define kIOFlashStorageOptionRawPageIO 0x002 5 | #define kIOFlashStorageOptionXXXX 0x004 6 | //0xC0 == kIOFlashStorageOptionUseAES | kIOFlashStorageOptionHomogenize 7 | 8 | #define kIOFlashControllerReadPage 0x1 9 | #define kIOFlashControllerWritePage 0x2 10 | #define kIOFlashControllerDisableKeepout 0xa 11 | 12 | 13 | struct kIOFlashControllerReadPageIn; 14 | struct kIOFlashControllerOut; 15 | 16 | //from ioflashstoragetool 17 | CFMutableDictionaryRef MakeOneStringProp(CFStringRef key, CFStringRef value); 18 | io_service_t _wait_for_io_service_matching_dict(CFDictionaryRef matching); 19 | int FSDConnect(const char* name); 20 | int FSDGetPropertyForKey(io_object_t obj, CFStringRef name, void* out, uint32_t outLen, CFMutableDictionaryRef dict); 21 | void findPartitionLocation(CFStringRef contentHint, CFMutableDictionaryRef dict);//findNvramLocation 22 | IOReturn FSDReadPageHelper(struct kIOFlashControllerReadPageIn* in, struct kIOFlashControllerOut* out); 23 | IOReturn FSDReadPageWithOptions(uint32_t ceNum, uint32_t pageNum, void* buffer, void* spareBuffer, uint32_t spareSize, uint32_t options, struct kIOFlashControllerOut* out); 24 | IOReturn FSDReadBootPage(uint32_t ceNum, uint32_t pageNum,uint32_t* buffer, struct kIOFlashControllerOut* out); 25 | 26 | CFMutableDictionaryRef FSDGetInfo(int); 27 | int IOFlashStorage_kernel_patch(); 28 | 29 | CFDictionaryRef nand_dump(int fd); 30 | int dump_nand_to_socket(int fd); 31 | int nand_proxy(int fd); 32 | 33 | struct kIOFlashControllerReadPageIn 34 | { 35 | uint32_t page; 36 | uint32_t ce; 37 | uint32_t options; 38 | void* buffer; 39 | uint32_t bufferSize; 40 | void* spare; 41 | uint32_t spareSize; 42 | };//sizeof = 0x1C 43 | 44 | //sizeof=0x8 45 | struct kIOFlashControllerOut 46 | { 47 | uint32_t ret1; 48 | uint32_t ret2; 49 | }; 50 | 51 | //sizeof=0x50 AppleIOPFMIDMACommand? 52 | struct IOFlashCommandStruct 53 | { 54 | uint32_t flags0; 55 | uint32_t flags1; 56 | uint32_t field8; 57 | uint32_t fieldC; 58 | uint32_t* page_ptr; 59 | void* bufferDesc;//IOMemoryDescriptor* 60 | uint32_t field18; 61 | uint32_t field1C; 62 | uint32_t field20; 63 | uint32_t* ce_ptr; 64 | void* spareVA; 65 | uint32_t spareSize; 66 | uint32_t field30; 67 | uint32_t field34; 68 | uint32_t field38; 69 | uint32_t errorCode; 70 | uint32_t field40; 71 | uint32_t field44; 72 | uint32_t field48; 73 | uint32_t field4C; 74 | }; 75 | 76 | typedef struct IOExternalMethodArguments 77 | { 78 | uint32_t version; 79 | 80 | uint32_t selector; 81 | 82 | mach_port_t asyncWakePort; 83 | io_user_reference_t * asyncReference; 84 | uint32_t asyncReferenceCount; 85 | 86 | const uint64_t * scalarInput; 87 | uint32_t scalarInputCount; 88 | 89 | const void * structureInput; 90 | uint32_t structureInputSize; 91 | 92 | //IOMemoryDescriptor * structureInputDescriptor; 93 | void * structureInputDescriptor; 94 | 95 | uint64_t * scalarOutput; 96 | uint32_t scalarOutputCount; 97 | 98 | void * structureOutput; 99 | uint32_t structureOutputSize; 100 | 101 | void * structureOutputDescriptor; 102 | uint32_t structureOutputDescriptorSize; 103 | 104 | uint32_t __reservedA; 105 | 106 | //OSObject ** structureVariableOutputData; 107 | void ** structureVariableOutputData; 108 | 109 | uint32_t __reserved[30]; 110 | } IOExternalMethodArguments; 111 | 112 | typedef struct proxy_read_cmd 113 | { 114 | uint32_t ce; 115 | uint32_t page; 116 | uint32_t spareSize; 117 | uint32_t options; 118 | } proxy_read_cmd; 119 | -------------------------------------------------------------------------------- /ramdisk_tools/ioflash/ioflashstoragekit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ioflash.h" 5 | #include "../util.h" 6 | 7 | #define LISTEN_PORT 2000 8 | 9 | #define CMD_DUMP 0 10 | #define CMD_PROXY 1 11 | 12 | int main(int argc, char* argv[]) 13 | { 14 | int one=1; 15 | int cmd=0; 16 | 17 | if(!IOFlashStorage_kernel_patch()) 18 | return -1; 19 | 20 | CFMutableDictionaryRef dict = FSDGetInfo(1); 21 | if(dict == NULL) 22 | { 23 | fprintf(stderr, "FAILed to get NAND infos"); 24 | return -1; 25 | } 26 | 27 | check_special_pages(); 28 | 29 | int sl = create_listening_socket(LISTEN_PORT); 30 | if(sl == -1) 31 | { 32 | fprintf(stderr, "Error calling create_listening_socket\n"); 33 | return -1; 34 | } 35 | 36 | fprintf(stderr, "NAND dumper listening on port %d\n", LISTEN_PORT); 37 | 38 | while(1) 39 | { 40 | int s = accept(sl, NULL, NULL); 41 | setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(int)); 42 | 43 | int r = read(s, (void*) &cmd, sizeof(int)); 44 | if(r == sizeof(int)) 45 | { 46 | if(cmd == CMD_DUMP) 47 | { 48 | nand_dump(s); 49 | } 50 | else if(cmd == CMD_PROXY) 51 | { 52 | nand_proxy(s); 53 | } 54 | } 55 | shutdown(s, SHUT_RDWR); 56 | close(s); 57 | } 58 | return 0; 59 | } -------------------------------------------------------------------------------- /ramdisk_tools/kernel_patcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | mach_port_t kernel_task=0; 9 | 10 | kern_return_t write_kernel(mach_port_t p, void* addr, uint32_t value) 11 | { 12 | pointer_t buf; 13 | unsigned int sz; 14 | 15 | kern_return_t r = vm_write(p, (vm_address_t)addr, (vm_address_t)&value, sizeof(value)); 16 | if (r) 17 | { 18 | fprintf(stderr, "vm_write into kernel_task failed\n"); 19 | } 20 | else 21 | { 22 | //fix cache issue 23 | vm_read(p, (vm_address_t) addr, sizeof(value), &buf, &sz); 24 | fprintf(stderr, "vm_write into kernel_task OK %x\n", *((uint32_t*) buf)); 25 | } 26 | return r; 27 | } 28 | 29 | int patch_IOAESAccelerator() 30 | { 31 | kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task); 32 | 33 | if( r != 0) 34 | { 35 | fprintf(stderr, "task_for_pid returned %x : missing tfp0 kernel patch or wrong entitlements\n", r); 36 | return 0; 37 | } 38 | uint32_t i; 39 | pointer_t buf; 40 | unsigned int sz; 41 | 42 | vm_address_t addr = 0x80002000; 43 | 44 | while( addr < (0x80002000 + 0xA00000)) 45 | { 46 | vm_read(kernel_task, addr, 2048, &buf, &sz); 47 | if( buf == NULL || sz == 0) 48 | continue; 49 | uint8_t* p = (uint8_t*) buf; 50 | 51 | for(i=0; i < sz; i++) 52 | { 53 | //"IOAESAccelerator enable UID" : (h("67 D0 40 F6"), h("00 20 40 F6")), 54 | if (*((uint32_t*)&p[i]) == 0xF640d067) 55 | { 56 | fprintf(stderr, "Found IOAESAccelerator UID ptr at %x, patching kernel\n", (uint32_t) addr + i); 57 | write_kernel(kernel_task, (void*) (addr + i), (uint32_t) 0xF6402000); 58 | return 0; 59 | } 60 | } 61 | addr += 2048; 62 | } 63 | fprintf(stderr, "IOAESAccelerator Kernel patching failed\n"); 64 | return -1; 65 | } 66 | 67 | /* 68 | int main(int argc, char** argv) 69 | { 70 | return patch_IOAESAccelerator(); 71 | } 72 | */ -------------------------------------------------------------------------------- /ramdisk_tools/keychain_dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbhinavBansal/iOS-DataProtection-ToolKit/25ba659b4613e573126443f73734b01af136a392/ramdisk_tools/keychain_dump -------------------------------------------------------------------------------- /ramdisk_tools/keystore_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.keystore.device 6 | 7 | get-task-allow 8 | 9 | run-unsigned-code 10 | 11 | task_for_pid-allow 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /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 | #include "util.h" 10 | 11 | #define TCP_PORT 1999 12 | 13 | int send_progress_message(int socket, int progress, int total) 14 | { 15 | const void* keys[3] = {CFSTR("MessageType"), CFSTR("Progress"), CFSTR("Total")}; 16 | const void* values[3] = {CFSTR("Progress"), NULL, NULL}; 17 | 18 | CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &progress); 19 | CFNumberRef number2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &total); 20 | values[1] = number; 21 | values[2] = number2; 22 | CFDictionaryRef msg = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 23 | CFRelease(number); 24 | CFRelease(number2); 25 | int res = send_object(socket, msg); 26 | CFRelease(msg); 27 | return res; 28 | } 29 | 30 | int send_object(int socket, CFTypeRef obj) 31 | { 32 | uint32_t len = 0; 33 | int res = -1; 34 | 35 | if(obj == NULL) 36 | return res; 37 | 38 | CFDataRef outdata = CFPropertyListCreateData(kCFAllocatorDefault, obj, kCFPropertyListXMLFormat_v1_0, 0, NULL); 39 | if (outdata != NULL) 40 | { 41 | len = CFDataGetLength(outdata); 42 | write(socket, &len, 4); 43 | res = write(socket, CFDataGetBytePtr(outdata), CFDataGetLength(outdata)); 44 | CFRelease(outdata); 45 | } 46 | return res; 47 | } 48 | 49 | int handle_client(int socket, CFDictionaryRef handlers) 50 | { 51 | uint32_t len=0; 52 | uint32_t received,i; 53 | CFDataRef data; 54 | CFDictionaryRef plist; 55 | CFTypeRef out = NULL; 56 | uint8_t* buffer; 57 | CFTypeRef (*handler)(int, CFDictionaryRef dict) = NULL; 58 | 59 | while(1) 60 | { 61 | if(recv(socket, &len, 4, 0) != 4) 62 | break; 63 | //printf("len=%x\n", len); 64 | 65 | if (len > PLIST_MAX_SIZE) 66 | break; 67 | 68 | buffer = malloc(len); 69 | 70 | if(buffer == NULL) 71 | break; 72 | 73 | for(i=0; i < len; ) 74 | { 75 | received = recv(socket, &buffer[i], len - i, 0); 76 | if (received == -1) 77 | break; 78 | i += received; 79 | } 80 | 81 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, len, kCFAllocatorNull); 82 | 83 | if(data == NULL) 84 | { 85 | free(buffer); 86 | continue; 87 | } 88 | 89 | plist = (CFDictionaryRef) CFPropertyListCreateWithData (kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL); 90 | 91 | if(plist == NULL || CFGetTypeID(plist) != CFDictionaryGetTypeID()) 92 | { 93 | CFRelease(data); 94 | free(buffer); 95 | send_object(socket, CFSTR("invalid XML plist dictionary")); 96 | continue; 97 | } 98 | 99 | if (CFDictionaryContainsKey(plist, CFSTR("Request"))) 100 | { 101 | CFStringRef request = CFDictionaryGetValue(plist, CFSTR("Request")); 102 | 103 | handler = CFDictionaryGetValue(handlers, request); 104 | 105 | if (handler != NULL) 106 | { 107 | out = handler(socket, plist); 108 | if (out == NULL) 109 | out = CFSTR("Request did not return any result"); 110 | } 111 | else 112 | { 113 | out = CFSTR("No handler defined for Request"); 114 | } 115 | } 116 | else 117 | { 118 | out = CFSTR("request dictionary needs to contain Request key"); 119 | } 120 | 121 | if(out == NULL) 122 | out = CFSTR("no response"); 123 | 124 | send_object(socket, out); 125 | CFRelease(out); 126 | 127 | CFRelease(plist); 128 | CFRelease(data); 129 | free(buffer); 130 | } 131 | send_object(socket, CFSTR("kthxbye")); 132 | return 0; 133 | } 134 | 135 | void serve_plist_rpc(int port, CFDictionaryRef handlers) 136 | { 137 | int quit = 0; 138 | int one=1; 139 | printf("plist_rpc: listening on port %d\n", port); 140 | int sl = create_listening_socket(port); 141 | 142 | while(!quit) 143 | { 144 | int s = accept(sl, NULL, NULL); 145 | setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(int)); 146 | 147 | handle_client(s, handlers); 148 | shutdown(s, SHUT_RDWR); 149 | close(s); 150 | } 151 | close(sl); 152 | } 153 | 154 | CFStringRef testHandler(int s, CFDictionaryRef dict) 155 | { 156 | printf("lol\n"); 157 | return CFSTR("Hello, World!"); 158 | } 159 | 160 | -------------------------------------------------------------------------------- /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/registry.h: -------------------------------------------------------------------------------- 1 | void get_device_infos(CFMutableDictionaryRef out); -------------------------------------------------------------------------------- /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 | CFDictionaryRef remote_aes(int socket, CFDictionaryRef dict); 8 | -------------------------------------------------------------------------------- /ramdisk_tools/scripts/mount_partitions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -a /dev/disk0s1s2 ]; then # test for iOS 5 data partition 4 | mount_hfs /dev/disk0s1s1 /mnt1 2>/dev/null 5 | mount_hfs /dev/disk0s1s2 /mnt2 2>/dev/null 6 | elif [ -a /dev/disk0s2s1 ]; then # test for iOS 4 data partition 7 | mount_hfs /dev/disk0s1 /mnt1 2>/dev/null 8 | mount_hfs /dev/disk0s2s1 /mnt2 2>/dev/null 9 | elif [ -a /dev/disk0s2 ]; then 10 | mount_hfs /dev/disk0s1 /mnt1 2>/dev/null 11 | mount_hfs /dev/disk0s2 /mnt2 2>/dev/null 12 | else 13 | echo "Error mounting partitions. Please try it manually" 14 | fi -------------------------------------------------------------------------------- /ramdisk_tools/shsh_dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | #include 6 | #include 7 | #include 8 | #include "ioflash/ioflash.h" 9 | #include "util.h" 10 | 11 | struct IMG2 12 | { 13 | uint32_t magic; 14 | uint32_t block_size; 15 | uint32_t images_offset; 16 | uint32_t images_block; 17 | uint32_t images_length; 18 | uint8_t padding[0x1c]; 19 | uint32_t crc32; 20 | }; 21 | 22 | struct IMG3 23 | { 24 | uint32_t magic; 25 | uint32_t fullSize; 26 | uint32_t sizeNoPack; 27 | uint32_t sigCheckArea; 28 | uint32_t iden; 29 | }; 30 | 31 | struct IMG3_TLV 32 | { 33 | uint32_t tag; 34 | uint32_t total_length; 35 | uint32_t data_length; 36 | uint8_t payload[1]; 37 | }; 38 | 39 | void printIMG2(struct IMG2* s) 40 | { 41 | printf("magic= %x\n", s->magic); 42 | printf("block_size= %x\n", s->block_size); 43 | printf("images_offset= %x\n", s->images_offset); 44 | printf("images_block= %x\n", s->images_block); 45 | printf("images_length= %x\n", s->images_length); 46 | } 47 | void printIMG3(struct IMG3* s) 48 | { 49 | char iden[10]={0}; 50 | memcpy(iden, &s->iden, 4); 51 | printf("magic= %x\n", s->magic); 52 | printf("fullSize= %x\n", s->fullSize); 53 | printf("iden= %s\n", iden); 54 | } 55 | 56 | CFDataRef getIMG3Data(struct IMG3* img3) 57 | { 58 | CFDataRef data = NULL; 59 | uint8_t* p = (uint8_t*) img3; 60 | uint8_t* z = &p[20]; 61 | 62 | if(img3->magic != 'Img3') 63 | return NULL; 64 | 65 | while(z < &p[img3->fullSize]) 66 | { 67 | struct IMG3_TLV* item = (struct IMG3_TLV*) z; 68 | if( item->tag == 'DATA') 69 | { 70 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, item->payload, item->data_length, NULL); 71 | return data; 72 | } 73 | z += item->total_length; 74 | } 75 | return NULL; 76 | } 77 | 78 | 79 | extern uint32_t gPagesPerBlock; 80 | extern uint32_t gBytesPerPage ; 81 | extern uint32_t gBootloaderBytes ; 82 | 83 | int main(int argc, char* argv[]) 84 | { 85 | int one=1; 86 | int cmd=0; 87 | 88 | CFMutableDictionaryRef dict = FSDGetInfo(1); 89 | if (dict == NULL) 90 | { 91 | fprintf(stderr, "FAILed to get NAND infos"); 92 | return -1; 93 | } 94 | if(!IOFlashStorage_kernel_patch()) 95 | return -1; 96 | 97 | struct kIOFlashControllerOut out; 98 | uint32_t bootSize = gBootloaderBytes * gPagesPerBlock * 8; 99 | 100 | printf("Mallocing %x bytes for boot partition\n", bootSize); 101 | uint8_t* boot = malloc(bootSize); 102 | if( boot == NULL) 103 | { 104 | return -1; 105 | } 106 | 107 | uint8_t* buffer = malloc(gBytesPerPage); 108 | if( buffer == NULL) 109 | { 110 | return -1; 111 | } 112 | 113 | uint32_t block, page, off=0; 114 | 115 | for(block=8; block < 16; block++) 116 | { 117 | for(page=0; page < gPagesPerBlock; page++) 118 | { 119 | if(FSDReadBootPage(0, block*gPagesPerBlock + page, buffer, &out)) 120 | { 121 | //printf("FSDReadBootPage error %x\n", block*gPagesPerBlock + page); 122 | //return -1; 123 | } 124 | memcpy(&boot[off], buffer, gBootloaderBytes); 125 | off += gBootloaderBytes; 126 | } 127 | } 128 | 129 | printIMG2((struct IMG2*) boot); 130 | struct IMG2* img2 = (struct IMG2*) boot; 131 | 132 | if( img2->magic != 0x494d4732) 133 | { 134 | printf("Bag IMG2 magic : %x\n", img2->magic); 135 | return -1; 136 | } 137 | uint32_t start = img2->block_size * img2->images_block; 138 | 139 | uint32_t end = start + img2->block_size * img2->images_length; 140 | 141 | if( end < start) 142 | { 143 | return -1; 144 | } 145 | printf("start %x end %x\n", start, end); 146 | uint8_t* p = &boot[start]; 147 | 148 | CFMutableDictionaryRef resultsDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 149 | 150 | if(dict == NULL) 151 | { 152 | return -1; 153 | } 154 | 155 | while(p < &boot[end]) 156 | { 157 | struct IMG3* img3 = (struct IMG3*) p; 158 | if(img3->magic != 'Img3') 159 | break; 160 | printIMG3(img3); 161 | 162 | if(img3->iden == 'SCAB') 163 | { 164 | CFDataRef data = getIMG3Data(img3); 165 | if(data) 166 | { 167 | CFDictionaryAddValue(resultsDict, CFSTR("APTicket"), data); 168 | writePlistToStdout(resultsDict); 169 | CFRelease(data); 170 | } 171 | } 172 | p += img3->fullSize; 173 | 174 | } 175 | return 0; 176 | } -------------------------------------------------------------------------------- /ramdisk_tools/tfp0.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | run-unsigned-code 8 | 9 | task_for_pid-allow 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /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 | void writePlistToStdout(CFDictionaryRef out); 78 | 79 | int mountDataPartition(const char* mountpoint); 80 | 81 | int create_listening_socket(int port); -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------