I'm building an in-process JNI library fuzzer using Frida and I think I got everything to work except for multidimensional arrays.
When testing on Linux_64, I'm not able to even create a valid hook for a function which takes multidimensional arrays. No matter what I try I'm getting something like:
Exception in thread "main" java.lang.NoClassDefFoundError: [L[I;
at CallCrashingFun.crashingMethod_dbarr(Native Method)
at CallCrashingFun.main(CallCrashingFun.java:100)
Caused by: java.lang.ClassNotFoundException: [I
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
My hooking script looks similar to this:
var t_class = Java.use("CallCrashingFun")
var method_name = "crashingMethod_dbarr"
t_class[method_name].implementation = function(dbint) {
console.log("Hook works!")
}
/* Also tried with params
t_class[method_name].overload.apply(t_class[method_name], param_types).implementation = function(dbint) {
console.log("Hook works!")
}*/
/* This however doesn't crash
var imp_cp = t_class[method_name].implementation
t_class[method_name].implementation = imp_cp
*/
The Java code I use for tests:
System.loadLibrary("native");
int arr[] = {2,2,2};
int[][] dbarr = {arr};
new CallCrashingFun().crashingMethod_dbarr(dbarr);
private native void crashingMethod_dbarr(int[][] dbarr);
The JNI C++ code:
JNIEXPORT void JNICALL Java_CallCrashingFun_crashingMethod_1dbarr
(JNIEnv *env, jobject thisObject, jobjectArray dbtab) {
int i, j;
std::cout << "DbArray: " << "[" << std::endl;
jsize len = (env)->GetArrayLength(dbtab);
for (i=0; i<len; i++) {
std::cout << "[";
jintArray insArr = (jintArray) (env)->GetObjectArrayElement(dbtab, i);
jsize inlen = (env)->GetArrayLength(insArr);
jint *body = (env)->GetIntArrayElements(insArr, 0);
for (j=0; j<inlen; j++) {
std::cout << body[i] << ",";
}
std::cout << "]" << std::endl;
}
std::cout << "]" << std::endl;
}
Java version that I'm using:
$ /usr/bin/java --version
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
openjdk 11.0.17 2022-10-18
OpenJDK Runtime Environment Temurin-11.0.17+8 (build 11.0.17+8)
OpenJDK 64-Bit Server VM Temurin-11.0.17+8 (build 11.0.17+8, mixed mode)
Frida server version:
frida-server-16.0.8-linux-x86_64
Without hook the function works correctly:
DbArray: [
[2,2,2,]
]
How can I get this hook to work?
Related
I am trying to run a java program using c++ code. I tried below code
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args);
// Construct a String
jstring jstr = env->NewStringUTF("Hello World");
// First get the class that contains the method you need to call
jclass clazz = env->FindClass("java/lang/String");
// Get the method that you want to call
jmethodID to_lower = env->GetMethodID(clazz, "toLowerCase",
"()Ljava/lang/String;");
// Call the method on the object
jobject result = env->CallObjectMethod(jstr, to_lower);
// Get a C-style string
const char* str = env->GetStringUTFChars((jstring)result, NULL);
printf("%s\n", str);
// Clean up
env->ReleaseStringUTFChars(jstr, str);
// Shutdown the VM.
vm->DestroyJavaVM();
}
I used below command to compile the code
g++ LoadJVM.c -I/c/apps64/Java/jdk-11.0.1/include -I/c/apps64/Java/jdk-11.0.1/include/win32 -L/c/apps64/Java/jdk-11.0.1/lib/ -ljvm
It compiles fine, but when i run the executable like below, i am facing error
./a.exe
Error
error while loading shared libraries: jvm.dll: cannot open shared object file: No such file or directory
Any Idea why this jvm.dll is not getting loaded?
PS: I am compiling and running from Git-Bash on windows 10.
It looks like your jvm.dll can not be found.
Let's say we have 32bit MinGW installation (this is the version I have).
simple.cc
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args);
printf("Hello");
// Shutdown the VM.
(*vm).DestroyJavaVM();
}
compilation and execution
> export JAVA_HOME="/c/Program\ Files\ \(x86\)/Java/jdk1.8.0_211/"
> export PATH="/c/Program Files (x86)/Java/jdk1.8.0_211/jre/bin/server/":"$PATH"
> g++ -o simple simple.cc -I"$JAVA_HOME/include/" -I"$JAVA_HOME/include/win32/" -L"$JAVA_HOME/lib" -ljvm
> ./simple
Hello
you have to make sure that jvm.dll is visible on %PATH% - $PATH inside git-bash.
I am writing a Java application that executes USB I/O on Windows 10 with Java 10 JDK. My i/o library is the libusb api. The app loads a JNI library .dll compiled/built in Visual Studio 2017 with both Microsoft Visual 2013 C++ and Microsoft Visual C++ 2015-2019 installed. This application generates the following crash warning when ran inside a Netbeans 11.1 project.
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000002e1bbcd122e, pid=444, tid=3244
JRE version: Java(TM) SE Runtime Environment (10.0+46) (build 10+46)
Java VM: Java HotSpot(TM) 64-Bit Server VM (10+46, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
Problematic frame:
C [VCRUNTIME140D.dll+0x122e]
The problem function is my USB read function within the C code in the VisualStudio-built .dll.
JNI.c
JNIEXPORT jint JNICALL Java_SWMAPI_IoUSB_read
(JNIEnv * env, jobject thisObj, jbyteArray jArr, jint size, jlong javaHandle){
//Convert jLong to device handle pointer
libusb_device_handle * handle = (libusb_device_handle * )javaHandle;
//jbyteArray jArr: byte [] buffer. Must be overwritten with USB read data from device with
// corresponding handle javaHandle.
//jlong javaHandle: long passed from java representing the device to I/O.
//jint size: jArr length (e.g. buffer.length), used for debugging.
int status; //return code value
int bytes_written;
int bytes_read;
MESSAGE Message; //C struct containing 9 bytes of message header and (n) bytes of payload.
int length = (*env)->GetArrayLength(env, jArr);
jbyte * bufferIn = (*env)->GetPrimitiveArrayCritical(env, jArr, NULL); //get memory from jArr
//copy data in bufferIn to a Message struct.
memcpy((unsigned char *)&Message, (unsigned char *)bufferIn, length);
//write the Message out to device
bytes_written = libusb_control_transfer(handle, CTRL_OUT, MEM_RQ, 0, 0, (unsigned char *)&Message, length, 0);
if(bytes_written == length){
//read data in from Device to &Message
bytes_read = libusb_control_transfer(handle, CTRL_IN, MEM_RQ, 0, 0, (unsigned char
*)&Message, sizeof(MESSAGE), 30000);
status = (bytes_written < 0) ? bytes_read : // I/O Error
(bytes_written < length) ? USB_STATUS_SHORT_WRITE : // Check for short write
LIBUSB_SUCCESS;
if(Message.payload.length >= 0){ //If read data > 0
printf("Attempting memcpy\n");
fflush(stdout);
// The error appears on the line below
memcpy((unsigned char *)bufferIn,(unsigned char *)&Message, MAX_HEADER_LENGTH +
Message.payload.length);
printf("Success memcpy\n");
fflush(stdout);
}
}
(*env)->ReleasePrimitiveArrayCritical(env, jArr, bufferIn, 0);
return status;
}
This function has been working for my project up until today. Its frequency is approx 1 out of 3 runs. Can anyone please advise me on how I can move forward to solving this issue?
I am trying to call the following java method from C++
final String[] games = GameLoader.listGames();
where GameLoader was imported with import player.GameLoader;. The GameLoader class exists within a jar file. I am trying to use JNI to load the jar file from C++ and then call the above method. The following is my C++ code which I have tried to extend from this SO post.
#include <iostream>
#include <string.h>
#include <jni.h>
#include <stdlib.h>
using namespace std;
#define PATH_SEPARATOR ';'
#define USER_CLASSPATH "Ludii-0.3.0.jar"
#define GAME_LOADER "player/GameLoader"
JNIEnv *env;
JavaVM *jvm;
jint res;
void initJVM() {
#ifdef JNI_VERSION_1_2
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString =
"-Djava.class.path=" USER_CLASSPATH;
vm_args.version = 0x00010002;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_TRUE;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
JDK1_1InitArgs vm_args;
char classpath[1024];
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Append USER_CLASSPATH to the default system class path */
sprintf(classpath, "%s%c%s",
vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
vm_args.classpath = classpath;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
#endif /* JNI_VERSION_1_2 */
}
void closeJVM() {
jvm->DestroyJavaVM();
}
int main() {
initJVM();
jclass gameLoader = env->FindClass(GAME_LOADER);
//final String[] games = GameLoader.listGames();
jmethodID mid = env->GetMethodID(gameLoader,"listGames","()[Ljava/lang/String;");
jobjectArray stringArray = (jobjectArray) env->CallObjectMethod(gameLoader,mid);
closeJVM();
}
I am able to successfully create the JVM and the code compiles however at runtime I get the error
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f0e835619d7, pid=3504, tid=0x00007f0e84028740
#
# JRE version: OpenJDK Runtime Environment (8.0_222-b10) (build 1.8.0_222-8u222-b10-1ubuntu1~16.04.1-b10)
# Java VM: OpenJDK 64-Bit Server VM (25.222-b10 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x6849d7]
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/alex/jni_examples/hs_err_pid3504.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
Aborted (core dumped)
I think that the error is related to the CallObjectMethod call but I'm not sure.
Also I am using Java 8
EDIT:
It looks like mid evaluated to 0 which means that the method was not found. I guess this is the problem however I'm not sure why it wasn't found. This was checked with
int main() {
initJVM();
jclass gameLoader = env->FindClass("player/GameLoader");
//final String[] games = GameLoader.listGames();
if(gameLoader == NULL)
{
cout << "Could not load class!" << endl;
return 1;
}
jmethodID mid = env->GetMethodID(gameLoader,"listGames","()[Ljava/lang/String;");
if(mid == NULL)
{
cout << "Could not load method!" << endl;
return 1;
}
jobjectArray stringArray = (jobjectArray) env->CallObjectMethod(gameLoader,mid);
if(stringArray == NULL)
{
cout << "Could not load object!" << endl;
return 1;
}
closeJVM();
}
ANOTHER EDIT:
So it looks like the problem was that listGames() should be found with GetStaticMethodID rather than GetMethodID and it should be called with CallStaticObjectMethod rather than CallObjectMethod. Thank you.
I am getting this error when I execute C++ code from Java. I placed cout statements in C++ code to identify if C++ part got executed completely and found that C++ code is working fine but when its reaching java side I am getting the below exception.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007fd5894aeaea, pid=8998, tid=0x00007fd58a01e700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_101-b13) (build 1.8.0_101-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libc.so.6+0x88aea] strlen+0x2a
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/user1/workspace/ImageProcessor/hs_err_pid8998.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
My Java class is
public class ShingleCoOrdJNA extends Structure {
public static class ByReference extends ShingleCoOrdJNA implements Structure.ByReference {}
public static class ByValue extends ShingleCoOrdJNA implements Structure.ByValue {}
public Point.ByValue ShiP1;
public Point.ByValue ShiP2;
public Point.ByValue ShiP3;
public Point.ByValue ShiP4;
//public Point.ByReference vDamagePts;
public StringByReference vDamagePts;
public boolean bIsGood;
public float fDamagePercentage;
public ShingleCoOrdJNA()
{
this.bIsGood = true;
this.fDamagePercentage = 0;
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ShiP1","ShiP2","ShiP3","ShiP4","vDamagePts","bIsGood","fDamagePercentage"});
}
}
StringByReference class is
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(int size) {
super(size < 4 ? 4 : size);
getPointer().clear(size < 4 ? 4 : size);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
public String getValue() {
return getPointer().getString(0);
}
}
From java I am calling like this.
ShingleCoOrdJNAList.ByReference shingleCoordList = new ShingleCoOrdJNAList.ByReference();
shingleCoordList.shingleCoords = new ShingleCoOrdJNA.ByReference();
IntByReference size = new IntByReference();
TestImgProcInterface.INSTANCE.callPerformShingleDetection(newMat.getNativeObjAddr(), pointList, 4, shingleCoordList, size, false, true);
System.out.println(shingleCoordList.size());
C++ function
extern "C" void callPerformShingleDetection(Mat &FrameMat, struct PointListJNA pointList, int pointSize, struct ShingleCoOrdJNAList &damagePts, int &damagePtsSize, bool bShowResult, bool bDoDamageAnalysis) {
vector<cv::Point> vPolyList;
Point pXY;
for(int i=0;i<pointSize;i++) {
pXY.x = pointList.points[i].x;
pXY.y = pointList.points[i].y;
vPolyList.push_back(pXY);
}
vector<ShingleCoOrd> vShingleList;
PerformShingleDetection(FrameMat, vPolyList, vShingleList, bShowResult, bDoDamageAnalysis);
std::cout << "Image processing completed" << endl;
damagePts = {};
damagePts.size = vShingleList.size();
damagePts.shingleCoords = (ShingleCoOrdJNA*)malloc(sizeof(ShingleCoOrdJNA) * vShingleList.size());
std::cout << "ShingleCoordJNA memmory allocated" << endl;
for(int j=0;j<vShingleList.size();j++) {
damagePts.shingleCoords[j].ShiP1 = getJNAPoint(vShingleList[j].ShiP1);
damagePts.shingleCoords[j].ShiP2 = getJNAPoint(vShingleList[j].ShiP2);
damagePts.shingleCoords[j].ShiP3 = getJNAPoint(vShingleList[j].ShiP3);
damagePts.shingleCoords[j].ShiP4 = getJNAPoint(vShingleList[j].ShiP4);
damagePts.shingleCoords[j].bIsGood = vShingleList[j].bIsGood;
damagePts.shingleCoords[j].fDamagePercentage = vShingleList[j].fDamagePercentage;
/*damagePts.shingleCoords[j].vDamagePts = (Points*)malloc(sizeof(Points) * vShingleList[j].vDamagePts.size());
for(int m=0;m<vShingleList[j].vDamagePts.size();m++) {
damagePts.shingleCoords[j].vDamagePts[m] = getJNAPoint(vShingleList[j].vDamagePts[m]);
}*/
std::cout << "Damage String making" << endl;
damagePts.shingleCoords[j].vDamagePts = (char*)malloc(921600*sizeof(char));
std::stringstream s;
for(int m=0;m<vShingleList[j].vDamagePts.size();m++) {
s << s << vShingleList[j].vDamagePts[m].x << "," << vShingleList[j].vDamagePts[m].y << "#";
}
strcpy (damagePts.shingleCoords[j].vDamagePts, s.str().c_str());
std::cout << "Damage" << damagePts.shingleCoords[j].vDamagePts << endl;
}
std::cout << "Size of shingle detected" << vShingleList.size() << endl;
}
I am trying to call non static method from java to C++ using JNI
My Java Code is here:
public class hellojava
{
public static void main(String args[])
{
System.out.println("Hello World!");
System.out.println("This is the main function from the HelloWorld java class.");
}
public void message()
{
System.out.println("call from object");
}
}
And my C++ code is here:
#include <stdio.h>
#include <jni.h>
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=/home/../nonstaticJavaMethods/";
//Path to the java source code
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
int main(int argc, char* argv[])
{
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if (env == NULL)
return 1;
//jclass clsH=NULL;
jmethodID midMain = NULL;
jstring square;
jclass clsH = env->FindClass("helloWorld");
jmethodID constructor = env->GetMethodID(clsH, "<init>", "void(V)");
jobject object = env->NewObject(clsH, constructor);
//Obtaining Method IDs
if (clsH != NULL)
{ midMain = env->GetMethodID(clsH, "message", "void(V)");
env->CallVoidMethod(clsH, midMain, object,NULL);
}
else
{
printf("\nUnable to find the requested class\n");
}
//Release resources.
int n = jvm->DestroyJavaVM();
return 0;
}
My code compiles but it is giving me runtime error. Following is the error
A fatal error has been detected by the Java Runtime Environment:
SIGSEGV (0xb) at pc=0x00007fdf3f5126bb, pid=11302, tid=140596827092800
JRE version: OpenJDK Runtime Environment (7.0_55-b14) (build 1.7.0_55-b14)
Java VM: OpenJDK 64-Bit Server VM (24.51-b03 mixed mode linux-amd64 compressed oops)
Problematic frame:
V [libjvm.so+0x5c46bb] alloc_object(_jclass*, Thread*)+0x1b
Failed to write core dump. Core dumps have been disabled. To enable core dumping,
try
"ulimit -c unlimited" before starting Java again
An error report file with more information is saved as
/home/../nonstaticJavaMethods/hs_err_pid11302.log
Aborted!
Additionally to immibis' answer, i also think the call
jclass clsH = env->FindClass("helloWorld");
isn't returning anything, as your class is called
public class hellojava
So your application is probably seg-faulting in GetMethodID() or NewObject()
void(V) is not a valid method descriptor.
Because there is no method called <init> with the descriptor void(V) (which there can't be, because it's invalid), GetMethodID returns 0. Then you try to create a new object using this invalid method ID.
The method descriptor for a method that takes no arguments and returns void (which a constructor is) is ()V.