Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

  • A+
所属分类:Asura笔记本
摘要

本文转发语NCK大佬的博客,并且自己跟着做了一遍 有一点点不同 大致上是大佬的文章:
https://www.cnblogs.com/fuhua/p/12725771.html

本文转发语NCK大佬的博客,并且自己跟着做了一遍 有一点点不同 大致上是大佬的文章:
https://www.cnblogs.com/fuhua/p/12725771.html

前面几篇文章演示的是比较原始的创建JNI项目的方法,旨在了解JNI项目构建原理!
但是构建项目效率很低,开发,调试都存在很大的效率低下问题。
本篇文章将演示利用Android Studio快速构建JNI项目。本篇文章要点

  1. 利用Android Studio快速构建JNI项目
  2. 添加日志打印
  3. Android Studio调试C/C++代码
  4. JNI动态注册
  5. 简易计算器实现。

1. 新建项目

打开Android Studio新建Project,选中Native c++选项,此选项可以帮助开发人员快速创建JNI项目,免去手动配置等麻烦问题。

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

项目取名为JNIRegisterDynamic,点击Next
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

使用 C++17标准,点击Finish
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

2. 安装NDK开发组件

File->Settings->Android SDK->SDK Tools选项下,安装LLDB,NDK,CMake

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

等待安装完毕

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

File->Project Structure->SDK Location->Android NDK Location ,选择Default xxxx选项,从而配置完成NDK

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

为了验证上一步是否配置成功,需要来到local.properties,如果同时出现ndk.dir=xxx sdk.dir=xxx 证明配置成功

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

此时如果我们对native-lib.cpp进行编辑,可以看到出现了智能提示。就代表我们的环境配置没有问题了。
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

3. 添加日志打印

接下来我们添加日志打印输出,将下面代码添加到cpp文件头部,使用的时候直接调用就行,比如:LOGI("我是输出的日志信息");

1 2 3 4 5 
#include <android/log.h> #define LOG_TAG    "JniDebugLogger" #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__) 

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

接下来我们在C/C++代码下断点,并点击Debug图标。看是否能正确断下
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

注意,当出现如下界面时,千万别点击,只需要什么都不做,等几秒钟,断点断下就行
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

JNI动态注册和简易计算器实现

接下来我们在MainActivity中定义4个Native方法,分别为 add(+) sub(-) mul(*) div(/)

1 2 3 4 5 6 7 
    private native int add(int a, int b);      private native int sub(int a, int b);      private native int mul(int a, int b);      private native int div(int a, int b); 

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

在native-lib.cpp里实现MainActivity的方法,native-lib.cpp源码如下

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 
#include <jni.h> #include <string>  #include <android/log.h>  #define LOG_TAG    "JniDebugLogger" #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)  extern "C" JNIEXPORT jstring JNICALL Java_com_example_jniregisterdynamic_MainActivity_stringFromJNI(         JNIEnv *env,         jobject /* this */) {     std::string hello = "Hello from C++";     return env->NewStringUTF(hello.c_str()); }  jint NativeAdd(JNIEnv *env, jobject obj, jint a, jint b) {     return a + b; }  jint NativeSub(JNIEnv *env, jobject obj, jint a, jint b) {     return a - b; }  jint NativeMul(JNIEnv *env, jobject obj, jint a, jint b) {     return a * b; }  jint NativeDiv(JNIEnv *env, jobject obj, jint a, jint b) {     return a / b; }  // JNI函数签名数组 JNINativeMethod jniNativeMethods[]         {                 {"add", "(II)I", (void *) NativeAdd},                 {"sub", "(II)I", (void *) NativeSub},                 {"mul", "(II)I", (void *) NativeMul},                 {"div", "(II)I", (void *) NativeDiv}         };  jint RegistNativeMethods(JNIEnv *env) {     //获得class     jclass clazz = env->FindClass("com/example/jniregisterdynamic/MainActivity");     //执行动态注册     if (env->RegisterNatives(clazz, jniNativeMethods,                              sizeof(jniNativeMethods) / sizeof(jniNativeMethods[0])) == JNI_OK) {          return JNI_OK;     }     return JNI_ERR; }  JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {     JNIEnv *jniEnv = nullptr;     if (vm->GetEnv((void **) &jniEnv, JNI_VERSION_1_6) != JNI_OK) {         LOGE("GetEnv ERROR");         return JNI_ERR;     }     if (RegistNativeMethods(jniEnv) != JNI_OK) {         LOGE("RegistNativeMethods FAILED");         return JNI_ERR;     }     return JNI_VERSION_1_6; } 

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

在MainActivity里添加测试代码,运行测试

1 
tv.setText("add" + add(1, 6) + " sub" + sub(10, 3) + " mul" + mul(3, 6) + " div" + div(9, 3)); 

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

运行测试Native层没有问题,接下来添加Java层代码并在界面增加控件,实现简单的计算器。MainActivity代码如下

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 
package com.example.jniregisterdynamic;  import androidx.appcompat.app.AppCompatActivity;  import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView;  public class MainActivity extends AppCompatActivity {      // Used to load the "native-lib" library on application startup.     static {         System.loadLibrary("native-lib");     }      private native int add(int a, int b);      private native int sub(int a, int b);      private native int mul(int a, int b);      private native int div(int a, int b);      @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("add" + add(1, 6) + " sub" + sub(10, 3) + " mul" + mul(3, 6) + " div" + div(9, 3));  //        tv.setText(stringFromJNI());         Button btn_add = (Button) findViewById(R.id.btn_add);         Button btn_sub = (Button) findViewById(R.id.btn_sub);         Button btn_mul = (Button) findViewById(R.id.btn_mul);         Button btn_div = (Button) findViewById(R.id.btn_div);          View.OnClickListener ocl = new View.OnClickListener() {             @Override             public void onClick(View v) {                 EditText editA = (EditText) findViewById(R.id.editA);                 int nA = Integer.parseInt(editA.getText().toString());                 EditText editB = (EditText) findViewById(R.id.editB);                 int nB = Integer.parseInt(editB.getText().toString());                 TextView tv = findViewById(R.id.text_value);                 switch (v.getId()) {                     case R.id.btn_add:                         tv.setText("" + add(nA, nB));                         break;                     case R.id.btn_sub:                         tv.setText("" + sub(nA, nB));                         break;                     case R.id.btn_mul:                         tv.setText("" + mul(nA, nB));                         break;                     case R.id.btn_div:                         tv.setText("" + div(nA, nB));                         break;                 }             }         };         btn_add.setOnClickListener(ocl);         btn_sub.setOnClickListener(ocl);         btn_mul.setOnClickListener(ocl);         btn_div.setOnClickListener(ocl);     }      /**      * A native method that is implemented by the "native-lib" native library,      * which is packaged with this application.      */     public native String stringFromJNI(); }  

activity_main.xml代码如下

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".MainActivity">      <EditText         android:id="@+id/editA"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="91dp"         android:ems="10"         android:inputType="textPersonName"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toStartOf="parent"         app:layout_constraintTop_toTopOf="parent"  />      <EditText         android:id="@+id/editB"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="56dp"         android:ems="10"         android:inputType="textPersonName"         app:layout_constraintStart_toStartOf="@+id/editA"         app:layout_constraintTop_toBottomOf="@+id/editA" />      <Button         android:id="@+id/btn_add"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginEnd="16dp"         android:text="@string/btn_add"         app:layout_constraintBaseline_toBaselineOf="@+id/btn_sub"         app:layout_constraintEnd_toStartOf="@+id/btn_sub"         app:layout_constraintHorizontal_chainStyle="packed"         app:layout_constraintStart_toStartOf="parent"  />      <Button         android:id="@+id/btn_sub"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="60dp"         android:layout_marginEnd="5dp"         android:text="@string/btn_sub"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toEndOf="@+id/btn_add"         app:layout_constraintTop_toBottomOf="@+id/editB" />      <Button         android:id="@+id/btn_mul"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginEnd="16dp"         android:text="@string/btn_mul"         app:layout_constraintBaseline_toBaselineOf="@+id/btn_div"         app:layout_constraintEnd_toStartOf="@+id/btn_div"         app:layout_constraintHorizontal_chainStyle="packed"         app:layout_constraintStart_toStartOf="parent"  />      <Button         android:id="@+id/btn_div"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="34dp"         android:layout_marginEnd="5dp"         android:text="@string/btn_div"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toEndOf="@+id/btn_mul"         app:layout_constraintTop_toBottomOf="@+id/btn_sub" />      <TextView         android:id="@+id/text_value"         android:layout_width="92dp"         android:layout_height="23dp"         android:text="@string/str_text_value"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintHorizontal_bias="0.498"         app:layout_constraintLeft_toLeftOf="parent"         app:layout_constraintRight_toRightOf="parent"         app:layout_constraintTop_toTopOf="parent"         app:layout_constraintVertical_bias="0.795"  /> </androidx.constraintlayout.widget.ConstraintLayout> 

Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

测试运行
Android逆向 Android Studio JNI 快速构建项目+动态注册+简易计算器

源代码:
https://github.com/luodaoyi/Android_JNI/tree/master/04_JNI_register_dynamic

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: