Some misconceptions about the security of iOS apps

There are many myths about iOS apps that conflict with reality and can hinder attempts to protect them. Here are five examples.

  • Myth #1: iOS apps are not as exposed to reverse engineering and hacking attacks as Android.

    Reality: In the iOS vs Android security debate, the assumption that iOS is significantly ahead of Android in matters of mobile security has been questioned by recent Promon research and weakened by the Digital Markets Act (DMA) that requires Apple to allow sideloading on iOS.

  • Myth #2: iOS apps are secure by default because Apple’s App Store reviews them for security and safety.

    Reality: While all iOS apps are encrypted by design whenever they are uploaded to the Apple Store, that doesn’t mean that the entire app is encrypted, or that they are encrypted for mobile app security (rather than copywrite, for example).

  • Myth #3: Code obfuscation is not necessary for iOS apps because iOS binaries are compiled.

    Reality: During the review check, Apple does not perform a deep dive into an app’s binary for security weaknesses. Also, compiled apps still retain valuable information that needs obfuscated.

  • Myth #4: Apple security updates are enough to protect apps from all new threats.

    Reality: While Apple provides regular updates to all its devices simultaneously that fixes OS-level vulnerabilities, these updates don’t fix weaknesses in the app’s code.

  • Myth #5: iOS apps are encrypted by Apple and therefore don’t need any further protection.

    Reality: When objectively tested, iOS app encryption is much less extensive than often assumed.

Want the big picture?
Learn more about the limitations of code obfuscation and its role in your app security strategy.
Read the guide

 

Do iOS apps need obfuscation to enhance their security?

The fact is that iOS apps can greatly benefit from obfuscation. In fact, they may need it, depending on the app’s purpose, security risks, and threat model. This is particularly true when iOS systems are used for security sensitive apps that handle sensitive data e.g. payment or healthcare applications.

iOS binaries are no different from binaries on other platforms and are easily disassembled with the right tools. There are reverse engineering tools that can extract names, methods, structures, and functionality from iOS binaries that are not obfuscated.

One point to note is that the use of Objective-C, common for iOS apps, makes it particularly easy to hook and subvert application functionality through a technique called ‘Method Swizzling’. However, iOS apps work well with a layered approach to security that uses specific obfuscation techniques for iOS and other techniques along with obfuscation.

iOS_obfuscation_blog_post_image (1)


As the diagram shows, there is a lose coupling between the Objective-C method selector and its implementation (IMP). Method Swizzling redirects selector to a different implementation.

The common programming languages for iOS apps

As mentioned above, Objective-C along with Swift are the most common programming languages for iOS apps. Although both languages are compiled into machine code, this makes reverse engineering relatively straightforward with disassemblers.

  • Both languages require metadata in the binary when compiled into machine code, which makes it easier to understand. This is particularly true of Objective-C.
  • Apple’s deprecation of LLVM bitcode in Xcode could make it harder to protect iOS apps’ code with common LLVM based obfuscators.

What are the different approaches to iOS code obfuscation?

There are different approaches to obfuscation depending on their compiler stage: source, intermediate, or post-build. These are the most common for iOS.

  • The intermediate level: this is the intermediate code that is is produced from the compiler front-end before being passed to the compiler back-end. Not all toolchains allow this but LLVM (Low Level Virtual Machine) based toolchains do. Apple’s Xcode does for for the present.
    • This is the most common for iOS. In fact, most application security tools work at this stage.
    • Obfuscation here is toolchain dependent, needs access to the source code to obfuscate, and may slow compilation down.
  • The binary level or post-build: this is binary code that is altered after compilation is complete but before distribution. Post-build obfuscation therefore takes place outside the application lifecycle.
    • There are many benefits to binary-level obfuscators. They are not tied to a source code and compiler, and do not need integrated with toolchain or any specific development tools.
    • A consequence of this is that security professionals working on iOS apps are independent from development teams when applying security policies.

Which are the best obfuscation techniques for enhancing iOS apps security?

The most effective obfuscation techniques for iOS are tailored for Swift and Objective-C applications. Here are some of the most relevant obfuscation techniques for iOS apps.

  • Renaming: Objective-C metadata renaming/hiding is useful to remove meaning from app code.
  • Control flow obfuscation techniques: These hide app call graphs that help to visualise app function. Examples of these techniques include block splitting and control flow flattening.
  • Data encryption: This hides static data values, like string literals, which often clearly indicate the purpose of a function, or may be sensitive like API URLs or keys.
  • Integrity checking: This helps protect against unauthorised modification of code (or data).
  • Debug information stripping: Often compiled apps are littered with compilation artefacts, which are useful to assist the reverser. Extended debug stripping can help remove or deliberately corrupt some of these to break decompilers.

Control_Flow_Flattening_Techniques

In this diagram, A and B are function entry points in the original code blocks. Block splitting divides and shuffles the code. The arrows show how the control flow now jumps rather than moves in a linear trajectory. Control flow flattening uses a dispatch function (?) to obfuscate the code blocks and control flow.

Technical challenges to using obfuscation techniques for iOS security

Although using obfuscation techniques for iOS app security is powerful, implementing it brings some technical challenges. For example, iOS does not permit writeable executable code sections, which means that code cannot be modified at runtime. This is a benefit in that it makes apps harder to exploit, but it also limits the scope of some obfuscation techniques.

Other technical challenges revolve around Apple’s App Store.

  • Apple’s app store review guidelines can result in rejection for overly heavy or aggressive obfuscation. This is because heavy obfuscation can cause performance issues as well as possible poor user experience.
  • iOS apps require strict adherence to Apple’s build and linking process. They are validated by Apple’s App store submission process. Obfuscators need to be aware of this and work within those confines or apps risk failing submission.

Other app security techniques that works best beside obfuscation for iOS

iOS application security is strengthened by layering multiple obfuscation techniques, but also layering other companion strategies along with obfuscation. An example is code integrity verification e.g., Apple’s Code Signing enforcement to ensure binaries are unmodified. This can be independently verified in case the device is jailbroken and the OS is no longer performing this.

Here are some others:

  • Anti-tampering, binary integrity and runtime integrity checks
  • Anti-debugging and breakpoint detection to prevent common debuggers
  • Anti-hooking to thwart powerful iOS hooking frameworks like Cydia and Frida
  • Anti-emulation to prevent a protected app from running in an emulated environment like Corellium
  • File or resource encryption to protect app assets
  • Jailbreak detection to detect a compromised app sandbox, which would make the app vulnerable

Dynamic obfuscation techniques in iOS app security

Dynamic obfuscation enables code variation at runtime, so that it’s not fixed at the point of distribution. This makes the code a moving target for deobfuscation attempts. The problem with static obfuscation techniques is that an actor could use a decompiler to unobfuscate the code, and then potentially use an AI large language model to reconstruct the unobfuscated code version. AI interpreting code like this is not far away.

The obfuscation techniques described so far for iOS are static obfuscation techniques. Static techniques are starting to become vulnerable to AI based approaches, as described above. This is why there is a growing need to move to dynamic techniques, and ask the question: Which dynamic techniques are best suited to iOS?

Answering this question is complicated by the issue of code signing. A limitation of iOS is that the code has to be fixed and signed at distribution as part of Apple’s requirements. This means code cannot be generated at runtime. Other methods for changing iOS code while still using disassemblers and decompilers are required.

  • Stack machine processing: Implementing a stack based machine rather than a registered based machine in your code will make is harder for disassemblers to be able to interpret it.
  • Return orientated programming: This technique means the code flow is not inherent in the actual code, and so a stack of return addresses is the data needed to piece the code together again.
  • Virtual machine obfuscation: This allows for code changes without interrupting the run because the code is represented as data and is interpreted differently. And because it is no longer code, is doesn't need to be signeda key point is iOS obfuscation.
Everything you need to know about obfuscation
Get the full overview on all things code obfuscation.
Read the guide