Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I detect if an app has been cracked without examining the SignerIdentity?

There used to be a method to check if an application was purchased from the App Store, to protect against cracking:

NSBundle *bundle = [NSBundle mainBundle]; 
NSDictionary *info = [bundle infoDictionary]; 
if ([info objectForKey: @"SignerIdentity"] != nil) 
{ /* do something */  }

but this method no longer works because the crackers have found ways around altering the Info.plist. I'm aware of this older question, but the answers presented there rely on the above technique, which is no longer valid.

How can you detect whether your application was cracked or purchased legitimately from the App Store without reading the SignerIdentity from the Info.plist?

like image 670
Dmitry Avatar asked Oct 08 '12 01:10

Dmitry


2 Answers

I like Mick's answer personally as it's short and simple.

Greg's response isn't valid -- Mick's code only checks whether the App can open that URL so there should be no chance of crashing.

I've implemented the following in one of my apps before which does a more strict check of whether the app is encrypted or not, if it's not it's most likely a cracked app:

From analytics, this method has prevented thousands of pirated users for me and took maybe 5 minutes to implement so the cost of doing it was almost nothing -- for me, I didn't care if it increased sales (which I was sure it wasn't going to anyway--it's more that I don't want people freeloading off of my hard work). In addition, a good amount of my app's content feeds information after figuring out whether the app is pirated or not and returns junk data if it is.

In main.m

#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <TargetConditionals.h>

#if TARGET_IPHONE_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
#define LC_ENCRYPTION_INFO 0x21
struct encryption_info_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint32_t cryptoff;
    uint32_t cryptsize;
    uint32_t cryptid;
};
#endif

static BOOL isEncrypted();

static BOOL isEncrypted () {
    const struct mach_header *header;
    Dl_info dlinfo;

    /* Fetch the dlinfo for main() */
    if (dladdr(main, &dlinfo) == 0 || dlinfo.dli_fbase == NULL) {
        //NSLog(@"Could not find main() symbol (very odd)");
        return NO;
    }
    header = dlinfo.dli_fbase;

    /* Compute the image size and search for a UUID */
    struct load_command *cmd = (struct load_command *) (header+1);

    for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++) {
        /* Encryption info segment */
        if (cmd->cmd == LC_ENCRYPTION_INFO) {
            struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) cmd;
            /* Check if binary encryption is enabled */
            if (crypt_cmd->cryptid < 1) {
                /* Disabled, probably pirated */
                return NO;
            }

            /* Probably not pirated <-- can't say for certain, maybe theres a way around it */
            return YES;
        }

        cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
    }

    /* Encryption info not found */
    return NO;
}
like image 63
webstersx Avatar answered Oct 24 '22 14:10

webstersx


The official Apple's answer:

Hello Dmitry,

Thank you for contacting Apple Developer Technical Support (DTS). 

DTS does not provide code-level support for DRM issues.  

Please try posting your inquiry to Apple Development Forum:

<https://devforums.apple.com>

While you were initially charged a Technical Support Incident (TSI) for this request, we have assigned a replacement TSI back to your account.

Thank you for understanding our support policies.

Best Regards,

Apple Developer Support 
Worldwide Developer Relations
like image 42
Dmitry Avatar answered Oct 24 '22 14:10

Dmitry