3 min read
Why Native Code Obfuscation Techniques is Essential for Mobile Apps
Martin Rupp (guest) : 25. June 2020
In the mobile environment, source code is often distributed without enough security. Programs compiled as bytecode, such as the ones developed for Java or .NET, contain almost all the original information from the source code. Programs developed with native code, usually developed in C, Objective-C, or C++, are much more difficult to reverse.
In this article, we take a closer look at the differences between interpreted code and native code in mobile operating systems and why we still need native code obfuscation for mobile apps.
Interpreted Code vs. Native Code in Mobile Operating Systems
Android
In Android, applications are generally compiled in a java application, turned into class bytecode files by the Java compiler, and then into dex class files by the Dalvik Android VM (Android runtime). Xamarin allows developers to use .NET. However, the mono compiler behind Xamarin transforms the C# code into Java bytecode as well. This is interpreted code.
On the native side, developers can use the Android NDK (Native Development Kit) to interact directly with the kernel and the hardware to produce native code applications, using C and C++.
For an average mobile developer, using the NDK is much more difficult than developing with Java or Xamarin. Generally speaking, it is not recommended to use it unless it’s necessary, like interfacing a library using native code, for instance.
When attackers are targeting native code, the Dalvik VM is bypassed and a native Android application is produced instead. Other than the Dalvik VM, there are not many code obfuscators available for native code. It's possible to use the obfuscator provided by LLVM [1] in the Android NDK toolchain. LLVM is the default compiler since NDK r13b [2], while GCC [3] has been removed since NDK v18b.
iOS
The native code development in iOS uses either Swift or Objective-C. Objective-C is C provided with some object-oriented features, while Swift is usually referred to as “Objective-C without C.” There are not a lot of applications using Java targeting iOS. However, Xamarin and C# is a popular way to build iOS applications as well.
In iOS, most attacks against native code will come from the weaknesses of the Objective-C runtime:
- The application design, e.g the class signature, etc., is stored into the binary itself, allowing an attacker to easily reconstruct the application architecture.
- The reflection mechanism in Objective-C allows attackers to intercept and modify the application state.
- The messaging framework in Objective-C is too simple, and messages can be easily tracked and manipulated.
- Generally speaking, many attacks can be done against the Objective-C runtime and attackers can bypass authorization, sanity checks, etc.
As a first defense, iOS banking app developers can write parts of their code that deals with sensitive data, in plain C to prevent the attacker from using Objective-C reverse engineering tools like class-dump, class-dump-z, Cycript, or the Frida Instrumentation Framework.
Native Code Obfuscation Methods for Mobile Apps
There are many methods to obfuscate native code in both Android and iOS mobile apps:
- Layout & Data Obfuscation
Obscure all data structures, permute all variables together and rename them with incomprehensible tokenized names, permute the data stored in arrays or dictionaries, etc.
- Control Flow Obfuscation
Reorganize the control flow of the application, inject dead/dummy code, and remove functions’ prototypes by inlining them in other functions, where they are initially called. Use proxy methods to redirect the flow of execution and the process tree.
- Anti-de-obfuscator
Counter the techniques of known de-obfuscators by preventing them from operating by using some of their weaknesses.
- Stripping Binaries
Strip the symbol table of the binaries, by removing all information that is not needed for execution.
In Summary
Obfuscating mobile operating system native code for mobile apps may be, paradoxically, more difficult than obfuscating non-native code.
There are, however, several tools and methods that provide good protection against native decompilers and other instrumentation frameworks.
Banking and other mobile apps that employ native code can use these code obfuscation techniques to protect themselves from malevolent reverse engineering.
Background Information, References and Further Reading
- Read more articles about application security for mobile banking applications (2018 - today), by Martin Rupp, Stefan Hansen and more
- MASC Mobile App Security Core (2019), Web page by Cryptomathic
- PCI Mobile Payment Acceptance Security Guidelines for Developers version 2 (September 2017), by the Emerging Technologies, PCI Security Standards Council
- [1] LLVM. The LLVM Project is a collection of modular and reusable compiler and toolchain technologies
- [2] NDK. The Android NDK is a toolset that lets you implement parts of your app in native code, using languages such as C and C++
- [3] GCC. The GNU Compiler Collection is a compiler system produced by the GNU Project supporting various programming languages