How to determine at run-time if app is for development, app store or ad hoc distribution?
Asked Answered
H

5

32

Is there a way to determine programmatically if the currently running app was built and signed for development only or whether it was built for distribution? And can one determine if was build for app store or ad hoc distribution?

Is it e.g. possibly to access the code signature and get the information from there? Or are there certain files present in one of variants that don't exist in the other ones? Is part of the bundle info? Or can it be derived from the executable file?

Any hints are appreciated.


It seems that the embedded.mobileprovision file is in ASN.1 format.

Heptamerous answered 6/8, 2010 at 18:4 Comment(0)
S
30

The easiest way to check is to look at embedded.mobileprovision ([[NSBundle mainBundle] pathForResource:@"embedded.mobileprovision" ofType:nil]):

  • It's a bit of a pain to parse since it's a signed plist (PKCS#7 signed data, according to openssl asn1parse -inform der), but a bad hack is to just look for <plist and </plist>.
  • Development contains UDIDs and <key>get-task-allow</key><true/>
  • Ad Hoc distribution contains UDIDs (and get-task-allow=false)
  • App Store distribution contains no UDIDs.

The other thing you can check is the entitlements embedded in the executable (otool -l lists it as LC_CODE_SIGNATURE). Parsing this is even more tedious (you need to parse the Mach-O header and load commands, and for "universal" binaries which are now the default, you'll need to check the currently-loaded architecture or all architectures).

  • Development builds contain <key>get-task-allow</key><true/>
  • Ad Hoc and App Store builds contain <key>get-task-allow</key><false/>

I don't think the entitlements distinguish between Ad Hoc and App Store builds.

Apart from those and the certificate it's signed with, there's no difference between Development/Ad Hoc/App Store apps (there are a few other things in the entitlements/provisioning profile, but nothing more reliable that I can think of).

Security considerations

Neither of these are that difficult to circumvent. For the first method, the app could just "swizzle" -[NSBundle pathForResource:ofType:]. The second method is a bit more difficult depending on what API you use to read the file.

Stedmann answered 6/8, 2010 at 19:5 Comment(5)
Thanks a lot for your useful input. The reason for determining the distribution type is that I'd like to sell a library that can be used for free during development and testing but requires a license for App Store distribution. The embedded.mobileprovision files that I found in the build directory of Xcode are binary files with some XML embedded. Is this the same once the app is installed on the device, or is the XML part installed only?Heptamerous
Hi Codo, I'm in the same situation... how did you end up implementing the check?Uptodate
For in house distribution you will see this: <key>ProvisionsAllDevices</key> <true/>Alpestrine
@SveinungKvalBakken I'm assuming you mean Enterprise In-House distribution. I also think it can be treated like App Store distribution, unless you want to offer special licence terms for In-House distribution.Stedmann
Thanks for this! I've wrapped it up in a category, in the hope that it will save someone some work somewhere down the line: github.com/blindsightcorp/BSMobileProvisionHandwriting
M
12

openssl asn1parse -inform DEM -in *Mobile_Provision_File* -strparse 54 is the easiest way to access the data that I've found.

EDIT:

security cms -D -i *Mobile_Provision_File* is actually easier. The openssl command leaves some garbage in the output.

Methedrine answered 26/3, 2012 at 15:20 Comment(1)
Brilliant. This is something I had been looking for for a very long time.Constrained
H
2

I've extracted an embedded.mobileprovision file and pasted into an online ASN.1 viewer (e.g. http://www.geocities.co.jp/SiliconValley-SanJose/3377/asn1JS.html), and that's what a got:

SEQUENCE {
   OBJECTIDENTIFIER 1.2.840.113549.1.7.2 (signedData)
   [0] {
      SEQUENCE {
         INTEGER 1
         SET {
            SEQUENCE {
               OBJECTIDENTIFIER 1.3.14.3.2.26
               NULL 
            }
         }
         SEQUENCE {
            OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data)
            [0] {
               OCTETSTRING 3c3f786d6c20766 ... 6c6973743e0a
            }
         }
         [0] {
            SEQUENCE {
               SEQUENCE {
                  [0] {
                     INTEGER 2
                  }
 ... [much more]

With this and some ASN.1 knowledge, your explanation makes perfect sense.

The interesting part is the octet string starting 3c3f786d6c. That's the XML part in Apple's property list format that contains all the answers about the distribution type (developer, ad-hoc, App Store).

Heptamerous answered 9/8, 2010 at 17:43 Comment(0)
M
0
#if (DEBUG)
#define SERVER @"aaaa.com/dev"
#else
#define SERVER @"aaa.com/pro"
#endif

that's the way i distinguish the debug and release mode ,

but i have no idea for adhoc or production unless use the provision profile name

Meade answered 23/3, 2014 at 16:46 Comment(0)
F
0

I create a gist to detect Ad Hoc build
See : https://gist.github.com/iShawnWang/d904934efded271d83b36288562df410

AdHoc detect with following 2 conditions :

1.embedded.mobileprovision contains field ProvisionedDevices (Debug and Ad Hoc Build contains this field ,Release not)

2.it is not DEBUG Build , we can use #ifdef DEBUG to decide it

NS_INLINE BOOL isAdHoc(){
    BOOL isAdHoc = NO;
    BOOL isDebug;

#ifdef DEBUG
    isDebug=YES;
#else
    isDebug=NO;
#endif

    NSData *data=[NSData dataWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"embedded" withExtension:@"mobileprovision"]];
    NSString *str=[[NSString alloc]initWithData:data encoding:NSISOLatin1StringEncoding];
    NSRange rangeOfDevicesUDIDs = [str rangeOfString:@"ProvisionedDevices"];

    isAdHoc = rangeOfDevicesUDIDs.location!=NSNotFound && !isDebug;
    return isAdHoc;
}
Feed answered 14/10, 2016 at 11:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.