Andriod APP inversa - desarrollo JNI

Introducción a JNI

JNI es la interfaz de programación en lenguaje nativo (Java Native Interface). Permite que el código Java que se ejecuta en la JVM interopere con el código nativo escrito en C, C++ o ensamblador.

El significado de la existencia de JNI:

  • [Desarrollo] Algunas funciones subyacentes del sistema] ava no se pueden llamar directamente y solo se pueden realizar con la ayuda de la programación C y C++.

  • [Desarrollo] Para algunas funciones con requisitos de rendimiento relativamente altos, es más eficiente usar C y C++.

  • [Crawler] Use C y C++ para el algoritmo central para aumentar la dificultad del craqueo inverso.


instalación JNI

Después de instalar NDK, puede desarrollar JNI basado en Android Studio.

  • Al crear un nuevo proyecto de Android, se usa C para desarrollar el código central. [Plantilla nativa de C++]

  • Plantilla nativa de C++ (plantilla vacía + configuración básica de C)


registro estático

Si desea llamar al código C en Java en combinación con JNI.

  • Para crear una clase Java, no necesita implementar una lógica específica, solo defina clases y métodos.

package com.nb.fucker;

// com.nb.fucker.encryptUtils
public class encryptUtils {
    // 加载C文件
    static {
        System.loadLibrary("encrypt");
    }
    public static native int add(int  v1, int v2);

    public static native String sign(String origin);
}
  • Cree archivos C/C++ y escriba códigos para implementar funciones específicas.

  • comando para generar automáticamente archivos de encabezado (rutas a clases)

javac -h ./ encryptUtils.java
  • Nombre de la función del lenguaje C, reglas de nomenclatura -> Java_package name_class name_method name

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_nb_fucker_encryptUtils */

#ifndef _Included_com_nb_fucker_encryptUtils
#define _Included_com_nb_fucker_encryptUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_nb_fucker_encryptUtils
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint

JNICALL Java_com_nb_fucker_encryptUtils_add(JNIEnv *env, jclass obj, jint v1, jint v2) {
    // 写 C 语言代码 + env是JNI对象 + obj当前类 encryptUtils + v1、v2 是参数
    return v1 + v2;
}

/*
 * Class:     com_nb_fucker_encryptUtils
 * Method:    sign
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring

JNICALL Java_com_nb_fucker_encryptUtils_sign(JNIEnv *env, jclass obj, jstring origin) {
    char data[] = "wupeiqi";

    return (*env)->NewStringUTF(env, data); // 将 c中的字符串 转换成 java中的String

}

#ifdef __cplusplus
}
#endif
#endif
  • Configurar CMakeLists.txt

add_library( # Sets the name of the library.
        encrypt

        # Sets the library as a shared library.
        SHARED

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

target_link_libraries( # Specifies the target library.
        fucker encrypt
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

transferir

int v1 = encryptUtils.add(1, 2);
String v2 = encryptUtils.sign("xxxxx");

valor

Al invertir los archivos so de los sitios web de otras personas, conozca la correspondencia entre sus nombres de archivo.


registro dinámico

Pasos para el registro dinámico:

  • clase Java:


public class DynamicUtils {
    static {
        System.loadLibrary("dynamic");
    }
    public static native int add(int v1, int v2);
}
  • Función en C:

JNI_OnLoad
    -- 动态找到add
jint plus(JNIEnv *env, jclass obj, jint v1, jint v2) {
    return v1 + v2;
}

static JNINativeMethod gMethod[] = {
       //Java函数  ---->  C语言中的函数
        {"add", "(II)I", (void *) plus},
};

/*
 * System.loadLibrary("包")时会自动调用
 */

JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;

    // 在Java虚拟机中获取 env
    if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

    // 找到 Java 中的类,env=JNI
    jclass clazz = (*env)->FindClass(env, "com/nb/fucker/DynamicUtils");

    // 将类中的方法注册到JNI中
    int res = (*env)->RegisterNatives(env, clazz, gMethod, 1);
    if(res < 0) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}
  • Configurar CMakeLists.txt

add_library( # Sets the name of the library.
        dynamic

        # Sets the library as a shared library.
        SHARED

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

target_link_libraries( # Specifies the target library.
        fucker dynamic

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
  • transferir

int v3 = DynamicUtils.add(3, 4);
Log.e("DynamicUtils.add===>", String.valueOf(v3));

JNI llama a miembros en Java

Si desea llamar a miembros en Java en JNI, use:

  • Ejemplo 1: (método estático: int+int->int)

// Java
package com.nb.dk;

class Query{
    public static int getData(int v1, int v2) {
        return v1 + v2;
    }
}
// JNI
jclass cls = (*env) -> FindClass(env, "com/nb/dk/Query");
jmethodID mid = (*env) -> GetStaticMethodID(env, cls, "getData", "(II)I");
// "(II)I": 
//        JNI中 I 对应 Java中的 int 数据类型;
//        (II)-->代表参数是2个 int;
//        括号外的 I ---> 代表返回值是 int;
int res = (*env) -> CallStaticIntMethod(env, cls, mid, 1, 2);
  • Ejemplo 2: (método estático: int+int->String)

// Java
package com.nb.dk;

class Query{
    public static String getData(int v1, int v2) {
        return v1 + v2;
    }
}
// JNI
jclass cls = (*env) -> FindClass(env, "com/nb/dk/Query");
jmethodID mid = (*env) -> GetStaticMethodID(env, cls, "getData", "(II)Ljava/lang/String;");
// "(II)Ljava/lang/String;": 
//        JNI中 I 对应 Java中的 int 数据类型;
//        (II)-->代表参数是2个 int;
//        括号外的 Ljava/lang/String; ---> 代表返回值是 String;
int res = (*env) -> CallStaticIntMethod(env, cls, mid, 1, 2);
  • Ejemplo 3: (método estático: int+String->String)

// Java
package com.nb.dk;

class Query{
    public static String getData(String v1, int v2) {
        return String.valueOf(v1 + v2);
    }
}
// JNI, C语言
jclass cls = (*env) -> FindClass(env, "com/nb/dk/Query");
jmethodID mid = (*env) -> GetStaticMethodID(env, cls, "getData", "(Ljava/lang/String;I)Ljava/lang/String;");
// (Ljava/lang/String;I)Ljava/lang/String;": 
//        JNI中 I 对应 Java中的 int 数据类型;
//        (Ljava/lang/String;I)-->代表参数是第一个数据类型是String; 第二个数据类型是int;
//        括号外的 Ljava/lang/String; ---> 代表返回值是 String;
jstring arg1 = (*env)->NewStringUTF(env, "哈哈哈");    // 将C语言的字符串转化成 java的字符串
int res = (*env) -> CallStaticIntMethod(env, cls, mid, arg1, 2);
  • Ejemplo 4: (método dinámico: int+String->String)

// Java
package com.nb.dk;

class Query{
    // 构造方法
    public Query(int arg1, int arg2, String arg3) {
    
    }
    // getData
    public static String getData(String v1, int v2) {
        return String.valueOf(v1 + v2);
    }
}
// JNI
jclass cls = (*env) -> FindClass(env, "com/nb/dk/Query");
// "<init>" 找类中的构造方法
// v --> void
jmethodID init = (*env) -> GetStaticMethodID(env, cls, "<init>", "(IILjava/lang/String;)v");

// 创建对象
jobject cls_object = (*env)->NewObject(env, cls, init, 1, 2, (*env)->NewStringUTF(env, "哈哈哈"));

jmethodID mid = (*env) -> GetMethodID(env, cls, "getData", "(II)Ljava/lang/String;");
jstring arg1 = (*env)->NewStringUTF(env, "字符串啊");
int res = (*env) -> CallStaticIntMethod(env, cls_object, mid, arg1, 2);

Supongo que te gusta

Origin blog.csdn.net/m0_57126939/article/details/128853276
Recomendado
Clasificación