1#!/bin/bash 2 3############################################################################### 4# kcinstall 5# 6# A script for personalizing and installing kernelcaches and related files to 7# iOS devices. 8# 9# Andrew Myrick, Mike Smith 10# Copyright © 2012,2103 Apple Inc. All rights reserved. 11############################################################################### 12 13EDM="xcrun -sdk iphoneos.internal embedded_device_map" 14MOBDEV=`xcrun -sdk iphoneos.internal -f mobdev` 15PERSONALIZE_IMG4="xcrun -sdk iphoneos.internal personalize_img4" 16TCPRELAY="xcrun -sdk iphoneos.internal tcprelay" 17FSREMOUNT="`dirname $0`/fsremount" 18 19CLEAN_TMP= 20TCPRELAY_OUTPUT= 21TCPRELAY_PID= 22 23kBoardIDKey="BoardId" 24kChipIDKey="ChipID" 25kECIDKey="UniqueChipID" 26 27VERBOSELEVEL=0 28ROOTPASS="alpine" 29KCACHEDST=/System/Library/Caches/com.apple.kernelcaches/kernelcache 30SEPOSDST=/usr/standalone/firmware/sep-firmware.img4 31PTYPE=" -X" 32BOARDID= 33CHIPID= 34ECID= 35LOCATIONID= 36UDID= 37 38function usage() { 39 echo "Usage: `basename $0` [-l location|-d udid] [options] [-S path|-C path] [-k kernelcache|-s sepos|-c file]" 40 echo 41 echo "Device selection:" 42 echo " -l Location ID" 43 echo " -u UDID" 44 echo 45 echo "Options:" 46 echo " -F Force local signing" 47 echo " -h Print this help" 48 echo " -k Kernelcache to install" 49 echo " -s SEP/OS to install" 50 echo " -c arbitrary file to install" 51 echo " -S override SEP/OS install location" 52 echo " -C override SEP/OS install location" 53 echo " -p Root password (default: alpine)" 54 echo " -X Enable user authlisting (default)" 55 echo " -v Enable verbosity (may specify more than once)" 56} 57 58function cleanup() { 59 if [[ $TCPRELAY_PID ]]; then 60 kill $TCPRELAY_PID 61 wait $TCPRELAY_PID 2>/dev/null 62 fi 63 if [ $CLEAN_TMP ]; then 64 rm -rf $TMPDIR 65 fi 66} 67 68trap cleanup EXIT 69exec 9>/dev/null 70 71args=$(getopt Fhk:l:p:s:S:c:C:u:vX $*) 72if [ $? != 0 ]; then 73 usage; exit 1 74fi 75set -- $args 76while [ $# -gt 0 ]; do 77 case $1 in 78 -F) 79 PTYPE=" -F";; 80 -h) 81 usage; exit 0;; 82 -k) 83 KCACHE=$2; shift;; 84 -s) 85 SEPOS=$2; shift;; 86 -S) 87 SEPOSDST=$2; shift;; 88 -c) 89 COPYFILE=$2; shift;; 90 -C) 91 COPYDST=$2; shift;; 92 -l) 93 if [[ $UDID ]]; then 94 echo "Error: -l may not be specified with -u" 95 echo 96 usage; exit 1; 97 fi; 98 LOCATIONID=$2; 99 shift;; 100 -p) 101 ROOTPASS=$2; 102 shift;; 103 -u) 104 if [[ $LOCATIONID ]]; then 105 echo "Error: -u may not be specified with -l" 106 echo 107 usage; exit 1; 108 fi; 109 UDID=$2; 110 shift;; 111 -v) 112 case $VERBOSELEVEL in 113 0) 114 exec 9>&1 115 VERBOSELEVEL=1;; 116 1) 117 set -x 118 VERBOSELEVEL=2;; 119 *) 120 ;; 121 esac;; 122 -X) 123 PTYPE=" -X";; 124 --) 125 if [ $# != 1 ]; then 126 echo "Unrecognized options: $*" 127 usage; exit 1 128 fi 129 ;; 130 *) 131 echo "Unrecognized option: $1" 132 usage; exit 1;; 133 esac 134 shift 135done 136 137# Validate kernelcache and device location 138 139if [[ ( -z $KCACHE && -z $SEPOS && -z $COPYFILE ) ]]; then 140 echo "Error: at least one of -k, -s or -c must be specified." 141 echo 142 usage; exit 1; 143fi 144 145if [[ $LOCATIONID ]]; then 146 mobdev list 2>&1 | grep $LOCATIONID > /dev/null 147 if [ $? -ne 0 ]; then 148 echo "Cannot find device at location $LOCATIONID" 149 exit $? 150 fi 151 MBDEVICE=" -l $LOCATIONID" 152 TRDEVICE=" --locationid $LOCATIONID" 153elif [[ $UDID ]]; then 154 mobdev list 2>&1 | grep $UDID > /dev/null 155 if [ $? -ne 0 ]; then 156 echo "Cannot find device with UDID $UDID" 157 exit $? 158 fi 159 MBDEVICE=" -u $UDID" 160 TRDEVICE=" --serialnumber $UDID" 161fi 162 163TMPDIR=`mktemp -d -t \`basename $0\`` 164if [[ -z $TMPDIR ]]; then 165 echo "Could not create temporary directory" 166 exit 1; 167fi 168CLEAN_TMP=1 169 170# Personalize the kernelcache / SEP/OS if needed 171 172CHIPID=`$MOBDEV $MBDEVICE get NULL $kChipIDKey 2>&1 | awk '/CFNumber/ {print $5}' | sed 's/[+|,]//g'` 173if [[ -z $CHIPID ]]; then 174 echo "Failed to read ChipID from device" 175 exit 1; 176fi 177 178IMAGEFORMAT=`$EDM -query SELECT DISTINCT ImageFormat FROM Targets WHERE ChipID==$CHIPID` 179if [[ $IMAGEFORMAT == 'im4p' ]]; then 180 BOARDID=`$MOBDEV $MBDEVICE get NULL $kBoardIDKey 2>&1 | awk '/CFNumber/ {print $5}' | sed 's/[+|,]//g'` 181 if [[ -z $BOARDID ]]; then 182 echo "Failed to read BoardID from device" 183 exit 1; 184 fi 185 186 ECID=`$MOBDEV $MBDEVICE get NULL $kECIDKey 2>&1 | awk '/ECID in hex/ { print $4}'` 187 if [[ -z $ECID ]]; then 188 echo "Failed to read ECID from device" 189 exit 1; 190 fi 191 192 if [[ -n $KCACHE ]]; then 193 echo "Personalizing kernelcache for device with BoardID=`printf %d $BOARDID` ChipID=`printf 0x%x $CHIPID` ECID=`printf 0x%x $ECID`" 194 $PERSONALIZE_IMG4 -a -b $BOARDID -c $CHIPID -d 1 -e $ECID -n 0 -s 0 -i KernelCache=$KCACHE -i RestoreKernelCache=$KCACHE -o $TMPDIR $PTYPE >&9 195 if [ $? -ne 0 ]; then 196 echo "Personalization failed." 197 exit 1 198 fi 199 KCACHE=$TMPDIR/"`basename ${KCACHE}`.img4" 200 fi 201 202 if [[ -n $SEPOS ]]; then 203 echo "Personalizing SEP/OS for device with BoardID=`printf %d $BOARDID` ChipID=`printf 0x%x $CHIPID` ECID=`printf 0x%x $ECID`" 204 $PERSONALIZE_IMG4 -a -b $BOARDID -c $CHIPID -d 1 -e $ECID -n 0 -s 0 -i SEP=$SEPOS -i RestoreSEP=$SEPOS -l -o $TMPDIR $PTYPE >&9 205 if [ $? -ne 0 ]; then 206 echo "Personalization failed." 207 exit 1 208 fi 209 SEPOS=$TMPDIR/"`basename ${SEPOS%.*}`.img4" 210 fi 211fi 212 213# Fire up tcprelay and wait for it start 214 215TCPRELAY_OUTPUT=`mktemp -t tcprelay` 216if [[ -z $TCPRELAY_OUTPUT ]]; then 217 echo "Could not create tcprelay output" 218 exit 1; 219fi 220$TCPRELAY $TRDEVICE --dynamicports --autoexit telnet rsync > $TCPRELAY_OUTPUT 2>&1 & 221TCPRELAY_PID=$! 222 223while [[ `stat -f "%z" $TCPRELAY_OUTPUT` -eq 0 ]]; do 224 sleep 1 225done 226 227TELNET_PORT=`awk '/127\.0\.0\.1.*telnet/ {print $9}' $TCPRELAY_OUTPUT | awk -F : '{print $2}'` 228RSYNC_PORT=`awk '/127\.0\.0\.1.*rsync/ {print $9}' $TCPRELAY_OUTPUT | awk -F : '{print $2}'` 229 230# Mount the device's root filesystem read-write 231 232$FSREMOUNT localhost $TELNET_PORT $ROOTPASS rw >&9 233case $? in 234 128) 235 SKIP_MOUNT_RO=1;; 236 0) 237 ;; 238 *) 239 echo "Failed to mount root filesystem rw" 240 exit 1;; 241esac 242 243# Send over the kernelcache 244if [[ -n $KCACHE ]]; then 245 RSYNC_PASSWORD=$ROOTPASS rsync -v $KCACHE rsync://root@localhost:$RSYNC_PORT/root/$KCACHEDST >&9 246 if [ $? -ne 0 ]; then 247 echo "Failed to install kernelcache" 248 exit 1 249 else 250 echo "Kernelcache installed successfully." 251 fi 252fi 253 254# Send over the SEP/OS 255if [[ -n $SEPOS ]]; then 256 RSYNC_PASSWORD=$ROOTPASS rsync -v $SEPOS rsync://root@localhost:$RSYNC_PORT/root/$SEPOSDST >&9 257 if [ $? -ne 0 ]; then 258 echo "Failed to install SEP/OS" 259 exit 1 260 else 261 echo "SEP/OS installed successfully." 262 fi 263fi 264 265# Copy the file 266if [[ -n $COPYFILE ]]; then 267 RSYNC_PASSWORD=$ROOTPASS rsync -v $COPYFILE rsync://root@localhost:$RSYNC_PORT/root/$COPYDST >&9 268 if [ $? -ne 0 ]; then 269 echo "Failed to install $COPYDST" 270 exit 1 271 else 272 echo "$COPYDST installed successfully." 273 fi 274fi 275 276 277# Remount the root filesystem read-only if needed 278 279if [ ! $SKIP_MOUNT_RO ]; then 280 $FSREMOUNT localhost $TELNET_PORT $ROOTPASS ro >&9 281 if [ $? -ne 0 ]; then 282 echo "Failed to mount root filesystem ro" 283 exit 1 284 fi 285fi 286 287