AndroidStudio版本: 4.0.1

使用AndroidStudio进行ndk开发很简单,我们的目标是生成一个so文件,里面有一个getSign方法,在Java层调用so文件中的getSign方法获取。

先创建一个NDK项目,创建的时候拉到最下面选择Native C++,然后Next:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

然后输入项目的名字:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

这一步保持默认即可(反正我也不懂C++…):

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

创建完项目之后糟糕红色叹号了,有这么个提示:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

这是因为创建的项目没有配置NDK,NDK需要单独下载,可以去这个页面选择自己平台对应的NDK下载:

https://developer.android.com/ndk/downloads?hl=zh-cn

下载完解压到本地即可,注意解压后的路径名中尽量不要包含中文以免无谓踩坑。

然后回到AndroidStudio,为项目设置上刚刚下载的这个NDK,菜单选择File–>Project Structure:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

切换到SDK Location,然后在Android NDK Location那一项选择刚刚下载的NDK解压到的目录,OK之后项目就会自动开始sync。

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

sync完之后就不会报错了,还显示了个小对号:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

切换到Project视图看下生成的项目结构:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

先看MainActivity自动生成的内容:

package cc11001100.android.ndk_study_003;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

自动加载了一个native-lab的so文件,然后还自动声明了一个stringFromJNI的native方法,然后再来看cpp下自动生成的这个native-lib.cpp文件:

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

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

看起来跟我们想要的结果已经差不多了,不行,名字不一样,接下来就是修改名字为getSign,先改Java层的MainActivity,注意修改的时候使用重构重命名,Shift+6,改完之后:

package cc11001100.android.ndk_study_003;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(getSign());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String getSign();
}

会发现native-lib.cpp的名字也自动修改了,都不用我们手动干预,很方便:

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

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

然后Run一下看看安装效果:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

OK,接下来打包成apk,然后反编译观察一下这种方式打包的效果是怎样的:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

选择打包成apk:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

key可以创建一个新的也可以用老的:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

构建release包,签名版本为V2,然后“Finish”等一段时间:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

如果打包成功的话,在app下会多出一个release文件夹,下面有个app-release.apk文件,这就是本次打包成功的apk文件:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

然后启动jeb,把打包好的apk文件拖到jeb中看下,项目结构是这样的:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

反编译MainActivity看下:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

然后到lib下,把so文件拿出来:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

然后拖到IDA64中,在Function name窗口中输入Java搜索我们的JNI方法,因为我们是静态注册的,所以这里是能搜到的,然后双击搜索到的函数名,查看其汇编代码:

Android逆向笔记之AndroidStudio生成so并调用native方法-冯金伟博客园

然后分析这段汇编的代码就能还原原本逻辑了,其实arm汇编我也没整太明白,就赶紧结束以免露馅,本篇文章到此为止吧。