Search in sources :

Example 16 with MethodNode

use of jadx.core.dex.nodes.MethodNode in project jadx by skylot.

the class Deobfuscator method resolveOverridingInternal.

@Nullable
private static ClassNode resolveOverridingInternal(DexNode dex, ClassNode cls, String signature, Set<MethodInfo> overrideSet, ClassNode rootClass) {
    ClassNode result = null;
    for (MethodNode m : cls.getMethods()) {
        if (m.getMethodInfo().getShortId().startsWith(signature)) {
            result = cls;
            if (!overrideSet.contains(m.getMethodInfo())) {
                overrideSet.add(m.getMethodInfo());
            }
            break;
        }
    }
    ArgType superClass = cls.getSuperClass();
    if (superClass != null) {
        ClassNode superNode = dex.resolveClass(superClass);
        if (superNode != null) {
            ClassNode clsWithMth = resolveOverridingInternal(dex, superNode, signature, overrideSet, rootClass);
            if (clsWithMth != null) {
                if ((result != null) && (result != cls)) {
                    if (clsWithMth != result) {
                        LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'", signature, result.getFullName(), clsWithMth.getFullName(), rootClass.getFullName()));
                    }
                } else {
                    result = clsWithMth;
                }
            }
        }
    }
    for (ArgType iFaceType : cls.getInterfaces()) {
        ClassNode iFaceNode = dex.resolveClass(iFaceType);
        if (iFaceNode != null) {
            ClassNode clsWithMth = resolveOverridingInternal(dex, iFaceNode, signature, overrideSet, rootClass);
            if (clsWithMth != null) {
                if ((result != null) && (result != cls)) {
                    if (clsWithMth != result) {
                        LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'", signature, result.getFullName(), clsWithMth.getFullName(), rootClass.getFullName()));
                    }
                } else {
                    result = clsWithMth;
                }
            }
        }
    }
    return result;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) ClassNode(jadx.core.dex.nodes.ClassNode) MethodNode(jadx.core.dex.nodes.MethodNode) Nullable(org.jetbrains.annotations.Nullable)

Example 17 with MethodNode

use of jadx.core.dex.nodes.MethodNode in project jadx by skylot.

the class ModVisitor method processInvoke.

private static void processInvoke(MethodNode mth, BlockNode block, int insnNumber, InstructionRemover remover) {
    ClassNode parentClass = mth.getParentClass();
    InsnNode insn = block.getInstructions().get(insnNumber);
    InvokeNode inv = (InvokeNode) insn;
    MethodInfo callMth = inv.getCallMth();
    if (!callMth.isConstructor()) {
        return;
    }
    InsnNode instArgAssignInsn = ((RegisterArg) inv.getArg(0)).getAssignInsn();
    ConstructorInsn co = new ConstructorInsn(mth, inv);
    boolean remove = false;
    if (co.isSuper() && (co.getArgsCount() == 0 || parentClass.isEnum())) {
        remove = true;
    } else if (co.isThis() && co.getArgsCount() == 0) {
        MethodNode defCo = parentClass.searchMethodByName(callMth.getShortId());
        if (defCo == null || defCo.isNoCode()) {
            // default constructor not implemented
            remove = true;
        }
    }
    // remove super() call in instance initializer
    if (parentClass.isAnonymous() && mth.isDefaultConstructor() && co.isSuper()) {
        remove = true;
    }
    if (remove) {
        remover.add(insn);
        return;
    }
    if (co.isNewInstance()) {
        InsnNode newInstInsn = removeAssignChain(instArgAssignInsn, remover, InsnType.NEW_INSTANCE);
        if (newInstInsn != null) {
            RegisterArg instArg = newInstInsn.getResult();
            RegisterArg resultArg = co.getResult();
            if (!resultArg.equals(instArg)) {
                // replace all usages of 'instArg' with result of this constructor instruction
                for (RegisterArg useArg : new ArrayList<RegisterArg>(instArg.getSVar().getUseList())) {
                    RegisterArg dup = resultArg.duplicate();
                    InsnNode parentInsn = useArg.getParentInsn();
                    parentInsn.replaceArg(useArg, dup);
                    dup.setParentInsn(parentInsn);
                    resultArg.getSVar().use(dup);
                }
            }
        }
    }
    ConstructorInsn replace = processConstructor(mth, co);
    if (replace != null) {
        co = replace;
    }
    replaceInsn(block, insnNumber, co);
    processAnonymousConstructor(mth, co);
}
Also used : ClassNode(jadx.core.dex.nodes.ClassNode) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) MethodNode(jadx.core.dex.nodes.MethodNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) ArrayList(java.util.ArrayList) MethodInfo(jadx.core.dex.info.MethodInfo) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Example 18 with MethodNode

use of jadx.core.dex.nodes.MethodNode in project jadx by skylot.

the class ModVisitor method processConstructor.

/**
	 * Replace call of synthetic constructor
	 */
private static ConstructorInsn processConstructor(MethodNode mth, ConstructorInsn co) {
    MethodNode callMth = mth.dex().resolveMethod(co.getCallMth());
    if (callMth == null || !callMth.getAccessFlags().isSynthetic() || !allArgsNull(co)) {
        return null;
    }
    ClassNode classNode = mth.dex().resolveClass(callMth.getParentClass().getClassInfo());
    if (classNode == null) {
        return null;
    }
    boolean passThis = co.getArgsCount() >= 1 && co.getArg(0).isThis();
    String ctrId = "<init>(" + (passThis ? TypeGen.signature(co.getArg(0).getType()) : "") + ")V";
    MethodNode defCtr = classNode.searchMethodByName(ctrId);
    if (defCtr == null) {
        return null;
    }
    ConstructorInsn newInsn = new ConstructorInsn(defCtr.getMethodInfo(), co.getCallType(), co.getInstanceArg());
    newInsn.setResult(co.getResult());
    return newInsn;
}
Also used : ClassNode(jadx.core.dex.nodes.ClassNode) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) MethodNode(jadx.core.dex.nodes.MethodNode) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Example 19 with MethodNode

use of jadx.core.dex.nodes.MethodNode in project jadx by skylot.

the class ReSugarCode method getEnumMap.

private static EnumMapAttr.KeyValueMap getEnumMap(MethodNode mth, FieldNode field) {
    ClassNode syntheticClass = field.getParentClass();
    EnumMapAttr mapAttr = syntheticClass.get(AType.ENUM_MAP);
    if (mapAttr != null) {
        return mapAttr.getMap(field);
    }
    mapAttr = new EnumMapAttr();
    syntheticClass.addAttr(mapAttr);
    MethodNode clsInitMth = syntheticClass.searchMethodByName("<clinit>()V");
    if (clsInitMth == null || clsInitMth.isNoCode()) {
        return null;
    }
    if (clsInitMth.getBasicBlocks() == null) {
        try {
            clsInitMth.load();
        } catch (DecodeException e) {
            LOG.error("Load failed", e);
            return null;
        }
        if (clsInitMth.getBasicBlocks() == null) {
            // TODO:
            return null;
        }
    }
    for (BlockNode block : clsInitMth.getBasicBlocks()) {
        for (InsnNode insn : block.getInstructions()) {
            if (insn.getType() == InsnType.APUT) {
                addToEnumMap(mth, mapAttr, insn);
            }
        }
    }
    return mapAttr.getMap(field);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ClassNode(jadx.core.dex.nodes.ClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) MethodNode(jadx.core.dex.nodes.MethodNode) EnumMapAttr(jadx.core.dex.attributes.nodes.EnumMapAttr) DecodeException(jadx.core.utils.exceptions.DecodeException)

Example 20 with MethodNode

use of jadx.core.dex.nodes.MethodNode in project jadx by skylot.

the class EnumVisitor method visit.

@Override
public boolean visit(ClassNode cls) throws JadxException {
    if (!cls.isEnum()) {
        return true;
    }
    // search class init method
    MethodNode staticMethod = null;
    for (MethodNode mth : cls.getMethods()) {
        MethodInfo mi = mth.getMethodInfo();
        if (mi.isClassInit()) {
            staticMethod = mth;
            break;
        }
    }
    if (staticMethod == null) {
        ErrorsCounter.classError(cls, "Enum class init method not found");
        return true;
    }
    ArgType clsType = cls.getClassInfo().getType();
    String enumConstructor = "<init>(Ljava/lang/String;I)V";
    // TODO: detect these methods by analyzing method instructions
    String valuesOfMethod = "valueOf(Ljava/lang/String;)" + TypeGen.signature(clsType);
    String valuesMethod = "values()" + TypeGen.signature(ArgType.array(clsType));
    // collect enum fields, remove synthetic
    List<FieldNode> enumFields = new ArrayList<FieldNode>();
    for (FieldNode f : cls.getFields()) {
        if (f.getAccessFlags().isEnum()) {
            enumFields.add(f);
            f.add(AFlag.DONT_GENERATE);
        } else if (f.getAccessFlags().isSynthetic()) {
            f.add(AFlag.DONT_GENERATE);
        }
    }
    // remove synthetic methods
    for (MethodNode mth : cls.getMethods()) {
        MethodInfo mi = mth.getMethodInfo();
        if (mi.isClassInit()) {
            continue;
        }
        String shortId = mi.getShortId();
        boolean isSynthetic = mth.getAccessFlags().isSynthetic();
        if (mi.isConstructor() && !isSynthetic) {
            if (shortId.equals(enumConstructor)) {
                mth.add(AFlag.DONT_GENERATE);
            }
        } else if (isSynthetic || shortId.equals(valuesMethod) || shortId.equals(valuesOfMethod)) {
            mth.add(AFlag.DONT_GENERATE);
        }
    }
    EnumClassAttr attr = new EnumClassAttr(enumFields.size());
    cls.addAttr(attr);
    attr.setStaticMethod(staticMethod);
    ClassInfo classInfo = cls.getClassInfo();
    // move enum specific instruction from static method to separate list
    BlockNode staticBlock = staticMethod.getBasicBlocks().get(0);
    List<InsnNode> enumPutInsns = new ArrayList<InsnNode>();
    List<InsnNode> list = staticBlock.getInstructions();
    int size = list.size();
    for (int i = 0; i < size; i++) {
        InsnNode insn = list.get(i);
        if (insn.getType() != InsnType.SPUT) {
            continue;
        }
        FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
        if (!f.getDeclClass().equals(classInfo)) {
            continue;
        }
        FieldNode fieldNode = cls.searchField(f);
        if (fieldNode != null && isEnumArrayField(classInfo, fieldNode)) {
            if (i == size - 1) {
                staticMethod.add(AFlag.DONT_GENERATE);
            } else {
                list.subList(0, i + 1).clear();
            }
            break;
        } else {
            enumPutInsns.add(insn);
        }
    }
    for (InsnNode putInsn : enumPutInsns) {
        ConstructorInsn co = getConstructorInsn(putInsn);
        if (co == null || co.getArgsCount() < 2) {
            continue;
        }
        ClassInfo clsInfo = co.getClassType();
        ClassNode constrCls = cls.dex().resolveClass(clsInfo);
        if (constrCls == null) {
            continue;
        }
        if (!clsInfo.equals(classInfo) && !constrCls.getAccessFlags().isEnum()) {
            continue;
        }
        FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) putInsn).getIndex();
        String name = getConstString(cls.dex(), co.getArg(0));
        if (name != null && !fieldInfo.getAlias().equals(name) && NameMapper.isValidIdentifier(name)) {
            // LOG.debug("Rename enum field: '{}' to '{}' in {}", fieldInfo.getName(), name, cls);
            fieldInfo.setAlias(name);
        }
        EnumField field = new EnumField(fieldInfo, co, 2);
        attr.getFields().add(field);
        if (!co.getClassType().equals(classInfo)) {
            // enum contains additional methods
            for (ClassNode innerCls : cls.getInnerClasses()) {
                processEnumInnerCls(co, field, innerCls);
            }
        }
    }
    return false;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) BlockNode(jadx.core.dex.nodes.BlockNode) ClassNode(jadx.core.dex.nodes.ClassNode) EnumField(jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField) FieldNode(jadx.core.dex.nodes.FieldNode) ArrayList(java.util.ArrayList) EnumClassAttr(jadx.core.dex.attributes.nodes.EnumClassAttr) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) MethodNode(jadx.core.dex.nodes.MethodNode) MethodInfo(jadx.core.dex.info.MethodInfo) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) FieldInfo(jadx.core.dex.info.FieldInfo) ClassInfo(jadx.core.dex.info.ClassInfo)

Aggregations

MethodNode (jadx.core.dex.nodes.MethodNode)27 ClassNode (jadx.core.dex.nodes.ClassNode)12 FieldNode (jadx.core.dex.nodes.FieldNode)9 MethodInfo (jadx.core.dex.info.MethodInfo)7 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)7 InsnNode (jadx.core.dex.nodes.InsnNode)7 ClassInfo (jadx.core.dex.info.ClassInfo)5 ConstructorInsn (jadx.core.dex.instructions.mods.ConstructorInsn)5 BlockNode (jadx.core.dex.nodes.BlockNode)5 ConstClassNode (jadx.core.dex.instructions.ConstClassNode)4 ArgType (jadx.core.dex.instructions.args.ArgType)4 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)4 ArrayList (java.util.ArrayList)4 FieldInfo (jadx.core.dex.info.FieldInfo)3 InsnArg (jadx.core.dex.instructions.args.InsnArg)3 IRegion (jadx.core.dex.nodes.IRegion)3 IntegrationTest (jadx.tests.api.IntegrationTest)3 HashSet (java.util.HashSet)3 Test (org.junit.Test)3 EnumClassAttr (jadx.core.dex.attributes.nodes.EnumClassAttr)2