JNA pass stringbyreference - java

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;
}

Related

Hooking functions which take multidimensional arrays

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?

Using JNI to call Java Method that Returns String Array from Cpp

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.

Access violation when calling the Zebra printer API

# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x5f0c25fe, pid=14780, tid=11168
#
# JRE version: Java(TM) SE Runtime Environment (7.0_80-b15) (build 1.7.0_80-b15)
# Java VM: Java HotSpot(TM) Client VM (24.80-b11 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [ZBRGraphics.dll+0x25fe]
I keep getting this error when using the Zebra printer DLL in Java program.
public class Tester {
public static void main(String[] args) {
ZBRGraphics zGraphics = ZBRGraphics.INSTANCE;
String text = "Print this";
byte[] textB = text.getBytes(StandardCharsets.UTF_8);
String font= "Arial";
byte[] fontB = text.getBytes(StandardCharsets.UTF_8);
System.out.println(zGraphics.ZBRGDIDrawText(0, 0, textB, fontB, 12, 1, 0x0FF0000, 0));
}
}
public interface ZBRGraphics extends Library {
ZBRGraphics INSTANCE = (ZBRGraphics) Native.loadLibrary("ZBRGraphics", ZBRGraphics.class);
int ZBRGDIDrawText(int x, int y, byte[] text, byte[] font, int fontSize, int fontStyle, int color, int err);
}
I have the DLL in C:\Windows\System32 and in my 32 bit Java .
I'm using a 64 bit machine as my laptop for development.
If my google-fu skills are any good, you appear to be interfacing with the Zebra printer's API. According to the "ZXP1 & ZXP3 Software Developers Reference Manual" (found here), the Java mapping of the function is incorrect.
This is the actual C function prototype:
int ZBRGDIDrawText(
int x,
int y,
char *text,
char *font,
int fontSize,
int fontStyle,
int color,
int *err
)
As you can see, err is not an int, but a pointer to one. Also, since text and font are strings, you can just use a String as the Java type. Additionally, the API docs say that the return value is an int with either 1 for success or 0 for failure, meaning that you can use a boolean for ease of use.
The following Java mapping should be correct:
boolean ZBRGDIDrawText(
int x,
int y,
String text,
String font,
int fontSize,
int fontStyle,
int color,
IntByReference err
);
and you might use it like so:
IntByReference returnCode = new IntByReference(0);
boolean success = zGraphics.ZBRGDIDrawText(
0,
0,
"Print this",
"Arial",
12,
1,
0x0FF0000,
returnCode
);
if (success) {
System.out.println("success");
} else {
System.out.println("ZBRGDIDrawText failed with code " + returnCode.getValue());
}

call nonstatic methods from java to cpp using JNI

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.

Programmatically change the desktop wallpaper periodically

What is the best way to go about creating a program that would change the desktop wallpaper periodically? I would also like to create a GUI around the program. I am a Computer Science student, and as such I know basic programming in Java, and C++ among others. This will be done on Windows 7 OS.
What would be the best language to use for a project like this?
Ideally I would like to use the system clock to trigger the change. Is this possible?
Am I in over my head?
Any answers will be very much appreciated. Thank you.
In Java :
import java.util.*;
public class changer
{
public static native int SystemParametersInfo(int uiAction,int uiParam,String pvParam,int fWinIni);
static
{
System.loadLibrary("user32");
}
public int Change(String path)
{
return SystemParametersInfo(20, 0, path, 0);
}
public static void main(String args[])
{
String wallpaper_file = "c:\\wallpaper.jpg";
changer mychanger = new changer();
mychanger.Change(wallpaper_file);
}
}
In Win32 C++, You can use SetTimer to trigger a change.
#define STRICT 1
#include <windows.h>
#include <iostream.h>
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
LPWSTR wallpaper_file = L"C:\\Wallpapers\\wallpaper.png";
int return_value = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, wallpaper_file, SPIF_UPDATEINIFILE);
cout << "Programmatically change the desktop wallpaper periodically: " << dwTime << '\n';
cout.flush();
}
int main(int argc, char *argv[], char *envp[])
{
int Counter=0;
MSG Msg;
UINT TimerId = SetTimer(NULL, 0, 2000, &TimerProc); //2000 milliseconds
cout << "TimerId: " << TimerId << '\n';
if (!TimerId)
return 16;
while (GetMessage(&Msg, NULL, 0, 0))
{
++Counter;
if (Msg.message == WM_TIMER)
cout << "Counter: " << Counter << "; timer message\n";
else
cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}
This is a reasonably straightforward project, and can be done easily with any language that can call Win32 API functions (C++, for example). The non-obvious function to change the wallpaper is SystemParametersInfo with the SPI_SETDESKWALLPAPER flag. You give it a file name of a new image, and the wallpaper changes.

Categories

Resources