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);