分析jni调用时的一些函数及其函数功能.
如 GetEnv …
本文已长草.
基本类型 #
<jni.h>文件存放的位置在\Android\sdk\ndk-bundle\platforms\android-24\arch-arm\usr\include\jni.h
现在来看一下jni.h头文件中内容:
class _jobject {}; typedef _jobject* jobject;
class _jclass : public _jobject {}; typedef _jclass* jclass;
class _jstring : public _jobject {}; typedef _jstring* jstring;
class _jarray : public _jobject {}; typedef _jarray* jarray;
class _jobjectArray : public _jarray {}; typedef _jobjectArray* jobjectArray;
class _jbooleanArray : public _jarray {}; typedef _jbooleanArray* jbooleanArray;
class _jbyteArray : public _jarray {}; typedef _jbyteArray* jbyteArray;
class _jcharArray : public _jarray {}; typedef _jcharArray* jcharArray;
class _jshortArray : public _jarray {}; typedef _jshortArray* jshortArray;
class _jintArray : public _jarray {}; typedef _jintArray* jintArray;
class _jlongArray : public _jarray {}; typedef _jlongArray* jlongArray;
class _jfloatArray : public _jarray {}; typedef _jfloatArray* jfloatArray;
class _jdoubleArray : public _jarray {}; typedef _jdoubleArray* jdoubleArray;
class _jthrowable : public _jobject {}; typedef _jthrowable* jthrowable;
从右边的typedef可以看出,每一个Jni中的cpp类型都有一个Java中的类型与之相对应.
这里我们重点分析经常看到的_JNIEnv,_JavaVM,JNIEnv,JavaVM
struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
JNINativeInterface为Native层的接口函数指针表, Jni中的本地函数通过这些接口来调用java层的函数.
_JNIEnv是一个object, 包含一个指向JNINativeInterface的指针变量function和一些接口函数.
JNIEnv在cpp中的定义为_JNIEnv, 在c中的定义为 struct JNINativeInterface*.
JNIEnv: 每一个线程中都有一个属于自己线程的env, 且只在创建自己的线程内有效, 不能跨线程传递.
下面分析JavaVM:
struct _JavaVM { struct JNIInvokeInterface {
const struct JNIInvokeInterface* functions; void* reserved0;
void* reserved1;
void* reserved2;
#if defined(__cplusplus)
jint DestroyJavaVM()
{ return functions->DestroyJavaVM(this); } jint (*DestroyJavaVM)(JavaVM*);
jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
{ return functions->AttachCurrentThread(this, p_env, thr_args); } jint (*DetachCurrentThread)(JavaVM*);
jint DetachCurrentThread() jint (*GetEnv)(JavaVM*, void**, jint);
{ return functions->DetachCurrentThread(this); } jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
jint GetEnv(void** env, jint version) };
{ return functions->GetEnv(this, env, version); }
jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
{ return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
#endif /*__cplusplus*/
};
JavaVM在cpp中定义为_JavaVM, 在c中定义为指向JNIInvokeInterface的指针. JavaVM只有一个, 因为它是java虚拟机在Jni中的表示.
在用ida加载.apk中.so文件时会发现识别出来的native函数是这样的:
int __fastcall Java_com_njctf_mobile_easycrack_MainActivity_parseText(int a1, int a2, int a3);
java层的函数调用是这样的:
public native String parseText(String arg1);
而这里的a1就是我们的env, a2就是jobject或者jclass, a3就是String arg1了. 我们在导入<jni.h>头文件和添加了Structures之后, 就可以对ida中的参数类型和参数名字进行修改了.
修改之后的结果:
int __fastcall Java_com_njctf_mobile_easycrack_MainActivity_parseText(_JNIEnv *env, jobject *obj, jstring inputString);