gestalt |gəˈSHtält, -ˈSHtôlt | (also Gestalt)
noun (pl. gestalten |-ˈSHtältn, -ˈSHtôltn| or gestalts) Psychology
an organized whole that is perceived as more than the sum of its parts.
About
One of the criticisms I've been getting with the 1st edition of "Mac OS X and iOS Internals" (MOXiI) is that I provided no coverage of Apple's extremely rich and versatile's frameworks and libraries - merely mentioning them in passing as part of the overview of Chapter II. The 2nd edition aims to correct that, by dissecting them - especially the private ones, so as to provide a clearer view for developers who wish to draw on their amazing offerings. (Naturally, this only applies to non-AppStore apps).
Partial headers exist for frameworks, mostly the output of automatic tools such as classdump-z (for Objective-C) and their ilk. But the header information is often lacking, and there exists no documentation as to how the frameworks work - and that's what I'm trying to provide. MOXiI 2 will have key private frameworks reversed, and explained in detail. It will, however, provide the results of the reversing, and not the process itself. That's where these writeups come in, as additional resources for the avid reader. In previous ones I had explained the process of reversing and reincarnating the 802.11 framework, and now the current victim is MobileGestalt.
MobileGestalt
The libMobileGestalt.dylib, even though technically not a framework per se, it is of utmost importance, as it serves iOS as a central repository for all of the system's properties - both static and runtime. In that, it can be conceived as the parallel of OS X's Gestalt, which is part of CoreServices (in CarbonCore). But similarities end in name only. OS X's Gestalt is somewhat documented (in its header file), and has been effectively deprecared as of 10.8. MobileGestalt is entirely undocumented, and isn't going away any time soon.
Quite a few system daemons and apps in iOS rely on MobileGestalt, which rests in /usr/lib/libMobileGestalt.dylib. Its placement in /usr/lib makes it more of a "simple library", but its exposed APIs follow the framework conventions, and uses the MG prefix. Apple's own definition of "framework" is loose, at best (every framework is a special case of a dylib, though usually with additional coponents - data files, helper daemons, etc).
If you look for MG on the iOS filesystem, however, you won't find it - like all key frameworks and libraries, it has been prelinked into the /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm[v7|64]. Fortunately, jtool and other tools (like decache) can extract from the shared cache - so you might want to follow along by breaking out MG from a decrypted DMG or from your device itself. I never got to complete JTool's ARM32 disassembler, instead focusing on ARM64, so I'll be demonstrating MG on an iPhone 6, like so:
Output 1: Extracting libMobileGestalt from the shared cache
The resulting file is big - because the shared cache merges all of its components' __LINKEDIT into one huge segment - but nonetheless works for reversing, being a legitimate and well formatted Mach-O. You can use jtool (or otool and nm) to examine its dependencies and exports:
Output 2: Examining the extracted libMobileGestalt
As the above shows, MobileGestalt's main dependency is on the IOKit.framework, which is what it uses to get hardware related information. Additionally, it exports to sets of symbols (MG* and _MG*), with the main ones allowing to retrieve "Answers" (Using Get for float, Bool, Int32/64, and Copy for CF* answers), and notifications (the MGRegisterFor[Bulk]Updates and MGCancelNotifications).
Ask me no questions..
The "Questions" for which the "Answers" will be returned are string properties. This is well known by reversed headers, and many StackOverflow cases. To figure out what the common questions are, I've added support in JTool (v0.91+) for recognizing MGCopyAnswer, which takes a CFString. It then became a simple task to iterate over the MG users with a shell script, and let JTool retrieve the keys automatically:.
Output 3: Using jtool to retrieve use cases of MobileGestalt
As the above shows, (and for the moment, ignore the weird-looking base64 encodings), MobileGestalt provides a plethora of information - around 200 or so questions - on various aspects of the system. And those 200 make just about half of the possible keys - there's many more still, including useful ones (e.g. AirplaneMode, MobileEquipmentIdentifier, etc), which can be reversed as well. I've cobbled together a wonderful list of about 400(!) thus far, which these narrow margins cannot contain - But MOXiI 2 will.
Arguably, you can get the information in other ways, yes - I/O kit provides the lion's share of the above. But it's much easier to use a centralized mechanism, rather than walk the I/O Registry. Further, some of these values are from user mode programs (e.g. PasswordProtected - wicked useful - it changes depending on whether the lock screen is enabled or not).
Using MobileGestalt
Using MG is easy, as the following code shows:
Listing 1: The code for a simple gestalt tool
If you prefer to define the functions directly, rather than using dlopen(3)/dlsym(3), you can compile the code with something like gcc-iphone mg.c -o mg -L/${PATH_TO_YOUR_IPHONE_DEVELOPER_LIBS}/SDKs/iPhoneOS8.3.sdk/usr/lib -lMobileGestalt. And, no, you don't need to cut/paste - the code + binary is provided at the end of the article.
By trying the code on the list of keys above, you'll see it works in most cases. In a few, it can fail - as if the keys don't exist. The failures are for the more "sensitive" or "Protected" keys. For this, MobileGestalt makes use of an entitlement -
Output 4: Dumping the entitlements for SpringBoard
On my jailbroken devices (8.1.2) nearly all keys are recoverable, even sans entitlement, but Apple is cracking down on this in 8.3, and starting to enforce the entitlement, which is a fine-grained array with entries for the unique IDs (e.g. MLBSerialNumber, BluetoothAddress, UniqueChipID, MobileEquipmentIdentifier, etc, and everything which can contribute to UDID). I haven't had a chance to disassemble 8.3 or 8.4b's libs (yet), but if I were Apple I'd move everything out of process to XPC - which is required for proper enforcement of entitlements, and isn't hard, since it's already used in some cases (see next).
Help
MobileGestalt dynamically loads libMobileGestaltExtensions.dylib, which in turn calls on several private frameworks (IOMobileFrameBuffer, ManagedConfiguration, MobileKeyBag, MobileWiFi, StoreServices, SoftwareBehaviorServices and Sharing). That's a bit more complicated, though, so I'll leave it for the book.
In some cases, MobileGestalt calls out to its helper daemon - /usr/libexec/MobileGestaltHelper via - you guessed it - XPC. A simple trick to tell you when the Helper is involved is to kill -STOP it, and see if your gestalt question hangs. The Helper is a tiny daemon (~500 lines of assembly), which uses MobileGestalt itself as well (It calls MGSetServer, then sets up an XPC connection handler and answers connections by MGServerCopyAnswerWithError over [NSXPCConnection currentConnection]). Its plist (associating it with the Mach service) is defined thus:
Listing 2 The property list for launching MobileGestaltHelper
From the looks of things, the daemon isn't enforcing any entitlement (that is it doesn't directly call csops or SecTask... APIs, though with all the dlopen()ing performed by the library, I've yet to verify that its extensions don't). The daemon itself, however, is running as uid mobile, and declares entitlements for itself as follows:
Output 5: Dumping the entitlements for MobileGestaltHelper
The entitlements are required in cases where the Helper itself needs IPC, to communicate with the CoreTelephony daemon (CommCenter), lockdownd, or Wifid). For example, BasebandPostponementStatusBlob . Why the extra protection? Because that particular key has tons of "good stuff", e.g:
Listing 3: The contents of the BasebandPostponementStatusBlue (requires CommCenter.fine-grained entitlement)
This leaves just one quandary - what are those weird looking keys in the key dump from jtool, above?
(A rather pathetic) Obfuscation
While most keys are self explanatory, looking at the list above, you'll no doubt see some weird garbage-y looking ones as well. Those aren't a jtool bug :) - Apple uses obfuscation for some keys. The character set chosen ([A-Za-z0-9+/]) reeks of Base64. To uncover the obfuscation, though, we have to disassemble MGCopyAnswer*:
Disass 1: Dumping MGCopyAnswer
Both functions call on 0x1918a8100, which is the unnamed "CopyAnswer". To spare you the boring ASM, I'll focus directly on the relevant portion, which is obfuscating the key, like so (similar code in 1918a672c):
Disass 2: The obfuscation, in plain assembly
In other words, we have:
Listing 4: The obfuscation, in pseudocode
The obfuscated blobs are, therefore, an MD5 of "MGCopyAnswer" concatenated with the Question. Think keyed hash, with plaintext key :). The Resulting base64 will always have a "==" - because base64 encodes 6-bits per character, and 128 leaves a remainder of 2 from 126 - so these are removed, and we end up with that blob. MD5 is irreversible, but it's simple to create a small program which "brute forces" keys, and obtain a mapping. In fact, the code from Listing 1 can be modified to perform the obfuscation quite easily, which will give you:
Output 6: guesstalt in action (Continued from Output 3)
The obfuscated values are also used internally by MG - dumping its __TEXT.__cstring will show you plenty of them:
Output 7: Using jtool to isolate obfuscated keys, and a false positive or two..
It follows, then, that MobileGestalt will allow queries on either form of keys - clear or obfuscated.You can use the tool included to corroborate this. Apple likely has some keys used mainly in obfuscated form, as they have their definitions in kMG* constants.
Caching
While quite a few of the Gestalt keys are transient, the most useful ones end up being quite static. MobileGestalt maintains a cache of values in /var/mobile/Library/Caches/com.apple.MobileGestalt.plist. The keys there are obfuscated, but we know how to get past that already:
Output 8: The MobileGestalt cache from an iPad Air 2
What's still missing (my @TODO for MOXiI 2)
A list of all 400 or so keys
Explanation of GestaltExtensions, w/Example
Registering for notifications
IPC flow example with the Helper
(minor) 8.3-4 and 9.0 diffs
Final notes (and the usual book/training plug)
The code from the listing above - which I've affectionally dubbed guesstalt (as I used it to brute force values) is available for download from the website, along with other enhancements, like mapping the keys to their obfuscated form. I've also provided the entitlements required to get past protected keys, as well as CoreTelephony, Wifi, etc (in cases where MG queries these daemons directly, by dlopen()ing their respective frameworks in your process address space). There is a veritable treasure trove here. I haven't taken to documenting the above keys or other 200 or so (I'll eventually add the list in a txt file that guesstalt will be able to parse), but this should prove to be a great vantage points for iOS coders who want to get this information into their apps or tweaks. As usual, the code is free for you to use and abuse, though credit (where due), tweet, feedback or a forum post would be appreciated.
This makes guesstalt the first "official" tool (of several planned) to accompany MOXiI 2. The book itself (Volume I, User Mode) will be out around late October - once Apple releases iOS 9 and 10.11 (or 11?). This way I can ensure that the book is up-to-date with the latest and greatest, and hopefully make it relevant for the foreseeable future (unlike MOXiI 1, which my then-publisher didn't let me cover 10.8/iOS 6 in..). You can view Volume I's Table of Contents here, and see the ongoing list of requests by readers (and add your own!) on on the book's forum. In particular, I'm taking requests for other frameworks and daemons to dissect.
If you can't wait for the book - or want a deeper understanding of reversing in the context of OS X/iOS - Technologeeks' Reverse Engineering on OS X and iOS training is scheduled for March 14th, in DC. Yours truly will be there to deliver the training - and I'd love it if we had a packed classroom! Registration is open - email i/n/f/o@TG for that! You're also welcome to Follow @Technologeeks for more updates about their courses and my Android/OSX/iOS work, or check out the RSS feed if you just want book updates.
Lastly, you're always welcome to comment or ask questions on the Book's forum (People discuss these articles in Reddit and other fora - which kind of defeats the purpose when they could ask the author directly..- and that's exactly what the book forum is for).