public void addClassTreeHook(HookClass origin, HookClass to) { addSuperclassHook(origin, to); Set<HookClass> superclassHookSet = new HashSet<HookClass>(); superclassHookSet.add(origin); for (ClassDefItem classDef : mDexFile.ClassDefsSection.getItems()) { HookClass superclass = new HookClass(classDef.getSuperclass()); if (superclassHookSet.contains(superclass)) { TypeIdItem classType = classDef.getClassType(); HookClass newHook = new HookClass(classType); superclassHookSet.add(newHook); mHooks.put(newHook, classType); } } HookClass[] superclassHooks = superclassHookSet.toArray(new HookClass[0]); HashSet<EncodedMethod> newClassMethods = getClassMethodsMap().get(to); if (newClassMethods != null) { for (EncodedMethod newVirtual : newClassMethods) { if (newVirtual.isDirect()) { continue; } for (HookClass superclass : superclassHooks) { HookMethod deadMethod = new HookMethod(newVirtual.method); deadMethod.mClasspath = superclass.mClasspath; mDead.add(deadMethod); } } } }
/** * Hooks the specified method and all call-through methods * * @param from * @param to */ public void addMethodHook(HookMethod from, MethodIdItem to) { mMethodHooksExist = true; Queue<HookMethod> affectedMethods = new LinkedList<HookMethod>(); affectedMethods.add(from); do { HookMethod affected = affectedMethods.remove(); mHooks.put(affected, to); Set<String> allSubclasses = getSubclassMap().get(affected.mClasspath); if (allSubclasses == null) { continue; } for (String subclass : allSubclasses) { HookMethod possible = affected.clone(); possible.mClasspath = subclass; MethodIdItem possibleMethodInfo = getMethodMap().get(possible); if (possibleMethodInfo == null || possibleMethodInfo.isFallthrough()) { affectedMethods.add(possible); } } } while (!affectedMethods.isEmpty()); }
public void hookSuperclass(HookMap hooks, ClassDefItem classDef) { HookItem oldTarget = HookItem.getInstance(classDef.getSuperclass()); if (oldTarget == null) { return; } if (!hooks.containsKey(oldTarget)) { return; } TypeIdItem newTarget = (TypeIdItem) hooks.get(oldTarget); assert (newTarget != null); if (newTarget == classDef.getClassType()) { return; } classDef.setSuperclass(newTarget); HookClass classType = new HookClass(classDef.getClassType()); if (hooks.mIgnoreMethods.contains(classType)) { return; } if (hooks.mDead.isEmpty()) { return; } // get rid of virtual methods so the hooked class method is called instead String className = newTarget.getTypeDescriptor(); List<EncodedMethod> newDirects = new LinkedList<EncodedMethod>(); List<EncodedMethod> newVirtuals = new LinkedList<EncodedMethod>(); ClassDataItem classData = classDef.getClassData(); for (EncodedMethod encodedMethod : classData.getDirectMethods()) { newDirects.add(encodedMethod); } for (EncodedMethod encodedMethod : classData.getVirtualMethods()) { HookMethod method = new HookMethod(encodedMethod.method); method.mClasspath = className; if (!hooks.mDead.contains(method)) { newVirtuals.add(encodedMethod); } } classData.update(newDirects, newVirtuals); }
public HookMethod clone() { HookMethod result = new HookMethod(mClasspath, mName, null, mReturn); result.mArgs = mArgs; return result; }