For app developers, the low-level virtual machine bitcode has been a staple of the Apple toolchain and Android Native Development Kit for the past seven years. With the release of the Xcode 14 beta, which will soon become the standard for iOS and macOS development starting this year, Apple has discontinued the option to build bitcode apps.
This has far-reaching implications for the application security industry, which has largely designed and integrated its approach to code obfuscation around bitcode. Unless security vendors adapt, many apps will face a yawning gap in their security in the not too distant future.
What is code obfuscation?
Code obfuscation is a powerful code protection technique and an essential part of application security products. The idea behind obfuscation is to modify an executable in such a way that it is no longer transparent to a hacker, but still remains fully functional.
SEE: Mobile Security Policy (TechRepublic Premium)
When done effectively, obfuscation makes reverse engineering a program extremely difficult and is therefore used to protect sensitive intellectual property. For example, obfuscation can be used to hide an algorithm that a company doesn’t want competitors to understand—mainly to protect the security code.
In the area of app shielding, we use a number of tools to create a secure environment for apps to run. This includes things like hook detection, anti-debug, and anti-tampering, all of which ironically are vulnerable to tampering or removal unless well hidden. Obfuscation is therefore used to protect these tools.
Obfuscation can be introduced at three different levels: the source-based level, the native binary level, and by far the most dominant approach, the middle level. Between many compilers and the native code is an intermediate layer where optimizations are made.
Low-Level Virtual Machine is the most famous example of this. LLVM is a set of compiler and toolchain technologies that can be used to develop a front end for any programming language and a back end for any instruction set architecture. LLVM is useful as it allows compilers like Clang or Rustc to target different backends like Linux on X86_64, armv7, iOS and Windows. If an obfuscator can operate at this level, it is the easiest to build and maintain, since it is not tied to either the front-end compiler language or the back-end machine’s instruction set.
However, there is a downside: it’s often tied to the toolchain. For apps on iOS and macOS, those that obfuscate at the mid-level are subject to changes or major revisions from Apple’s integrated software development – such as: B. Xcode 14.
What is bit code?
Bitcode is a serialized version of LLVM’s Intermediate Representation.
A major reason for the popular use of LLVM in app development, and by extension Bitcode, is that it is open source and available to everyone. This has led to many vendors developing obfuscators that work with bitcode. The advantage for them is that they too can address many backends and typically also several frontends. The fact that the LLVM libraries also provide all the APIs needed to manipulate the bitcode further contributed to their dominance.
Apple previously used bitcode in its toolchain because it had multiple CPU architectures to support it, such as Intel, arm32, and arm64. In some cases, Apple has even required apps to be submitted in bitcode format – not machine code. This has allowed Apple to lower the final level of machine code for the particular device it is to be installed on.
How will Bitcode be affected by future Xcode versions?
Apple has now reached a point where all of its new hardware uses arm64 and no longer requires LLVM’s flexible backends. In particular, the WWDC 2022 keynote mentioned that better optimization is only possible for this architecture, suggesting that the LLVM interlayer may not be used for this purpose in the future.
This has led to a major overhaul in the form of the Xcode 14 beta, where Apple dropped the option to build bitcode apps. iOS and macOS developers can still use bitcode with a warning, but this will be removed later. Essentially, now it’s not that easy to create bitcode apps.
Why is this important and who is affected?
Future Xcode versions can now prevent security providers from using bitcode. Obfuscation providers typically take two approaches to bitcode obfuscation, which are impacted differently.
The first approach is app obfuscation, where the obfuscator acts on the entire app in bitcode format, post-build, as an IPA or Xcarchive file. This is a great approach because the obfuscator doesn’t need to be tightly integrated into the toolchain and obfuscations can work on the entire app rather than individual modules at once.
The second is a toolchain-integrated approach, where the obfuscator replaces or patches components in the Apple toolchain to ensure it’s called during the build process. This can cause maintenance issues, but typically this is a lightweight integration by creating wrappers around the existing clang compiler.
The first approach is now effectively obsolete. Vendors using this will likely continue their work (with warnings) for at least another year. However, this method is likely to be prevented in Xcode 15 or 16.
The second approach could also be shaky in the future, as we don’t know if Apple will ever remove LLVM or prevent access to it in the compiler – possibly even without warning. All vendors currently using an LLVM-based obfuscator to protect iOS and macOS apps are affected by this change.
What does this mean for the future of application security?
Eventually, LLVM will become less useful and possibly disappear altogether as Apple seeks to leverage its unified architecture for CPU, GPU, and ML accelerators. Xcode 14 already includes toolchain components that compete with LLVM for this. If LLVM goes away, Apple’s platforms could be much more difficult to protect in the future and therefore fewer vendors will have products available for it.
It’s entirely possible that this change will jeopardize the security of many apps in the App Store. Whether this happens or not depends on the adaptability of the security vendors. Those using a toolchain-integrated approach will be fine for now, but they run the risk of this approach being phased out without warning in the future.
It is likely that we will see an increase in the native binary approach to obfuscation. The main difference with this obfuscation approach is that the generated machine code is manipulated directly. Not many obfuscators currently use this method because it is particularly difficult and may need to support many binary formats and/or CPU instruction sets.
While the future of code obfuscation may be uncertain, one thing is certain: app developers must take a proactive approach, monitor security vendors, and plan accordingly if they want to ensure their apps remain secure.
Andrew Whaley is Senior Technical Director at Promon, a Norwegian app security company. With extensive experience in penetration testing, application hardening, code obfuscation, cryptography and blockchain, Andrew leads Promon’s R&D team in enhancing the company’s core product suite with new security features.