转:http://blog.csdn.net/l173864930/article/details/38467497
继续
注入之后
完成了注入,那只是万里长征的第一步。
众所周知,Android的应用进程,都是由Zygote孵化的子进程,每个进程都运行在独立的JVM中。通过ptrace的注入方式,我们得到了在目标进程执行代码的机会,但距离修改JVM的内容,还差那么一点点。我们重新看一下《二》中被注入SO的关键代码:
- 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;
示例三
我们知道,在JVM进程中,JavaVM是全局唯一的,而JNIEnv则是按线程分配。另外,Dalvik的线程跟Linux线程是一一对应的,因此我们可以把自身所在的线程Attatch到JavaVM,JavaVM就会为我们分配JNIEnv对象了。通过阅读Dalvik源码,从AndroidRuntime中我们可以得到JavaVm的地址,再通过JavaVm所提供的AttachCurrentThead和DetachCurrentThread两个函数,即可完成JNIEnv的获取,示例代码如下:
- JNIEnv *jni_env = NULL;
- JavaVM *jvm = AndroidRuntime::getJavaVM();
- jvm-AttachCurrentThread(&jni_env, NULL);
- //TODO 使用JNIEnv
- jvm->DetachCurrentThread();
先找到SystemClassLoader
- //ClassLoader.getSystemClassLoader()
- 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);
- }
- 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);
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的代码:
package com.demo.inject2;
import java.lang.reflect.Method;
import android.content.Context;
import android.util.Log;
/**
*
* @author boyliang
*
*/
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
看看示例三的输出
- 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的方法。