3

currently i am working on a project where i need to intercept the results of java native method calls for further analysis.

There are multiple ways to achieve that but the way of my choice is: at native binding time, re-bind the addresses of java native methods to the address of my own wrapper-function, which would call the initial native function by itself and then return its result while intercepting the returned variable. The wrapper function should be generic, meaning it would handle the return-type and parameters in a right manner.

In the code below, nativeIntInterceptor is wrapping int returning functions:

typedef jint (JNICALL * intNativeCall) (JNIEnv *env, jclass clazz, jobject obj);

struct binding{

public:
    jmethodID methId;
    intNativeCall initialMethodAddress;
    void* newMethodAddress;
    char* name;
    char* sig;

binding(jmethodID methId, void* methodAddress, char* name, char* sig){
    printf("creating binding for %s ith signature %s \n", name , sig);
    this->methId = methId;
    this->name = name;
    this->sig=sig;
    this->initialMethodAddress = (intNativeCall) methodAddress;
    this->newMethodAddress =(void*) &nativeIntInterceptor;
}

jint JNICALL nativeIntInterceptor(JNIEnv *env, jclass clazz, jobject obj)
{
    printf("EXECUTING %s WITH SIGNATURE %s \n",name,sig);
    jint  returnVal = initialMethodAddress(env, clazz, obj);
    printf("RESULT WAS %d ...\n",returnVal);
    return returnVal;
}

};

Now, in my agent, at native binding time, I need to initialize the binding objects in order to bind native functions to the wrapper functions in those objects. Here is the code:

void JNICALL
NativeMethodBind(jvmtiEnv *jvmti_env,
    JNIEnv* jni_env,
    jthread thread,
    jmethodID method,
    void* address,
    void** new_address_ptr)
{
char* name_ptr;
char* signature_ptr;
char* generic_ptr;
jvmti_env->GetMethodName(method, &name_ptr, &signature_ptr, &generic_ptr);


if (strstr(signature_ptr, ")V") != NULL) {
    //      printf("VOID RETURNING METHOD\n");

}else if(strstr(signature_ptr, ")I") != NULL){
    // binding jint returning method

    binding* b = new binding(method, address, name_ptr, signature_ptr);
    bindings.push_back(*b);

    *new_address_ptr = b->newMethodAddress;
}
}

At this point when I the native method is called, the wrapper function ( nativeIntInterceptor ) gets called correctly. However, it doesnt have access to all these local variables and just prints me

EXECUTING (null) WITH SIGNATURE (null)

Basically my wrapper function, when called through a pointer, cannot see the object's local variables and thus cannot call the original native function... Is there a way to resolve this? How can i provide my wrapper function with all the required infos?

Aksim Elnik
  • 425
  • 6
  • 27
  • This certainly seems possible, if difficult. What OS? What you're asking to do seems really close to what the run-time linker does. – Andrew Henle Mar 29 '17 at 12:56
  • I do this on windows, but i see no difference for linux though. – Aksim Elnik Mar 29 '17 at 14:57
  • 1
    On Linux, this seems close to what you want to do: http://stackoverflow.com/questions/25138015/tracing-calls-to-a-shared-library There are some solutions here for Windows: http://stackoverflow.com/questions/311268/monitoring-application-calls-to-dll I suspect you'd have to go through the source code for those to see how they work, and getting the arguments in a generic manner might be impossible, but that's where I'd start. I'm actually surprised your question hasn't generated any answers or comments - it's an interesting problem that seems feasible but hard. – Andrew Henle Mar 30 '17 at 09:27

0 Answers0