A (long) evening with Mobile_Obliterator
and a look into iOS entitlements
Jonathan Levin, http://www.newosxbook.com/ - 12/31/13
1. About
Part of what I do is reverse engineering. Most of the iOS-related information in the book (at least, those I was allowed to publish) was gleaned by reverse engineering by disassembling binaries, and occasionally debugging them. This is also why I ended up writing JTool, which started as a simple Mach-O header dump utility, but took a life on its own and ended up with its own disassembler.
When I noticed /usr/libexec/mobile_obliterator
, I couldn't help but be intrigued. It's a small executable (60-70k) with a big name. It's the binary responsible for Apple's "remote device wipe" feature. Not an overly sophisticated one (as I'll demostrate here) but it makes for a great demonstration of a virtually undocumented feature of iOS (which I admit I had to only scratch the surface of in the book) - Entitlements. With nothing else to do on a 13 hour flight in economy, this article is long overdue. Oh, and - happy new year :-)
Why should you care? (Target Audience)
If you want to know how entitlements work at the low-level, this should prove to be a good read. If you want to see examples of using JTool (some are in the forum), there are some here. You can follow along if you have the iOS filesystem image. It's encrypted, but you don't have to read the book to get around that..The mobile_obliterator has been rewritten in iOS7 to use XPC. We'll get to that, too.
Why Obliterate?
iOS devices have a wipe feature. This is a feature of last resort if your i-Device falls into the wrong hands. In those cases, you don't want personal data, and possibly confidential data, exposed. "Wiping" involves nuking all the user's data in /var/mobile
- which is intentionally a separate partition. The responsible entity for starting mobile_obliterator is SpringBoard - in many ways the core binary in iOS, responsible for the familiar GUI, and more. In practice, however, it is launchd which starts mobile_obliterator, the same way it starts all other processes in iOS. This can be seen in mobile_obliterator's property list file:
From the plist we see that the binary (/usr/libexec/mobile_obliterator
) is associated with a Mach service - com.apple.mobile.obliteration
iOS has a private framework - MobileObliteration.framework. While this framework, like most others, is in the shared library cache, a symbolicated version of it exists in the iOS SDK. Disassembling it reveals a fairly simple library:
Thus, we have the function of perform_command,
and three exported commands: Mobile_Obliterate, and its reboot and Synchronous variants. The library is easy to disassemble, and can be further decompiled. What follows is JTool's decompilation, with further annotation:
The MobileObliteration.framework, therefore, is in effect a simple XPC client of mobile_obliterator, using MOXPC calls (from the MobileSystemServices
private framework). Incidentally, XPC itself isn't much more than wrappers over the venerable Mach bootstrap server functionality (still maintained by launchd
). The various exported functions fall through to perform_command
, with the only subtle difference being the setting of additional keys in the CFDictionary passed to perform_command (Specifically, Mobile_Obliterate_Reboot
sets the ObliterationRebootType
key to ObliterationRebootNow
and Mobile_Obliterate_Synchronous
sets the SyncType
key to Synchronous
.
Meanwhile...
On the other side of launchd, mobile_obliterator wakes up, and initializes the XPC support. After opening /dev/console, it logs a startup message, and calls MOXPCTransportOpen
to claim the com.apple.mobile.obliteration
channel (as is rightfully his, by the launchdaemon plist), and calls MOXPCTransportSetMessageHandler to install a callback function for incoming messages, before going into a dispatch_main
message loop. When messages come in, mobile_obliterator inspects the CFDictionary for the above mentioned keys, to determine if a reboot or a synchronous obliteration was requested. Once it figures out what the client requested, it can proceed to obliterate the device
But... not so fast! While the mobile obliterator aims to please, it must exercise some discretion. Specifically, it can't just allow any client to connect. It therefore requires clients to have a special entitlement to allow its services to be invoked. Entitlements form the crux of the iOS permission model. Very similar to Android's Dalvik-level permissions, they implement a declarative security model wherein a given application can specify to iOS it requires special capabilities. Servers can then request iOS to verify a client has the required entitlements before granting it access to the service.
Entitlements
A client specifies its entitlements in its binary - they are embedded in the code signature, as an entitlement blob (kSecCodeMagicEntitlement = 0xfade7171
). Doing so allows Apple to ensure they are not misused: Apple is the sole provider of code signatures in iOS, so apps can't simply request entitlements without Apple's App Review process flagging them. Once a binary is code signed by Apple, even its own developer can no longer modify it in any way. You can use jtool to view both the code signature and the entitlements - the latter is such common usage I added a separate --ent option for it). Using jtool on Springboard reveals plenty of entitlements:
During the Mach-O object loading, the kernel loads the code signature (LC_CODE_SIGNATURE load command) using a dedicated function (load_code_signature
in bsd/kern/mach_loader.c
). The function loads the code signature and stores it in the unified buffer cache, as a blob. Because it is in kernel memory, the code signature (once verified) can be fully trusted. In other words, the binary does not have a way to access its own entitlements (at least not from user mode)
Servers can validate that a client holds the entitlement by using the public Security.Framework
. Turning once more to mobile_obliterator
, we see (full disassembly given; also possible to skim through annotations):
The obliteration process itself isn't terribly complicated (though it's possible to walk through it with jtool as well). On a side note, iOS 6's obliterator (pre-XPC) had an easter egg in outputting ""And you will know my name is the Lord when I lay my vengeance upon thee."
CSOPS
The Security.Framework
SecTask APIs (visible in the OS X SDK Headers (SecTask.h
), but not in those of iOS) obtain the entitlements by calling on Apple's proprietary system calls in XNU dealing with code signing - csops
(#169) and csops_audittoken
(#170). These system calls are undocumented, but their implementation in the XNU open sources (bsd/kern/kern_proc.c) is straightforward to read. The relevant code is shown below:
The heart of the function is cs_entitlements_blob_get
(in bsd/kern/ubc_subr.c
). This function locates the entitlements blob in the bigger code signing super blob , and returns it to the caller. The blob itself is just the embedded plist. More information on the code signing blob itself can be found in the open source portion of Securitya (specifically, ./libsecurity_codesigning/lib/cscdefs.c and .h
, so I won't get into it here.
Other notes
This article, while detailing more than the book has on entitlements, is still only scraping the surface. I've so far counted well over 100 entitlements, from miscellaneous providers ranging from SpringBoard to the various servers in /usr/libexec. Apple's own apps (in /Applications) make heavy use of entitlements (you might want to try jtool --ent
on some. For third party developers, the only entitlements Apple allows are those in XCode, which are limited to iCloud access and a few other paltry features. I'm working on a list of entitlements, providers and consumers. This will take more time, though
iOS also has a daemon - tccd
(part of the TCC.framework
) which relies on entitlements (and provides an example of a case where the entitlement value can be an array, as in com.apple.private.tcc.allow
. TCC (also present in OS X) is responsible for the UIAlert which pops up every now and then for "application XXX would like to access your photos/contacts/etc". Time (and reader interest) permitting, I'll cover this in a future article.
Summary
CS_ENTITLEMENTS_BLOB
, as part of the code signatureSecTask
APIsSecTask
APIs, in turn, call on csops (syscall #169) or csops_audittoken (#170)