I found out that many users use so-called "IAP crackers" instead of purchasing the items in in-app purchase (IAP). I also learned that Zynga Poker and Pokerist already detect IAP crackers and prevent the fake IAP. I would like to detect which phone is using IAP cracker. For Cydia hacking tool, I could find it with Application path.
But for I don't believe iAP crackers fall into specific applications. I think I can check that by calling "Url Scheme" but I don't know the name. Is there anybody who knows how?
The best solution at the moment seems to be verifying IAP transactions using an external server, then sending back some sort of device-specific key to unlock the paid item that can only be generated on that server. This isn't bulletproof, but it should make your app highly resistant to any general-purpose IAP cracking system; someone who wanted to crack your app would pretty much have to develop a crack specifically for it. (which is far more complicated, well beyond the reach of most of the people using IAP Cracker)
Here's what you'd basically need to do:
- Design your in-app security solution; some sort of a unique key that unlocks your added functionality. If the added functionality takes the form of an data file then this might be an encryption key to unscramble that file, if it's all in code then it's a bit harder but there are lots of creative solutions out there (encrypted string constants, e.g.). Whatever it is, though, it should rely on or check for the presence of some piece of data that it'll get from your web server.
- Modify your IAP processing code so that when it sees a transaction processed, it sends the details of that transaction to your web server and fetches back the unique key needed in step 1.
- Write a simple script on your web server that takes the transaction details, verifies them with Apple (see the developer docs for details on how receipt verification works - pretty simple JSON request), and upon a successful verification returns the key from step 1.
(see text after EDIT below for some extra verification you need to do now in step 3)
In your case, since your app has already been cracked and you're trying to deactivate people who obtained your IAP item illicitly, you'd push this functionality out in a new version of your app, then call a restoreCompletedTransactions the first time the new version was run to re-validate / reactivate purchases for your legitimate users and block everyone else.
I should add, however, that this is a LOT of work - took us a couple of weeks of programmer time to get it operating smoothly, though there's open-source code floating around now that will handle most of steps 2 and 3 for you. There's also a support and PR cost to that reactivation step - inevitably some people will have changed iTunes accounts or be without an internet connection or something like that and they'll probably be pretty ticked off to even briefly lose access to something they legitimately paid for.
You need to weigh whether it's really worth investing the time in this, when the crack is only available to jailbreak users (so something like 90% of your potential customers are unaffected) and most of the people installing it were unlikely to pay for your app anyway; don't be scared by the sheer numbers of users cracking your app, many people will happily download something for free even if they'd never pay for it. You would probably be better off putting your time into improvements that benefit legitimate users (and encourage more of them to buy your app).
EDIT A year later this is still (mostly) accurate, but to deal with the new crack announced today that intercepts and then re-sends genuine receipts, there's now a bit more work needed on the server side. (fortunately, if you already have a verification server set up you should be able to do this without updating your app) Two new requirements:
1) Check that the product IDs (both the application ID and the IAP product one) in the decrypted receipt you get back from Apple's server actually match the product that the user is purchasing.
2) Check that the transaction ID in the receipt (or the restore transaction ID for a restore receipt) has never been used before, by keeping a log of previously used transaction IDs.
Even with IAP cracking available to non-jailbroken users now, though, my basic point remains that this may be more trouble than it's worth - to make back the amount of time you'll spend implementing and maintaining a thoroughly un-fun batch of code, you'd need to get a LOT of extra sales from people who were, after all, so disinclined to pay for your product that they were willing to massively compromise their iPhone's security in order to avoid doing so.
I just found a $20 component on BinPress that claims to provide this protection for you. In fact, it was reading their description that prompted me to search for IAP Cracker and led me to this question!
From a quick read through the description it seems worth trying at least as a cheap barrier to these attacks.
This component provides protection against tools that bypass in-app purchases and unlock premium content for free, such as the most popular 'iAP Cracker'. Protection is managed via a hosted receipt verification service hosted on our servers. It comes with both proven security and reliability against cracking tools and is meant to be as easy as possible to integrate for the developer.
'In-app purchase verification' is for those who don't maintain a server and want to avoid managing purchase verification themselves – it's a huge time saver: Implementing it is as easy as inserting a few extra lines of code (see below). From then on, the server will do its magic and it'll verify each receipt with an Apple server. It'll also provide you with a count of purchases made.
Apple stated this problem here: In-App Purchase Receipt Validation on iOS
As described in the text, validate your transactions after they have completed and you should be fine (hopefully).
You should try system("dpkg -l | grep iapCracker > /var/tmp/logiap.txt"); then fill a NSString with the content of logiap.txt and check if the string cointain something. But I don't know if apple allow you to do this ;)
To detect IAP Cracker you can simply check for installed package with NSFileManager
. I've tried it with Cydia to detect a jailbreak and it works fine.
As Cydia is automaticly installed on every jailbroken device, you can check for Jailbreak like this:
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]){
NSLog(@"Jailbreak detected");
}
IAP Cracker is just some package, that is also installed in your system, you can check for it too.
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/iap.dylib"]){
NSLog(@"IAP Cracker detected");
}
Does anybody knows if it's violating some Apple guidelines?
The NSFileManager
method, written by @Morpheus2002 was not working for me, and might be violating Apple's guidelines. To check if Cydia is installed and therefore if the device is jailbroken, you can check if you can open cydia://home
URL scheme as suggested @MarkJohnson:
if (![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://home"]]) {
NSLog(@"Jailbreak is not detected");
} else {
NSLog(@"Jailbreak is detected");
}
Will be submitting this in an app this week (May 2015). So will see if Apple approves
+(BOOL)isJailbroken {
#if (TARGET_IPHONE_SIMULATOR)
return NO;
#endif
#ifndef IS_APP_EXTENSION
NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
BOOL doesHaveCydia = [[UIApplication sharedApplication] canOpenURL:url];
if (doesHaveCydia) {
return YES;
}
NSError* error=nil;
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/System" error:&error];
//NSLog(@"blah %i error %@",(int)[files count], error);
if (error==nil) {
//A non-jailbroken device will have an operation not permitted error.
//Jailbroken device should have a list of files and a nil error.
if (files) {
NSLog(@"jailbreak? %i",(int)[files count]);
}
return YES;
}
return NO;
#else
return NO;
#endif
}