Digging In The Vineyard, Part 2
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 /var/mobile/Applications
, so
that looks like a great place to point find
at:
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-E4CB62B1B137/iphone.app/vinebug@2x.png
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
binary.
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
Let's get the binary off the phone to take a closer look at it in a less cloistered environment. One or more of class-dump, file(1), and otool might reveal more information.
$ scp root@10.0.1.3:/var/mobile/Applications/C36542DB-CAA1-4C7C-8C45-E4CB62B1B137/iphone.app/iphone vine-iphone
root@10.0.1.3'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 scp
ed 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
methods like 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
signS3Request:
method,
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. gdb
's 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 objc_msgSend
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:
r0
to hold a pointer toself
,AmazonAuthUtils
in this case.r1
to contain aSEL
representingHMACSign:withKey:usingAlgorithm:
.r2
to reference theNSData
passed as the value toHMACSign:
.r3
to reference theNSString
containing exactly what we want, theNSString
holding the AWS secret key, the argument towithKey:
.
And thusly.
(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
orderly fashion.
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.