【APP逆向14】JNI开发简介之二

  • 简介:上一篇我们讲到了java调用C,今天继续聊C调用java

  • 1.C调用java的静态方法

    • 1.1:入口,java调用C的代码
package com.nb.s4;

class EncryptUtils {
    static {
        System.loadLibrary("enc");
    }
    
    public static native String v8();
}
  • 1.2:C语言实现,调用java代码
#include <jni.h>
#include <string.h>
#include <syslog.h>
#include<stdlib.h>


JNIEXPORT jstring

JNICALL
Java_com_nb_s4luffy_EncryptUtils_v8(JNIEnv *env, jclass clazz) {

    // 找到类
    jclass cls = (*env)->FindClass(env, "com/nb/s4/SignQuery");

    // 找到方法
    jmethodID method1 = (*env)->GetStaticMethodID(env, cls, "getPart1", "()Ljava/lang/String;");
    jmethodID method2 = (*env)->GetStaticMethodID(env, cls, "getPart2", "(I)Ljava/lang/String;");
    jmethodID method3 = (*env)->GetStaticMethodID(env, cls, "getPart3","(Ljava/lang/String;)Ljava/lang/String;");
    jmethodID method4 = (*env)->GetStaticMethodID(env, cls, "getPart4", "(Ljava/lang/String;I)I");


    // 执行方法
    jstring res1 = (*env)->CallStaticObjectMethod(env, cls, method1);
    jstring res2 = (*env)->CallStaticObjectMethod(env, cls, method2, 100);
    jstring res3 = (*env)->CallStaticObjectMethod(env,cls,method3,(*env)->NewStringUTF(env, "hahahahh"));
    jint res4 = (*env)->CallStaticIntMethod(env,cls,method4,(*env)->NewStringUTF(env, "hahahahh"),18);

    char *p1 = (*env)->GetStringUTFChars(env, res1, 0);
    char *p2 = (*env)->GetStringUTFChars(env, res2, 0);
    char *p3 = (*env)->GetStringUTFChars(env, res3, 0);

    char *result = malloc(50);
    strcat(result,p1);
    strcat(result,p2);
    strcat(result,p3);

    return (*env)->NewStringUTF(env, result);
}
  • 1.3:被c调用的java代码
package com.nb.s4;

public class SignQuery {

    public static String getPart1() {
        return "xwliang";
    }

    public static String getPart2(int len) {
        return "root".substring(2);
    }

    public static String getPart3(String prev) {
        return "xxx";
    }

    public static int getPart4(String prev, int v1) {
        return 100;
    }
}
  • 2.C调用java的实例方法
    • 2.1:C语言入口,java调C
package com.nb.s4;

class EncryptUtils {
    static {
        System.loadLibrary("enc");
    }
    
    public static native String v9();
}
  • 2.2:C语言实现算法,其中部分代码调用java
#include <jni.h>
#include <string.h>
#include <syslog.h>
#include<stdlib.h>


JNIEXPORT jstring

JNICALL
Java_com_nb_s4luffy_EncryptUtils_v9(JNIEnv *env, jclass clazz) {

    // 找到类
    jclass cls = (*env)->FindClass(env, "com/nb/s4luffy/SignQuery2");

    // 找到构造方法
    jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;I)V");

    // 实例化对象 new SignQuery2(...)
    jobject cls_obj = (*env)->NewObject(env, cls, init, (*env)->NewStringUTF(env, "hahahahh"), 22);

    // 找到方法
    jmethodID method1 = (*env)->GetMethodID(env, cls, "getPart1", "()Ljava/lang/String;");
    jmethodID method2 = (*env)->GetMethodID(env, cls, "getPart2", "(I)Ljava/lang/String;");
    jmethodID method3 = (*env)->GetMethodID(env, cls, "getPart3","(Ljava/lang/String;)Ljava/lang/String;");
    jmethodID method4 = (*env)->GetMethodID(env, cls, "getPart4", "(Ljava/lang/String;I)I");


    // 执行方法
    jstring res1 = (*env)->CallObjectMethod(env, cls_obj, method1);
    jstring res2 = (*env)->CallObjectMethod(env, cls_obj, method2, 100);
    jstring res3 = (*env)->CallObjectMethod(env,cls_obj,method3,(*env)->NewStringUTF(env, "hahahahh"));
    jint res4 = (*env)->CallIntMethod(env,cls_obj,method4,(*env)->NewStringUTF(env, "hahahahh"),18);


    char *p1 = (*env)->GetStringUTFChars(env, res1, 0);

    return (*env)->NewStringUTF(env, p1);
}
  • 2.3:被调用的java
package com.nb.s4;

public class SignQuery {
    String name;
    String city;
    int count;

    public SignQuery(String city, int count) {
        this.name = "xwliang";
        this.city = city;
        this.count = count;
    }

    public String getPart1() {
        return this.name;
    }

    public String getPart2(int len) {
        return "root".substring(2);
    }

    public String getPart3(String prev) {
        return "xxx-";
    }

    public int getPart4(String prev, int v1) {
        return 100;
    }
}
  • 3.静态注册与动态注册
    • 3.1:上述编写的C语言的函数和Java的对应关系,在函数名上就可以体现,例如:
Java_com_nb_s2long_EncryptUtils_s2
Java_com_nb_s2long_EncryptUtils_s5

这种称为静态注册,如果是静态注册,那么在逆向时,是比较方便的,直接可以找到函数在C中的实现。

  • 3.2:动态注册
package com.nb.s3jni;

class DynamicUtils {

    static {
        System.loadLibrary("dynamic");
    }

    public static native int add(int v1, int v2);
}

#include <jni.h>


jint plus(JNIEnv *env, jobject obj, jint v1, jint v2) {
    return v1 + v2;
}


static JNINativeMethod gMethods[] = {
        {"add", "(II)I", (void *) plus},
};


JNIEXPORT jint 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中的类
    jclass clazz = (*env)->FindClass(env, "com/nb/s3jni/DynamicUtils");

    // 将类中的方法注册到JNI中 (RegisterNatives)
    int res = (*env)->RegisterNatives(env, clazz, gMethods, 1);  //第三个参数,与C中的方法对应;第4个参数,代表对应关系的个数
    if (res < 0) {
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
}

  • 3.3:这种情况下,在逆向时,就不能直接找对应关系了,就需要去找jni_onload
JNI_Onload方法中
	int res = (*env)->RegisterNatives(env, clazz, gMethods, 2);

然后根据gMethods找到java与C的对应关系。

posted @ 2024-02-05 22:06  Tony_xiao  阅读(34)  评论(0编辑  收藏  举报