This excerpt is from iPhone Forensics. iPhone Forensics supplies the knowledge necessary to conduct complete and highly specialized forensic analysis of the iPhone, iPhone 3G, and iPod Touch.
When any computer is turned on, files are read and
written. iPhone examiners need only be concerned with what is written,
as the iPhone’s filesystem is mounted with the noatime option, even if the option is not
specified in /etc/fstab. This option prevents access
times from being updated when a file is read or its metadata (such as
its name) is changed on the device. Therefore, the access time shown on
a file should reflect either its creation or the last time some change
was made to the content, allowing you to concentrate on only the files
that have been actually changed.
In the likely event that you don’t possess special equipment to physically dump the iPhone’s memory chip, the device must be powered on and booted into its operating system to recover data. Furthermore, the forensic tools described in this book require that the device be rebooted after the toolkit payload is installed.
Just like a desktop operating system, the iPhone’s Leopard operating system performs minor writes to certain files upon booting. The purpose of most writes is to replace or reset existing configuration files, and writes generally don’t add any new data to the filesystem. Some writes, however, append a very minor amount of data to files. Overall, the writes to the filesystem are minimal, but are disclosed here in Table A.1, “Bytes added to files during boot” for integrity.
On iPhone firmware versions lower than or equal to 1.1.2, the
mobile directory is replaced with
root.
Table A.1. Bytes added to files during boot
Filename | Estimated magnitude of change |
|---|---|
| 28 bytes |
| 1275 bytes |
| 121 bytes |
| 3 bytes |
| 76 bytes |
| 3252 bytes |
| 320 bytes |
| 144 appended |
| Inode only |
| 7168 bytes |
| 783 bytes |
| 730 bytes |
| 1305 bytes |
| 2284 bytes |
| 4380 bytes |
Unless otherwise noted, all changes are performed as overwrites to existing data, but this isn’t guaranteed.
In addition to the changes noted in Table A.1, “Bytes added to files during boot”, the files listed in Table A.2, “Bytes added to files during login” may be written to or recreated when someone logs into the device, causing bytes to be added.
The forensic toolkit payload installed by iLiberty+ places a set of open source tools onto the otherwise read-only portion of the device, resulting in no destruction to user-level data stored on the device’s media partition. At the time of payload installation, the following files are written to the system (root) partition.
File size may vary depending on the application and payload versions used. Some files are deleted after toolkit installation.
/usr/libexec/ipluspwns (basepack)
-rwxr-xr-x 1 root wheel 25212 Mar 27 08:59 chmod*
-rwxr-xr-x 1 root wheel 38320 Mar 27 08:59 echo*
-rwxr-xr-x 1 root wheel 23292 Mar 27 08:59 iPipe*
-rwxr-xr-x 1 root wheel 14352 Mar 27 08:59 mv*
-rwxr-xr-x 1 root wheel 13760 Mar 27 08:59 reboot*
-rwxr-xr-x 1 root wheel 19128 Mar 27 08:59 rm*
-rwxr-xr-x 1 root wheel 1298880 Mar 27 08:59 sh*
-rwxr-xr-x 1 root wheel 39036 Mar 27 08:59 sleep*
-rwxr-xr-x 1 root wheel 14916 Mar 27 08:59 umount*
-rwxr-xr-x 1 root wheel 141528 Mar 27 08:59 unzip*
/bin (basepack)
-rwxr-xr-x 1 root wheel 134152 Mar 27 08:59 awk
-rwxr-xr-x 1 root wheel 23368 Mar 27 08:59 blcheck
-rwxr-xr-x 1 root wheel 14368 Mar 27 08:59 cat
-rwxr-xr-x 1 root wheel 25212 Mar 27 08:59 chmod
-rwxr-xr-x 1 root wheel 80660 Mar 27 08:59 chown
-rwxr-xr-x 1 root wheel 19644 Mar 27 08:59 cp
-rwxr-xr-x 1 root wheel 18972 Mar 27 08:59 cut
-rwxr-xr-x 1 root wheel 33288 Mar 27 08:59 dd
-rwxr-xr-x 1 root wheel 9212 Mar 27 08:59 dirname
-rw-r--r-- 1 root wheel 2971 Apr 1 20:25 functions.inc
-rwxr-xr-x 1 root wheel 158708 Mar 27 08:59 grep
-rwxr-xr-x 1 root wheel 18056 Mar 31 14:03 iEdit
-rwxr-xr-x 1 root wheel 20776 Mar 27 08:59 igsm
-rwxr-xr-x 1 root wheel 13492 Mar 31 14:03 ln
-rwxr-xr-x 1 root wheel 41028 Mar 27 08:59 ls
-rwxr-xr-x 1 root wheel 13348 Mar 31 14:03 mkdir
-rwxr-xr-x 1 root wheel 24244 Mar 27 08:59 plutil
-rwxr-xr-x 1 root wheel 13760 Mar 27 08:59 reboot
-rwxr-xr-x 1 root wheel 19172 Mar 27 08:59 rm
-rwxr-xr-x 1 root wheel 42888 Mar 27 08:59 sed
-rwxr-xr-x 1 root wheel 1298880 Mar 27 08:59 sh
-rwxr-xr-x 1 root wheel 9392 Mar 27 08:59 sleep
-rwxr-xr-x 1 root wheel 260244 Mar 27 08:59 tar
-rwxr-xr-x 1 root wheel 141528 Mar 27 08:59 unzip
/bin (payload)
-rwxr-xr-x 1 root wheel 591364 Mar 16 09:23 bash
-rwxr-xr-x 1 root wheel 45804 Feb 29 04:55 cat
-rwxr-xr-x 1 root wheel 74456 Feb 29 04:55 chgrp
-rwxr-xr-x 1 root wheel 65632 Feb 29 04:55 chmod
-rwxr-xr-x 1 root wheel 74724 Feb 29 04:55 chown
-rwxr-xr-x 1 root wheel 159704 Feb 29 04:55 cp
-rwxr-xr-x 1 root wheel 33288 Apr 7 10:25 dd
-rwxr-xr-x 1 root wheel 119948 Mar 27 07:48 grep
-rwxr-xr-x 1 root wheel 115848 Feb 29 04:55 ln
-rwxr-xr-x 1 root wheel 146360 Feb 29 04:55 ls
-rwxr-xr-x 1 root wheel 44452 Feb 29 04:55 mkdir
-rwxr-xr-x 1 root wheel 45900 Feb 29 04:55 mknod
-rwxr-xr-x 1 root wheel 169368 Feb 29 04:55 mv
-rwxr-xr-x 1 root wheel 39292 Feb 29 04:55 pwd
-rwxr-xr-x 1 root wheel 13760 Apr 8 00:35 reboot
-rwxr-xr-x 1 root wheel 142636 Feb 29 04:55 rm
lrwxr-xr-x 1 root wheel 4 Apr 8 00:18 sh -> bash
-rwxr-xr-x 1 root wheel 17004 Feb 27 18:50 sync
/etc (payload)
-rw-r--r-- 1 root wheel 1418 Jun 12 2006 ssh_config
-rw-r--r-- 1 root wheel 3230 Aug 25 2007 sshd_config
/sbin (payload)
-rwxr-xr-x 1 root wheel 185008 Apr 8 00:34 fsck_hfs
-rwxr-xr-x 1 root wheel 18052 May 7 12:12 md5
-rwxr-xr-x 1 root wheel 19236 Apr 8 00:34 mount_hfs
-rwxr-xr-x 1 root wheel 46300 Apr 8 00:35 newfs_hfs
-rwxr-xr-x 1 root wheel 191976 May 7 12:22 ping
-rwxr-xr-x 1 root wheel 14916 Apr 8 00:37 umount
/usr/bin (payload)
-rwsr-xr-x 1 root wheel 31712 Feb 27 18:50 login
-rwxr-xr-x 1 root wheel 29520 Apr 8 00:34 nc
-rwxr-xr-x 1 root wheel 56284 Aug 23 2007 scp
-rwxr-xr-x 1 root wheel 88876 Aug 23 2007 sftp
-rwxr-xr-x 1 root wheel 340340 Aug 23 2007 ssh
-rwxr-xr-x 1 root wheel 103960 Aug 23 2007 ssh-add
-rwxr-xr-x 1 root wheel 87336 Aug 23 2007 ssh-agent
-rwxr-xr-x 1 root wheel 134264 Aug 23 2007 ssh-keygen
-rwxr-xr-x 1 root wheel 198048 Aug 23 2007 ssh-keyscan
/usr/lib (payload)
lrwxr-xr-x 1 root wheel 18 Apr 8 00:18 libcurses.dylib ->
libncurses.5.dylib
-r-xr-xr-x 1 root wheel 35392 Jan 3 20:31 libhistory.5.2.dylib
lrwxr-xr-x 1 root wheel 20 Apr 8 00:18 libhistory.5.dylib ->
libhistory.5.2.dylib
lrwxr-xr-x 1 root wheel 20 Apr 8 00:18 libhistory.dylib ->
libhistory.5.2.dylib
-rw-r--r-- 1 root wheel 60780 Jan 14 21:44 libintl.8.0.2.dylib
lrwxr-xr-x 1 root wheel 19 Apr 8 00:18 libintl.8.dylib ->
libintl.8.0.2.dylib
lrwxr-xr-x 1 root wheel 19 Apr 8 00:18 libintl.dylib ->
libintl.8.0.2.dylib
-rw-r--r-- 1 root wheel 801 Jan 14 21:44 libintl.la
-rwxr-xr-x 1 root wheel 105156 Feb 23 06:30 libncurses++.a
-rwxr-xr-x 1 root wheel 379360 Feb 23 06:30 libncurses.5.dylib
lrwxr-xr-x 1 root wheel 18 Apr 8 00:18 libncurses.dylib ->
libncurses.5.dylib
-r-xr-xr-x 1 root wheel 239308 Jan 3 20:31 libreadline.5.2.dylib
lrwxr-xr-x 1 root wheel 21 Apr 8 00:18 libreadline.5.dylib ->
libreadline.5.2.dylib
lrwxr-xr-x 1 root wheel 21 Apr 8 00:18 libreadline.dylib ->
libreadline.5.2.dylib
-rwxr-xr-x 1 root wheel 247684 Jan 4 05:35 libresolv.dylib
lrwxr-xr-x 1 root wheel 17 Apr 8 00:18 terminfo -> ../share/terminfo
/usr/libexec (payload)
-rwxr-xr-x 1 root wheel 59372 Aug 23 2007 sftp-server
-rwxr-xr-x 1 root wheel 200664 Aug 23 2007 ssh-keysign
-rwxr-xr-x 1 root wheel 35280 Aug 23 2007 ssh-rand-helper
-r-xr-xr-x 1 root wheel 425 Dec 20 2006 sshd-keygen-wrapper
/usr/sbin (payload)
-rwxr-xr-x 1 root wheel 32784 Apr 8 00:36 fdisk
-rwxr-xr-x 1 root wheel 414512 Aug 23 2007 sshd
/Library/LaunchDaemons (payload)
-rw-r--r-- 1 root wheel 828 Feb 4 2006 com.openssh.sshd.plistThis section explains some low-level technical details of the operations performed by the iLiberty+ tool. These techniques are intended for those desiring a technical explanation of the procedure or who seek to reproduce or reimplement it, and are not necessary for general forensic examination.
Many different methods have been devised by the iPhone development community to gain access to an iPhone’s operating system, but very few of them are able to do so without destroying evidence, or even destroying the entire filesystem. The technique used in this manual is considered to be forensically safe in that it is cdisclosures-sourcecodeble of accessing the device without corrupting user data.
A RAM disk is a filesystem that resides in memory, and is not physically written on disk. Most Unix kernels are cdisclosures-sourcecodeble of booting the operating system from memory, and most versions of iPhone software also support this.
The technique used by iLiberty+ for iPhone software versions 1.0.2–1.1.4 gains access to the operating system by booting an unsigned RAM disk from the iPhone’s resident memory. This RAM disk is copied into the iPhone’s memory and booted by setting the appropriate kernel flags using Apple’s MobileDevice framework. This section is based specifically on version 7.4.2 of the device framework. Because the function calls change slightly for newer versions of the framework, you will have to install this framework with a copy of iTunes 7.4.2 in order to reproduce the procedure in this section.
Once the unsigned RAM disk is booted, the iPhone’s disk-based filesystem is mounted and the selected payload is copied. Depending on the payload, this could simply enable shell access, or install a surveillance kit or any other type of software. When the device boots back into its normal operating mode, the installed payload will be executed, performing whatever tasks it was designed for.
iLiberty+’s custom RAM disk differs from the RAM disk used by Apple to install software updates and perform restores. The custom iLiberty+ RAM disk consists of a disk image containing the necessary ARM-architecture files to boot and install a custom payload on the iPhone. The RAM disk itself is padded with 0x800 bytes to contain an 8900 header, and may additionally pad between 0xCC2000 and 0xD1000 zero bytes to assist in aligning the execution space of the disk.
Once a custom RAM disk has been assembled, it is executed using private and undocumented function calls within Apple’s MobileDevice framework. In short, this involves the following procedures.
The device is placed into recovery mode either manually (by
holding the Home and Power buttons until forced into recovery mode),
or by using the MobileDevice function AMDeviceEnterRecovery. The RAM disk image is
sent to the device using the private __sendFileToDevice function after looking up
its symbol address in the framework.
The following commands are sent to the device using the private
__sendCommandToDevice function after
looking up its symbol address in the MobileDevice framework. This sets
the kernel’s boot arguments to boot from a RAM disk, and specifies the
memory address of the approximate location of the custom image copied
to the device.
setenv boot-args rd=md0 -s -x pmd0=0x9340000.0xA00000 saveenv fsboot
Depending on the cdisclosures-sourcecodecity and firmware version of the device,
different memory addresses may be necessary. The memory address
0x09CC2000.0x0133D000 has also
been reported to succeed.
Once the RAM disk has booted and the payload has been delivered,
the device can be booted back into normal operating mode by sending
the following commands to the device using __sendCommandToDevice:
setenv boot-args [Empty] setenv auto-boot true saveenv fsboot
Depending on the version of iPhone firmware, the fsboot command may be replaced with
bootx.
The following source code illustrates the process of booting an unsigned RAM disk in C. The example waits for the device to be connected in recovery mode and then issues the commands to send and boot a RAM disk as described in the previous section. The RAM disk image and needed framework library are provided by the implementer. This code was designed to run on the Mac OS X operating system running iTunes 7.4.2 MobileDevice framework. Comments are provided inline.
To build this example, use the following command:
$ gcc –o inject-ramdisk inject-ramdisk.c –framework CoreFoundation
–framework MobileDevice –F/System/Library/PrivateFrameworksThe complete code for inject-ramdisk.c follows:
#include <stdio.h> #include <mach-o/nlist.h> #include <CoreFoundation/CoreFoundation.h>/* Path to the MobileDevice framework is used to look up symbols and offsets */#define MOBILEDEVICE_FRAMEWORK "/System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/ MobileDevice"/* Used as a pointer to the iPhone/iTouch device, when booted into recovery */typedef struct AMRecoveryModeDevice *AMRecoveryModeDevice_t;/* Memory pointers to private functions inside the MobileDevice framework */typedef int(*symbol) (AMRecoveryModeDevice_t, CFStringRef) \ __attribute__ ((regparm(2))); static symbol sendCommandToDevice; static symbol sendFileToDevice;/* Very simple symbol lookup. Returns the position of the function in memory */static unsigned int loadSymbol (const char *path, const char *name) { struct nlist nl[2]; memset(&nl, 0, sizeof(nl)); nl[0].n_un.n_name = (char *) name; if (nlist(path, nl) < 0 || nl[0].n_type == N_UNDF) { return 0; } return nl[0].n_value; }/* How to proceed when the device is connected in recovery mode.* This is the function responsible for sending the ramdisk image and booting* into the memory location containing it. */void Recovery_Connect(AMRecoveryModeDevice_t device) { int r; fprintf(stderr, "Recovery_Connect: DEVICE CONNECTED in Recovery Mode\n");/* Upload RAM disk image from file */r = sendFileToDevice(device, CFSTR("ramdisk.bin")); fprintf(stderr, "sendFileToDevice returned %d\n", r);/* Set the boot environment arguments sent to the kernel */r = sendCommandToDevice(device, CFSTR("setenv boot-args rd=md0 -s -x pmd0=0x9340000.0xA00000")); fprintf(stderr, "sendCommandToDevice returned %d\n", r);/* Instruct the device to save the environment variable change */r = sendCommandToDevice(device, CFSTR("saveenv")); fprintf(stderr, "sendCommandToDevice returned %d\n", r);/* Invoke boot sequence (bootx may also be used) */r = sendCommandToDevice(device, CFSTR("fsboot")); fprintf(stderr, "sendCommandToDevice returned %d\n", r); }/* Used for notification only */void Recovery_Disconnect(AMRecoveryModeDevice_t device) { fprintf(stderr, "Recovery_Disconnect: Device Disconnected\n"); }/* Main program loop */int main(int argc, char *argv[]) { AMRecoveryModeDevice_t recoveryModeDevice; unsigned int r;/* Find the __sendCommandToDevice and __sendFileToDevice symbols */sendCommandToDevice = (symbol) loadSymbol (MOBILEDEVICE_FRAMEWORK, "__sendCommandToDevice"); if (!sendCommandToDevice) { fprintf(stderr, "ERROR: Could not locate symbol: " "__sendCommandToDevice in %s\n", MOBILEDEVICE_FRAMEWORK); return EXIT_FAILURE; } fprintf(stderr, "sendCommandToDevice: %08x\n", sendCommandToDevice); sendFileToDevice = (symbol) loadSymbol (MOBILEDEVICE_FRAMEWORK, "__sendFileToDevice"); if (!sendFileToDevice) { fprintf(stderr, "ERROR: Could not locate symbol: " "__sendFileToDevice in %s\n", MOBILEDEVICE_FRAMEWORK); return EXIT_FAILURE; }/* Invoke callback functions for recovery mode connect and disconnect */r = AMRestoreRegisterForDeviceNotifications( NULL, Recovery_Connect, NULL, Recovery_Disconnect, 0, NULL); fprintf(stderr, "AMRestoreRegisterForDeviceNotifications returned %d\n", r); fprintf(stderr, "Waiting for device in restore mode...\n");/* Loop */CFRunLoopRun(); }
Once the RAM disk has been injected and booted, iLiberty+’s work
is complete and the RAM disk has delivered whatever payload it was
written to deliver. The device can then be returned to normal
operating mode by issuing the following commands in place of those in
the Recovery_Connect
function:
/* Reset and save the default boot-related environment variables */sendCommandToDevice(device, CFSTR("setenv auto-boot true")); sendCommandToDevice(device, CFSTR("setenv boot-args ")); sendCommandToDevice(device, CFSTR("saveenv"));/* Boot the device (bootx may also be used) */sendCommandToDevice(device, CFSTR("fsboot"));
The device will now boot into normal operating mode for all subsequent boots.
Copyright © 2009 O'Reilly Media, Inc.