The previous post in this series involved trying to make a post to Vine outside of the iOS app by reverse engineering their API. That led to two discoveries:
- The Vine API is thankfully simple to deal with.
- Being able to make the right API calls is not all that useful without the keys required to upload a video to the Vine S3 bucket.
I'm going to need to find the Keymaster.
To follow along at home with this post, you'll need a jailbroken iOS device.
I've got an iPhone running iOS 5 that meets this criteria, but I hear that kind
of operation can be performed on iOS 6 these days. Go on,
brick liberate your iPhone, then continue onward. You'll also want to
install ssh while you're at it,
and then you can get a working copy of gdb
onto the device. I never said this was going to be easy.
Running Vine on the device and grepping the process list doesn't actually reveal the location of the app—the binary must have a non-obvious name.
Gabriel-Girondas-iPhone:~ root# ps ax | grep -i vine 59390 s000 R+ 0:00.00 grep -i vine
Applications from the App Store are installed in
that looks like a great place to point
Gabriel-Girondas-iPhone:~ root# find /var/mobile/Applications -iname '*vine*' /var/mobile/Applications/5EA25DA6-8D29-491E-9C46-DB304017241D/Bing.app/MapSDKResources.bundle/MapControlLibraryResources.bundle/pin_VineyardsWineries.png /var/mobile/Applications/5EA25DA6-8D29-491E-9C46-DB304017241D/Bing.app/MapSDKResources.bundle/MapControlLibraryResources.bundle/pin_VineyardsWineriesClick.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/Library/Caches/com.crashlytics.data/com.vine.iphone /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/Library/Caches/com.vine.iphone /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/Library/Preferences/com.vine.iphone.plist /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineLocationIcon.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineLocationIcon@2x.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineLocationTag.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineLocationTag@2x.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineMainFeedLocationIcon.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/VineMainFeedLocationIcon@2x.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/vinebug.png /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137firstname.lastname@example.org
Taking a cue from Clippy, Bing has appeared at the most inopportune time to just
get in the way. However, it looks like the app bundle has been located at
/var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137, and a quick
grep of the process list for that UUID shows the location of the running Vine
Gabriel-Girondas-iPhone:~ root# ps ax | grep C36542DB-CAA1-4C7C-8C45-E4CB62B1B137 59361 ?? Ss 0:04.51 /var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/iphone 59429 s000 R+ 0:00.00 grep C36542DB-CAA1-4C7C-8C45-E4CB62B1B137
$ scp email@example.com:/var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/iphone vine-iphone firstname.lastname@example.org's password: iphone 100% 3312KB 3.2MB/s 00:01 $ file vine-iphone vine-iphone: Mach-O universal binary with 2 architectures vine-iphone (for architecture armv7): Mach-O executable arm vine-iphone (for architecture cputype (12) cpusubtype (11)): Mach-O executable arm $ class-dump vine-iphone /* * Generated by class-dump 3.4 (64 bit). * * class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2012 by Steve Nygard. */ #pragma mark - /* * File: vine-iphone * UUID: 922C1689-2984-337D-983E-AABB8599F67A * Arch: armv7 * Minimum iOS version: 5.0.0 * SDK version: 6.0.0 * * Objective-C Garbage Collection: Unsupported * This file is encrypted: * cryptid: 0x00000001, cryptoff: 0x00002000, cryptsize: 0x00139000 */ $ otool -o vine-iphone | head -n 20 vine-iphone (architecture armv7): Contents of (__DATA,__objc_classlist) section 0013cc34 0x16902c isa 0x169018 superclass 0x0 cache 0x0 vtable 0x0 data 0x13da80 (struct class_ro_t *) flags 0x94 RO_HAS_CXX_STRUCTORS instanceStart 4 instanceSize 32 ivarLayout 0x1318f4 layout map: 0x73 0x6f 0x6d 0x65 0x20 0x73 0x74 0x72 0x69 0x6e 0x67 0x20 0x66 0x72 0x6f 0x6d 0x20 0x61 0x20 0x70 0x72 0x6f 0x74 0x65 0x63 0x74 0x65 0x64 0x20 0x73 0x65 0x63 0x74 0x69 0x6f 0x6e name 0x131873 some string from a protected section baseMethods 0x13d854 (struct method_list_t *) entsize 12 count 30 name 0xffa0f some string from a protected section types 0x133cda some string from a protected section imp 0x3441
As suspected, the binary is DRM-laden, so
class-dump can't do much besides
point that out, and running
strings(1) against it isn't going to reveal
anything of any use either.
otool prints some vaguely interesting
Objective-C runtime information, but the encryption thwarts it as well.
If we had a decrypted binary we could probably find out more information about the application, and I indeed dumped one when doing research for this post. Instructions on doing this are fairly readily available, and there are apps in Cydia that will perform the entire process for you.
However, for the purpose of pulling the keys from the binary, the information that I found most useful was a list of Objective-C classes used in the application. It isn't necessary to dump a decrypted copy of the app for this— the Objective-C runtime will happily spit it out. Dumping a decrypted copy of the app may be useful for other endeavours, so it's a handy technique to keep in mind. For the purposes of just dumping the classes, I've written a tiny chunk of C to pull this off instead.
I have that checked out, built the iOS version, and
scped it over to the iOS
device. Time to attach
gdb to the Vine process and see if we can avoid
segfault-city and garner some useful information.
Gabriel-Girondas-iPhone:~ root# ./gdb -p 59361 GNU gdb 6.3.50-20050815 (Apple version gdb-1821) (Fri Jun 29 08:41:41 UTC 2012) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "arm-apple-darwin". /private/var/root/59361: No such file or directory Attaching to process 59361. Reading symbols for shared libraries . done Reading symbols for shared libraries ............................................................................................................................................................................ done Reading symbols for shared libraries + done 0x31473004 in mach_msg_trap () (gdb) bt #0 0x31473004 in mach_msg_trap () #1 0x31473200 in mach_msg () #2 0x372a03f2 in __CFRunLoopServiceMachPort () #3 0x3729f0f0 in __CFRunLoopRun () #4 0x372224a4 in CFRunLoopRunSpecific () #5 0x3722236c in CFRunLoopRunInMode () #6 0x339e1438 in GSEventRunModal () #7 0x30fcecd4 in UIApplicationMain () #8 0x0005042a in ?? () #9 0x000503e0 in ?? () (gdb) info sources No symbol table is loaded. Use the "file" command. (gdb) call (void *) dlopen("/var/root/objc_rt_class_dump.dylib") Reading symbols for shared libraries warning: Could not find object file "/Users/ggironda/Repositories/objc_rt_class_dump/objc_rt_class_dump.o" - no debug information available for "/Users/ggironda/Repositories/objc_rt_class_dump/objc_rt_class_dump.c". . done $1 = (void *) 0x2e4540 (gdb)
Loading the library leaves a file at
/tmp/objc_rt_class_dump.txt on the
device, the content being a list of the Objective-C classes in the application,
along with property names, class and instance method names, and method
implementation addresses. Grepping this for “Amazon” shows that the AWS iOS SDK
is obviously in use here.
$ grep -i amazon objc_rt_class_dump.txt AmazonS3Client AmazonErrorHandler AmazonAbstractWebServiceClient AmazonJSON AmazonRequestDelegate AmazonCredentials AmazonURLRequest AmazonMD5Util AmazonDictionaryUnmarshaller AmazonServiceResponseUnmarshaller AmazonServiceResponse AmazonServiceRequest AmazonWebServiceClient AmazonUnmarshallerXMLParserDelegate AmazonSignatureException AmazonServiceException AmazonLogger AmazonClientException AmazonAuthUtils AmazonSDKUtil
Checking out the file in a text editor shows lots of interesting sounding
initWithAccessKey:withSecretKey:, which would yield the required
keys right there and then. The problem is attaching
gdb before the app can
call this method, and unfortunately, just executing the binary doesn't launch
the app like it does under OS X. Thanks Obama.
Finding a place where the secret key is passed as an argument, or available as
an instance variable sounds like an easier place to slide in and intercept the
key. Trawling through the list of methods on
AmazonS3Client reveals a
and reading the code for it lands us on a promising looking class method,
+[AmazonAUthUtils HMACSign:withKey:usingAlgorithm:]. Setting a breakpoint on
the method name itself won't work due to the lack of symbols.
(gdb) break +[AmazonAUthUtils HMACSign:withKey:usingAlgorithm:] Function "+[AmazonAUthUtils HMACSign:withKey:usingAlgorithm:]" not defined. Make breakpoint pending on future shared library load? (y or [n])
Thankfully, that rickety chunk of C has provided us with a bounty of addresses to use instead.
$ grep HMACSign objc_rt_class_dump.txt HMACSign:withKey:usingAlgorithm: 0x1532b9
Setting a breakpoint at this address and recording a Vine leads to an exciting pause in program execution, rather than the terrifying kind.
(gdb) break *0x1532b9 Breakpoint 1 at 0x1532b9 (gdb) c Continuing. Reading symbols for shared libraries . done Breakpoint 1, 0x001532b8 in ?? () (gdb)
This is kind of another small world of shit. If debugging symbols were available
then there'd be smooth seas ahead, but there's just one more tricky little bit
of navigation involved.
info args is pretty useless, so another way of
accessing the function arguments is required. The standard ARM calling convention
states that registers r0 through r3 are used for holding argument values. A peek
at the internal mechanics of
shows that the implementation of a method is called with at least two arguments,
a pointer to the object that is
self, and the selector of the message that was
sent. Breaking that down into the arguments that should be given to the
implementation, one may expect:
r0to hold a pointer to
AmazonAuthUtilsin this case.
r1to contain a
r2to reference the
NSDatapassed as the value to
r3to reference the
NSStringcontaining exactly what we want, the
NSStringholding the AWS secret key, the argument to
(gdb) info args No symbol table info available. (gdb) po $r0 AmazonAuthUtils (gdb) po $r3 ISw3ArT0g0DthEREw4S4rEALk3yHER3but1mNOTM4KInGTh1sTH4T3asY (gdb)
I haven't printed the actual key here because there's no sign out on top of this
site that says “AWS Credential Storage”. If you're that interested, then follow
along at home. The work for this post is done, so feel free to exit
gdb in an
In part 3 of this series, I'll tie it all together. Now you too can have yet another place to assault innocent phone-holders with tired old animated gifs.
Update: Check out part 3.