生活随笔
收集整理的這篇文章主要介紹了
进击的Android Hook 注入术《四》
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
目錄(?)[-]
繼續(xù)注入之后 示例三輸出 最后
繼續(xù)
在前《一》、《二》、《三》里已經(jīng)把注入的技術(shù)介紹完了,這章開始說注入之后需要做的事情。如果對注入技術(shù)已經(jīng)比較熟悉了,那么可以直接看本章,否則建議先把前三章閱讀一遍會(huì)比較好。
注入之后
完成了注入,那只是萬里長征的第一步。 眾所周知,Android的應(yīng)用進(jìn)程,都是由Zygote孵化的子進(jìn)程,每個(gè)進(jìn)程都運(yùn)行在獨(dú)立的JVM中。通過ptrace的注入方式,我們得到了在目標(biāo)進(jìn)程執(zhí)行代碼的機(jī)會(huì),但距離修改JVM的內(nèi)容,還差那么一點(diǎn)點(diǎn)。我們重新看一下《二》中被注入SO的關(guān)鍵代碼:
[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;???? 當(dāng)so被注入后,我們的邏輯代碼實(shí)際上是跑在一個(gè)Linux線程上,這樣做的目的是為了不對主線程造成干擾。我們的目標(biāo)是打通Java層,很自然的聯(lián)想到JNI,通過JNI我們就是可以跟Java層互動(dòng)了。但這里缺少了一個(gè)非常重要的元素——JNIEnv,沒有這個(gè)對象,JNI就無從說起了。
示例三
我們知道,在JVM進(jìn)程中,JavaVM是全局唯一的,而JNIEnv則是按線程分配。另外,Dalvik的線程跟Linux線程是一一對應(yīng)的,因此我們可以把自身所在的線程Attatch到JavaVM,JavaVM就會(huì)為我們分配JNIEnv對象了。通過閱讀Dalvik源碼,從AndroidRuntime中我們可以得到JavaVm的地址,再通過JavaVm所提供的AttachCurrentThead和DetachCurrentThread兩個(gè)函數(shù),即可完成JNIEnv的獲取,示例代碼如下:
[java] view plain
copy JNIEnv?*jni_env?=?NULL;??JavaVM?*jvm?=?AndroidRuntime::getJavaVM();??jvm-AttachCurrentThread(&jni_env,?NULL);??????jvm->DetachCurrentThread();?? 至此,我們就拿到了至關(guān)重要的JNIEnv對象了。接下來,我們通過DexClassLoader加載我們的dex文件,關(guān)鍵代碼如下所示: 先找到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,找到自定義方法的入口,并調(diào)用
[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邏輯開始執(zhí)行了。我讓com.demo.inject2.EntryClass.invoke作為的入口函數(shù),從invoke里用上《三》示例中的com.demo.inject的代碼,對com.demo.host打印的數(shù)據(jù)再進(jìn)行修改(同一個(gè)進(jìn)程被連續(xù)注入兩次,應(yīng)該是比較痛苦的)。下面看看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;??????}??}?? 代碼跟《三》的示例非常相似,只是入口點(diǎn)不一樣罷了。注意,這里同樣有雙親委派的限制。
輸出
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?? 從兩次的字符串輸出,證明這次的注入修改已經(jīng)成功了。 示例中的所有代碼,都已經(jīng)上傳到https://github.com/boyliang/Java_Injection
最后
到目前為止,我們已經(jīng)實(shí)現(xiàn)如下功能:
- 注入目標(biāo)進(jìn)程
- 獲取JNIEnv地址;
- 另目標(biāo)進(jìn)程加載Dex,并執(zhí)行指定的方法;
距離我們的目標(biāo),還差一步——截獲broadcastIntent方法,在《五》里我會(huì)再介紹一種叫BinderProxy的技術(shù),通過這種技術(shù),我們可以截獲任意的BinderService的方法。
原文地址: http://blog.csdn.net/l173864930/article/details/38467497
總結(jié)
以上是生活随笔為你收集整理的进击的Android Hook 注入术《四》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。