How Facebook-Research app works

How Facebook-Research app works

Last night I saw this tweet from Will Strafach:

After reading that article I just needed to reverse this iOS app and see how it worked, this is what I've found so far:

Downloading the app:

As the article mentions, you can download it from 3rd parties like Applause and BetaBound, but after signing up and downloading they both open iTunes with the manifest located at hxxps://r.facebook-program.com/ios/stable/manifest.plist and this is its content:

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> 
	<dict> 
		<key>items</key> 
		<array> 
			<dict> 
				<key>assets</key> 
				<array> 
					<dict> 
						<key>kind</key> 
						<string>software-package</string> 
						<key>url</key> 
						<string>
							<![CDATA[https://r.facebook-program.com/ios/stable/package.ipa]]>
						</string> 
					</dict> 
				</array> 
				<key>metadata</key> 
				<dict> 
					<key>bundle-identifier</key> 
					<string>com.facebook.research.internalDevelopment</string> 
					<key>bundle-version</key> 
					<string>121335361</string> 
					<key>kind</key> 
					<string>software</string> 
					<key>title</key> 
					<string>Facebook Research</string> 
				</dict> 
			</dict> 
		</array> 
	</dict> 
</plist>

As you can see they are using com.facebook.research.internalDevelopment as their Bundle Identifier. internalDevelopment 😁and the software-package (a.k.a. the app) is located at hxxps://r.facebook-program.com/ios/stable/package.ipa (SHA256: 96b282e39e465d57eba440c53b73f442bc4ce6fc10a4445bdd90a412f87c42bd) although, like Will said, it probably won't be there for long.

Static Analysis:

The actuall app is called PowerLogs and uses this embedded.mobileprovision:

As you can see it belongs to Facebook Inc (In-House).
Then I opened the Info.plist file and found these two values (remember FacebookClientToken, it will be important later):

FacebookAppID: 166732727149960
FacebookClientToken: 2d49f15626c6430ec7cbdf77f9a977cc

After this, I loaded the binary in Hopper and started browsing through some classes/methods, wanted to find where was the app connecting to; that's when I found a class called PLServerApis and its initialization method in pseudo-C looks like this:

-(void *)init {
    r7 = (sp - 0x14) + 0xc;
    sp = sp - 0x30;
    r1 = @selector(init);
    asm { strd       r0, r2, [sp, #0x28 + var_20] };
    r4 = objc_msgSendSuper2(sp + 0x8, r1);
    if (r4 != 0x0) {
            [NSURL URLWithString:@"https://graph.onavo.com"];
            r10 = _objc_retainAutoreleasedReturnValue;
            r5 = (r10)();
            var_24 = r5;
            r0 = [AFHTTPSessionManager alloc];
            r0 = [r0 initWithBaseURL:r5];
            r11 = *ivar_offset(_client);
            r8 = _objc_release;
            r1 = *(r4 + r11);
            *(r4 + r11) = r0;
            (r8)(r1, r1, 0x144098);
            var_28 = *(r4 + r11);
            [AFJSONResponseSerializer serializer];
            r5 = (r10)();
            [var_28 setResponseSerializer:r5];
            (r8)(r5);
            r5 = *(r4 + r11);
            [AFJSONRequestSerializer serializer];
            r6 = (r10)();
            [r5 setRequestSerializer:r6];
            (r8)(r6);
            (r8)(var_24);
    }
    r0 = r4;
    return r0;
}

The API endpoints use the Onavo host hxxps://graph.onavo.com, as Will mentioned, this "research" app looks like it's just an Onavo wrapper.

Also I think since this is a research app, the developers really like to hard-code values like this access_token (ON|255936594766932|c0a691bb6a59bb36ee4cc35e5d0f92f1):

-(void)registerWithInvitationCode:(void *)arg2 success:(void *)arg3 failure:(void *)arg4 {
    r3 = arg3;
    r1 = _cmd;
    var_DC = self;
    var_1C = *___stack_chk_guard;
    var_EC = _objc_retain;
    r10 = [arg2 retain];
    var_E8 = [r3 retain];
    var_E0 = [arg4 retain];
    r4 = &@class(BaseUtils);
    r0 = *r4;
    r0 = [r0 generateSecureRandomAlphaNumericStringOfLength:0x18];
    r8 = _objc_retainAutoreleasedReturnValue;
    var_E4 = (r8)();
    var_A4 = @"access_token";
    var_60 = @"ON|255936594766932|c0a691bb6a59bb36ee4cc35e5d0f92f1";
    var_A0 = @"brand";
    var_9C = @"country";
    var_5C = @"Apple";
    r0 = *r4;
    r0 = [r0 getIsoCoutryCode];
    r7 = r7;
    var_F0 = (r8)();
    var_98 = @"device_identifier";
    var_94 = @"imei_unique_identifier";
    r0 = @class(UIDevice);
    r1 = 0x129b28;
    :
}

Another example is the ONVEventer class (which is the class that handles most of the events withing the app) because it's initialized this way:

if ([*0x17810c initialized] == 0x0) {
            r1 = @selector(initialized);
            r8 = *0x17810c;
            r5 = [objc_msgSend(@class(Utils), @selector(getFacebookAppId)) retain];
            r0 = [r8 setAppId:r5];
            r0 = [r5 release];
            r8 = *0x17810c;
            r5 = [objc_msgSend(@class(Utils), @selector(getFacebookClientToken)) retain];
            r0 = [r8 setLoginSecret:r5];
            r0 = [r5 release];
            :
            :
}

The getFacebookClientToken method returns the FacebookClientToken found in the Info.plist πŸ˜‰

(Update: phwd confirmed these tokens are not secrets)

The app also has a plugin called PacketTunnelResearch.appex that contains a binary called PacketTunnelResearch which I'm guessing is handling the actuall VPN functionality:
PacketiTunnelResearch

And based on the amount of onavo references it's pretty clear Facebook was reusing Onavo's code for this app:
isApnProxied

Sadly I didn't install the app when before Apple revoked Facebook's Enterprise Certificate(s), so I tried using Cydia Impactor to install it, but in order to install apps with Network Extensions we need a paid account:
impactor

Even with a paid account Impactor can't sign the entitlements correctly:
impactor-paid

This means I won't be able to dynamically check the app πŸ˜”

Apple responds

revoked-cert
facebook-apps-offline

Photo by Glen Carrie on Unsplash