Java
  • About This Book
  • 🍖Prerequisites
    • 反射
      • 反射基本使用
      • 高版本JDK反射绕过
      • 反射调用命令执行
      • 反射构造HashMap
      • 方法句柄
    • 类加载
      • 动态加载字节码
      • 双亲委派模型
      • BCEL
      • SPI
    • RMI & JNDI
      • RPC Intro
      • RMI
      • JEP 290
      • JNDI
    • Misc
      • Unsafe
      • 代理模式
      • JMX
      • JDWP
      • JPDA
      • JVMTI
      • JNA
      • Java Security Manager
  • 👻Serial Journey
    • URLDNS
    • SerialVersionUID
    • Commons Collection 🥏
      • CC1-TransformedMap
      • CC1-LazyMap
      • CC6
      • CC3
      • CC2
    • FastJson 🪁
      • FastJson-Basic Usage
      • FastJson-TemplatesImpl
      • FastJson-JdbcRowSetImpl
      • FastJson-BasicDataSource
      • FastJson-ByPass
      • FastJson与原生反序列化(一)
      • FastJson与原生反序列化(二)
      • Jackson的原生反序列化利用
    • Other Components
      • SnakeYaml
      • C3P0
      • AspectJWeaver
      • Rome
      • Spring
      • Hessian
      • Hessian_Only_JDK
      • Kryo
      • Dubbo
  • 🌵RASP
    • JavaAgent
    • JVM
    • ByteCode
    • JNI
    • ASM 🪡
      • ASM Intro
      • Class Generation
      • Class Transformation
    • Rasp防御命令执行
    • OpenRASP
  • 🐎Memory Shell
    • Tomcat-Architecture
    • Servlet API
      • Listener
      • Filter
      • Servlet
    • Tomcat-Middlewares
      • Tomcat-Valve
      • Tomcat-Executor
      • Tomcat-Upgrade
    • Agent MemShell
    • WebSocket
    • 内存马查杀
    • IDEA本地调试Tomcat
  • ✂️JDBC Attack
    • MySQL JDBC Attack
    • H2 JDBC Attack
  • 🎨Templates
    • FreeMarker
    • Thymeleaf
    • Enjoy
  • 🎏MessageQueue
    • ActiveMQ CNVD-2023-69477
    • AMQP CVE-2023-34050
    • Spring-Kafka CVE-2023-34040
    • RocketMQ CVE-2023-33246
  • 🛡️Shiro
    • Shiro Intro
    • Request URI ByPass
    • Context Path ByPass
    • Remember Me反序列化 CC-Shiro
    • CB1与无CC依赖的反序列化链
  • 🍺Others
    • Deserialization Twice
    • A New Blazer 4 getter RCE
    • Apache Commons Jxpath
    • El Attack
    • Spel Attack
    • C3P0原生反序列化的JNDI打法
    • Log4j
    • Echo Tech
      • SpringBoot Under Tomcat
    • CTF 🚩
      • 长城杯-b4bycoffee (ROME反序列化)
      • MTCTF2022(CB+Shiro绕过)
      • CISCN 2023 西南赛区半决赛 (Hessian原生JDK+Kryo反序列化)
      • CISCN 2023 初赛 (高版本Commons Collections下其他依赖的利用)
      • CISCN 2021 总决赛 ezj4va (AspectJWeaver写字节码文件到classpath)
      • D^3CTF2023 (新的getter+高版本JNDI不出网+Hessian异常toString)
      • WMCTF2023(CC链花式玩法+盲读文件)
      • 第六届安洵杯网络安全挑战赛(CB PriorityQueue替代+Postgresql JDBC Attack+FreeMarker)
  • 🔍Code Inspector
    • CodeQL 🧶
      • Tutorial
        • Intro
        • Module
        • Predicate
        • Query
        • Type
      • CodeQL 4 Java
        • Basics
        • DFA
        • Example
    • SootUp ✨
      • Intro
      • Jimple
      • DFA
      • CG
    • Tabby 🔦
      • install
    • Theory
      • Static Analysis
        • Intro
        • IR & CFG
        • DFA
        • DFA-Foundation
        • Interprocedural Analysis
        • Pointer Analysis
        • Pointer Analysis Foundation
        • PTA-Context Sensitivity
        • Taint Anlysis
        • Datalog
Powered by GitBook
On this page
  • 0x01 What Is JNI
  • 0x02 Best Pratice
  • Dynamic Register
  • JNI Interface
  • Build

Was this helpful?

  1. 🌵RASP

JNI

PreviousByteCodeNextASM 🪡

Last updated 1 year ago

Was this helpful?

0x01 What Is JNI

JNI:Java Native Interface

Java是基于C语言实现的,很多底层API都是通过调用JNI来实现的。

与硬件、操作系统交互的操作可以使用JNI来提升程序性能

JNI让Java能够调用编译好的动态链接库里的方法(存在跨平台问题👊)

像我们熟悉的Class.forName()最底层就是C去实现的,它被native修饰

0x02 Best Pratice

  • 定义native修饰方法

public class JNITest {
    private native void say();
    static {
        System.loadLibrary("JniHi");
        // System.load(String fileName); 加载绝对路径
    }

    public static void main(String[] args) {
        new JNITest().say();
    }
}
  • javah生成.h头文件

javac -h . JNITest.java(JDK ≥ 10)

老版本:javah -jni JNITest

得到JNITest.h头文件和JNITest.class文件

  • C++实现头文件

VS新建dll项目,调试属性=》C/C++预编译头 => 不使用预编译头

生成后得到x64的dll

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <iostream>
#include "jni.h"
#include "JNITest.h"
#include <stdio.h>
#include<stdlib.h>

JNIEXPORT void JNICALL
Java_JNITest_say(JNIEnv* env, jobject obj)
{
	system("calc");
	return;
}

javah生成的头文件中的函数命名方式是有非常强制性的约束

(JNIEnv *, jclass, jstring)表示分别是JNI环境变量对象、java调用的类对象、参数入参类型

  • 加载dll

将生成的JniHi.dll放在class同目录下,执行java JNITest

成功弹出计算器

Dynamic Register

上面只是定义了一个native方法,然后通过System.loadLibrary()或System.load()加载native方法对应的动态链接库,来实现Java层面调用C/C++提供的服务。

还有另外一种方法来实现native方法,在JNI_OnLoad函数中进行函数映射,将java里面的方法映射到自己实现的C/C++函数,这样就不用通过javah生成头文件了(还有那串又臭又长的函数名)。JNI_OnLoad会在加载动态链接库时首先被调用。

既然这样的话,我们就能将原本java里定义的native方法映射到我们自己实现的方法。

JNI Interface

JNI_OnLoad

JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved);

第一个参数表示Java虚拟机,第二个参数一般为NULL,返回值为JNI版本。

JNINativeMethod

typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;

该结构体定义了C/C++函数与Java方法的映射

  • name:Java中定义的native方法名

  • signature:native方法的函数签名

  • fnPtr:C/C++中native函数指针

注册的时候需要设置一个JNINativeMethod数组,数组中有几个元素,就表示映射到一个类的多少个native方法。

native方法通过JNI函数来访问JVM中的数据结构。

JNIEnv

Java本地接口环境,一般为一个指针,指向native方法的一个函数表

可以从JavaVM获取JNIEnv,第一个参数为JNIEnv的二级指针,第二个参数为JNI版本

jint GetEnv(void **penv, jint version) {
    return functions->GetEnv(this, penv, version);
}

JNIEnv提供了一些与Java建立桥梁的方法,如FindClass,根据类名字符串找到对应的jclass

jclass FindClass(const char *name) {
    return functions->FindClass(this, name);
}

RegisterNatives 注册C/C++函数,映射到Java层的native方法

jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
                     jint nMethods) {
    return functions->RegisterNatives(this,clazz,methods,nMethods);
}
  • clazz:要注册方法所在的Java类

  • methods:Java方法与native方法映射的关系数组

  • nMethods:映射的方法个数,一般为methods数组元素的个数

此外JNIEnv还有一些用于jxxx的Java数据类型和C数据类型之间转换的方法,这里不展开。

Build

CLion新建项目

CMakeLists.txt👇

cmake_minimum_required(VERSION 3.26)
project(NativeRasp)

set(CMAKE_CXX_STANDARD 17)

# 创建分享动态链接库文件
add_library(NativeRasp SHARED library.cpp)

# 设置jni头文件包含路径
set(JAVA_INCLUDE_PATH path2jdk/include)
set(JAVA_AWT_INCLUDE_PATH path2jdk/include/win32)
set(BUILD_USE_64BITS on)

# 包含头文件
include_directories(${JAVA_INCLUDE_PATH} ${JAVA_AWT_INCLUDE_PATH})

library.cpp👇,这里为方便编写,就不管stdHandles标准输入输出错误这些了。

#include <iostream>
#include <jni.h>
#include <cstring>

JNIEXPORT jlong JNICALL
rasp_create(JNIEnv *env, jclass ignored,
            jstring cmd,
            jstring envBlock,
            jstring dir,
            jlongArray stdHandles,
            jboolean redirectErrorStream) {
    const int listSize = 5;
    const char *blacklist[listSize] = {"calc", "nc", "echo", "mv", "cp"};
    if (cmd != NULL && stdHandles != NULL) {
        const char *cmd_ = env->GetStringUTFChars(cmd, JNI_FALSE);
        for (int i = 0; i < listSize; i++) {
            if (strcmp(blacklist[i], cmd_) == 0) {
                printf("illegal command: %s\n", blacklist[i]);
                exit(1);
            }
        }
        system(cmd_);
    }
    return 0;
}

static const JNINativeMethod method[] = {
        {"create", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[JZ)J", (void *) rasp_create}
};
static const char *className = "java/lang/ProcessImpl";

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    printf("JNI_OnLoad Start\n");
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    jclass jclazz = env->FindClass(className);
    if (jclazz == NULL) {
        printf("cannot get class: %s\n", className);
        return -1;
    }
    if (0 > env->RegisterNatives(jclazz, method, sizeof(method) / sizeof(JNINativeMethod))) {
        printf("register native method failed!\n");
        return -1;
    }
    return JNI_VERSION_1_6;
}

Build得到一个动态链接库

import java.io.IOException;

public class Test {
    static {
        System.load("path/libNativeRasp.dll");
    }
    public static void main(String[] args) throws IOException {
        System.out.println("Evil Command Coming~");
        Runtime.getRuntime().exec("calc");
    }
}

无法包含jni.h的看这里:

JNI报错:"无法打开源文件jni.h" "JNIEXPORT此声明没有存储类或类型说明符"_"无法打开源文件 “jni.h"
image-20230322164250276
image-20230322172805579
image-20231029194401186
image-20231029195029812
image-20231029200100188