What is Ndk – Troubleinthepeace


Preamble

Recently at my company, I was assigned a pretty good task. My company has a game written on the android platform. The game is written in android, but mainly uses the web view to display. However, some logic such as setting session for the user, authenticate for the user is located. on android.

You are viewing: What is Ndk

You probably already know, android app is written in java, translated into dex file, then distributed on google playstore as apk file. Therefore, android app has an inherent weakness that every java app has, that is security. What is the security weakness here? That’s why any java app can be reverse engineer very easily.

This stems from the nature of java being translated into bytecode in a form quite “close” to a normal programming language, and the bytecode contains all the necessary information so that you can recompile the original program intact.

So how does this security weakness relate to the app I’m in charge of? As I just said above, in the game I’m in charge of, the authentication logic for the user will be on the android side. This means on android app will be in charge of:

Encrypt the user’s uuid, send it to the server Server will receive that uuid, and send the session key back to the user for the user to set in a cookie.

You will probably wonder how simple this authentication process is. Yes, this process is too simple, resulting in that as long as user A (the bad guy) knows the uuid of user B (the victim), A will be able to fake any action of B like sending something from B. for A.

So why not do a better authentication process, like using an extra token like a onetime password that only the user knows, or how to “hide” the uuid so that other users don’t know. That’s right! However, due to some “historical” reasons of the legacy code, we cannot change the authentication process so easily.

So with the current flow code, with the android weakness I mentioned above, someone with a little programming knowledge can easily decompile the logic used for authentication that I mentioned above. Which includes encoding the user uuid, but when you see the logic code, the encryption is also redundant. The reason why is redundant is because the current code is using “Symmetric Cryptography Algorithm”. Symmetric here means symmetric encryption algorithm, which typically includes algorithms like blowfish, AES, DES.

Simply put, symmetric algorithms are sender and receiver will use same key, same initialize vector (These concepts will be covered in more detail in the next section), so just decompile the code and user A (the bad guy) will get the key and initialize the vector to make a valid request using the user’s uuid. B.

So how do we solve this problem? After discussing with the company for a while, I came up with a temporary “fire-fighting” solution, which is to move logic into native code using ndk and C, the purpose to achieve is:

“Hide” the user uuid encryption logic, hide the initial parameters such as key and initialize vector. Therefore, user A will not know how to make a valid request with user B’s uuid.

This workaround why I say is temporary, because if user A has a little more knowledge about ndk, then the interface provided in ndk code will be public, so it can still be taken advantage of. this point to make a valid request. However, because I can’t think of another solution, temporarily using this method will limit the “fuzzy chicken” hackers.

So to go in this direction we need to learn about two things: Android NDK and the way to use encryption algorithms on ndk (here is using C language), that is opensslThe introduction is a bit long, but here you have understood why the title of the article is Android NDK and open SSL.

Below we will go about 2 issues to solve in turn: Android NDK and OpenSSL

Android NDK

The Android NDK is a development kit that enables you to develop Android applications that are partially based on code written in C or C++. You will need the NDK in high performance products, where the code that is built into binary will maximize performance. The logic code performed on the ndk below I will call it native code.

About the working mechanism of ndk, you can understand simply as shown in the figure below, your app will communicate with native code through an interface called JNI.

Simply put, JNI is a set of standard java communication protocols that make java code possible talk okay with C/C++ code, maybe transmission data between the two parties.

*

To learn more about android ndk, you can go to android home page at android home page. Below I will summarize the steps required to use ndk.

See also: What is a Merger – Translation Meaning of the word Merger

Setting

The way to install the android ndk is quite similar to the sdk, that is, you simply download the ndk and put it somewhere. In that NDK kit will contain all the tools to be able to build ndk native code from C/C++ source (including build script and necessary header files). The installation process can be understood briefly through the following script (running on unix environment):

wget http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2tar yxvf android-ndk64-r10-darwin-x86.tar.bz2mv android-ndk64-r10-darwin- x86 ~/echo “export PATH=$PATH:/~/android-ndk64-r10-darwin-x86” >> ~/.bash_profileecho “export ANDROID_NDK_ROOT=/Users/huydo/android-ndk64-r10-darwin-x86” > > ~/.bash_profilesource ~/.bash_profile After running the above script, android ndk has been added to the system path, making it possible to type commands like ndk-build from anywhere

Use

In the ndk you download, there are quite a few examples of how to use ndk, from simple (like hello world) to more complex examples like image processing (which requires sending data between android apps). and ndk app is quite complicated). You can refer to those examples to have a realistic view of the ndk program. Below I will briefly describe my usage process.

As you can see in the image above, the android app and native code will “talk” to each other through a common “language” called jni. So there will be 2 possibilities, leading to 2 contexts for using ndk:

1. Write some important code logic on the native code side, and leave the rest logic on the android app side as usual. The communication will be called from the java side through jni. This approach is advantageous in that we take advantage of all the strengths of the android frame work, and only the absolutely necessary logic is included in the native code.2. Write “native activity”, ie the logic of the activity such as display, life cycle, call other activities.. will be fully coded on the native side. This way is actually quite rarely used, often used in cases where the data is too difficult to pass between java and native, then coding the activity on native is also a necessary option.

In this article, I will follow approach 1, to solve the problem in the following direction:

Put the logic for encoding the user uuid into a C file, build the binary and call that logic on the java side via JNI.

Coding and building

To follow approach 1 as mentioned above, we can easily visualize the work to be done:

Step 1: Write logic coding code in C, receive as input a string describing the user’s uuid, the output is an encrypted string. Step 2: Build that code into a dynamic library file (.so file) and “Embed” that dynamic library file into android projectStep 3: Write logic code to call native code on java.

Step 1: Structure of a native code file written on C

Normally, we will create a folder named jni and put all the code, headers, related libraries in it.

*

File native code written in C is quite simple, just summarized in 2 steps:

include library Write functions based on jni’s convention to create “interfaces”, and the java side will call these “interfaces” quite easily

A great example of native code is as follows:

#include #include jstringJava_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) return (*env)->NewStringUTF(env, “Hello from JNI ! “);You notice the function name of native code will easily notice convention like in the picture below:

*

Thanks to that convention, you will find it easier than ever to call the logic of that function on the java side.

In addition, you can notice some special points in a piece of native code as below:

The return value here is jstring, which is a special data type of jni, which when java calls, the jni library will perform the conversion (marshalling) this value to java String type. JNIEvn* env variable , you can imagine this is a pointer to the VirtualMachine (Dalvik) of android, thanks to this env we can manipulate backwards from the native side, to be able to use the android side logic. As in the above code, we can see that thanks to env, we can create a unicode string from within C code.

Step 2: Build that code into .so file

To build the native C file that we just wrote above, we need to do 2 things:

Create 2 files Android.mk and Application.mk in the jni directory that we mentioned above Android.mk is responsible for “describing” the module to the build system. In this file we will write the module what files we have, where the path is, what other libraries do we use (dependency). In an app there can be many Android.mk files while we have many modules.Application.mk will be responsible for “describing” our app to the build system. Usually in this file we will describe the modules the app will use, as well as a description of the CPU architecture the app will support (typically including ARM, x86 and MIPS)Build using ndk-build to the fullest. simply by typing the command ndk-build in the current folder.

*

After using the ndk-build command to build, the build result is that the .so files will be copied to the directory. libs in the root folder as shown above. You can see that corresponding to each CPU architecture, there will be a folder created, in each folder there are different .so files used only with a certain architecture.

Step 3: Write logic code to call native code on java

Having built the static library, we only have one last step to use the logic above in the android code. As mentioned above, the interface of jni code will be used according to the convention that includes: package name, class name and cfunction name. That means: your java code in android will have to have the same package name, class name and function name as jni’s interface, then you can use that logic.

See also: What is Net Revenue – What is Net Revenue

So according to our example here, we need to do 3 things:

package name of the code must be com/example/hellojniClass name must be HelloJni You must define a function called stringFromJNI to invoke logic from native code.

package com.example.hellojni;import android.app.Activity;import android.widget.TextView;import android.os.Bundle;public class HelloJni extends Activity{

Categories:

About Troubleinthepeace

Troubleinthepeace specializing in synthesizing information about daily life activities

View all posts by Troubleinthepeace →

Trả lời

Email của bạn sẽ không được hiển thị công khai.