Uncategorized

Command Line iOS Device Management

The other day, we installed libimobiledevice and used it to view the logs of an iOS device. But you can do much more with the commands that were installed. In fact, if you have a paired device, you can actually use these commands to do some remedial regression testing and other pretty cool things. So this is going to be part two of that article, basically.

First up, make sure the device is paired (note: not all commands require a device to be unlocked). But, all interaction with a device requires the device to be paired. You can use the command line (e.g. if you’re running this on Linux) to view the logs and manage devices, but if you’re not paired using iTunes or another tool, you’ll need to use idevicepair to pair your device, followed by the pair verb (which is very different from the pear verb):

idevicepair pair

You can also unpair using the unpair verb:

idevicepair unpair

The first command we’ll use is idevicedate, which simply returns with the date and time stamp currently on the device:

/usr/local/bin/idevicedate

The response would look similar to the following:

Thu Nov 13 08:58:30 CST 2014

Next, let’s check the apps installed on a device. We can do this with the ideviceinstaller command (also part of the ilibmobiledevice suite of tools). Here, we’ll use the -l option to just list what’s installed:

/usr/local/bin/ideviceinstaller -l

The output would show the app, along with the version of the app at rest on the device:

com.apple.Pages - Pages 1716

To uninstall one of the listed apps, use the –uninstall option:

ideviceinstaller --uninstall com.protogeo.Moves

You can also install apps provided you’ve cached the ipa file (e.g. via iTunes).

ideviceinstaller --install /Users/charlesedge/Music/iTunes/iTunes\ Media/Mobile\ Applications/Box\ 3.3.0.ipa

Which returns the following:

Copying '/Users/charlesedge/Music/iTunes/iTunes Media/Mobile Applications/Box 3.3.0.ipa' to device... DONE.
Installing 'net.box.BoxNet'
Install - CreatingStagingDirectory (5%)
Install - ExtractingPackage (15%)
Install - InspectingPackage (20%)
Install - TakingInstallLock (20%)
Install - PreflightingApplication (30%)
Install - VerifyingApplication (40%)
Install - CreatingContainer (50%)
Install - InstallingApplication (60%)
Install - PostflightingApplication (70%)
Install - SandboxingApplication (80%)
Install - GeneratingApplicationMap (90%)
Install - Complete

When run against a device, the app can then open apps provided the AppleID owns the app.

There’s also a command for ideviceprovision, which can be used to view provisioning profiles, when run with the list verb:

/usr/local/bin/ideviceprovision list

The ideviceprovision command can also form the basis of a tool like wirelurker by allowing you to install a provisioning profile

/usr/local/bin/ideviceprovision install angrybirds.mobileprovision

The file would look something like the following:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>AppIDName</key>
<string>Angry Birds</string>
<key>ApplicationIdentifierPrefix</key>
<array>
<string>ASDFJKL</string>
</array>
<key>CreationDate</key>
<date>2014-11-16T02:14:09Z</date>
<key>DeveloperCertificates</key>
<array>
<data>
MYCERT
</data>
</array>
<key>Entitlements</key>
<dict>
<key>application-identifier</key>
<string>ASDFJKL.com.rovio.angrybirds</string>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>ASDFJKL</string>
</array>
<key>com.apple.developer.rovio</key>
<string>ASDFJKL*</string>
<key>get-task-allow</key>
<true/>
</dict>
<key>Name</key>
<string>Angry Birds</string>
<key>ProvisionedDevices</key>
<array>
<string>MYUDID</string>
</array>
<key>TeamIdentifier</key>
<array>
<string>ASDFJKL</string>
</array>
<key>Version</key>
<integer>1</integer>
</dict>
</plist>

You can also remove this, by feeding in the UUID of the provisioning profile (obtained using the list verb but replacing MYUUID from below codeblock):

/usr/local/bin/ideviceprovision remove MYUUID

Note: I’m going to leave my rant about how wirelurker is about as much a security vulnerability as `rm` is due to the fact that it’s how you test the impact of upgrading apps on devices during the development process to another post – where I’ll also beg Apple not to let a little bad press cause them to rip away some of the few deployment and testing tools we actually have for the platform.

Or you could so something more annoying like put a device into recovery mode, so it would need to be plugged into a computer running iTunes and get a new ipsw installed, which is as simple as feeding the udid into ideviceenterrecovery:

/usr/local/bin/ideviceenterrecovery af36e5d7065d4ad666bf047b6e4de26dd144578c

Which brings up an interesting question, how would you get the udid? You can use ideviceinfo:

ActivationState: Activated
ActivationStateAcknowledged: true
BasebandActivationTicketVersion: V2
BasebandCertId: 3554301762
BasebandChipID: 7282913
BasebandKeyHashInformation:
AKeyStatus: 2
SKeyHash: 7MQEUyvzG4gjjZc7KsNNAVTS8g4=
SKeyStatus: 0
BasebandMasterKeyHash: AEA5CCE143668D0EFB4CE1F2C94C966A6496CZZZ
BasebandRegionSKU: BAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZZZ==
BasebandSerialNumber: JErUEw==
BasebandStatus: BBInfoAvailable
BasebandVersion: 3.11.00
BluetoothAddress: 90:fd:61:a6:f6:ZZ
BoardId: 0
BrickState: false
BuildVersion: 12B411
CPUArchitecture: arm64
CarrierBundleInfoArray[1]:
0:
CFBundleIdentifier: com.apple.Verizon_LTE_US
CFBundleVersion: 18.0
IntegratedCircuitCardIdentity: 89148000001085935ZZZ
InternationalMobileSubscriberIdentity: 311480110469ZZZ
MCC: 311
MNC: 480
SIMGID1: uuAAAAAAAAA=
SIMGID2: //////////8=
CertID: 3554301762
ChipID: 35168
ChipSerialNo: JErUEw==
CompassCalibration: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
DeviceClass: iPhone
DeviceColor: #3b3b3c
DeviceName: OK Computer
DevicePublicKey: LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQUxzV1BCWWJtM0FzK3ZRV2hOcnYvTTBSMWxFWi9QMVhPZzUyTG5GaEN5VUFlOVpPOWd2TC9NUzkKSXFMbTRZT3d6LytQeEdDMmlnTlRRbFlsKzdJY1dleFQ3dTBhZTI4UGtQL0N4OFYvV0dicWhqOGNmMHZDeVNVcApPa1FPWlFRYmJhRVVDN0pNaDExVW1ZdmllajYwN3cyRWh0THB4MysvZWR4cjlLNWtudXl6QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQo=
DieID: 5177734985296
EthernetAddress: 90:fd:61:a6:f6:13
FirmwareVersion: iBoot-2261.3.32
FusingStatus: 3
HardwareModel: N51AP
HardwarePlatform: s5l8960x
HostAttached: true
IntegratedCircuitCardIdentity: 89148000001085935111
InternationalMobileEquipmentIdentity: 352008065544111
InternationalMobileSubscriberIdentity: 311480110469111
MLBSerialNumber: F3Y34040ZEDF7GRA
MobileEquipmentIdentifier: 35200806554111
MobileSubscriberCountryCode: 311
MobileSubscriberNetworkCode: 480
ModelNumber: NE341
NonVolatileRAM:
auto-boot: dHJ1ZQ==
backlight-level: MTQ0MA==
boot-args:
bootdelay: MA==
PartitionType:
PasswordProtected: false
PhoneNumber: (612) 867-5309
PkHash: 09pXQgM5cjY6TJJNOOzO//R5JuGKqjHElfshBbnxZZZ=
ProductType: iPhone7,1
ProductVersion: 8.1
ProductionSOC: true
ProtocolVersion: 2
ProximitySensorCalibration: T00DAA0KQTgQAwAAAABeAQAAbgAEAP7zZgMEAAtS9wLuAjAAWYbZAY+GkhkAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
RegionInfo: LL/A
SBLockdownEverRegisteredKey: true
SIMGID1: ug==
SIMGID2: /w==
SIMStatus: kCTSIMSupportSIMStatusReady
SIMTrayStatus: kCTSIMSupportSIMTrayInsertedWithSIM
SerialNumber: F97N61XZFZZZ
SoftwareBehavior: EQAAAAAAAAAAAAAAAAAAAA==
SoftwareBundleVersion:
SupportedDeviceFamilies[1]:
0: 1
TelephonyCapability: true
TimeIntervalSince1970: 1416017216.873442
TimeZone: America/Chicago
TimeZoneOffsetFromUTC: -21600.000000
TrustedHostAttached: true
UniqueChipID: 5177734985296
UniqueDeviceID: af36e5d7065d4ad666bf047b6e4de26dd1445ZZZ
UseRaptorCerts: true
Uses24HourClock: false
WiFiAddress: 90:fd:61:a6:f6:ZZ
WirelessBoardSerialNumber: D81C55315781
kCTPostponementInfoPRIVersion: 0.1.90
kCTPostponementInfoPRLName: 1
kCTPostponementStatus: kCTPostponementStatusActivated

The ideviceinfo output above shows more information that I knew you could actually get about a device previously. You can grep for the UniqueDeviceID and

ideviceinfo | grep UniqueDeviceID | awk '{ print $2}'

This would just return with the UDID. Since that’s blank when there’s no device connected, you can run a loop that waits a few seconds when empty and then uses that UDID as a $1 in some script. Of course, it’s much easier to use a command they built for this called idevice_id:

idevice_id -l

Next, you can use idevicediagnostics to obtain some information about the current state of the device:

idevicediagnostics diagnostics All -u af36e5d7065d4ad666bf047b6e4de26dd1445789

Which has an output similar to the following:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>GasGauge</key>
<dict>
<key>CycleCount</key>
<integer>78</integer>
<key>DesignCapacity</key>
<integer>1550</integer>
<key>FullChargeCapacity</key>
<integer>1600</integer>
<key>Status</key>
<string>Success</string>
</dict>
<key>HDMI</key>
<dict>
<key>Connection</key>
<string>Unplugged</string>
<key>Status</key>
<string>Success</string>
</dict>
<key>NAND</key>
<dict>
<key>Status</key>
<string>NANDInfoFailed</string>
</dict>
<key>WiFi</key>
<dict>
<key>Active</key>
<string>YES</string>
<key>Status</key>
<string>Success</string>
</dict>
</dict>
</plist>

Or query the IOreg of the device:

idevicediagnostics ioreg IODeviceTree -u af36e5d7065d4ad666bf047b6e4de26dd1445789

The output is way too long to paste in here, but interesting (kinda’). The idevicediagnostics command can also do some basic tasks such as restart, sleep and shutdown (each sent as a verb without a required UDID):

idevicediagnostics restart

The crash reports on a device (which include reports for uninstalled apps, forensically providing a glimpse into what apps were removed from a device and when) can all be extracted from a paired device as well, using idevicecrashreport:

idevicecrashreport -e /test

You can then view the logs or grep through them for specific pieces of information:

cat /Test/Baseband/log-bb-2014-08-06-stats.plist

The last command we’re going to cover in this article is idevicebackup2, used to backup devices. Here, we’re going to feed it the udid (which I’m lazily using the idevice_id command from earlier in backticks to grab the udid and backing up into that /test directory.

idevicebackup2 -u `idevice_id -l` backup /test

Here, we’ve backed up whatever device is plugged in, to the /test directory. Subsequent backups will be incrementals.