美文网首页
AndFix 的原理 --- 替换为补丁包的方法

AndFix 的原理 --- 替换为补丁包的方法

作者: 石器时代小古董 | 来源:发表于2020-03-04 14:52 被阅读0次

使用补丁包中的方法信息进行替换

1.在 Java 层获取 补丁包方法的信息

通过 DexFile 获取到补丁包中的方法对象。

public class DexManager {
    private static final String     TAG         = "DexManager";
    private static final DexManager ourInstance = new DexManager();

    public static DexManager getInstance() {
        return ourInstance;
    }

    private DexManager() {
    }

    private Context mContext;

    public void setContext(Context context) {
        this.mContext = context;
    }

    public void loadDex(File file) {
        try {
            DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
                    new File(mContext.getCacheDir(), "opt").getAbsolutePath(),
                    Context.MODE_PRIVATE);
            Enumeration<String> entries = dexFile.entries();
            while (entries.hasMoreElements()) {
                String className = entries.nextElement();
                //                Class.forName(className);//为什么不能用这种方式?这种方式只能获取安装app中的class
                Class fixClazz = dexFile.loadClass(className, mContext.getClassLoader());
                if (fixClazz != null) {
                    fixClass(fixClazz);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void fixClass(Class fixClazz) {
        Method[] methods = fixClazz.getDeclaredMethods();
        //        Method[] methods = fixClazz.getMethods();
        MethodReplace methodReplace;
        String className;
        String methodName;
        Class<?> bugClass;
        Method bugMethod;
        for (Method fixMethod : methods) {
            methodReplace = fixMethod.getAnnotation(MethodReplace.class);
            if (methodReplace == null) {
                continue;
            }
            Log.e(TAG, "找到修复好的方法: " + fixMethod.getDeclaringClass() + "@" + fixMethod.getName());
            className = methodReplace.className();
            methodName = methodReplace.methodName();
            if (!TextUtils.isEmpty(className) && !TextUtils.isEmpty(methodName)) {
                try {
                    bugClass = Class.forName(className);
                    bugMethod =
                            bugClass.getDeclaredMethod(methodName, fixMethod.getParameterTypes());
                    replace(bugMethod, fixMethod);
                    Log.e(TAG, "修复完成!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                Log.e(TAG, "/修复好的方法未设置自定义注解属性");
            }
        }
    }

    private native void replace(Method bugMethod, Method fixMethod);

    static {
        System.loadLibrary("native-lib");
    }
}

2.使用补丁包中的方法信息替换

#include <jni.h>
#include <string>
#include <android/log.h>
#include "art_5_1.h"

extern "C"
JNIEXPORT void JNICALL
Java_com_netease_andfix_DexManager_replace(JNIEnv *env, jobject instance, jobject bugMethod,
                                           jobject fixMethod) {
    env->FindClass()
    //ba获得指向被替换的目标方法的指针(有bug的方法的指针)
    art::mirror::ArtMethod *bugArtMethod = reinterpret_cast<art::mirror::ArtMethod *>(env->FromReflectedMethod(
            bugMethod));
    //获得指向新的方法的指针(被修复了的方法的指针)
    art::mirror::ArtMethod *fixArtMethod = reinterpret_cast<art::mirror::ArtMethod *>(env->FromReflectedMethod(
            fixMethod));
    reinterpret_cast<art::mirror::Class *>(fixArtMethod->declaring_class_)->class_loader_ =
            reinterpret_cast<art::mirror::Class *>(bugArtMethod->declaring_class_)->class_loader_; //for plugin classloader
    reinterpret_cast<art::mirror::Class *>(fixArtMethod->declaring_class_)->clinit_thread_id_ =
            reinterpret_cast<art::mirror::Class *>(bugArtMethod->declaring_class_)->clinit_thread_id_;
    reinterpret_cast<art::mirror::Class *>(fixArtMethod->declaring_class_)->status_ =
            reinterpret_cast<art::mirror::Class *>(bugArtMethod->declaring_class_)->status_ - 1;
    reinterpret_cast<art::mirror::Class *>(fixArtMethod->declaring_class_)->super_class_ = 0;
    //把就函数的成员变量替换为新函数的
    bugArtMethod->declaring_class_ = fixArtMethod->declaring_class_;
    bugArtMethod->dex_cache_resolved_methods_ = fixArtMethod->dex_cache_resolved_methods_;
    bugArtMethod->access_flags_ = fixArtMethod->access_flags_;
    bugArtMethod->dex_cache_resolved_types_ = fixArtMethod->dex_cache_resolved_types_;
    bugArtMethod->dex_code_item_offset_ = fixArtMethod->dex_code_item_offset_;
    bugArtMethod->method_index_ = fixArtMethod->method_index_;
    bugArtMethod->dex_method_index_ = fixArtMethod->dex_method_index_;

    bugArtMethod->ptr_sized_fields_.entry_point_from_interpreter_ = fixArtMethod->ptr_sized_fields_.entry_point_from_interpreter_;
    bugArtMethod->ptr_sized_fields_.entry_point_from_jni_ = fixArtMethod->ptr_sized_fields_.entry_point_from_jni_;
    bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
    __android_log_print(ANDROID_LOG_ERROR, "AndFix","replace_5_1: %d , %d",
                        static_cast<const char *>(bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_),
                        fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_);

}

相关文章

网友评论

      本文标题:AndFix 的原理 --- 替换为补丁包的方法

      本文链接:https://www.haomeiwen.com/subject/ptivlhtx.html