精华内容
下载资源
问答
  • DEX 注入

    2013-04-23 15:26:33
     首先简单介绍一下进程注入的概念: ...由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码放到一个共享库中,即.so文件。被注入的那段代码只负责加载这个.

    转载:http://www.myhack58.com/Article/html/3/92/2013/38033.htm

     首先简单介绍一下进程注入的概念:
      进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码放到一个共享库中,即.so文件。被注入的那段代码只负责加载这个.so,并执行里面的函数。
      由于.so中的函数是在目标进程中执行的,所以在.so中的函数可以修改目标进程空间的任何内存,当然也可以加钩子,从而达到改变目标进程工作机制的目的。
      当然不是任何进程都有权限执行注入操作的。Android平台上的进程注入是基于ptrace()的,要调用ptrace()需要有root权限。目前市面上的主流安全软件也都是基于进程注入来管理和控制其他应用进程的。这也就是为什么这些安全软件需要获得root权限的原因。
      关于如何.so注入的实现,有兴趣的朋友可以参考看雪论坛的上的一个注入库LibInject 
    和洗大师的一个开源项目Android Injector Library
      .so注入以后已经可以干很多事情了,但毕竟是在native层。想要在native层直接修改Java层的变量和逻辑还是很不方便的。况且Android平台的绝大多数应用都是用Java代码写的。因此自然而然就会想到,有没有什么方式可以将dex文件注入目标进程,然后执行dex文件中的Java代码?

      经过一段时间的研究,笔者找到了一个切实可行的方法。这里分享给大家:首先,所有的Java类都是由类加载器(ClassLoader)加载的,我们要从特定的路径下加载一个我们自己的dex文件,就必须要有一个自己类加载器才行。有了这个类加载器我们就可以加载我们自己的类,并用反射调用这个类里面的方法。其次,要构造生成这样一个类加载器必须要获得现有的类加载器,因为类加载器是双亲委派模式的。现有的类加载器可以通过反射获得。只是这些都需要用native代码实现。
    下面简述一下dex注入的过程:
    1.  将.so注入目标进程,执行.so文件中的某个函数。
    2.  在这个函数里先获得一个JNIEnv指针,通过这个指针就可以调JNI函数了。
    3.  反射得到当前应用进程的PathClassLoader,用这个ClassLoader来构造一个DexClassLoader对象。Dex文件路径作为一个参数传入DexClassLoader的构造函数,另一个重要的参数是,一个具有可写权限的文件夹路径。因为在做dex优化时,需要生成优化过的dex文件,这跟生成/data/dalvik-cache/下的dex文件是一个道理。
    4.  通过这个DexClassLoader对象,来加载目标类,然后反射目标类中的目标函数。最终调用之。

    参考代码:

    代码:
    //功能:调用dexPath文件中的className类的methodName方法。
    //dexPath: dex/jar/apk 文件路径
    //dexOptDir: 优化目录, 这个目录的owner必须是要被注入进程的user,否则dex优化会失败
    //className: 目标类名,如“com.hook.Test”
    //methodName: 目标方法名,如"main", 在Java代码里必须定义为public static void main(String[] args);
    //argc,传给目标方法的参数个数
    //argv,传给目标方法的参数
    int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]) {
        ALOGD("Invoke dex E");
        JNIEnv* env = android::AndroidRuntime::getJNIEnv();
        jclass stringClass, classLoaderClass, dexClassLoaderClass, targetClass;
        jmethodID getSystemClassLoaderMethod, dexClassLoaderContructor, loadClassMethod, targetMethod;
        jobject systemClassLoaderObject, dexClassLoaderObject;
        jstring dexPathString, dexOptDirString, classNameString, tmpString;    
        jobjectArray stringArray;
    
        /* Get SystemClasLoader */
        stringClass = env->FindClass("java/lang/String");
        classLoaderClass = env->FindClass("java/lang/ClassLoader");
        dexClassLoaderClass = env->FindClass("dalvik/system/DexClassLoader");
        getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
        systemClassLoaderObject = env->CallStaticObjectMethod(classLoaderClass, getSystemClassLoaderMethod);
    
        /* Create DexClassLoader */
        dexClassLoaderContructor = env->GetMethodID(dexClassLoaderClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
        dexPathString = env->NewStringUTF(dexPath);
        dexOptDirString = env->NewStringUTF(dexOptDir);
        dexClassLoaderObject = env->NewObject(dexClassLoaderClass, dexClassLoaderContructor, dexPathString, dexOptDirString, NULL, systemClassLoaderObject);
    
        /* Use DexClassLoader to load target class */
        loadClassMethod = env->GetMethodID(dexClassLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
        classNameString = env->NewStringUTF(className);
        targetClass = (jclass)env->CallObjectMethod(dexClassLoaderObject, loadClassMethod, classNameString);
        if (!targetClass) {
            ALOGE("Failed to load target class %s", className);
            return -1;
        }
    
        /* Invoke target method */
        targetMethod = env->GetStaticMethodID(targetClass, methodName, "([Ljava/lang/String;)V");
        if (!targetMethod) {
            ALOGE("Failed to load target method %s", methodName);
            return -1;
        }
        stringArray = env->NewObjectArray(argc, stringClass, NULL);
        for (int i = 0; i < argc; i++) {
            tmpString = env->NewStringUTF(argv[i]);
            env->SetObjectArrayElement(stringArray, i, tmpString);
        }
        env->CallStaticVoidMethod(targetClass, targetMethod, stringArray);
        ALOGD("Invoke dex X");
        return 0;
    }
    
     

    展开全文
  • dex注入实现详解

    千次阅读 2016-03-14 04:01:56
    如果既想使用第三方APP,又不想看到一些无良的广告,那dex注入基本无法避免。本文针对网上一些大牛分享的文章,进行了一些简单的实现,总结和分享自是不能少的。Ps:感谢金山毒霸实现了该功能,感谢大牛们破解之后的...

    最近在研究Android绿色安全这一块,具体到上层的业务就是“去第三方APP的广告”。如果既想使用第三方APP,又不想看到一些无良的广告,那dex注入基本无法避免。本文针对网上一些大牛分享的文章,进行了一些简单的实现,总结和分享自是不能少的。Ps:感谢金山毒霸实现了该功能,感谢大牛们破解之后的无私分享。

    参考文章

    金山手机毒霸工作原理【引用1】

    【原创】手机毒霸去广告功能分析一:总体分析【引用2】

    【原创】手机毒霸去广告功能分析三:java代码(dex)注入

    Android中的so注入(inject)和挂钩(hook) - For both x86 and arm 【引用3】

    源码相关

    android.os.Handler 自行eclipse 关联即可;

    android.app.ActivityThread 在线代码

    实现目标

    系统:Android 4.2.2 平板
    功能:将一段dex代码注入到HelloWord APP中,dex对应的java代码要求能够拦截目标APP中的onPause与onResume 回调,输出打印。

    基本原理

    其实原理在各路大牛的文章里面已经解释的很清楚了,这里再不厌其烦的絮叨絮叨,主要是捋一捋思路,别整乱喽。

    1.获得root权限后,通过ptrace()注入到指定pid的进程中;

    Android下的注入都是从Linux下ptrace()函数继承下来的,具体原理不便深入。网上大牛已有相关的开源工具,这里采用【引用3】篇幅中博主开源出的代码,注意修改对应参数即可。【引用3】中是以注入系统进程/system/bin/surfaceflinger为例的,我们这里需要修改成目标APP的包名。这部分拿到开源代码之后使用ndk编译生成注入工具文件inject;

    2.注入代码调用功能库.so中的接口,它的作用是利用反射注入dex文件、并调用相应的java代码;

    这里对应的就是【引用3】中hello.c部分了,作为注入的功能代码关键部分,这部分不能打印两句草草了事。这里采用【引用1】中对金山毒霸分析结果得出的代码拿出来来实现dex注入与java层代码调用,具体实现与分析见后文。这里也是C代码通过ndk编译生成注入功能库,呃,libhelloTool.so;

    3.生成dex的java源码通过反射置换 ActivityThread 中mH属性中的的mCallback回调,来实现拦截Activity生命周期回调的HOOK功能;

    通过上一步程序会执行到java层中,既然要下钩子,就要弄清楚我们要钩在哪里才有效。很明显的,既然要拦截界面的onPause、onResume消息,那就必须要了解Activity的生命周期回调在底层是如何实现消息分发的,知其所以然之后才好下手。有了前面提到的几篇大牛博客的文章,我们可以很清晰的定位到android.app.ActivityThread 类中的mH变量:

    public final class ActivityThread {
    …
    final H mH = new H();
    …
    private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
        synchronized (this) {
            if (DEBUG_MESSAGES) Slog.v(
                TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
                + ": " + arg1 + " / " + obj);
            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            mH.sendMessage(msg);
        }
    }
    …
    private class H extends Handler {
        public static final int LAUNCH_ACTIVITY         = 100;
        public static final int PAUSE_ACTIVITY          = 101;
        public static final int PAUSE_ACTIVITY_FINISHING= 102;
        public static final int STOP_ACTIVITY_SHOW      = 103;
        public static final int STOP_ACTIVITY_HIDE      = 104;
        public static final int SHOW_WINDOW             = 105;
        public static final int HIDE_WINDOW             = 106;
        public static final int RESUME_ACTIVITY         = 107;
        public static final int SEND_RESULT             = 108;
                   …
                   public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
    
    
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                                     …
            }
         }
        …
    }
    

    从源码上就能看出来,底层消息派发都在内部类H中实现,而H实际上是Handler的子类。对应的H本身是个final类型的内部私有类,做手脚不甚方便,考虑到要拦截的实际情况,伸手到其父类中的属性的mCallback回调就是个很好的选择了。从前面所引博客中对金山毒霸的反编译情况来看即是这个思路。引用【引用2】中的一句话即:

    f) 替换当前ActivityThread中的mH(Handler类型)的mCallback,用金山自定义的一个callback对象来包裹过原callback并且替换原callback,从而起到hook作用。

    实现流程

    必备工具

    1. root工具,想什么办法把测试机器root掉,或者直接用虚拟机;
    2. NDK工具,各路注入工具都需要ndk来编译,本人使用的版本是:android-ndk-r8b;
    3. 基础Android 开发环境,具体就不用多说了~

    注意:为了快速调通,这里所有参数都是写死的,这就限制了后续验证流程必须要实现过程中的代码编写的一致。如果只是作为预研、测试是否可行的阶段,这种做法无可厚非;相对的如果是正规的开发流程中,在迭代周期里面做好通用性的设计是必要的。

    开始实现

    建立目标APP
    这一步最简单了,新建一个HelloWord Android工程,运行安装到测试机器中,我这里设置了包名为:com.inject.helloword 后面注入工具中需要用到;

    注入工具

    如【引用3】的方法,简历文件夹填好配置文件。编辑injec.c文件更换参数,主要在main函数中:

    int main(int argc, char** argv) {
        pid_t target_pid;
         //更换为目标应用的包名
        target_pid = find_pid_of("com.inject.helloword");
        if (-1 == target_pid) {
            printf("Can't find the process\n");
            return -1;
        }
         //设置注入代码库位置、调用接口与参数
        inject_remote_process(target_pid, "/data/libhelloTool.so", "hook_entry",  "I'm parameter!hehe", strlen("I'm parameter! hehe "));
        return 0;
    }
    

    如果想深入研究注入的原理,可以仔细分析相关函数的实现即可,NDK编译后生成注入工具inject文件;

    kf2lc@kf2lc-OptiPlex-3020:~/develop/inject/jni$ ndk-build

    Compile x86 : inject <= jni inject.c

    Executable : inject

    Install : inject =libs/x86/inject

    Compile thumb : inject <= jni inject.c

    Executable : inject

    Install : inject =libs/armeabi-v7a/inject

    注入代码库

    建立文件夹如【引用3】所述,修改注入接口方法hook_entry如【引用1】中的分析实现,代码并注释如下:

    #include <unistd.h> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <android/log.h> 
    #include <elf.h> 
    #include <fcntl.h> 
    #include <jni.h>
    #include <dlfcn.h>
    
    #define LOG_TAG "DEBUG" 
    #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)   
    
    int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]);
    
    int hook_entry(char * a){ 
        LOGD("Hook success, pid = %d\n", getpid()); 
        LOGD("Hello %s\n", a); 
        //参数直接写死是个取巧的方法
        int ret = invoke_dex_method("/data/injects/DexInject.apk","/data/data/com.inject.helloword/cache","com/inject/dexinject/HookTool","dexInject",0,NULL);
        LOGD("Hello %d\n",ret);
        return 0; 
    }
    
    JNIEnv* (*getJNIEnv)();
    /**
    * PARAM:
    * dexPath要注入的apk/jar路径
    * dexOptDir  缓存路径,注意需要目标应用进程中可写的目录
    * className  执行方法所在类名
    * methodName 执行的方法名
    * argc   参数之流这里没有使用
    * argv  参数之流这里没有使用
    */
    int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]) {
        //获取JNIEnv
        void* handle = dlopen("/system/lib/libandroid_runtime.so", RTLD_NOW);
        getJNIEnv = dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv");
        JNIEnv* env = getJNIEnv();
    
        //调用ClassLoader中的getSystemClassLoader方法获取当前进程的ClassLoader
        jclass classloaderClass = (*env)->FindClass(env,"java/lang/ClassLoader");
        jmethodID getsysloaderMethod = (*env)->GetStaticMethodID(env,classloaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
        jobject loader = (*env)->CallStaticObjectMethod(env, classloaderClass, getsysloaderMethod);
    
        //以进程现有的ClassLoader、要注入的dex路径为参数构造注入后的DexClassLoader
        jstring dexpath = (*env)->NewStringUTF(env, dexPath);
        jstring dex_odex_path = (*env)->NewStringUTF(env,dexOptDir);
        jclass dexLoaderClass = (*env)->FindClass(env,"dalvik/system/DexClassLoader");
        jmethodID initDexLoaderMethod = (*env)->GetMethodID(env, dexLoaderClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
        jobject dexLoader = (*env)->NewObject(env, dexLoaderClass, initDexLoaderMethod,dexpath,dex_odex_path,NULL,loader);
    
        //获取新出炉的DexClassLoader中findClass方法加载dex中要执行代码所在类
        jmethodID findclassMethod = (*env)->GetMethodID(env,dexLoaderClass,"findClass","(Ljava/lang/String;)Ljava/lang/Class;");
        jstring javaClassName = (*env)->NewStringUTF(env,className);
        jclass javaClientClass = (*env)->CallObjectMethod(env,dexLoader,findclassMethod,javaClassName);
    
        //获取注入dex中要执行的方法
        jmethodID start_inject_method = (*env)->GetStaticMethodID(env, javaClientClass, methodName, "()V");
        //执行之注意目标方法必须是静态公有的
        (*env)->CallStaticVoidMethod(env,javaClientClass,start_inject_method);
    }
    

    原帖中倒数第二句GetStaticMethodID方法所给的参数有误,这里修正一下,如此就完成了dex注入并调用了java代码中的:com.inject.dexinject. HookTool. dexInject() 方法。同上采用NDK编译,生成注入库:libhelloTool.so。

    生成dex

    说是dex注入,实际上从上一段的代码中可以知道最终采用的是DexClassLoader类来实现注入。托之前研究过一段APK加壳的福,对这里还相对比较了解,DexClassLoader的主要参数路径实际上应该是一个apk/jar的路径,具体可见相关的SDK文档。这里直接编一个APK丢进去就好。
    建立Android应用工程DexInject,干掉无关的界面配置。建立如下类:

    1.自定义Callback,加入拦截操作代码(打印);

    public class HookCallback implements Callback{
         public static final int RESUME_ACTIVITY         = 107;
         public static final int PAUSE_ACTIVITY          = 101;
    
         private Callback mParentCallback;
         public HookCallback(Callback parentCallback){
                   mParentCallback = parentCallback;
         }
    
    
         @Override
         public boolean handleMessage(Message msg) {
                   switch (msg.what) {
                   case RESUME_ACTIVITY:
                            Log.d(HookTool.TAG, "hook activity resume!!!");
                            break;
    
                   case PAUSE_ACTIVITY:
                            Log.d(HookTool.TAG, "hook activity pause!!!");
                   default:
                            Log.d(HookTool.TAG, "hook a " + msg.what);
                            break;
                   }
    
                   if(mParentCallback != null){
                            return mParentCallback.handleMessage(msg);
                   }else{
                            return false;
                   }
         }
    
    }
    

    2.工具类,拦截实现代码;

    public class HookTool {
         public static final String TAG = "Inject";
    
         public static void dexInject() {
                   Log.d(TAG, "this is dex code,welcome to HookTool~");
                   try {          
                            Object currentActivityThread = ReflectUtils.invokeStaticMethod(
                                               "android.app.ActivityThread",                                                     "currentActivityThread",
                                               new Class[] {}, new Object[] {});
    
                            Handler localHandler = (Handler) ReflectUtils.getFiled("android.app.ActivityThread","mH",currentActivityThread);
                            HookCallback oriCallback = (HookCallback) ReflectUtils.getFieldObject(Handler.class, localHandler, "mCallback");
                            HookCallback hookCallBack = new HookCallback(oriCallback);
                            ReflectUtils.setFieldObject(Handler.class, localHandler, "mCallback", hookCallBack);
                   } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                   }
         }
    
    }
    

    3.反射工具类

    这部分就不贴了,反射工具到处都是。
    最后编译生成DexInject.apk

    验证结果

    1. 测试机器上点击目标APP HelloWord;
    2. Push各路工具和数据到测试机器:

      adb push DexInject.apk /data/injects
      adb push inject /data/
      adb push libhelloTool.so /data/

    3. 运行注入工具:

    这是按home退出APP再进入,通过日志过滤器可以得到:


    原文地址: http://taoyuanxiaoqi.com/2015/03/16/dexinject/

    展开全文
  • OSCHINA 本期高手问答(7月29日- 8月4日)我们请来了 @jiangsai (江赛)为大家解答关于 Android Dex 注入技术 方面的问题。 江赛,@jiangsai ,听云移动研发总监,拥有10多年研发经验,早期主要从事网络设备协议栈...

    OSCHINA 本期高手问答(7月29日- 8月4日)我们请来了 @jiangsai (江赛)为大家解答关于 Android Dex 注入技术 方面的问题。

    江赛,@jiangsai ,听云移动研发总监,拥有10多年研发经验,早期主要从事网络设备协议栈开发,对 Linux Kernel、TCP/IP 协议栈等有一定的研究,从 2010 年开始从事移动设备及相关应用开发,从 Android 系统移植开始到 App 开发,对 Android build system、framework、App 开发有较深入的理解。

    Android Dex 注入的一些方法:

    1、通过分析smali代码

           可参考的开源项目:Androguard,ApkAnalyzer
    

    2、通过分析 dalvik bytecode

            可使用 dexlib2
    

    3、通过分析 Java bytecode

           可使用 ASM,需要在 dx 阶段来进行
    

    4、 非 Root 下,对于 C 接口的 hook

            需要通过修改相应的汇编指令
    

    文章转载自 开源中国社区 [http://www.oschina.net]

    展开全文
  • 当app上线后发现紧急bug,如果重新发布版本周期比较长,并且对用户体验不好,此时热修复就派上用场了。热修复就是为紧急bug而生,能够快速修复bug,并且用户无感知。... 注入dex的前提是需要dex分包,这里使用M...

            当app上线后发现紧急bug,如果重新发布版本周期比较长,并且对用户体验不好,此时热修复就派上用场了。热修复就是为紧急bug而生,能够快速修复bug,并且用户无感知。针对热修复,阿里系先后推出AndFix、HotFix、SophFix,腾讯系也推出QQ空间超级补丁、微信Tinker。在这里,主要讨论是注入dex实现热修复。

            注入dex的前提是需要dex分包,这里使用MultiDex进行分包,具体操作步骤如下:

            1、导入依赖

    compile 'com.android.support:multidex:1.0.1'
               2、使能dex分包

    multiDexEnabled true
               3、编辑分包文件

    com.frank.fix/MainActivity.class
    com.frank.fix/MyApplication.class
               4、调用文件进行分包

        buildTypes {
            release {
                multiDexKeepFile file('dex.keep')
            }
        }
               5、在Application重写attachBaseContext方法

    	@Override
    	protected void attachBaseContext(Context base) {
    		MultiDex.install(base);
    		FixUtil.loadFixedDex(base);
    		super.attachBaseContext(base);
    	}

            有两个ClassLoader(DexClassLoader和PathClassLoader)在注入dex发挥重要作用。其中,DexClassLoader用于加载指定的dex文件,PathClassLoader用于加载主dex文件,两者都继承于BasedDexClassLoader,都保存于它的私有变量pathList的dexElements里面。这就需要反射得到pathList和dexElements:

    	private static Object getField(Object obj, Class<?> clazz, String field) {
    		Field localField;
    		try {
    			localField = clazz.getDeclaredField(field);
    			localField.setAccessible(true);
    			return localField.get(obj);
    		} catch (NoSuchFieldException | IllegalAccessException e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    	private static Object getPathList(Object baseDexClassLoader) throws Exception {
    			return getField(baseDexClassLoader,Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
    	}
    
    	private static Object getDexElements(Object obj) throws Exception {
    			return getField(obj,obj.getClass(),"dexElements");
    	}

            在得到pathList和dexElements后,就可以加载主dex和修复bug的dex,然后合并dex数组:

    	private static void dexInject(final Context appContext, File filesDir,HashSet<File> loadedDex) {
    		String optimizeDir = filesDir.getAbsolutePath()+File.separator+"opt_dex";
    		File optimizedFile = new File(optimizeDir);
    		if(!optimizedFile.exists()){
    			boolean hasDir = optimizedFile.mkdirs();
    			if(!hasDir){
    				Log.e(TAG, "make directory fail...");
    				return;
    			}
    		}
    		//1.加载应用程序的dex
    		try {
    			PathClassLoader pathLoader = (PathClassLoader) appContext.getClassLoader();
    
    			for (File dex : loadedDex) {
    				//2.加载指定的修复的dex文件。
    				DexClassLoader classLoader = new DexClassLoader(dex.getAbsolutePath(),
    						optimizedFile.getAbsolutePath(), null, pathLoader);
    				Object dexObj = getPathList(classLoader);
    				Object pathObj = getPathList(pathLoader);
    				Object mDexElementsList = getDexElements(dexObj);
    				Object pathDexElementsList = getDexElements(pathObj);
    				//3.合并dex
    				Object dexElements = combineArray(mDexElementsList,pathDexElementsList);
    				//4.重新赋值给PathList里面的dexElements
    				Object pathList = getPathList(pathLoader);
    				setField(pathList,pathList.getClass(),"dexElements",dexElements);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
        }
            dex一般保存在/data/data/packageName/odex路径下,我们需要做的是从这个路径找到修复bug的dex文件,然后调用上面方法来合并dex:
    	public static void loadFixedDex(Context context){
    		if(context == null){
    			return ;
    		}
    		File fileDir = context.getDir(DEX_DIR,Context.MODE_PRIVATE);
    		File[] listFiles = fileDir.listFiles();
    		for(File file:listFiles){
    			//找到对应格式的dex文件
    			if(file.getName().startsWith(PREFIX)&&file.getName().endsWith(SUFFIX)){
    				loadedDex.add(file);
    			}
    		}
    		//dex合并
    		dexInject(context,fileDir,loadedDex);
    	}
            为了验证是否修复bug,可以把修改bug后的代码编译成class文件,再使用dx.bat批处理工具编译成dex文件。把编译好的dex文件拷贝到sd卡根目录(项目中是从服务器下载dex文件),然后把dex拷贝到app私有路径下。android studio的class路径见下图:

             在打包dex文件时,注意:class文件需要存放在绝对路径下。例如,我这里放置的文件夹是/com/frank/test/BugClass.class。dx.bat工具在Android/sdk/build-tools/xxx(API版本)路径,可以设置系统环境变量,也可以直接使用cmd命令行cd到该路径,使用命令
    dx --dex --output D:\dex\class2.dex D:\dex进行打包dex:


            备注:注入dex过程参考动脑老师思路。

    展开全文
  • 当app上线后发现紧急bug,如果重新发布版本周期比较长,并且对用户体验不好,此时热修复就派上用场了。热修复就是为紧急bug而生,能够快速修复bug,并且用户无感知。... 注入dex的前提是需要dex分包,这里使用M...
  • android通过反射注入dex到dexElements数组,实现bug的热修复
  • 通过优化,Android通过反射注入Dex到dexElements数组,实现Bug的热修复,
  • java代码(dex注入

    千次阅读 2013-04-10 17:51:36
    首先简单介绍一下进程注入的概念: 进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的...
  • Dex替换

    2019-12-10 17:03:46
    * dex注入,优先使用自定义dex中的类 * * @param path * @param base */ private void InjectDex(String path, Context base) { //添加自定义加载路径 //思路:获取类加载路径表,将自己的插在最前面 try { ...
  • 首先简单介绍一下进程注入的概念:进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码...
  • 首先简单介绍一下进程注入的概念:进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码...
  • 首先简单介绍一下进程注入的概念:进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码...
  • 前面的博客《Android平台dalvik模式下java Hook框架 ddi 的分析(1)》中,已经分析了dalvik模式下... ddi 框架Hook java方法的原理和流程,这里来学习一下ddi框架代码中涉及到的 dex文件的注入和调用。将一个Android的
  • android_dex_injection 该项目将帮助您将dex文件加载到目标程序,但是U必须将其与so文件注入器一起使用。
  • 该交易所完全是部署在链上的,并由 Runtime 层控制,任何用户都可以在 Acala 网络的操作平台上使用该 DeX ,用户向 DeX 注入资金,就能获得 DeX 产生的交易费收益,另外 DeX 作为 Honzon 协议中的清算人,会为用户...
  • 当我在想在service.jar里注入我的dex的时候,我发现service服务起来后不会走nativeForkSystemServerPost 我在我的dex调用 Class.forName("com.android.server.policy.PhoneWindowManager");函数 如果...
  • 文章目录动态注入so 动态库注入DEX 注入 动态注入 指将一段程序或一个完整的可执行文件加载到目标程序中 和 Hook 的异同 同: 都会修改目标程序的运行时行为 异: Hook:用 Hook 框架对程序 Hook 后,会修改原...
  • dex: 类加载过程

    2017-04-05 17:07:24
    2、插件化实现,就是在application初始化前,要将dex文件注入到 系统的classloader中;3、android虚拟机的类加载机制是一个类只会被加载一次;4、类加载器:BaseDexClassloader有两个子类 PathCla
  • 在将apk和zip文件交给artist之前,它用作预处理步骤,其主要任务是部分合并codelib,以便artist模块可以将对codelib方法的调用注入目标代码中。部分合并意味着将codelib dex文件添加到目标中,并使用现有的目标dex...
  • 上一篇插件化知识详细分解及原理 之代理,hook,反射,...不过值得注意的是,除了第一个dex文件以外,其他的dex文件都是以资源的形式被加载的,换句话说,就是Application初始化前将dex文件注入到系统的ClassLoader...
  • 外部动态加载DEX文件的安全风险源于:Anroid4.1之前的系统版本容许Android应用将动态加载的DEX文件存储在被其他应用任意读写的目录中(如sdcard),因此不能够保护应用免遭恶意代码的注入;所加载的DEX易...
  • /* 当第一个类执行到此函数时,我们在dvmDefineClass执行之前...注入我们的dump代码;即DumpClass()函数 */ staticvoidDalvik_dalvik_system_DexFile_defineClassNative(constu4*args, JValue*pResult) { S...
  • 通过smali注入log和函数调用堆栈

    千次阅读 2016-02-04 10:59:46
    0x00 smali注入log,看... 有几点要说明: 1、在上文中,crack.smali,并不是作者直接写的smali文件,而是先写java代码然后编译成dex,再用apktool把dex反编译成smali得到的。我们也可以用这种方法来注入我们自己
  • SmaliInjector (对重度混淆过的apk比dex2jar处理得更可靠的注入工具)
  • 同时,该模型利用dex2jar等工具,解决了Android字节码的特殊格式带来的注入困难。并通过实现系统库的动态注入,完成了Android的全覆盖注入。此模型无需用户了解底层字节码,并兼顾便捷性、灵活性和功能性。文章通过实验,...

空空如也

空空如也

1 2 3 4 5 6
收藏数 104
精华内容 41
关键字:

dex注入