Search in sources :

Example 1 with ConstStringNode

use of jadx.core.dex.instructions.ConstStringNode in project jadx by skylot.

the class SimplifyVisitor method convertInvoke.

private static InsnNode convertInvoke(MethodNode mth, InsnNode insn) {
    MethodInfo callMth = ((InvokeNode) insn).getCallMth();
    // convert it to STRING_CONCAT pseudo instruction.
    if (callMth.getDeclClass().getFullName().equals(Consts.CLASS_STRING_BUILDER) && callMth.getShortId().equals(Consts.MTH_TOSTRING_SIGNATURE) && insn.getArg(0).isInsnWrap()) {
        try {
            List<InsnNode> chain = flattenInsnChain(insn);
            //RAF
            int constrIndex = -1;
            // string is created using .append() calls:
            if (chain.size() > 1 && chain.get(0).getType() == InsnType.CONSTRUCTOR) {
                constrIndex = 0;
            } else if (chain.size() > 2 && chain.get(1).getType() == InsnType.CONSTRUCTOR) {
                //RAF Case where the first string element is String arg to the
                // new StringBuilder("xxx") constructor
                constrIndex = 1;
            } else if (chain.size() > 3 && chain.get(2).getType() == InsnType.CONSTRUCTOR) {
                //RAF Case where the first string element is String.valueOf() arg
                // to the new StringBuilder(String.valueOf(zzz)) constructor
                constrIndex = 2;
            }
            if (constrIndex != -1) {
                // If we found a CONSTRUCTOR, is it a StringBuilder?
                ConstructorInsn constr = (ConstructorInsn) chain.get(constrIndex);
                if (constr.getClassType().getFullName().equals(Consts.CLASS_STRING_BUILDER)) {
                    int len = chain.size(), argInd = 1;
                    InsnNode concatInsn = new InsnNode(InsnType.STR_CONCAT, len - 1);
                    InsnNode argInsn;
                    if (constrIndex > 0) {
                        // There was an arg to the StringBuilder constr
                        InsnWrapArg iwa;
                        if (constrIndex == 2 && (argInsn = chain.get(1)).getType() == InsnType.INVOKE && ((InvokeNode) argInsn).getCallMth().getName().compareTo("valueOf") == 0) {
                            // The argument of new StringBuilder() is a String.valueOf(chainElement0)
                            iwa = (InsnWrapArg) argInsn.getArg(0);
                            // Cause for loop below to skip to after the constructor
                            argInd = 3;
                        } else {
                            InsnNode firstNode = chain.get(0);
                            if (firstNode instanceof ConstStringNode) {
                                ConstStringNode csn = (ConstStringNode) firstNode;
                                iwa = new InsnWrapArg(csn);
                                // Cause for loop below to skip to after the constructor
                                argInd = 2;
                            } else {
                                return null;
                            }
                        }
                        concatInsn.addArg(iwa);
                    }
                    for (; argInd < len; argInd++) {
                        // Add the .append(xxx) arg string to concat
                        concatInsn.addArg(chain.get(argInd).getArg(1));
                    }
                    concatInsn.setResult(insn.getResult());
                    return concatInsn;
                }
            // end of if constructor is for StringBuilder
            }
        // end of if we found a constructor early in the chain
        } catch (Throwable e) {
            LOG.debug("Can't convert string concatenation: {} insn: {}", mth, insn, e);
        }
    }
    return null;
}
Also used : IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) ConstStringNode(jadx.core.dex.instructions.ConstStringNode) MethodInfo(jadx.core.dex.info.MethodInfo) InsnWrapArg(jadx.core.dex.instructions.args.InsnWrapArg) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Example 2 with ConstStringNode

use of jadx.core.dex.instructions.ConstStringNode in project jadx by skylot.

the class InsnUtils method getConstValueByInsn.

/**
	 * Return constant value from insn or null if not constant.
	 *
	 * @return LiteralArg, String, ArgType or null
	 */
@Nullable
public static Object getConstValueByInsn(DexNode dex, InsnNode insn) {
    switch(insn.getType()) {
        case CONST:
            return insn.getArg(0);
        case CONST_STR:
            return ((ConstStringNode) insn).getString();
        case CONST_CLASS:
            return ((ConstClassNode) insn).getClsType();
        case SGET:
            FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
            FieldNode fieldNode = dex.resolveField(f);
            if (fieldNode != null) {
                FieldInitAttr attr = fieldNode.get(AType.FIELD_INIT);
                if (attr != null) {
                    return attr.getValue();
                }
            } else {
                LOG.warn("Field {} not found in dex {}", f, dex);
            }
            break;
    }
    return null;
}
Also used : FieldNode(jadx.core.dex.nodes.FieldNode) ConstStringNode(jadx.core.dex.instructions.ConstStringNode) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) FieldInfo(jadx.core.dex.info.FieldInfo) FieldInitAttr(jadx.core.dex.nodes.parser.FieldInitAttr) Nullable(org.jetbrains.annotations.Nullable)

Example 3 with ConstStringNode

use of jadx.core.dex.instructions.ConstStringNode in project jadx by skylot.

the class InsnGen method makeInsnBody.

private void makeInsnBody(CodeWriter code, InsnNode insn, Set<Flags> state) throws CodegenException {
    switch(insn.getType()) {
        case CONST_STR:
            String str = ((ConstStringNode) insn).getString();
            code.add(mth.dex().root().getStringUtils().unescapeString(str));
            break;
        case CONST_CLASS:
            ArgType clsType = ((ConstClassNode) insn).getClsType();
            useType(code, clsType);
            code.add(".class");
            break;
        case CONST:
            LiteralArg arg = (LiteralArg) insn.getArg(0);
            code.add(lit(arg));
            break;
        case MOVE:
            addArg(code, insn.getArg(0), false);
            break;
        case CHECK_CAST:
        case CAST:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                code.add('(');
                useType(code, (ArgType) ((IndexInsnNode) insn).getIndex());
                code.add(") ");
                addArg(code, insn.getArg(0), true);
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case ARITH:
            makeArith((ArithNode) insn, code, state);
            break;
        case NEG:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                code.add('-');
                addArg(code, insn.getArg(0));
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case RETURN:
            if (insn.getArgsCount() != 0) {
                code.add("return ");
                addArg(code, insn.getArg(0), false);
            } else {
                code.add("return");
            }
            break;
        case BREAK:
            code.add("break");
            LoopLabelAttr labelAttr = insn.get(AType.LOOP_LABEL);
            if (labelAttr != null) {
                code.add(' ').add(mgen.getNameGen().getLoopLabel(labelAttr));
            }
            break;
        case CONTINUE:
            code.add("continue");
            break;
        case THROW:
            code.add("throw ");
            addArg(code, insn.getArg(0), true);
            break;
        case CMP_L:
        case CMP_G:
            code.add('(');
            addArg(code, insn.getArg(0));
            code.add(" > ");
            addArg(code, insn.getArg(1));
            code.add(" ? 1 : (");
            addArg(code, insn.getArg(0));
            code.add(" == ");
            addArg(code, insn.getArg(1));
            code.add(" ? 0 : -1))");
            break;
        case INSTANCE_OF:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                addArg(code, insn.getArg(0));
                code.add(" instanceof ");
                useType(code, (ArgType) ((IndexInsnNode) insn).getIndex());
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case CONSTRUCTOR:
            makeConstructor((ConstructorInsn) insn, code);
            break;
        case INVOKE:
            makeInvoke((InvokeNode) insn, code);
            break;
        case NEW_ARRAY:
            {
                ArgType arrayType = ((NewArrayNode) insn).getArrayType();
                code.add("new ");
                useType(code, arrayType.getArrayRootElement());
                code.add('[');
                addArg(code, insn.getArg(0));
                code.add(']');
                int dim = arrayType.getArrayDimension();
                for (int i = 0; i < dim - 1; i++) {
                    code.add("[]");
                }
                break;
            }
        case ARRAY_LENGTH:
            addArg(code, insn.getArg(0));
            code.add(".length");
            break;
        case FILLED_NEW_ARRAY:
            filledNewArray((FilledNewArrayNode) insn, code);
            break;
        case AGET:
            addArg(code, insn.getArg(0));
            code.add('[');
            addArg(code, insn.getArg(1), false);
            code.add(']');
            break;
        case APUT:
            addArg(code, insn.getArg(0));
            code.add('[');
            addArg(code, insn.getArg(1), false);
            code.add("] = ");
            addArg(code, insn.getArg(2), false);
            break;
        case IGET:
            {
                FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
                instanceField(code, fieldInfo, insn.getArg(0));
                break;
            }
        case IPUT:
            {
                FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
                instanceField(code, fieldInfo, insn.getArg(1));
                code.add(" = ");
                addArg(code, insn.getArg(0), false);
                break;
            }
        case SGET:
            staticField(code, (FieldInfo) ((IndexInsnNode) insn).getIndex());
            break;
        case SPUT:
            FieldInfo field = (FieldInfo) ((IndexInsnNode) insn).getIndex();
            staticField(code, field);
            code.add(" = ");
            addArg(code, insn.getArg(0), false);
            break;
        case STR_CONCAT:
            boolean wrap = state.contains(Flags.BODY_ONLY);
            if (wrap) {
                code.add('(');
            }
            for (Iterator<InsnArg> it = insn.getArguments().iterator(); it.hasNext(); ) {
                addArg(code, it.next());
                if (it.hasNext()) {
                    code.add(" + ");
                }
            }
            if (wrap) {
                code.add(')');
            }
            break;
        case MONITOR_ENTER:
            if (isFallback()) {
                code.add("monitor-enter(");
                addArg(code, insn.getArg(0));
                code.add(')');
            }
            break;
        case MONITOR_EXIT:
            if (isFallback()) {
                code.add("monitor-exit(");
                addArg(code, insn.getArg(0));
                code.add(')');
            }
            break;
        case TERNARY:
            makeTernary((TernaryInsn) insn, code, state);
            break;
        case ONE_ARG:
            addArg(code, insn.getArg(0));
            break;
        /* fallback mode instructions */
        case IF:
            fallbackOnlyInsn(insn);
            IfNode ifInsn = (IfNode) insn;
            code.add("if (");
            addArg(code, insn.getArg(0));
            code.add(' ');
            code.add(ifInsn.getOp().getSymbol()).add(' ');
            addArg(code, insn.getArg(1));
            code.add(") goto ").add(MethodGen.getLabelName(ifInsn.getTarget()));
            break;
        case GOTO:
            fallbackOnlyInsn(insn);
            code.add("goto ").add(MethodGen.getLabelName(((GotoNode) insn).getTarget()));
            break;
        case MOVE_EXCEPTION:
            fallbackOnlyInsn(insn);
            code.add("move-exception");
            break;
        case SWITCH:
            fallbackOnlyInsn(insn);
            SwitchNode sw = (SwitchNode) insn;
            code.add("switch(");
            addArg(code, insn.getArg(0));
            code.add(") {");
            code.incIndent();
            for (int i = 0; i < sw.getCasesCount(); i++) {
                String key = sw.getKeys()[i].toString();
                code.startLine("case ").add(key).add(": goto ");
                code.add(MethodGen.getLabelName(sw.getTargets()[i])).add(';');
            }
            code.startLine("default: goto ");
            code.add(MethodGen.getLabelName(sw.getDefaultCaseOffset())).add(';');
            code.decIndent();
            code.startLine('}');
            break;
        case FILL_ARRAY:
            fallbackOnlyInsn(insn);
            FillArrayNode arrayNode = (FillArrayNode) insn;
            Object data = arrayNode.getData();
            String arrStr;
            if (data instanceof int[]) {
                arrStr = Arrays.toString((int[]) data);
            } else if (data instanceof short[]) {
                arrStr = Arrays.toString((short[]) data);
            } else if (data instanceof byte[]) {
                arrStr = Arrays.toString((byte[]) data);
            } else if (data instanceof long[]) {
                arrStr = Arrays.toString((long[]) data);
            } else {
                arrStr = "?";
            }
            code.add('{').add(arrStr.substring(1, arrStr.length() - 1)).add('}');
            break;
        case NEW_INSTANCE:
            // only fallback - make new instance in constructor invoke
            fallbackOnlyInsn(insn);
            code.add("new ").add(insn.getResult().getType().toString());
            break;
        case PHI:
        case MERGE:
            fallbackOnlyInsn(insn);
            code.add(insn.getType().toString()).add("(");
            for (InsnArg insnArg : insn.getArguments()) {
                addArg(code, insnArg);
                code.add(' ');
            }
            code.add(")");
            break;
        default:
            throw new CodegenException(mth, "Unknown instruction: " + insn.getType());
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) CodegenException(jadx.core.utils.exceptions.CodegenException) LoopLabelAttr(jadx.core.dex.attributes.nodes.LoopLabelAttr) ConstStringNode(jadx.core.dex.instructions.ConstStringNode) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) IfNode(jadx.core.dex.instructions.IfNode) SwitchNode(jadx.core.dex.instructions.SwitchNode) FillArrayNode(jadx.core.dex.instructions.FillArrayNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) FieldInfo(jadx.core.dex.info.FieldInfo) GotoNode(jadx.core.dex.instructions.GotoNode)

Aggregations

ConstStringNode (jadx.core.dex.instructions.ConstStringNode)3 FieldInfo (jadx.core.dex.info.FieldInfo)2 ConstClassNode (jadx.core.dex.instructions.ConstClassNode)2 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)2 LoopLabelAttr (jadx.core.dex.attributes.nodes.LoopLabelAttr)1 MethodInfo (jadx.core.dex.info.MethodInfo)1 FillArrayNode (jadx.core.dex.instructions.FillArrayNode)1 GotoNode (jadx.core.dex.instructions.GotoNode)1 IfNode (jadx.core.dex.instructions.IfNode)1 InvokeNode (jadx.core.dex.instructions.InvokeNode)1 SwitchNode (jadx.core.dex.instructions.SwitchNode)1 ArgType (jadx.core.dex.instructions.args.ArgType)1 InsnArg (jadx.core.dex.instructions.args.InsnArg)1 InsnWrapArg (jadx.core.dex.instructions.args.InsnWrapArg)1 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)1 ConstructorInsn (jadx.core.dex.instructions.mods.ConstructorInsn)1 FieldNode (jadx.core.dex.nodes.FieldNode)1 InsnNode (jadx.core.dex.nodes.InsnNode)1 FieldInitAttr (jadx.core.dex.nodes.parser.FieldInitAttr)1 CodegenException (jadx.core.utils.exceptions.CodegenException)1