生活随笔
收集整理的這篇文章主要介紹了
进击的Android Hook 注入术《四》
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄(?)[-]
繼續注入之后 示例三輸出 最后
繼續
在前《一》、《二》、《三》里已經把注入的技術介紹完了,這章開始說注入之后需要做的事情。如果對注入技術已經比較熟悉了,那么可以直接看本章,否則建議先把前三章閱讀一遍會比較好。
注入之后
完成了注入,那只是萬里長征的第一步。 眾所周知,Android的應用進程,都是由Zygote孵化的子進程,每個進程都運行在獨立的JVM中。通過ptrace的注入方式,我們得到了在目標進程執行代碼的機會,但距離修改JVM的內容,還差那么一點點。我們重新看一下《二》中被注入SO的關鍵代碼:
[cpp] view plain
copy void?Main();????????static?void*?_main(void*){????????Main();????????return?NULL;????}????????class?EntryClass?{????public:????????????EntryClass()?{????????????pthread_t?tid;????????????pthread_create(&tid,?NULL,?_main,?NULL);????????????pthread_detach(tid);????????}????????}?boy;???? 當so被注入后,我們的邏輯代碼實際上是跑在一個Linux線程上,這樣做的目的是為了不對主線程造成干擾。我們的目標是打通Java層,很自然的聯想到JNI,通過JNI我們就是可以跟Java層互動了。但這里缺少了一個非常重要的元素——JNIEnv,沒有這個對象,JNI就無從說起了。
示例三
我們知道,在JVM進程中,JavaVM是全局唯一的,而JNIEnv則是按線程分配。另外,Dalvik的線程跟Linux線程是一一對應的,因此我們可以把自身所在的線程Attatch到JavaVM,JavaVM就會為我們分配JNIEnv對象了。通過閱讀Dalvik源碼,從AndroidRuntime中我們可以得到JavaVm的地址,再通過JavaVm所提供的AttachCurrentThead和DetachCurrentThread兩個函數,即可完成JNIEnv的獲取,示例代碼如下:
[java] view plain
copy JNIEnv?*jni_env?=?NULL;??JavaVM?*jvm?=?AndroidRuntime::getJavaVM();??jvm-AttachCurrentThread(&jni_env,?NULL);??????jvm->DetachCurrentThread();?? 至此,我們就拿到了至關重要的JNIEnv對象了。接下來,我們通過DexClassLoader加載我們的dex文件,關鍵代碼如下所示: 先找到SystemClassLoader
[cpp] view plain
copy ??static?jobject?getSystemClassLoader(){???jclass?class_loader_claxx?=?jni_env->FindClass("java/lang/ClassLoader");???snprintf(sig_buffer,?512,?"()%s",?JCLASS_LOADER);???jmethodID?getSystemClassLoader_method?=?jni_env->GetStaticMethodID(class_loader_claxx,?"getSystemClassLoader",?sig_buffer);???return?jni_env->CallStaticObjectMethod(class_loader_claxx,?getSystemClassLoader_method);??}?? 然后通過SystemClassLoader,生成DexClassLoader對象
[cpp] view plain
copy snprintf(sig_buffer,?512,?"(%s%s%s%s)V",?JSTRING,?JSTRING,?JSTRING,?JCLASS_LOADER);??jmethodID?dexloader_init_method?=?jni_env->GetMethodID(dexloader_claxx,?"<init>",?sig_buffer);????snprintf(sig_buffer,?512,?"(%s)%s",?JSTRING,?JCLASS);??jmethodID?loadClass_method?=?jni_env->GetMethodID(dexloader_claxx,?"loadClass",?sig_buffer);????jobject?class_loader?=?getSystemClassLoader();??check_value(class_loader);????jobject?dex_loader_obj?=?jni_env->NewObject(dexloader_claxx,?dexloader_init_method,?apk_path,?dex_out_path,?NULL,?class_loader);?? 最后再通過dex_loader_obj加載dex,找到自定義方法的入口,并調用
[cpp] view plain
copy jstring?class_name?=?jni_env->NewStringUTF("com.demo.inject2.EntryClass");??jclass?entry_class?=?static_cast<jclass>(jni_env->CallObjectMethod(dex_loader_obj,?loadClass_method,?class_name));????jmethodID?invoke_method?=?jni_env->GetStaticMethodID(entry_class,?"invoke",?"(I)[Ljava/lang/Object;");??check_value(invoke_method);????jobjectArray?objectarray?=?(jobjectArray)?jni_env->CallStaticObjectMethod(entry_class,?invoke_method,?0);?? 至此我們的dex邏輯開始執行了。我讓com.demo.inject2.EntryClass.invoke作為的入口函數,從invoke里用上《三》示例中的com.demo.inject的代碼,對com.demo.host打印的數據再進行修改(同一個進程被連續注入兩次,應該是比較痛苦的)。下面看看inject2中invoke的代碼:
[java] view plain
copy package?com.demo.inject2;????import?java.lang.reflect.Method;????import?android.content.Context;??import?android.util.Log;??????????public?final?class?EntryClass?{????????public?static?Object[]?invoke(int?i)?{????????????try?{??????????????Log.i("TTT",?">>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?2!!!!<<<<<<<<<<<<<<");??????????????Context?context?=?ContexHunter.getContext();??????????????Class<?>?MainActivity_class?=?context.getClassLoader().loadClass("com.demo.host.MainActivity");??????????????Method?setA_method?=?MainActivity_class.getDeclaredMethod("setA",?int.class);??????????????setA_method.invoke(null,?1);??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}????????????return?null;??????}??}?? 代碼跟《三》的示例非常相似,只是入口點不一樣罷了。注意,這里同樣有雙親委派的限制。
輸出
am start com.demo.host/.MainActivity
./poison /data/local/tmp/libimportdex.so 738
看看示例三的輸出
[plain] view plain
copy com.demo.inject?starts.??I/TTT?????(??738):?com.demo.host?starts??I/TTT?????(??738):?1??I/TTT?????(??738):?2??I/TTT?????(??738):?3??I/TTT?????(??738):?4??I/TTT?????(??738):?5??I/TTT?????(??738):?>>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy!!!!<<<<<<<<<<<<<<??I/TTT?????(??738):?998??I/TTT?????(??738):?999??I/TTT?????(??738):?1000??I/TTT?????(??738):?1001??I/TTT?????(??738):?1002??I/TTT?????(??738):?1003??I/TTT?????(??738):?>>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?2!!!!<<<<<<<<<<<<<<??I/TTT?????(??738):?1??I/TTT?????(??738):?2??I/TTT?????(??738):?3??I/TTT?????(??738):?4??I/TTT?????(??738):?5??I/TTT?????(??738):?6??I/TTT?????(??738):?7?? 從兩次的字符串輸出,證明這次的注入修改已經成功了。 示例中的所有代碼,都已經上傳到https://github.com/boyliang/Java_Injection
最后
到目前為止,我們已經實現如下功能:
- 注入目標進程
- 獲取JNIEnv地址;
- 另目標進程加載Dex,并執行指定的方法;
距離我們的目標,還差一步——截獲broadcastIntent方法,在《五》里我會再介紹一種叫BinderProxy的技術,通過這種技術,我們可以截獲任意的BinderService的方法。
原文地址: http://blog.csdn.net/l173864930/article/details/38467497
總結
以上是生活随笔為你收集整理的进击的Android Hook 注入术《四》的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。