分析一些東西時偏形,想實(shí)現(xiàn)監(jiān)控Android JNI函數(shù)的調(diào)用液南,網(wǎng)上找了下,發(fā)現(xiàn)這個庫https://github.com/w296488320/JnitraceForCpp實(shí)現(xiàn)了這樣的效果滑凉,但是實(shí)際使用時,我自己遇到了一些問題畅姊,比如hook打印jobject數(shù)據(jù)時,陷入了死循環(huán)若未,然后調(diào)用FindClass解析時,有時也會閃退等粗合,最終自己處理問題后的版本如下https://github.com/carrys17/Study-Notes/tree/master/JniHelper
主要改動:
1、在getJObjectInfo等方法中壤追,會調(diào)用Jni方法去解析jobject數(shù)據(jù),例如調(diào)用CallObjectMethod時行冰,因?yàn)榍斑卙ook了CallObjectMethodV導(dǎo)致死循環(huán)伶丐。處理方式就是判斷定義一個CallObjectMethod_SAFE方法悼做,如果判斷到CallObjectMethodV_f不為空(即CallObjectMethodV函數(shù)已經(jīng)被hook了)哗魂,則調(diào)用它而不是CallObjectMethod方法。
jobject CallObjectMethod_SAFE(JNIEnv *env, jobject jobj, jmethodID jmethodId,...){
// WLOGD("enter CallObjectMethod_SAFE method, CallObjectMethodV_f = %p",CallObjectMethodV_f);
if (CallObjectMethodV_f){
va_list args;
jobject result;
va_start(args,jmethodId);
result = CallObjectMethodV_f(env, jobj,jmethodId,args);
va_end(args);
return result;
}else{
return env->CallObjectMethod(jobj,jmethodId);
}
}
// 直接通過toString獲取jobject 信息
const char *getJObjectToString(JNIEnv *env, jobject obj) {
if(!g_method_id_Object_toString){
g_method_id_Object_toString =
GetMethodID_SAFE(env,FindClass_SAFE(env,ENCRYPT("java/lang/Object")), ENCRYPT("toString"),
ENCRYPT("()Ljava/lang/String;"));
}
jobject jobj = CallObjectMethod_SAFE(env, obj, g_method_id_Object_toString);
return GetStringUTFChars_SAFE(env,(jstring) (jobj), nullptr);
}
2朽色、FindClass方法在部分JNI方法hook了之后再去調(diào)用時,會觸發(fā)閃退纵搁,從日志的行為看是一直打印了CallObjectMethod方法然后閃退,這里之所以會去調(diào)用FindClass腾誉,其實(shí)是為了最終拿到Object_toString的method_id,所以在init初始化的時候保存一個Object_toString的method_id
void init(JNIEnv *env, bool isForbidMode, const std::list<std::string> &forbid_list, const std::list<std::string> &filter_list){
WLOGD("enter init method");
g_method_id_Class_getName =
env->GetMethodID(env->FindClass(ENCRYPT("java/lang/Class")), ENCRYPT("getName"),
ENCRYPT("()Ljava/lang/String;"));
g_method_id_Object_toString =
env->GetMethodID(env->FindClass(ENCRYPT("java/lang/Object")), ENCRYPT("toString"),
ENCRYPT("()Ljava/lang/String;"));
gForbidSoList = std::list<std::string>(forbid_list);
gFilterSoList = std::list<std::string>(filter_list);
gIsForbidMode = isForbidMode;
WLOGD("init success!");
}
其他的一些就是避免我們主動調(diào)用的JNI方法解析數(shù)據(jù)時趣效,過濾掉不讓干擾我們分析目標(biāo)的JNI方法打印猪贪。
3跷敬、因?yàn)槲业膱鼍笆亲⑷雜o到目標(biāo)里邊热押,所以我們打印堆棧過濾一些so時,需要調(diào)用dladdr((void *) __builtin_return_address(1), &info);
而不是__builtin_return_address(0)
桶癣,因?yàn)?code>__builtin_return_address(0)獲取到的永遠(yuǎn)是我自己注入的so名稱