首页 > 其他分享 >day12-JNI案例

day12-JNI案例

时间:2023-10-21 15:00:58浏览次数:38  
标签:java day12 Utils 案例 justin env JNI public String

1 JNI类型签名


# 我们开发安卓--》写java代码---》通过JNI---》调用C代码(JNI的c代码)
				java中变量---》通过JNI---》转成c变量

image-20231021144045690

image-20231021144101246

2 JNI中java调用c案例

2.1 数字处理

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }

    // 1.1 数字类型处理
    // 在c语言中要对象 v进行具体实现---》jni代码---》c的函数名必须叫    Java_包名_类名_方法名(JNIEnv *env, jclass clazz, 后续的参数)
    public static native int v1(int a1, int a2);
}

demo.c

#include <jni.h>


//1.1  JNI编写 Utils.java中的v1方法
JNIEXPORT jint JNICALL
Java_com_justin_s9day11_Utils_v1(JNIEnv *env, jclass clazz, jint a1, jint a2) {
    return a1 + a2;
}

MainActivity.java

tv.setText(String.valueOf(Utils.v1(1,2)));

2.2 通过指针修改字符串

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
    
    // 1.2 修改字符串   传入 justin 字符串,在c中把字符串改变,返回回来
    public static native String v2(String s);
}

demo.c

#include <jni.h>
// 1.2  JNI编写 Utils.java中的v2方法,对字符串进行修改,然后返回
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v2(JNIEnv *env, jclass clazz, jstring s) {
    // 传入justin 字符串,把 justin 字符串的第1个位置和第4个位置,都变成 j

    // 1 把jstring类型的s,转成c语言 的 字符指针--》才能操作这个字符串
    // char info[]  = {'j','u','s','t','i','n'};
    char *info = (*env)->GetStringUTFChars(env, s, 0);  // 固定写法,指针指向s这个字符串
    info += 1;
    *info = 'j';  // 把字符串第1个位置的字符变成了 j
    info += 3;
    *info = 'j';  // 把字符串第4个位置的字符变成了 j
    info -= 4;    //让指针回到了 字符数组的第0个位置

    // 把字符数组 指针转成字符串类型返回--》固定用户
    return (*env)->NewStringUTF(env, info);

}

MainActivity.java

tv.setText(Utils.v2("aaaaaaaa"));

2.3 通过数组修改字符串

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
    
    // 1.3 修改字符串,传入 justin 字符串,在c中把字符串改变,返回回来,内部通过数组修改
    public static native String v3(String s);
}

demo.c

#include <jni.h>
// 1.3  JNI编写 Utils.java中的v2方法,对字符串进行修改,然后返回-->使用数组修改
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v3(JNIEnv *env, jclass clazz, jstring s) {
    // 指针,指向了字符数组
    char *info = (*env)->GetStringUTFChars(env, s, 0);  // 固定写法,指针指向s这个字符串
    // c语言指针的用法
    info[1] = 't';
    info[4] = 't';
    // 把字符数组 指针转成字符串类型返回--》固定用法
    return (*env)->NewStringUTF(env, info);


}


MainActivity.java

tv.setText(Utils.v3("aaaaaaaa"));

2.4 字符串拼接

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
    
     // 1.4 字符串拼接
    public static native String v4(String name,String role);
}

demo.c

#include <jni.h>
#include <malloc.h>
#include <string.h>
// 1.4 字符串串拼接
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v4(JNIEnv *env, jclass clazz, jstring name, jstring role) {
    // 1 把传入的name和role转成 字符指针
    char *nameString = (*env)->GetStringUTFChars(env, name, 0);
    char *roleString = (*env)->GetStringUTFChars(env, role, 0);
    char *s = malloc(strlen(nameString) + strlen(roleString) + 1);  // 定义一个指针,指定长度
    // 把name复制到s中去
    strcpy(s, nameString);
    // 把role拼接到后面
    strcat(s, roleString);
    //sprintf(s, "%s%s", name, role);
    return (*env)->NewStringUTF(env, s);
}


MainActivity.java

tv.setText(Utils.v4("justin","teacher"));

2.5 字符处理-把字符串转成16进制

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
    
        // 1.5 字符处理
    public static native String v5(String data);
}

demo.c

// 1.5 把传入的字符串,每一位,转成16进制返回(不足两位,用0补齐)
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v5(JNIEnv *env, jclass clazz, jstring data) {
    // data=     name=justin&age=19
    char *urlParams = (*env)->GetStringUTFChars(env, data, 0);
    //int size= strlen(urlParams);
    int size = GetStringLen(urlParams);

    char v34[size * 2]; // 定义一个char数组,长度是 size的两倍

    char *v28 = v34; // 取到指针,赋值给了v28指针类型

    for (int i = 0; urlParams[i] != '\0'; i++) {
        sprintf(v28, "%02x", urlParams[i]);  // 一位一位的取出 传入的字符串,把每一位转成16进制,不足2位,用0补齐
        v28 += 2;
    }

    return (*env)->NewStringUTF(env, v34);
}


MainActivity.java

tv.setText(Utils.v5("name=justin&age=19"));

2.6 字节处理-->java传进去的是字节类型

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
        // 1.6 字节处理
    public static native String v6(byte[] data);
    public static native String v7(byte[] data);

}

demo.c

// 1.6 字节处理---》把byte类型数组传入,转16进制后返回
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v6(JNIEnv *env, jclass clazz, jbyteArray data) {
    // 1 把 jbyteArray 类型,转成  c 字符数组
    char *byteArray = (*env)->GetByteArrayElements(env, data, 0);
    // 2 拿到传入的字节数组的长度
    int size = (*env)->GetArrayLength(env, data);
    //int size = GetStringLen(byteArray);

    char v34[size * 2];
    char *v28 = v34;

    for (int i = 0; byteArray[i] != '\0'; i++) {
        sprintf(v28, "%02x", byteArray[i]);
        v28 += 2;
    }
    return (*env)->NewStringUTF(env, v34);

}

// 1.7 do while 循环完成1.6的操作
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v7(JNIEnv *env, jclass clazz, jbyteArray data) {
    char *byteArray = (*env)->GetByteArrayElements(env, data, 0);
    int size = (*env)->GetArrayLength(env, data);
    char v34[size * 2];
    char *v28 = v34;
    int v29 = 0;
    do {
        sprintf(v28, "%02x", byteArray[v29++]);
        v28 += 2;
    } while (v29 !=  size);

    return (*env)->NewStringUTF(env, v34);
}

MainActivity.java

//tv.setText(Utils.v6("name=justin&age=19".getBytes()));
tv.setText(Utils.v7("name=justin&age=19".getBytes()));

3 JNI中c调用java案例

#  写android---》java写---》很容易被反编译---》看到我们的算法,可以复现算法---》安全性低--》大厂都会使用c做加密---》这个过程是java---》调用c---》上面讲的----》后面会有反编译的案例看到


# java---》调用c的加密---》在c 不用c写---》又调用java中的某个加密方法---》得到结果后--》再返回



# c调用java:
	静态方法:static修饰的,类来调用,不需要对象
    成员方法:需要对象来调用,需要在c中实例化得到对象再调用

3.1 调用java的静态方法

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }

	public static native String v8();
}

demo.c

// 2.1 c调用java案例
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v8(JNIEnv *env, jclass clazz) {
    // 调用java代码

    // 1 先找到要调用的类:
    jclass cls = (*env)->FindClass(env, "com/justin/s9day11/Foo");
    // 2 找到静态方法 getSign       ()Ljava/lang/String;最后一个参数是 getSign这个方法的参数和返回值签名
    // (参数签名)返回值签名
    //    jmethodID method1 = (*env)->GetStaticMethodID(env, cls, "getSign", "()Ljava/lang/String;");
    //    jmethodID method2 = (*env)->GetStaticMethodID(env, cls, "getSign","(Ljava/lang/String;)Ljava/lang/String;");
    jmethodID method3 = (*env)->GetStaticMethodID(env, cls, "getSign", "(Ljava/lang/String;I)Ljava/lang/String;");



    //3 z执行方法
    //jstring res1 = (*env)->CallStaticObjectMethod(env, cls, method1);
    //jstring res1 = (*env)->CallStaticObjectMethod(env, cls, method2,(*env)->NewStringUTF(env, "lqz"));
    jstring res1 = (*env)->CallStaticObjectMethod(env, cls, method3,(*env)->NewStringUTF(env, "lqz"),99);


    return res1;
    //4 如果想再继续用c操作,可以这么写
    //    char *p1 = (*env)->GetStringUTFChars(env, res1, 0);
    //    p1[0] = 'o';
    //
    //    return (*env)->NewStringUTF(env, p1);

}

MainActivity.java

tv.setText(Utils.v8());

Foo.java

package com.justin.s9day11;

public class Foo {

    public static String getSign() {
        return "justin123";
    }

    // 重载
    public static String getSign(String name) {
        return name + "_NB";
    }

    public static String getSign(String name, int age) {
        return name + String.valueOf(age);
    }
}

3.2 调用java的成员方法

Utils.java

package com.justin.s9day11;
public class Utils {
    static {
        System.loadLibrary("utils");
    }
 public static native String v9();

}

demo.c

// 2.2 c调用java的成员方法
JNIEXPORT jstring JNICALL
Java_com_justin_s9day11_Utils_v9(JNIEnv *env, jclass clazz) {
    // 调用Foo类中的ShowName这个成员方法

    // 1 找到类
    jclass cls = (*env)->FindClass(env, "com/justin/s9day11/Foo");
    // 2 找到构造方法
    jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;)V");
    //jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
    //jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;I)V");

    // 3 通过构造方法,实例化得到对象
    jobject cls_obj = (*env)->NewObject(env, cls, init, (*env)->NewStringUTF(env, "lqz"));

    //4 通过类,先找到方法
    jmethodID method1 = (*env)->GetMethodID(env, cls, "ShowName", "()Ljava/lang/String;");

    // 5 通过对象执行方法
    jstring res1 = (*env)->CallObjectMethod(env, cls_obj, method1);

    return res1;


}

MainActivity.java

tv.setText(Utils.v9());

Foo.java

package com.justin.s9day11;

public class Foo {
    public String name;



    // 构造方法
    public Foo(String name) {
        this.name = name+"_NB";

    }
    public Foo(String name,int age) {
        this.name = name;

    }

    // 成员方法
    public String ShowName() {
        return this.name;
    }
}

//Foo f=new Foo("lqz");
//f.ShowName()

4 JNI注册中的动态注册和静态注册

4.1 静态注册

上述编写的C语言的函数和Java的对应关系,在函数名上就可以体现,例如:

```

Java_com_justin_s8day12_Utils_v9
Java_com_justin_s8day12_Utils_v8

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

4.2 动态注册

# 动态注册步骤:
	1 新建c文件:dynamic.c
    
    2 在CMakeLists.txt注册
    add_library(
        dynamic
        SHARED
        dynamic.c)
    3 在CMakeLists.txt注册
    target_link_libraries(
        s9day11
        utils dynamic
        ${log-lib})
    4 新建Dynamic.java
    package com.justin.s9day11;
    public class Dynamic {
        static {
            System.loadLibrary("dynamic");
        }

        public static native int vv1(int a1,int a2);
        public static native int vv2(String s);


    }

dynamic.c

#include <jni.h>


// 静态注册---》通过vv1---》按固定模板,就能找到c的方法,很简单---》反编译也是这么找
//JNIEXPORT jint JNICALL
//Java_com_justin_s9day11_Dynamic_vv2(JNIEnv *env, jclass clazz, jstring s) {
//    // TODO: implement vv2()
//}
//
//JNIEXPORT jint JNICALL
//Java_com_justin_s9day11_Dynamic_vv1(JNIEnv *env, jclass clazz, jint a1, jint a2) {
//    // TODO: implement vv1()
//}



// 动态注册  通过 java中的方法名,无法确定,c中跟那个方法对应
jint plus1(JNIEnv *env, jobject obj, jint v1, jint v2) {
    return v1 + v2;
}

jint plus2(JNIEnv *env, jobject obj, jstring s1) {
    return 100;
}

static JNINativeMethod gMethods[] = {
        {"vv1", "(II)I",                 (void *) plus1},
        {"vv2", "(Ljava/lang/String;)I", (void *) plus2},
};



// 1 只要是动态注册,都必须写一个方法---》JNI_OnLoad
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    // ----固定的开始----
    JNIEnv *env = NULL;
    if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    // ----固定的结束----


    // 找到Java中的类
    jclass clazz = (*env)->FindClass(env, "com/justin/s9day11/Dynamic");
    // 将类中的方法注册到JNI中 (RegisterNatives)
    int res = (*env)->RegisterNatives(env, clazz, gMethods,
                                      2);  //  最后的数字2 表示有两个对应关系:Dynamic.java中有两个方法跟我dynamic.c中有两个方法对应,如何对应的是gMethods决定的



    // ----固定的开始----
    if (res < 0) {
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
    // ----固定的结束----
}

5 反编译自己的app

# 1:静态注册---》 反编译自己app----》找到了jni调用位置---》通过System.loadLibrary("utils")---》确定是哪个so文件---》去so文件中,通过 静态注册方案找  v9 对应的c中的函数---》很容易找到

# 2 动态注册
	-反编译so后,找JNI_OnLoad
    -找到对应关系,双击进入,按F5,查看源代码

image-20231021144322382

image-20231021144329696

标签:java,day12,Utils,案例,justin,env,JNI,public,String
From: https://www.cnblogs.com/hanfe1/p/17778976.html

相关文章

  • day11-JNI介绍
    四JNI介绍和安装4.1JNI介绍JNI,javanativeinterface,Java本地开发接口,实现在安卓中JAVA和C语言之间的相互调用。#之前写安卓,全是用java写#后期可以用c写安卓,写了后,需要使用java调用c的方法,完成功能4.2NDK安装NDK是JNI开发的工具包NDK,NativeDevelopKits,本地开发工......
  • 案例8 交换机的MAC地址表
    1.在华三交换机上查看MAC地址表[SW1]displaymac-addressMACAddressVLANIDStatePort/NicknameAging[SW1]interfaceVlan-interface1[SW1-Vlan-interface1]ipaddress10.1.10.1428[SW1-Vlan-interface1]ping10.1.10.1Ping10.1.10.......
  • python 案例
    这个程序使用了两个包:datetime和playsound。datetime:这是Python标准库中的一个模块,用于处理日期和时间。它提供了许多函数和类,可以让您在Python程序中处理日期和时间。由于datetime是Python的内置模块,因此您无需安装任何其他软件包来使用它。playsound:这是一个第三方包,用于......
  • unique使用案例及原理
    使用案例#define_CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstring>#include<stdlib.h>#include<stdio.h>#include<math.h>#include<iomanip>#include<ctype.h>#include<ctime>#include<stack......
  • 服务器数据恢复-服务器多块硬盘掉线导致银行业务模块崩溃的数据恢复案例
    服务器故障&分析:某银行的业务模块崩溃,无法正常使用。排查服务器故障,发现运行该业务模块的服务器中多块硬盘离线,导致上层应用崩溃。故障服务器内多块硬盘掉线,硬盘掉线数量超过服务器raid阵列冗余级别所允许的硬盘掉线数量,导致服务器瘫痪。可以通过修复硬盘物理故障,提取故障盘数据......
  • Thymeleaf使用案例
    1、在项目中添加依赖项,以下2个缺一不可。<!--https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5--><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>3.1.......
  • 软考系列(系统架构师)- 2018年系统架构师软考案例分析考点
    试题一软件架构(非功能性需求、C/S架构)【问题1】(8分)在系统架构设计中,决定系统架构设计的非功能性需求主要有四类:操作性需求、性能需求、安全性需求和文化需求。请简要说明四类需求的含义。(1)操作性需求:指系统完成任务所需的操作环境要求及如何满足系统将来可能的需求变更的......
  • 2个数仓中不等值关联优化案例
    本文分享自华为云社区《GaussDB(DWS)性能调优:不等值关联优化》,作者:门前一棵葡萄树。场景1使用场景:本案例适合满足以下条件的场景关联条件使用OR连接关联条件中使用同一列做数据筛选原始语句SELECTt2.PARTNER_CHANNEL_CODEASCHANNEL_ID,t1.COUNTRY_CODE,t1.BRAND......
  • 案例4 配置SSH协议
    1.在华为设备上配置SSH协议1.1按图配置端口的ip地址,并做连通性测试[R1]interfaceg0/0/0[R1-GigabitEthernet0/0/0]ipaddress202.100.1.1255.255.255.252[R2]intg0/0/0[R2-GigabitEthernet0/0/0]ipaddress202.100.1.2255.255.255.252[R1-GigabitEthernet0/0/0]pi......
  • 常用JS加密/解密类型以及案例
    简介这里给大家汇总常用不常用的JS加密案例,免得大家用的时候到处去找例子。正题对称加密:替代字符表示法:使用Base64或类似的编码对数据进行简单的转换,不过这并不是真正的加密,而只是一种表示形式的转换。<!DOCTYPEhtml><html><body><h2>Base64编码示例</h2><p>原始文本:Hello......