Enhance the secure messaging app with the NDK (Native Development Kit) as an alternative means of defeating Java extraction.
- [Instructor] When developing Android apps, we can not only code in Java but also drop down a level and use native routines written in C or C++, typically where high performance is required or where platform-specific features need to be accessed. Native code routines are supported by Android Studio which allows developers to call them through the Java Native Interface, or JNI and compiles the native code routines into a separate .so module, which is linked with the standard app by-code.
The key security feature of native apps is that they don't get decompiled as Java code and an attacker looking to determine their function has to resort to assembly-level, reverse engineering in order to analyze them. This increases the cost of attack substantially. Let's take a look at how we build an Android app that has native code routines. The first thing we do at the Android Studio startup screen is to tick the C/C++ support box and open a new project. Let's call it: Native.
I'll select Tools, Android, SDK Manager and I'll select SDK Tools. We need to make sure we have three components installed: CMake, LLDB and NDK. If you don't have them, then tick the boxes and Android Studio will download them for you. Okay, we have the main activity displayed and we can see the structure of the app at the left. The first thing the code does is to load the native library and we can see in the app structure at the left we also now have a folder called cpp.
I'll expand this and double-click the nativeLib.cpp entry and we can see the skeleton native library in the main pane. This is a simple call which returns a string, "Hello from C++". We can see the exported name is stringfromJNI. Back in the main activity, we can see a call to stringfromJNI setting text and at the bottom of the code, a public method called stringfromJNI which is declared as native. Okay, I've transferred my code over to this app.
So, we now have a version which enables native support. Let's look at moving some of the sensitive data into a native routine. I've changed the routine stringfromJNI to be get string with a numeric argument. Now, I'll return either the key alias, the activation code or the activation file name. I've removed the declaration key alias, replacing it with a call to the native routine with argument one and the activation code with a call to the native routine with argument two. The string activation .dat is now replaced with get String 3 I've also moved the tamper detection to a callable function in wave tidy-up.
Okay, let's build and run it, now. Let's take a look at our native app using JadX. Here, we can see the application code and we can see our main activity coding with the calls to get string, but none of the native code. Using native code can provide significant security advantages, it increases the attack surface and C++ routines are more vulnerable to attack than Java code.
The key is to use it sparingly.
- Understanding Android OS, app, and hardware security components
- Using the Trusted Execution Environment
- Developing Android apps with security in mind
- Analyzing existing applications
- Understanding Android vulnerabilities
- Securing Android apps
- Developing secure enterprise apps