JNI の紹介
JNI は、ネイティブ言語のプログラミング インターフェイス (Java Native Interface) です。JVM で実行される Java コードは、C、C++、またはアセンブリで記述されたネイティブ コードと相互運用できます。
JNIの存在意義:
[開発] システムの基本機能] ava は直接呼び出すことができず、C および C++ プログラミングの助けを借りてのみ実現できます。
[開発] 比較的高いパフォーマンスが要求される一部の関数については、C および C++ を使用する方が効率的です。
[クローラー] コア アルゴリズムに C および C++ を使用して、リバース クラックの難易度を高めます。
JNI のインストール
NDK をインストールすると、Android Studio ベースの JNI を開発できます。
新しい Android プロジェクトを作成する場合、C を使用してコア コードを開発します。【ネイティブC++テンプレート】
ネイティブ C++ テンプレート (空のテンプレート + C 基本設定)
静的登録
JNI と組み合わせて Java で C コードを呼び出したい場合。
Java クラスを作成するには、特定のロジックを実装する必要はなく、クラスとメソッドを定義するだけです。
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);
}
C/C++ ファイルを作成し、コードを記述して特定の機能を実装します。
ヘッダー ファイル (クラスへのパス) を自動的に生成するコマンド
javac -h ./ encryptUtils.java
C言語関数名、命名規則 → Java_パッケージ名_クラス名_メソッド名
/* 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
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})
移行
int v1 = encryptUtils.add(1, 2);
String v2 = encryptUtils.sign("xxxxx");
価値
他人のサイトのsoファイルを逆にする場合は、ファイル名の対応を知っておきましょう。
動的登録
動的登録の手順:
Java クラス:
public class DynamicUtils {
static {
System.loadLibrary("dynamic");
}
public static native int add(int v1, int v2);
}
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;
}
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})
移行
int v3 = DynamicUtils.add(3, 4);
Log.e("DynamicUtils.add===>", String.valueOf(v3));
JNI は Java でメンバーを呼び出します
JNI で Java のメンバーを呼び出す場合は、次を使用します。
例 1: (静的メソッド: 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);
例 2: (静的メソッド: 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);
例 3: (静的メソッド: 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);
例 4: (動的メソッド: 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);