这几段代码不长,所以要挨个看,最后写了一个综合起来的方法,但是因为木有破解的工具──XCrack, PoedCrack, C4Crack,Crackulous,曾尝试下了前两个工具,但是都是exe文件。所以无法验证这些09年的代码是否在当前还能用。
// one
这段代码是首先确定不是iphone模拟器,我们可以捕获到进程id,来确定它不是root。基本上,任何时候只要有人破解你的应用一些进程就会作为root自动运行来执行程序。我们可以简单的确定用户不是root,这个方法的问题是,一些app并不会作为root来运行,所以被破解的程序依然不会受影响。
#if !TARGET_IPHONE_SIMULATOR
int root = getgid();
if (root <= 10) {
//Pirated
}
#endif
// two
这段代码主要是来自另一位iphonedersdk‘er,基本上,这个方法是结合了我所描述过的两个方法。1.核实plist文件的大小。2.加个甜蜜陷阱~
#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];
}
}
// three
这里我们做的就是验证一下_CodeSignature,CodeResources和ResourceRules.plist文件是否存在。任何时候有人想破解应用的时候,他们会排斥这些文件,因为它们会包括破解者的个人信息,当然,这个方法不是绝对的好,但是不会容易被破解。
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");
}
// four
下面这个方法是很前沿的技术,我们这里根据info.plist和执行文件的时间戳来和PkgInfo文件的比较。当hacker破解了一个应用的时候,他们基本上都会改主要的文件或者info.plist。因此时间戳是个不错的判断方法。但是,下面的留言者有给作者提了一些疑问,是说这种方法存在漏洞,即使自己建立了一个非常clean的应用,时间上还是不能保证info.plist和执行文件的时间戳小于pkg文件的时间戳,所以给了作者一些建议,就是取两者差的绝对值,大于10min,就基本上确定应用是被破解了。
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(fabs([infoModifiedDate timeIntervalSinceReferenceDate] - [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) > 600) {
//Pirated
}
if(fabs([infoModifiedDate2 timeIntervalSinceReferenceDate] - [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) > 600) {
//Pirated
}
//five
在讲这一个方法的时候,我要说的是先把main.m的后缀改成.mm,因为我们要将下面这段C++代码加在main.mm里面,这段代码确保在寻找消失的文件和时间戳中已经头晕了的我们在破解行为开始之前就停止它!这是我见过的最好的反破解方法。只要有破解的,它就会剥掉这个加密术来运行它,这个方法非常容易来检验你的执行程序是否被加密了。
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.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
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;
}
Last Code:
下面这段代码是根据上边的方法综合在一起的,因为那个放在main.mm里面的方法有一定的局限性,所以暂时不用它,下面这个方法就是(判断“时间戳+消失的文件”)这个方法可以放在我们应用的任何地方!
-(void) crackCheck {
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(fabs([infoModifiedDate timeIntervalSinceReferenceDate] - [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) > 600) {
if (gameState == kGameStateRunning) {
gameState = kGameStatePaused;
if (crackedProgress.hidden) {
crackedProgress.hidden = NO;}
if (crackedAlert.hidden) {
crackedAlert.hidden = NO;}
}
}
if(fabs([infoModifiedDate2 timeIntervalSinceReferenceDate] - [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) > 600) {
if (gameState == kGameStateRunning) {
gameState = kGameStatePaused;
if (crackedProgress.hidden) {
crackedProgress.hidden = NO;}
if (crackedAlert.hidden) {
crackedAlert.hidden = NO;}
}
}
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/_CodeSignature", bundlePath)];
if (!fileExists) {
if (gameState == kGameStateRunning) {
gameState = kGameStatePaused;
if (crackedProgress.hidden) {
crackedProgress.hidden = NO;}
if (crackedAlert.hidden) {
crackedAlert.hidden = NO;}
}
}
BOOL fileExists2 = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/CodeResources", bundlePath)];
if (!fileExists2) {
if (gameState == kGameStateRunning) {
gameState = kGameStatePaused;
if (crackedProgress.hidden) {
crackedProgress.hidden = NO;}
if (crackedAlert.hidden) {
crackedAlert.hidden = NO;}
}
}
BOOL fileExists3 = [[NSFileManager defaultManager] fileExistsAtPath:(@"%@/ResourceRules.plist", bundlePath)];
if (!fileExists3) {
if (gameState == kGameStateRunning) {
gameState = kGameStatePaused;
if (crackedProgress.hidden) {
crackedProgress.hidden = NO;}
if (crackedAlert.hidden) {
crackedAlert.hidden = NO;}
}
}
}