Welcome back everybody! This is the second tutorial on iPhone/iTouch Anti-Piracy code from all over the world. For those of you who are new to Anti-Piracy, let me get you updated: App Store Piracy today is running ramped, with over 5 Million pirates in counting, Developers are losing millions of dollars in revenue every day. Some companies have reported piracy rates of over 95%, after only one day.
*Since this tutorial is a collection of Anti-Piracy methods from all over, credits go to their respective authors. I would also like to add that I'm not going into the ethics of hacking or Anti-Piracy during this tutorial and would appreciate if comments about the ethics of Piracy and Anti-Piracy be omitted. Great, with that out of the way, Let's do this!
Let's start with something simple this time. Remember those SignerIdentity checks we did last time? Well, they're going to become obsolete soon with newer methods of cracking just on the horizon; so I thought we'd focus on other areas this time:
Code:
#if !TARGET_IPHONE_SIMULATOR
int root = getgid();
if (root <= 10) {
//Pirated
}
#endif
This code is very self explanatory. We are checking to make sure the user is not the iPhone Simulator, we're grabbing the process id, and checking to make sure it's not the root. Basically, whenever someone cracks your application, some automated processes run it as root in order to run gdb. We are simply making sure that user is not the root. This problem with this method is that the app does not have to be run as root, therefore many cracking applications can be adjusted around this.
This next method comes from one of our fellow iPhoneDevSDK'ers: javaconvert:
Code:
#define kInfoSize 500
//Place your NSLog Plist Size into the above Define statment
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
NSString* path = [NSString stringWithFormat:@"%@/Info.plist", bundlePath ];
NSDictionary *fileInfo = [[NSBundle mainBundle] infoDictionary];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *fileAttributes = [fileManager fileAttributesAtPath:path traverseLink:YES];
if (fileAttributes != nil) {
NSNumber *fileSize;
if(fileSize = [fileAttributes objectForKey:NSFileSize]){
NSLog(@"File Size: %qi\n", [fileSize unsignedLongLongValue]);
//Best to see the File Size and change it accordingly first
NSString *cSID = [[NSString alloc] initWithFormat:@"%@%@%@%@%@",@"Si",@"gne",@"rIde",@"ntity",@""];
BOOL checkedforPir = false;
if([fileInfo objectForKey:cSID] == nil || [fileInfo objectForKey:cSID] != nil) {
if([fileSize unsignedLongLongValue] == kInfoSize) {
checkedforPir = true;
}
}
if(!checkedforPir){
//Pirated
}
[cSID release];
}
}
Basically what we're doing here is combining 2 of the methods I posted in the last tutorial: Checking the plist size and adding a honeytrap.
This is where we get into some new stuff:
Code:
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/_CodeSignature", bundlePath)];
if (!fileExists) {
//Pirated
NSLog(@"Pirated");
}
BOOL fileExists2 = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/CodeResources", bundlePath)];
if (!fileExists2) {
//Pirated
NSLog(@"Pirated2");
}
BOOL fileExists3 = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/ResourceRules.plist", bundlePath)];
if (!fileExists3) {
//Pirated
NSLog(@"Pirated3");
}
Impressed right? I know I am. What we're doing here is checking to see if "_CodeSignature", "CodeResources", and the "ResourceRules.plist" files exist. Whenever someone cracks an application, they usually exclude the following files because they include the cracker's personal information. Once again, not the absolute best, but not easily crackable.
This next method is cutting edge technology:
Code:
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
NSString* path = [NSString stringWithFormat:@"%@/Info.plist", bundlePath];
NSString* path2 = [NSString stringWithFormat:@"%@/AppName", bundlePath];
NSDate* infoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] fileModificationDate];
NSDate* infoModifiedDate2 = [[[NSFileManager defaultManager] fileAttributesAtPath:path2 traverseLink:YES] fileModificationDate];
NSDate* pkgInfoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"PkgInfo"] traverseLink:YES] fileModificationDate];
if([infoModifiedDate timeIntervalSinceReferenceDate] > [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
//Pirated
}
if([infoModifiedDate2 timeIntervalSinceReferenceDate] > [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
//Pirated
}
What we're doing here is checking the timestamps on the info.plist and the executable file against the PkgInfo file to check if any of the files have been modified after the application was built. Whenever a hacker cracks an iPhone application, they *basically* have to modify the main file and/or info.plist file, which changes the timestamps. One of the only things they don't end up editing is the PkgInfo file, so by checking the executable and info.plist file's timestamps, we can make sure none of the files have been edited. *Anyone having trouble with this method, try building your project at the beginning of a minute (i.e. 3:14:00 instead of 3:14:59). This can cause a mismatch in timestamps between some of the first files in your project, and the last ones.
So now that we've messed around with looking for lost files and timestamps, we're gonna stop the act before it has occurred. This is were we're gonna stop messing around and pull out the big guns:
Code:
#import
#import
#import
#import
// The iPhone SDK doesn't have , but it does have ptrace, and it
// works just fine.
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
void ZNDebugIntegrity() {
// If all assertions are enabled, we're in a legitimate debug build.
#if TARGET_IPHONE_SIMULATOR || defined(DEBUG) || (!defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG))
return;
#endif
// Lame obfuscation of the string "ptrace".
char* ptrace_root = "socket";
char ptrace_name[] = {0xfd, 0x05, 0x0f, 0xf6, 0xfe, 0xf1, 0x00};
for (size_t i = 0; i < sizeof(ptrace_name); i++) {
ptrace_name[i] += ptrace_root[i];
}
void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, ptrace_name);
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
}
Yeah, it's a little more complicated. In a nutshell we're just checking to see if the debugger is attached to your application, and if it is, stopping the debugger. In order to crack an application you have to attach a debugger to it, stop it, and dump it from the memory. If you stop the debugger then you've cut the head from the snake.
The last method I have for you today is the best:
Code:
#import
#import
#import
/* The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from the iPhoneOS or
* Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just provide the definitions here. */
#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
int main (int argc, char *argv[]);
static BOOL is_encrypted () {
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? */
return YES;
}
cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
}
/* Encryption info not found */
return NO;
}
This is one of the best Anti-Piracy implementations that I've seen; no strings attached

What you're doing here is taking the Executable file and checking to see if their is any encryption on it. You can also check this on your mac by taking an executable file and typing in "otool -l *exectuable file*" in terminal. you can also check out Dr. Touch's
Anti-Crack commercial to see it in action. Whenever a pirate cracks an application it strips the encryption in order to run it, with this implementation it's very easy to check if your executable is encrypted.
Continued...