I'm at a total loss here. I'm trying to get a JVMTI agent library running but it keeps crashing for some reason.
I've narrowed it down this line:
(*jvm)->GetEnv(jvm, (void**)jvmti, JVMTI_VERSION_1_0);
this is the full code of the agent lib (in C):
#include <jvmti.h>
#include <stdlib.h>
jvmtiEnv* jvmti = NULL;
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
{
printf("Agent started.\n");
_flushall();
jint err = (*jvm)->GetEnv(jvm, (void**)jvmti, JVMTI_VERSION_1_0);
if (err != JNI_OK)
{
printf("Failed to get JVMTI env!\n");
_flushall();
return err;
}
return JNI_OK;
}
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved)
{
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}
As I tried to isolate what the issue was I wrote a very simple java app to test
this with:
public class Test
{
public static void main(String[] args)
{
System.out.println("Hello from java!");
}
}
If I run this from netbeans with the VM arg -agentpath set to my .dllcontaining the code above, the app seems to crash when it tries to call GetEnv().
I've made sure of the following things:
- The JVM and the dll are both 64bit.
- The library is most definitely being found and loaded (the printf output is visible before the crash.)
I don't know what else could probably be causing this, do I have to link against some JVMTI API lib that I don't know about?
Or could this be an issue with the java installation on my PC?
Thanks
You should be passing address of jvmti to GetEnv() as in:
jint err = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_1_0);
Related
I have a C (navive) program and a jar file with the main() method. From my native program I am initializing the JVM, and calling the main() method. I have no problems with this, everything is completely fine. But then I wanted to call back a C function from my java code.
The C function is defined in the native code in the same module as the one, that have created the JVM. The header is auto-generated, and the body is as simple as this:
JNIEXPORT void JNICALL Java_eu_raman_chakhouski_NativeUpdaterBus_connect0(JNIEnv* env, jclass clazz)
{
return;
}
So, from the java code I'm calling NativeUpdaterBus.connect0(), continuosly getting an UnsatisfiedLinkError. I have no System.loadLibrary() calls in my java code, because I thought, that there will be no problems calling the native code back from the java code if the target module is (possibly?) already loaded.
Well, maybe my approach is completely incorrect, but I can't see any obvious defects, maybe you could help?
What possibly could help (but I didn't tried any of these approaches, because I'm still not quite sure)
Use a kind of a "trampoline" dynamic library with these JNI methods, load it from the java code, then marshal native calls through it.
Define a java.lang.Runnable's anonymous inheritor, created with jni_env->DefineClass() but this involves some bytecode trickery.
Use an another, less invasive approach, like sockets, named pipes, etc. But in my case I'm using only one native process, so this might be an overkill.
I'm using OpenJDK 11.0.3 and Windows 10. My C program is compiled with the Microsoft cl.exe 19.16.27031.1 for x64 (Visual Studio 2017).
One possibility, as others have already mentioned, is to create a shared library (.dll) and call it from the native code and from Java to exchange data.
However, if you want to callback to a C function defined in the native code in the same module as the one the JVM originally created, you can use RegisterNatives.
Simple Example
C program creates JVM
it calls a Main of a class
the Java Main calls back a C function named connect0 in the calling C code
to have a test case the native C function constructs a Java string and returns it
the Java side prints the result
Java
package com.software7.test;
public class Main {
private native String connect0() ;
public static void main(String[] args) {
Main m = new Main();
m.makeTest(args);
}
private void makeTest(String[] args) {
System.out.println("Java: main called");
for (String arg : args) {
System.out.println(" -> Java: argument: '" + arg + "'");
}
String res = connect0(); //callback into native code
System.out.println("Java: result of connect0() is '" + res + "'"); //process returned String
}
}
C Program
One can create the Java VM in C as shown here
(works not only with cygwin but still with VS 2019) and then register with RegisterNatives native C callbacks. So using the function invoke_class from the link above it could look like this:
#include <stdio.h>
#include <windows.h>
#include <jni.h>
#include <stdlib.h>
#include <stdbool.h>
...
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
helloWorldClass = (*env)->FindClass(env, "com/software7/test/Main");
mainMethod = (*env)->GetStaticMethodID(env, helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "one argument");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, applicationArgs);
}
jstring connect0(JNIEnv* env, jobject thiz);
static JNINativeMethod native_methods[] = {
{ "connect0", "()Ljava/lang/String;", (void*)connect0 },
};
jstring connect0(JNIEnv* env, jobject thiz) {
printf("C: connect0 called\n");
return (*env)->NewStringUTF(env, "Some Result!!");
}
static bool register_native_methods(JNIEnv* env) {
jclass clazz = (*env)->FindClass(env, "com/software7/test/Main");
if (clazz == NULL) {
return false;
}
int num_methods = sizeof(native_methods) / sizeof(native_methods[0]);
if ((*env)->RegisterNatives(env, clazz, native_methods, num_methods) < 0) {
return false;
}
return true;
}
int main() {
printf("C: Program starts, creating VM...\n");
JNIEnv* env = create_vm();
if (env == NULL) {
printf("C: creating JVM failed\n");
return 1;
}
if (!register_native_methods(env)) {
printf("C: registering native methods failed\n");
return 1;
}
invoke_class(env);
destroy_vm();
getchar();
return 0;
}
Result
Links
Creating a JVM from a C Program: http://www.inonit.com/cygwin/jni/invocationApi/c.html
Registering Native Methods: https://docs.oracle.com/en/java/javase/11/docs/specs/jni/functions.html#registering-native-methods
System.loadLibrary() is essential for the jni lookup to work. You also have a more flexible System.load() alternative.
Make sure that the native method implementation is declared with extern "C" and is not hidden by linker.
So I'm working on a C++ Dll cheat/hack for a game (Minecraft). I created a little sample JNI project just to test things out, but a couple seconds after injecting the dll, Minecraft stops responding with a 'win32 unhandled exception'. I'm not experienced enough in C++ or using the JNI to understand what I'm doing wrong...
Here's my sample code (Not actually a hack, just wanted to try calling the clickMouse function to see if I was on the right track):
DWORD WINAPI Main_Thread(LPVOID lpParam)
{
HMODULE m_hDllInstance = LoadLibraryA("jvm.dll");
JavaVM *jvm;
JNIEnv *env;
typedef jint(JNICALL * GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
GetCreatedJavaVMs jni_GetCreatedJavaVMs =
(GetCreatedJavaVMs)GetProcAddress(m_hDllInstance, "JNI_GetCreatedJavaVMs");
jint size = 1;
jint vmCount;
jint ret = jni_GetCreatedJavaVMs(&jvm, size, &vmCount);
jint rc = jvm->AttachCurrentThread((void **)& env, NULL);
jclass Minecraft = env->FindClass("net.minecraft.client.Minecraft");
jmethodID constructor = env->GetMethodID(Minecraft, "<init>", "()V");
jobject mc = env->NewObject(Minecraft, constructor);
jmethodID clickMouse = env->GetMethodID(Minecraft, "clickMouse", "()V");
while (!GetAsyncKeyState(VK_END))
{
env->CallVoidMethod(mc, clickMouse);
}
jvm->DestroyJavaVM();
return S_OK;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
CreateThread(0, 0, Main_Thread, 0, 0, NULL);
}
return TRUE;
}
What's causing this to go wrong and how can I fix it?
P.S: Sorry if code looks a little funny, had a bit of trouble pasting it in here.
Edit: I tried running a debugger upon the crash, and it comes up with this: http://imgur.com/a/Uot9K. I'm still not sure how to fix this...
I'm trying to implement a java wrapper for RCSwitch in a Raspberry Pi. It works fine until the grabbing method reaches the 80th iteration. Then it slows down and I can't figure out why. It needs more than 5 minutes to return with a value.
I tried to figure out the problem, but I'm not out of memory, the raspberry still has more then 300mega. In spite ot this, I tried to run the JVM with the following parameter:-Xms5m -Xmx5m but the program still slowed down at the 80th iteration so I think its not a memory problem. My sender still sends the value, because if I restart the program it's working again until the 80th iteration, so it's not the lack of input data.
Here is the java part of the code:
public class RCSwitchWrapper {
public native int recievedValue(int PIN);
static{System.loadLibrary("RCSwitchWrapper");}
public static void main(String[] args){
RCSwitchWrapper wrapper = new RCSwitchWrapper();
int counter=0;
while(true){
counter++;
int grabbedData = wrapper.recievedValue(2);
System.out.println(counter+" grabbed data: "+grabbedData);
}
}
}
The C++ part of the code:
#include "RCSwitch.h"
#include "RCSwitchWrapper.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
RCSwitch mySwitch;
JNIEXPORT jint JNICALL Java_RCSwitchWrapper_recieveValue(JNIEnv *env, jobject obj,jint PIN){
if(wiringPiSetup()==-1){
printf("wiringpi error \n");
return 0;
}
mySwitch = RCSwitch();
mySwitch.enableReceive(PIN);
while(1){
if(mySwitch.available()){
int value = mySwitch.getReceivedValue();
return value;
}
mySwitch.resetAvailable();
return(-1);
}
}
Now I'm confused and can't think a solution.
Thanks in advance.
To support a static-analysis tool I want to instrument or monitor a Java program in such a way that I can determine for every reflective call (like Method.invoke(..)):
1.) which class C this method is invoked on, and
2.) which classloader loaded this class C.
Ideally I am looking for a solution that does not require me to statically modify the Java Runtime Library, i.e. I am looking for a load-time solution. However, the solution should be able to capture all reflective calls, even such calls that occur within the Java Runtime Library itself. (I played around with ClassFileTransformer but this seems to be applied only to classes that ClassFileTransformer itself does not depend on. In particular, a ClassFileTransfomer is not applied to the class "Class".)
Thanks!
Are you looking for something that can run in production? Or is it sufficient to instrument the application running in a test environment? If it's the latter, might want to consider running the application under a profiling tool. I've personally used and would recommend JProfiler, which lets you do call tracing and set up triggers to perform actions like logging when specific methods are invoked. It does not require any modifications to the hosted program and works just fine on the Java runtime library. There are open source tools, too, but I have not had as much success getting those to work.
If you need something that will run in production, you might want to investigate implementing your own custom Classloader or byte code manipulation via Javassist or CGLib, perhaps using AspectJ (AOP). That's obviously a more complication solution and I'm not sure it'll work without compile-time support, so hopefully the profiling tool is feasible for your situation.
The API that you are probably after is JVMTI. JVMTI allows you to register callbacks for the majority of events that occur within the JVM, including MethodEntry, MethodExit. You listen for those events and pull out the Method.invoke events. There are API calls to get the classloader for a specific class. However you will have to write tool in C or C++.
Here is an example that will get the filter out the java.lang.reflect.Method.invoke call and print it out. To get details regarding the object that has been called you will probably need to look at the stack frame.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <jvmti.h>
static jvmtiEnv *jvmti = NULL;
static jvmtiCapabilities capa;
static jint check_jvmti_error(jvmtiEnv *jvmti,
jvmtiError errnum,
const char *str) {
if (errnum != JVMTI_ERROR_NONE) {
char *errnum_str;
errnum_str = NULL;
(void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str);
printf("ERROR: JVMTI: %d(%s): %s\n",
errnum,
(errnum_str == NULL ? "Unknown" : errnum_str),
(str == NULL ? "" : str));
return JNI_ERR;
}
return JNI_OK;
}
void JNICALL callbackMethodEntry(jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jthread thread,
jmethodID method) {
char* method_name;
char* method_signature;
char* generic_ptr_method;
char* generic_ptr_class;
char* class_name;
jvmtiError error;
jclass clazz;
error = (*jvmti_env)->GetMethodName(jvmti_env,
method,
&method_name,
&method_signature,
&generic_ptr_method);
if (check_jvmti_error(jvmti_env, error, "Failed to get method name")) {
return;
}
if (strcmp("invoke", method_name) == 0) {
error
= (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method,
&clazz);
if (check_jvmti_error(jvmti_env, error,
"Failed to get class for method")) {
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
return;
}
error = (*jvmti_env)->GetClassSignature(jvmti_env, clazz, &class_name,
&generic_ptr_class);
if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) {
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
return;
}
if (strcmp("Ljava/lang/reflect/Method;", class_name) == 0) {
printf("Method entered: %s.%s.%s\n", class_name, method_name,
method_signature);
}
(*jvmti_env)->Deallocate(jvmti_env, class_name);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_class);
}
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
jint result;
jvmtiError error;
jvmtiEventCallbacks callbacks;
result = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_1_0);
if (result != JNI_OK || jvmti == NULL) {
printf("error\n");
return JNI_ERR;
} else {
printf("loaded agent\n");
}
(void) memset(&capa, 0, sizeof(jvmtiCapabilities));
capa.can_generate_method_entry_events = 1;
error = (*jvmti)->AddCapabilities(jvmti, &capa);
if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) {
return JNI_ERR;
}
(void) memset(&callbacks, 0, sizeof(callbacks));
callbacks.MethodEntry = &callbackMethodEntry;
error = (*jvmti)->SetEventCallbacks(jvmti,
&callbacks,
(jint) sizeof(callbacks));
if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) {
return JNI_ERR;
}
error = (*jvmti)->SetEventNotificationMode(jvmti,
JVMTI_ENABLE,
JVMTI_EVENT_METHOD_ENTRY,
(jthread) NULL);
if (check_jvmti_error(jvmti, error,
"Unable to set method entry notifications") != JNI_OK) {
return JNI_ERR;
}
return JNI_OK;
}
I'm using GetStringUTFChars to retrieve a string's value from the java code using JNI and releasing the string using ReleaseStringUTFChars. When the code is running on JRE 1.4 there is no memory leak but if the same code is running with a JRE 1.5 or higher version the memory increases. This is a part of the code
msg_id=(*env)->GetStringUTFChars(env, msgid,NULL);
opcdata_set_str(opc_msg_id, OPCDATA_MSGID, msg_id);
(*env)->ReleaseStringUTFChars(env, msgid,msg_id);
I'm unable to understand the reason for leak.Can someone help?
This one is because if I comment the rest of the code but leave this part the memory leak takes place. This is a part of the code that I'm using
JNIEXPORT jobjectArray JNICALL Java_msiAPI_msiAPI_msgtoescalate( JNIEnv *env,
jobject job,
jstring msgid,
jlong msgseverity,
jstring msgprefixtext,
jint flag )
{
opcdata opc_msg_id; /* data struct to store a mesg ID */
const char *msg_id;
int ret, ret2;
jint val;
val=67;
jstring str=NULL;
jobjectArray array = NULL;
jclass sclass=NULL;
/* create an opc_data structure to store message ids of */
/* messages to escalate */
if ((ret2=opcdata_create(OPCDTYPE_MESSAGE_ID, &opc_msg_id))!= OPC_ERR_OK)
{
fprintf(stderr, "Can't create opc_data structure to store message. opcdata_create()=%d\n", ret2);
cleanup_all();
}
//////////////////////////////////////////////////////////
msg_id=(*env)->GetStringUTFChars(env,msgid,NULL);
opcdata_set_str(opc_msg_id, OPCDATA_MSGID, msg_id);
(*env)->ReleaseStringUTFChars(env, msgid, msg_id);
ret=opcmsg_ack(connection,opc_msg_id);
//////////////////////////////////////////////////////////
if(flag==0 && ret==0)
{
sclass = (*env)->FindClass(env, "java/lang/String");
array = (*env)->NewObjectArray(env, 2, sclass, NULL);
str=(*env)->NewStringUTF(env,"0");
(*env)->SetObjectArrayElement(env,array,0,str);
(*env)->DeleteLocalRef(env, str);
str=(*env)->NewStringUTF(env,"0");
(*env)->SetObjectArrayElement(env,array,1,str);
(*env)->DeleteLocalRef(env, str);
}
opcdata_free(&opc_msg_id);
if(ret!=0)
return NULL;
else
return(array);
}
In the one above is if I comment the sections between ///// I don't see any memory leak.
Release array object.
(*env)->DeleteLocalRef(env, array);