Andriod APP逆向——JNI开发

JNI的简介

JNI 是本地语言编程接口(Java Native Interface)。它允许运行在 JVM 中的 Java 代码和用C、C++ 或 汇编 写的本地代码相互操作。

JNI存在的意义:

  • 【开发】一些系统底层功能]ava无法直接调用,只能借助C、C++编程来实现。

  • 【开发】对于一些性能要求比较高的功能,用C、C++更加高效。

  • 【爬虫】将核心算法用C、C++ 增加逆向破解的难度。


JNI安装

安装好NDK后,就可以基于Android Studio进行JNI开发。

  • 新建Android项目时,会用C去开发核心代码。【Native C++模版】

  • Native C++模版(Empty模版+C基本设置)


静态注册

如果想要在Java中结合JNI实现调用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文件时,知道他们文件名之间的对应关系。

扫描二维码关注公众号,回复: 14904695 查看本文章

动态注册

动态注册的步骤:

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

猜你喜欢

转载自blog.csdn.net/m0_57126939/article/details/128853276