JNI:拦截原生方法输出

时间:2017-03-29 09:34:03

标签: java java-native-interface javaagents

目前我正在开发一个项目,我需要拦截java本机方法调用的结果以进行进一步分析。

有多种方法可以实现这一点,但我选择的方式是:在本机绑定时,将java本机方法的地址重新绑定到我自己的包装函数的地址,这将调用初始本机函数本身然后在拦截返回的变量时返回其结果。包装函数应该是通用的,这意味着它将以正确的方式处理返回类型和参数。

在下面的代码中,nativeIntInterceptor包装int返回函数:

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

};

现在,在我的代理中,在本机绑定时,我需要初始化绑定对象,以便将本机函数绑定到这些对象中的包装函数。这是代码:

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

此时调用本机方法时,将正确调用包装函数(nativeIntInterceptor)。但是,它不能访问所有这些局部变量,只打印我

EXECUTING(null)WITH SIGNATURE(null)

基本上我的包装函数,当通过指针调用时,无法看到对象的局部变量,因此无法调用原始的本机函数...有没有办法解决这个问题?如何为我的包装函数提供所有必需的信息?

0 个答案:

没有答案