Use android studio to write so


Preface

This article is a practice of 52pojie's "Teaching My Brother Android Reverse Series Course" according to my own ideas, not entirely according to the original ideas.
The tools used in the original text are outdated, and now there is a simpler and more convenient way to write .so files.
Link to the original text: teach my brother to learn Android reverse engineering 06
Use Android Studio to write the first so . The android studio version used in this article is v4.1.1

Preliminary preparation

Using ndk to compile the .so file used by Android requires two things, the first is ndk (toolchain), and the second is the compilation configuration. Android's compilation configuration can use ndk-build or CMake two modes. At present, Android officially recommends cmake mode.
The latest version of android studio is very simple to install ndk, you only need to install it from the SDK manager.
First select the sdk manager in the toolbar,
Insert picture description here
then click the sdk tool tab, and choose to install ndk (side by side) and CMAKE.
Insert picture description here
After the installation is complete, you can try to compile .so. The following two cases are introduced. One is that the project has not been started yet, then you can choose to directly create a project that supports c/c++. Another situation is that the project itself has been created and c/c++ code needs to be added.

Directly create an Android project that supports c/c++

Select file-> new-> project, in the select a project template interface, select native c++ Insert picture description here
and click next to complete the remaining configuration.
Insert picture description here
After the configuration is complete, wait for a while, and android studio has created a project that supports c/c++.
Insert picture description here
As you can see, the project generates a C++ file by default, and implements a stringFromJNI method in it, which returns a string of strings, which is: "Hello from C++"

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    
    
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

We try to change this code to be implemented in C language.
First, create a new native-lib.c file in the cpp directory:
Insert picture description here
Insert picture description here
then open the CMAKEList.txt file in the cpp directory, change the native-lib.cpp in add_library to native-lib.c
Insert picture description here
and then delete the native- in the project lib.cpp file and click sync on the toolbar in the upper right corner. (After deleting native-lib.cpp, you may see that the cpp folder is emptied. Don't worry, the file will appear again
Insert picture description here
after the synchronization is completed .) After the synchronization is completed, write the following code in the native-lib.c file:

#include <jni.h>

JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
    
    
    // TODO: implement stringFromJNI()
    return (*env)->NewStringUTF(env, "hello from c language!");
}

Then click Run, you can see that the app is successfully run, and the string printed in C language is printed on the screen:

Support for importing c/c++ into existing projects

First create a new empty project:
Insert picture description here
switch the project directory to project and try to
Insert picture description here
create a new cpp folder under the app/src/main/ directory to store the C language code.
Insert picture description here
And create a new c/c++ source code file in the cpp folder, I named it main.c
Insert picture description here
and then create a new file in this directory, named CMakeLists.txt:
Insert picture description here
the directory structure after creation:
Insert picture description here
Then, right-click the app Folder, select link c++ project with gradle.
Insert picture description here
And select the location of the CMakeLists.txt file just created.
Insert picture description here
After clicking OK, the project will be automatically synchronized. Then go back to the CMakeLists.txt file you just created and add the following configuration:

cmake_minimum_required(VERSION 3.4.1)

add_library( 
        # Specifies the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        main.c)

Among them, cmake_minimum_required refers to the minimum version of cmake. The library name, static/dynamic, and files required for compilation are respectively declared in add_library. If you need to compile multiple libraries, you can directly add multiple add_library configuration sections.
After completion, click sync
Insert picture description here
to return to main.c, and add the following code:

#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
    
    
    return (*env)->NewStringUTF(env, "hello from c language");
}

JNIEXPORT jint JNICALL Java_com_example_myapplication_MainActivity_sum(JNIEnv *env, jobject thiz, jint num1, jint num2){
    
    
    return num1+num2;
}

The first function returns a string type text, and the second function is the homework of the original text, which calculates the sum of two parameters.
After the writing is completed, you can try to click the small hammer on the toolbar to try to compile (this step is only to verify whether there is a problem with the C language code, and you can skip it):
Insert picture description here
This interface appears, and the compilation is normal.
Back to MainActivity, add in the code

 static {
    
    
        System.loadLibrary("native-lib");
    }

The meaning of this piece of code is to load the native-lib.so we compiled
and then:

public native String stringFromJNI();
public native int sum(int num1, int num2);

This piece of code is to declare two functions implemented in so. Then add calls to the two functions in the onCreate function.

Log.i("from native-lib", stringFromJNI());
Log.i("from native-lib", "sum result: " + sum(10, 15));

The modified code is as follows:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    
    

    static {
    
    
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("from native-lib", stringFromJNI());
        Log.i("from native-lib", "sum result: " + sum(10, 15));
    }
    public native String stringFromJNI();
    public native int sum(int num1, int num2);
}

Click Run, you can see that our compiled .so is successfully called in LogCat.
Insert picture description here

Guess you like

Origin blog.csdn.net/qycc3391/article/details/114241225