As we all know, iOS apps running on jailbroken devices are very easy to be cracked and analyzed. Here I list some methods that can increase the difficulty of cracking, hoping to help.

Some practical tools

Prevent tweak attachment

Usually, when we analyze an app, we start by cracking the shell,

$ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/XXX.app/XXXCopy the code

The decrypted binary is then thrown to a decomcompiler like Hopper for processing. Throwing unshelled binaries into hopper decompilation is unreadable (encrypted by Apple). So cracking the shell is the first step to cracking the analytics app. There are two ways to guard against this step.

  1. Limit the segments in the binary header by setting the project build setting option in Xcode

     -Wl,-sectcreate,__RESTRICT,__restrict,/dev/nullCopy the code

    Add to “Other Linker Flags” (note that I encountered a problem in the project. On iPod Touch iOS 9.3 devices, the project using Swift caused the mysterious SWIFT standard library to not be found. This is not an issue on iOS 10 devices. I didn’t think it was because of the addition of this before. I didn’t find out the reason for this setting until I searched all the solutions online, such as the SO Post, which had no effect.)

  2. Setuid and setgid (Apple does not accept apps that call these functions because it can determine if your binary runtime contains these functions by looking at the symbol table)

For details, see resources 1,2

Detect targeted tweak on jailbroken devices

Typically on jailbroken phones we use TheOS to create tweak type projects. Then, for the class we are analyzing, use the mk file generated by the supplied logify.pl command to print the input and output parameters of all the methods of that class. This is very helpful in analyzing how the app works. Of course, we can also create a class mk to hook a function to work the way we want it to. For example, we can create a mk file for an app that uses AFNetWorking as a framework for binding certificates. The following methods of the Hook AFSecurityPolicy class:

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domainCopy the code

Make this method always return YES, and the certificate binding that most applications do will be invalidated. If you have used the Tweak template from TheOS, you will find this is fairly quick and easy.

For this step, can add a layer inside the main function of engineering judgment, first read/Library/MobileSubstrate/DynamicLibraries under all the contents of the file, Check if a plist contains your app’s bundle ID. If it does, you can tell if someone is trying to tweak your app. You can do this by, for example, crashing your app or limiting some functionality.

Can check references 4 specific principles, in simple terms, is MobileSubstrate in app when loaded into memory will first check/Library/MobileSubstrate/DynamicLibraries below to see if there is need to be loaded tweak, If yes, load, how to determine whether there is? This is based on the bundle ID in the PList.

The code reference is as follows:

static __inline__ __attribute__((always_inline)) int anti_tweak() { uint8_t lmb[] = {'S', 'u', 'b', 's', 't', 'r', 'a', 't', 'e', '/', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 0, }; NSString *dir = [NSString stringWithFormat:@"/%@/%@%s%@", @"Library", @"Mobile", lmb, @"Libraries"]; NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil]; NSArray *plistFiles = [dirFiles filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: [NSString stringWithFormat:@"%@ %@%@ '.%@%@'",@"self", @"EN", @"DSWITH", @"pli", @"st"]]]; int cnt = 0; for (NSString *file in plistFiles) { NSString *filePath = [dir stringByAppendingPathComponent:file]; NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; if (fileContent && [fileContent rangeOfString:[[NSBundle mainBundle] bundleIdentifier]].location ! = NSNotFound) { cnt ++; }} // Return the number of tweaks for this app, 0 means no return CNT; }Copy the code

The HTTP caught

Usually when we crack an app, we grab the bag. In this way, all the interfaces of our app, the interface data will be exposed to the reverse engineer. At this point, we can limit HTTP packet capture. Way is very simple, is to NSURLSessionConfiguration connectionProxyDictionary set to empty the dictionary, because this attribute is used to control the session available agent. See the official documentation, which is reference 5. Here is how to use AFNetWorking:

// Inherit AFHTTPSessionManager, Override the following method - (instancetype)initWithServerHost:(PDLServerHost*)serverHost {#ifdef DEBUG // DEBUG version of the package can still capture the package self = [super initWithBaseURL:serverHost.baseURL]; # else / / by using ephemeralSessionConfiguration session initiate requests without cookies and cache NSURLSessionConfiguration * conf =, etc [NSURLSessionConfiguration ephemeralSessionConfiguration]; conf.connectionProxyDictionary = @{}; self = [super initWithBaseURL:serverHost.baseURL sessionConfiguration:conf]; #endif return self; }Copy the code

However, because OC methods are easy to hook, avoiding packet capture is impossible, so I think the best way is to encrypt the request parameters (preferably asymmetric encryption, such as RSA).

Obfuscate (or encrypt) hard-coded plaintext strings

For shelled binaries, the reverse analyst has an important clue to the code, which is the hard-coded plaintext string. For example, if your app is caught and some data request interface is discovered, the reverse engineer can simply copy the character string into Hopper and search for it. By looking at where the character string is referenced, the corresponding logic code can be found quickly.

To guard against this step, all you need to do is encrypt or obfuscate the hard-coded plaintext. There is an open source code for this, UAObfuscatedString, but the open source obfuscation code is writing rather long strings (i.e., cumbersome) and does not support encryption. Recently I wrote a tool that encrypts plaintext strings in all code at compile time and decrypts strings at app run time. The features of this tool are as follows:

  1. Simple, developers can hardcode plaintext strings, and all encryption is handled automatically at the start of compilation
  2. The encryption or obfuscation method can be customized to improve the difficulty of decryption (in order not to affect the efficiency of app operation, it is necessary to provide a simple and fast encryption or obfuscation method)

Project address MixPlainText

Developing with Swift

Swift is a relatively new language for iOS development, and because Swift is not yet stable, the jailbreak community does not support it immediately. For example, class-dump does not support Swift binaries. TheOS also recently started supporting Swift, but has not yet added it to the main branch (see Features). So for now at least Swift may be a little safer than pure OC projects. Of course, as Swift becomes more stable and the jailbreak open source community becomes more supportive, this advantage may not be obvious.

Use static inline C functions

OC code is the easiest to break and analyze due to the dynamic nature of the LANGUAGE. In terms of security, functions written in C language are recommended. But C functions can also be hooked, mainly in three ways:

  1. Use Facebook’s open source Fishhook
  2. Use the hook C language function provided by MobileSubstrate method

     void MSHookFunction(void* function, void* replacement, void** p_original);Copy the code
  3. Use mach_override. For the difference between mach_override and fishhook, see mach_override and Fishhook

Because the above three ways can hook C functions. To avoid being hooked, the solution is to use static inline functions. In this case, there is no unified entry for the hooked functions. The reverse engineer can only understand the logic of the function if he wants to crack it.

Use block

Strictly speaking, the use of blocks does not improve security much, because as long as the reverse engineer finds a way to use the block, there is generally logic within the block. See Resources 6 for details on how and how to find them.

However, I personally believe that using block is safer than using OC directly. In my experience of reverse analysis app, I still don’t know how to hook the method of using blocks (if you know, you can make an issue on the blog and tell me, thank you 🙏 in advance). Meanwhile, for blocks containing nested or passed as parameters, It’s more complicated to deal with. Therefore, if you can combine the converging C functions, nested blocks, and block type parameters, security should be improved.

Code confusion

There are several ways code can be confused:

  1. Add useless code snippets that don’t affect logic and confuse the reverse engineer
  2. For key classes and methods, give them names that have nothing to do with the real intention

For the second, there are automation tools available, such as the one Mentioned by Nancy (see Resources 7).

Personally, the best encryption obfuscation tool is ios-class-Guard, but this project has been discontinued. But this kind of confusion I think is the ultimate solution.

Other methods

Such as ptrace undebugging, etc. (although it can be easily bypassed already)

// see http://iphonedevwiki.net/index.php/Crack_prevention for detail
static force_inline void disable_gdb() {
#ifndef DEBUG
    typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#ifndef PT_DENY_ATTACH
#define PT_DENY_ATTACH 31
#endif
    // this trick can be worked around,
    // see http://stackoverflow.com/questions/7034321/implementing-the-pt-deny-attach-anti-piracy-code
    void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, [@"".p.t.r.a.c.e UTF8String]);
    ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
    dlclose(handle);
#endif
}Copy the code

Matters needing attention

By understanding the runtime nature of OC and the structure of the Mach-O binaries, you can see that hook methods are simple to implement with the help of existing tools. Although I mentioned some solutions to improve security above, all these methods only increase the reverse difficulty of the reverse engineer, but cannot make the app indestructible. But doing something is definitely safer than doing nothing, don’t you think?

The resources

  1. Prevent tweak attachment
  2. Blocking Code Injection on iOS and OS X
  3. Crack prevention
  4. Cydia Substrate
  5. connection​Proxy​Dictionary
  6. IOS symbol table recovery & Reverse Alipay
  7. IOS Security (xXIII) : Objective-C code confusion
  8. IOS Security Attack and Defense (24) : Protection Solutions for Sensitive Logic (1)