ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C Часть 1

Распознавание взломанных приложений (Anti-Piracy)

В данной  статье описаны все возможные методы, которые необходимы для того чтобы распознать наличие взлома программы и возможные методы направленные на борьбу с процветающим пиратством.

Читаем очень внимательно! Все способы, которые будут описаны ниже, следует применять  только для ознакомительных целей с последующими методами защиты. За их рабочую способность наш сайт не несет никакой ответственности, это связано с постоянно обновляющимися технологическими компиляциями данных приложений и самой iOS. Подобранный материал послужит вам необходимым источником своего рода вдохновителем для того чтобы создать новую защитную систему.

Думаю что, достаточно разговаривать о формальностях, необходимо начинать:

1) Проверяем идентификатор:

<code data-result="[object Object]">#if !TARGET_IPHONE_SIMULATOR
    int root = getgid();
    if (root &lt;= 10) {
        //Крякнута
    }
#endif</code>

В данном случаи мы проверяем то, чтобы наш идентификатор процесса данного приложения не находился среди числа идентификаторов процессов системы ( поэтому стоит <= 10). Этот метод очень простой по своей реализации, так как он портативен и не нуждается в дополнительных библиотеках. Но не каждое приложение использует идентификатор системного процесса. Кроме всего этого, наш код очень легко будет обнаруживаться профессиональными хакерами.

2) Проверяем файлы. Данный метод, был предложен форумчанином крупнейшего иностранного форума девелоперов:

<code data-result="[object Object]">#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
", [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){
            //Крякнута
        }
        [cSID release];
    }
}</code>

Такой метод позволит проверить размер Signerldentitys в Info.plist. Если созданная строка находится в файле, то необходимо бить тревогу. Для лучшей маскировки от хакеров следует разбить строку на несколько частей. Я же вам рекомендую сделать побитовое смещение имеющихся строк.

3) Проверяем файлы. Это более усовершенстванное и весьма быстрое исполнение пункта под номером 2:

<code data-result="[object Object]">NSBundle *bundle = [NSBundle mainBundle];
NSDictionary *info = [bundle infoDictionary];
if ([info objectForKey: @"SignerIdentity"] != nil)
{
	//Крякнута
}</code>

Способ не нуждается в дополнительной библиотеке и очень портативен. Опять же следует разбить строки, так как если они открыты их довольно легко найти даже самым простым редактором. Необходимо спрятать строки  при помощи такого способа:

<code data-result="[object Object]">#define INIT_STRING @"SignerIdentity"
NSString *aString = INIT_STRING;</code>

Данные действия позволят скрыть SignerIdentitys 16-ричного редактора, а это делает взлом немного сложнее.

4) Проверяем файлы. Своего рода новинка:

<code data-result="[object Object]">NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
BOOL fileExists = [[NSFileManager defaultManager] 
                   fileExistsAtPath:(@"%@/_CodeSignature", bundlePath)];
if (!fileExists) {
    //Крякнута
}
BOOL fileExists2 = [[NSFileManager defaultManager] 
                    fileExistsAtPath:(@"%@/CodeResources", bundlePath)];
if (!fileExists2) {
    //Крякнута
}
BOOL fileExists3 = [[NSFileManager defaultManager] 
                    fileExistsAtPath:(@"%@/ResourceRules.plist", bundlePath)];
if (!fileExists3) {
    //Крякнута
}</code>

Такой метод просто проверит существование «_CodeSignatures», «CodeResource», и «ResourceRules.plcst». Во время взломов приложений данные файлы практически не учитываются и удаляются сами собой. По правде сказать- это не самый хороший метод, но его не просто взломать. Я вам рекомендую сделать побитовое смещение искомой строки.

5) Проверяем дату. Такой метод является вершиной технологий:

<code data-result="[object Object]">NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *path = [NSString stringWithFormat:@"%@/Info.plist", bundlePath];
NSString *path2 = [NSString stringWithFormat:@"%@/AppName", bundlePath];
NSString *path3 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"PkgInfo"];
NSDate* infoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] 
                            fileModificationDate];
NSDate* infoModifiedDate2 = [[[NSFileManager defaultManager] fileAttributesAtPath:path2 traverseLink:YES] 
                             fileModificationDate];
NSDate* pkgInfoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path3 traverseLink:YES] 
                               fileModificationDate];
if([infoModifiedDate timeIntervalSinceReferenceDate] &gt; [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
    //Крякнута
}
if([infoModifiedDate2 timeIntervalSinceReferenceDate] &gt; [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
    //Крякнута
}</code>

Это очень простой, но уникальный метод. Он проверяет даты модификаций Info.pliсt, бинарника, а также Pkg Info. С самого начала дата модификаций этих сложных 3х файлов была одинакова. После взломов даты модификаций файлов Info.pliсt и бинарника начинают меняться. Если дата Info.pliсt и бинарника немного позднее чем Pkg Info, то ваша программа была взломана или имелись попытки.

6) Анти-отладчик. Это очень действенный и мощный способ:

<code data-result="[object Object]">#import &lt;dlfcn.h&gt;  
#import &lt;mach-o/dyld.h&gt;  
#import &lt;TargetConditionals.h&gt;

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 TARGET_IPHONE_SIMULATOR || defined(DEBUG) || (!defined(NS_BLOCK_ASSERTIONS) &amp;&amp; !defined(NDEBUG))
    return;
#endif

    char* ptrace_root = "socket";
    char ptrace_name[] = {0xfd, 0x05, 0x0f, 0xf6, 0xfe, 0xf1, 0x00};
    for (size_t i = 0; i &lt; 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);
}</code>

Данный метод очень сложный по сравнению со всеми предыдущими. Вначале мы начинаем проверять, действует ли программа как отладчик или все-таки нет. Если действует, то необходимо остановить отладчик. При попытке взлома следует включить отладчик к приложению (Кракулоусы — не являются исключениями). Такой метод сможет успешно остановить процесс отладки и завершить его.

7) Шифрование. Способ проверки на SignerIdentitys, но с помощью применения процесса шифрования:

<code data-result="[object Object]">NSLog(@"Substitution Cipher:");
char symCipher[] = { '(', 'H', 'Z', '[', '9', '{', '+', 'k', ',', 'o', 'g', 'U', 
    ':', 'D', 'L', '#', 'S', ')', '!', 'F', '^', 'T', 'u', 'd', 'a', '-', 'A', 'f', 
    'z', ';', 'b', ''', 'v', 'm', 'B', '0', 'J', 'c', 'W', 't', '*', '|', 'O', 
    '', '7', 'E', '@', 'x', '"', 'X', 'V', 'r', 'n', 'Q', 'y', '&gt;', ']', '$', 
    '%', '_', '/', 'P', 'R', 'K', '}', '?', 'I', '8', 'Y', '=', 'N', '3', '.', 
    's', '&lt;', 'l', '4', 'w', 'j', 'G', '`', '2', 'i', 'C', '6', 'q', 'M', 'p', 
    '1', '5', '&amp;', 'e', 'h' };
char cfile[256];
[[[NSString alloc] initWithString:@"SignerIdentity"] getCString:cfile maxLength:sizeof(cfile) 
                                                       encoding:NSUTF8StringEncoding];
NSLog(@"%s",cfile);
for(int i=0;i&lt;strlen(cfile);i++)
cfile[i] = symCipher[cfile[i]-0x21];
NSLog(@"%s",cfile);
for(int i=0;i&lt;strlen(cfile);i++)
{
    for(int j=0;j&lt;sizeof(symCipher);j++)
    {
        if(cfile[i] == symCipher[j])
        {
            cfile[i] = j+0x21;
            break;
        }
    }
}
NSLog(@"%s",cfile);</code>

Для многих людей этот код покажется очень сложным, однако, это совсем не так. Мы применяем шифровку замены, основной криптографической формы, для того чтобы изменить строки SignerIdentitys. Так как вы сможете увидеть, что метод начинает шифровать строку SignerIdentitys в саму зашифрованную строку, а после этого действия расшифровываем ее снова в SignerIdentitys.

Расшифрованную строку необходимо записать в signIdentitys:

<code data-result="[object Object]">char symCipher[] = { '(', 'H', 'Z', '[', '9', '{', '+', 'k', ',', 'o', 'g', 
    'U', ':', 'D', 'L', '#', 'S', ')', '!', 'F', '^', 'T', 'u', 'd', 'a', 
    '-', 'A', 'f', 'z', ';', 'b', ''', 'v', 'm', 'B', '0', 'J', 'c', 'W', 
    't', '*', '|', 'O', '', '7', 'E', '@', 'x', '"', 'X', 'V', 'r', 'n', 
    'Q', 'y', '&gt;', ']', '$', '%', '_', '/', 'P', 'R', 'K', '}', '?', 'I', 
    '8', 'Y', '=', 'N', '3', '.', 's', '&lt;', 'l', '4', 'w', 'j', 'G', '`', 
    '2', 'i', 'C', '6', 'q', 'M', 'p', '1', '5', '&amp;', 'e', 'h' };
char csignid[] = "V.NwY2*8YwC.C1";
for(int i=0;i&lt;strlen(csignid);i++)
{
    for(int j=0;j&lt;sizeof(symCipher);j++)
    {
        if(csignid[i] == symCipher[j])
        {
            csignid[i] = j+0x21;
            break;
        }
    }
}
NSString* signIdentity = [[NSString alloc] initWithCString:csignid 
                                                  encoding:NSUTF8StringEncoding];
NSLog(@"%@", signIdentity);</code>

И о Боже! Мы смогли получить строку signIdentitys со значениями SignerIdentitys. Обнаружить его отладчиками для хакеров — очень сложно, даже где-то и  невозможно. После этого кода вы сможете спокойно применять стандартные проверки на наличие SignerIdentitysс применением  тайно созданной  строки signIdentitys.

8) Проверяем на JailBreak номер 1. Данный метод является самым анархичным:

<code data-result="[object Object]">BOOL yes;
NSString *path1 = [NSString stringWithFormat:
                   @"/%@%@%@%@%@%@%@",
                   @"App", @"lic",@"ati", 
                   @"ons/", @"Cyd", @"ia.", @"app"];
NSString *path2 = [NSString stringWithFormat:
                   @"/%@%@%@%@%@%@", @"pr", @"iva",
                   @"te/v", @"ar/l", @"ib/a", @"pt/"];
NSString *path3 = [NSString stringWithFormat:
                   @"/%@%@%@%@%@%@", @"us", @"r/l",@"ibe", 
                   @"xe", @"c/cy", @"dia"];
if ([[NSFileManager defaultManager] fileExistsAtPath:path1]
    || [[NSFileManager defaultManager] fileExistsAtPath:path2 isDirectory:&amp;yes]
    ||  [[NSFileManager defaultManager] fileExistsAtPath:path3 isDirectory:&amp;yes])
{
    //Крякнута
}</code>

По своей сущности он не служит методом, который определяет взлом. Такой метод просто проверяет существование папок, без которых, версию имеющую ключ, невозможно поставить. Данный метод подойдет только отчаявшимся людям, которые не могут воспринимать джейлбрейк, и являются его заядлыми противниками. Необходимо хорошенько спрятать искомый путь.

9) Проверяем на JailBreak номер 2. Возвращение легенды:

<code data-result="[object Object]">NSError *error;
NSString *str = @"Проверка записи. Если получилось прочитать значит у вас джейлбрейк!";

[str writeToFile:@"/private/test_jail.txt" atomically:YES 
        encoding:NSUTF8StringEncoding error:&amp;error];
if(error==nil){
    //Взломана
}</code>

Данный метод проверит возможности записи файлов в директорию системы, которая невозможна без джейлбрейка.

Самые скрытые(для отладчика) способы завершения процессов:

<code data-result="[object Object]">//1
close(0);

//2
[[UIApplication sharedApplication] terminate];

//3
[[UIApplication sharedApplication] terminateWithSuccess];

//4
UIWebView *a = [UIWebView alloc];
UIWindow *b = [UIWindow alloc];
UIView *c = [UIView alloc];
UILabel *d = [UILabel alloc];
UITextField *e = [UITextField alloc];
UIImageView *f = [UIImageView alloc];
UIImage *g = [UIImage alloc];
UISwitch *h = [UISwitch alloc];
UISegmentedControl *i = [UISegmentedControl alloc];
UITabBar *j = [UITabBar alloc];
[a alloc];
[b alloc];
[c alloc];
[d alloc];
[e alloc];
[f alloc];
[g alloc];
[h alloc];
[i alloc];
[j alloc];

//5
system("killall SpringBoard");

//6
notify_post("com.apple.language.changed");</code>

такие действия отладчиком весьма непросто заметить и даже понять, какой именно процесс они начнут провоцировать.

Пользуйтесь на здоровье и не отказывайте себе ни в чем!

Comments are closed.