package com.aruba.andfixapplication;
import android.content.Context;
import android.os.Build;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import dalvik.system.DexFile;
/**
* Created by aruba on 2020/4/30.
*/
public class DexManager {
private Context mContext;
private static final DexManager ourInstance = new DexManager();
public static DexManager getInstance() {
return ourInstance;
}
private DexManager() {
}
public void setContext(Context mContext) {
this.mContext = mContext;
}
public void loadDexFile(File file) {
try {
DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
new File(mContext.getCacheDir(), "fix.dex").getAbsolutePath(),
Context.MODE_PRIVATE);
//类名迭代器
Enumeration<String> entry = dexFile.entries();
while (entry.hasMoreElements()) {
String className = entry.nextElement();
//Class.forName()获取不到,因为没有加载,我们需要手动加载
Class clazz = dexFile.loadClass(className, mContext.getClassLoader());
if (clazz != null) {
//开始修复
fixClass(clazz);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void fixClass(Class clazz) {
//获取class中的方法
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
//获取注解
Replace replace = methods[i].getAnnotation(Replace.class);
if (replace == null) continue;
//获取注解中需要被修复的方法和类
String bugClazzStr = replace.clazz();
String bugMethodStr = replace.method();
try {
Class bugClazz = Class.forName(bugClazzStr);
//错误的方法
Method bugMethod = bugClazz.getMethod(bugMethodStr, methods[i].getParameterTypes());
if (Build.VERSION.SDK_INT <= 19) {//18版本以下,dalvik
replace(Build.VERSION.SDK_INT, bugMethod, methods[i], clazz);
} else if (Build.VERSION.SDK_INT == 24) {
replaceArt7(bugMethod, methods[i]);
} else {
replaceArt(bugMethod, methods[i]);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
private native void replace(int sdk, Method wrongMethod, Method rightMethod, Class rightClazz);
private native void replaceArt(Method wrongMethod, Method rightMethod);
private native void replaceArt7(Method wrongMethod, Method rightMethod);
}
7.0以下art虚拟机的ArtMethod头文件
/*
*
* Copyright (c) 2011 The Android Open Source Project
* Copyright (c) 2015, alipay.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* art_5_1.h
*
* @author : sanping.li@alipay.com
*
*/
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdint.h> /* C99 */
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4;
typedef signed char s1;
typedef signed short s2;
typedef signed int s4;
namespace art {
namespace mirror {
class Object {
public:
// The number of vtable entries in java.lang.Object.
uint32_t klass_;
uint32_t monitor_;
};
class Class : public Object {
public:
// Interface method table size. Increasing this value reduces the chance of two interface methods
// colliding in the interface method table but increases the size of classes that implement
// (non-marker) interfaces.
// defining class loader, or NULL for the "bootstrap" system loader
uint32_t class_loader_;
// For array classes, the component class object for instanceof/checkcast
// (for String[][][], this will be String[][]). NULL for non-array classes.
uint32_t component_type_;
// DexCache of resolved constant pool entries (will be NULL for classes generated by the
// runtime such as arrays and primitive classes).
uint32_t dex_cache_;
// Short cuts to dex_cache_ member for fast compiled code access.
uint32_t dex_cache_strings_;
// static, private, and <init> methods
uint32_t direct_methods_;
// instance fields
//
// These describe the layout of the contents of an Object.
// Note that only the fields directly declared by this class are
// listed in ifields; fields declared by a superclass are listed in
// the superclass's Class.ifields.
//
// All instance fields that refer to objects are guaranteed to be at
// the beginning of the field list. num_reference_instance_fields_
// specifies the number of reference fields.
uint32_t ifields_;
// The interface table (iftable_) contains pairs of a interface class and an array of the
// interface methods. There is one pair per interface supported by this class. That means one
// pair for each interface we support directly, indirectly via superclass, or indirectly via a
// superinterface. This will be null if neither we nor our superclass implement any interfaces.
//
// Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
// Invoke faceObj.blah(), where "blah" is part of the Face interface. We can't easily use a
// single vtable.
//
// For every interface a concrete class implements, we create an array of the concrete vtable_
// methods for the methods in the interface.
uint32_t iftable_;
// Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
uint32_t name_;
// Static fields
uint32_t sfields_;
// The superclass, or NULL if this is java.lang.Object, an interface or primitive type.
uint32_t super_class_;
// If class verify fails, we must return same error on subsequent tries.
uint32_t verify_error_class_;
// Virtual methods defined in this class; invoked through vtable.
uint32_t virtual_methods_;
// Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is
// copied in, and virtual methods from our class either replace those from the super or are
// appended. For abstract classes, methods may be created in the vtable that aren't in
// virtual_ methods_ for miranda methods.
uint32_t vtable_;
// Access flags; low 16 bits are defined by VM spec.
uint32_t access_flags_;
// Total size of the Class instance; used when allocating storage on gc heap.
// See also object_size_.
uint32_t class_size_;
// Tid used to check for recursive <clinit> invocation.
pid_t clinit_thread_id_;
// ClassDef index in dex file, -1 if no class definition such as an array.
// TODO: really 16bits
int32_t dex_class_def_idx_;
// Type index in dex file.
// TODO: really 16bits
int32_t dex_type_idx_;
// Number of instance fields that are object refs.
uint32_t num_reference_instance_fields_;
// Number of static fields that are object refs,
uint32_t num_reference_static_fields_;
// Total object size; used when allocating storage on gc heap.
// (For interfaces and abstract classes this will be zero.)
// See also class_size_.
uint32_t object_size_;
// Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes.
uint32_t primitive_type_;
// Bitmap of offsets of ifields.
uint32_t reference_instance_offsets_;
// Bitmap of offsets of sfields.
uint32_t reference_static_offsets_;
// State of class initialization.
int32_t status_;
// TODO: ?
// initiating class loader list
// NOTE: for classes with low serialNumber, these are unused, and the
// values are kept in a table in gDvm.
// InitiatingLoaderList initiating_loader_list_;
// The following data exist in real class objects.
// Embedded Imtable, for class object that's not an interface, fixed size.
// ImTableEntry embedded_imtable_[0];
// Embedded Vtable, for class object that's not an interface, variable size.
// VTableEntry embedded_vtable_[0];
// Static fields, variable size.
// uint32_t fields_[0];
// java.lang.Class
static void *java_lang_Class_;
};
class ArtField : public Object {
public:
uint32_t declaring_class_;
int32_t access_flags_;
int32_t field_dex_idx_;
int32_t offset_;
};
class ArtMethod : public Object {
public:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of. 适配andfix 不能做到这一改
uint32_t declaring_class_;
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. dex
uint32_t dex_cache_resolved_methods_;
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
uint32_t dex_cache_resolved_types_;
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
/* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
// Offset to the CodeItem.
uint32_t dex_code_item_offset_;
// Index into method_ids of the dex file associated with this method.
uint32_t dex_method_index_;
/* End of dex file fields. */
// Entry within a dispatch table for this method. For static/direct methods the index is into
// the declaringClass.directMethods, for virtual methods the vtable and for interface methods the
// ifTable.
uint32_t method_index_;
// Fake padding field gets inserted here.
// Must be the last fields in the method.
struct PtrSizedFields {
// Method dispatch from the interpreter invokes this pointer which may cause a bridge into
// compiled code.java方法 ----》 虚拟机 ----》方法的入口 entry_point_from_interpreter_
//art 解释模式 机器码
void *entry_point_from_interpreter_;
// Pointer to JNI function registered to this method, or a function to resolve the JNI function.
void *entry_point_from_jni_;
// Method dispatch from quick compiled code invokes this pointer which may cause bridging into
// portable compiled code or the interpreter.
// 机器码模式
void *entry_point_from_quick_compiled_code_;
} ptr_sized_fields_;
static void *java_lang_reflect_ArtMethod_;
};
}
}
7.0ArtMethod头文件
/*
*
* Copyright (c) 2011 The Android Open Source Project
* Copyright (c) 2016, alipay.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* art_7_0.h
*
* @author : sanping.li@alipay.com
*
*/
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <string>
#include <memory>
#include <sys/mman.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdint.h> /* C99 */
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4;
typedef signed char s1;
typedef signed short s2;
typedef signed int s4;
namespace art {
namespace mirror {
class Object {
public:
static uint32_t hash_code_seed;
uint32_t klass_;
uint32_t monitor_;
};
class Class: public Object {
public:
enum Status {
kStatusRetired = -2, // Retired, should not be used. Use the newly cloned one instead.
kStatusError = -1,
kStatusNotReady = 0,
kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
kStatusLoaded = 2, // DEX idx values resolved.
kStatusResolving = 3, // Just cloned from temporary class object.
kStatusResolved = 4, // Part of linking.
kStatusVerifying = 5, // In the process of being verified.
kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime.
kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime.
kStatusVerified = 8, // Logically part of linking; done pre-init.
kStatusInitializing = 9, // Class init in progress.
kStatusInitialized = 10, // Ready to go.
kStatusMax = 11,
};
// A magic value for reference_instance_offsets_. Ignore the bits and walk the super chain when
// this is the value.
// [This is an unlikely "natural" value, since it would be 30 non-ref instance fields followed by
// 2 ref instance fields.]
// Interface method table size. Increasing this value reduces the chance of two interface methods
// colliding in the interface method table but increases the size of classes that implement
// (non-marker) interfaces.
// 'Class' Object Fields
// Order governed by java field ordering. See art::ClassLinker::LinkFields.
uint32_t annotation_type_;
// Defining class loader, or null for the "bootstrap" system loader.
uint32_t class_loader_1;
// For array classes, the component class object for instanceof/checkcast
// (for String[][][], this will be String[][]). null for non-array classes.
uint32_t component_type_;
// DexCache of resolved constant pool entries (will be null for classes generated by the
// runtime such as arrays and primitive classes).
uint32_t dex_cache_;
// The interface table (iftable_) contains pairs of a interface class and an array of the
// interface methods. There is one pair per interface supported by this class. That means one
// pair for each interface we support directly, indirectly via superclass, or indirectly via a
// superinterface. This will be null if neither we nor our superclass implement any interfaces.
//
// Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
// Invoke faceObj.blah(), where "blah" is part of the Face interface. We can't easily use a
// single vtable.
//
// For every interface a concrete class implements, we create an array of the concrete vtable_
// methods for the methods in the interface.
uint32_t iftable_;
// Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
uint32_t name_;
// The superclass, or null if this is java.lang.Object or a primitive type.
//
// Note that interfaces have java.lang.Object as their
// superclass. This doesn't match the expectations in JNI
// GetSuperClass or java.lang.Class.getSuperClass() which need to
// check for interfaces and return null.
uint32_t super_class_;
// If class verify fails, we must return same error on subsequent tries. We may store either
// the class of the error, or an actual instance of Throwable here.
uint32_t verify_error_;
// Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is
// copied in, and virtual methods from our class either replace those from the super or are
// appended. For abstract classes, methods may be created in the vtable that aren't in
// virtual_ methods_ for miranda methods.
uint32_t vtable_;
// Access flags; low 16 bits are defined by VM spec.
// Note: Shuffled back.
uint32_t access_flags_;
// Short cuts to dex_cache_ member for fast compiled code access.
uint64_t dex_cache_strings_;
// instance fields
//
// These describe the layout of the contents of an Object.
// Note that only the fields directly declared by this class are
// listed in ifields; fields declared by a superclass are listed in
// the superclass's Class.ifields.
//
// ArtFields are allocated as a length prefixed ArtField array, and not an array of pointers to
// ArtFields.
uint64_t ifields_;
// Pointer to an ArtMethod length-prefixed array. All the methods where this class is the place
// where they are logically defined. This includes all private, static, final and virtual methods
// as well as inherited default methods and miranda methods.
//
// The slice methods_ [0, virtual_methods_offset_) are the direct (static, private, init) methods
// declared by this class.
//
// The slice methods_ [virtual_methods_offset_, copied_methods_offset_) are the virtual methods
// declared by this class.
//
// The slice methods_ [copied_methods_offset_, |methods_|) are the methods that are copied from
// interfaces such as miranda or default methods. These are copied for resolution purposes as this
// class is where they are (logically) declared as far as the virtual dispatch is concerned.
//
// Note that this field is used by the native debugger as the unique identifier for the type.
uint64_t methods_;
// Static fields length-prefixed array.
uint64_t sfields_;
// Class flags to help speed up visiting object references.
uint32_t class_flags_;
// Total size of the Class instance; used when allocating storage on gc heap.
// See also object_size_.
uint32_t class_size_;
// Tid used to check for recursive <clinit> invocation.
pid_t clinit_thread_id_;
// ClassDef index in dex file, -1 if no class definition such as an array.
// TODO: really 16bits
int32_t dex_class_def_idx_;
// Type index in dex file.
// TODO: really 16bits
int32_t dex_type_idx_;
// Number of instance fields that are object refs.
uint32_t num_reference_instance_fields_;
// Number of static fields that are object refs,
uint32_t num_reference_static_fields_;
// Total object size; used when allocating storage on gc heap.
// (For interfaces and abstract classes this will be zero.)
// See also class_size_.
uint32_t object_size_;
// The lower 16 bits contains a Primitive::Type value. The upper 16
// bits contains the size shift of the primitive type.
uint32_t primitive_type_;
// Bitmap of offsets of ifields.
uint32_t reference_instance_offsets_;
// State of class initialization.
Status status_;
// The offset of the first virtual method that is copied from an interface. This includes miranda,
// default, and default-conflict methods. Having a hard limit of ((2 << 16) - 1) for methods
// defined on a single class is well established in Java so we will use only uint16_t's here.
uint16_t copied_methods_offset_;
// The offset of the first declared virtual methods in the methods_ array.
uint16_t virtual_methods_offset_;
// TODO: ?
// initiating class loader list
// NOTE: for classes with low serialNumber, these are unused, and the
// values are kept in a table in gDvm.
// InitiatingLoaderList initiating_loader_list_;
// The following data exist in real class objects.
// Embedded Imtable, for class object that's not an interface, fixed size.
// ImTableEntry embedded_imtable_[0];
// Embedded Vtable, for class object that's not an interface, variable size.
// VTableEntry embedded_vtable_[0];
// Static fields, variable size.
// uint32_t fields_[0];
// java.lang.Class
static uint32_t java_lang_Class_;
};
class ArtField {
public:
uint32_t declaring_class_;
uint32_t access_flags_;
uint32_t field_dex_idx_;
uint32_t offset_;
};
class ArtMethod {
public:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of.
uint32_t declaring_class_;
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
/* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
// Offset to the CodeItem.
uint32_t dex_code_item_offset_;
// Index into method_ids of the dex file associated with this method.
uint32_t dex_method_index_;
/* End of dex file fields. */
// Entry within a dispatch table for this method. For static/direct methods the index is into
// the declaringClass.directMethods, for virtual methods the vtable and for interface methods the
// ifTable.
uint16_t method_index_;
// The hotness we measure for this method. Incremented by the interpreter. Not atomic, as we allow
// missing increments: if the method is hot, we will see it eventually.
uint16_t hotness_count_;
// Fake padding field gets inserted here.
// Must be the last fields in the method.
// PACKED(4) is necessary for the correctness of
// RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size).
struct PtrSizedFields {
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
ArtMethod** dex_cache_resolved_methods_;
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
void* dex_cache_resolved_types_;
// Pointer to JNI function registered to this method, or a function to resolve the JNI function,
// or the profiling data for non-native methods, or an ImtConflictTable.
void* entry_point_from_jni_;
// Method dispatch from quick compiled code invokes this pointer which may cause bridging into
// the interpreter.
void* entry_point_from_quick_compiled_code_;
} ptr_sized_fields_;
};
}
}
7.0以下
#include <jni.h>
#include "art_method.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_aruba_andfixapplication_DexManager_replaceArt(JNIEnv *env, jobject instance,
jobject wrongMethod, jobject rightMethod) {
// art虚拟机替换 art ArtMethod ---》Java方法
art::mirror::ArtMethod *wrong = (art::mirror::ArtMethod *) env->FromReflectedMethod(
wrongMethod);
art::mirror::ArtMethod *right = (art::mirror::ArtMethod *) env->FromReflectedMethod(
rightMethod);
wrong->declaring_class_ = right->declaring_class_;
wrong->dex_code_item_offset_ = right->dex_code_item_offset_;
wrong->dex_cache_resolved_methods_ = right->dex_cache_resolved_methods_;
wrong->dex_cache_resolved_types_ = right->dex_cache_resolved_types_;
wrong->access_flags_ = right->access_flags_;
wrong->method_index_ = right->method_index_;
wrong->dex_method_index_ = right->dex_method_index_;
wrong->ptr_sized_fields_.entry_point_from_jni_ = right->ptr_sized_fields_.entry_point_from_jni_;
wrong->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = right->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
wrong->ptr_sized_fields_.entry_point_from_interpreter_ = right->ptr_sized_fields_.entry_point_from_interpreter_;
}
7.0
#include <jni.h>
#include "art_7_0.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_aruba_andfixapplication_DexManager_replaceArt7(JNIEnv *env, jobject instance,
jobject wrongMethod, jobject rightMethod) {
// art虚拟机替换 art ArtMethod ---》Java方法
art::mirror::ArtMethod *wrong = (art::mirror::ArtMethod *) env->FromReflectedMethod(
wrongMethod);
art::mirror::ArtMethod *right = (art::mirror::ArtMethod *) env->FromReflectedMethod(
rightMethod);
wrong->declaring_class_ = right->declaring_class_;
wrong->dex_code_item_offset_ = right->dex_code_item_offset_;
wrong->method_index_ = right->method_index_;
wrong->dex_method_index_ = right->dex_method_index_;
//入口
wrong->ptr_sized_fields_.entry_point_from_jni_ = right->ptr_sized_fields_.entry_point_from_jni_;
//机器码模式
wrong->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = right->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
// 不一样
wrong->ptr_sized_fields_.entry_point_from_jni_ = right->ptr_sized_fields_.entry_point_from_jni_;
wrong->ptr_sized_fields_.dex_cache_resolved_methods_ = right->ptr_sized_fields_.dex_cache_resolved_methods_;
wrong->ptr_sized_fields_.dex_cache_resolved_types_ = right->ptr_sized_fields_.dex_cache_resolved_types_;
wrong->hotness_count_ = right->hotness_count_;
}