Andriod APP reverse - JNI development

Introduction to JNI

JNI is the native language programming interface (Java Native Interface). It allows Java code running in the JVM to interoperate with native code written in C, C++, or assembly.

The meaning of JNI's existence:

  • [Development] Some underlying functions of the system] ava cannot be called directly, and can only be realized with the help of C and C++ programming.

  • [Development] For some functions with relatively high performance requirements, it is more efficient to use C and C++.

  • [Crawler] Use C and C++ for the core algorithm to increase the difficulty of reverse cracking.


JNI installation

After installing NDK, you can develop JNI based on Android Studio.

  • When creating a new Android project, C is used to develop the core code. [Native C++ template]

  • Native C++ template (Empty template + C basic settings)


static registration

If you want to call C code in Java in combination with JNI.

  • To create a Java class, you don't need to implement specific logic, just define classes and methods.

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);
}
  • Create C/C++ files and write codes to implement specific functions.

  • command to automatically generate header files (paths into classes)

javac -h ./ encryptUtils.java
  • C language function name, naming rules -> 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
  • Configure 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})

transfer

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

value

When reversing the so files of other people's websites, know the correspondence between their file names.


dynamic registration

Steps for dynamic registration:

  • Java class:


public class DynamicUtils {
    static {
        System.loadLibrary("dynamic");
    }
    public static native int add(int v1, int v2);
}
  • Function in 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;
}
  • Configure 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})
  • transfer

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

JNI calls members in Java

If you want to call members in Java in JNI, use:

  • Example 1: (static method: 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);
  • Example 2: (static method: 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);
  • Example 3: (static method: 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);
  • Example 4: (dynamic method: 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);

Guess you like

Origin blog.csdn.net/m0_57126939/article/details/128853276