Search in sources :

Example 1 with DexMethodNode

use of com.googlecode.d2j.node.DexMethodNode in project dex2jar by pxb1988.

the class DexFix method fixStaticFinalFieldValue.

/**
     * init value to default if the field is static and final, and the field is not init in clinit method
     *
     * erase the default value if the field is init in clinit method
     * 
     * @param classNode
     */
public static void fixStaticFinalFieldValue(final DexClassNode classNode) {
    if (classNode.fields == null) {
        return;
    }
    final Map<String, DexFieldNode> fs = new HashMap<>();
    final Map<String, DexFieldNode> shouldNotBeAssigned = new HashMap<>();
    for (DexFieldNode fn : classNode.fields) {
        if ((fn.access & ACC_STATIC_FINAL) == ACC_STATIC_FINAL) {
            if (fn.cst == null) {
                char t = fn.field.getType().charAt(0);
                if (t == 'L' || t == '[') {
                    // ignore Object
                    continue;
                }
                fs.put(fn.field.getName() + ":" + fn.field.getType(), fn);
            } else if (isPrimitiveZero(fn.field.getType(), fn.cst)) {
                shouldNotBeAssigned.put(fn.field.getName() + ":" + fn.field.getType(), fn);
            }
        }
    }
    if (fs.isEmpty() && shouldNotBeAssigned.isEmpty()) {
        return;
    }
    DexMethodNode node = null;
    if (classNode.methods != null) {
        for (DexMethodNode mn : classNode.methods) {
            if (mn.method.getName().equals("<clinit>")) {
                node = mn;
                break;
            }
        }
    }
    if (node != null) {
        if (node.codeNode != null) {
            node.codeNode.accept(new DexCodeVisitor() {

                @Override
                public void visitFieldStmt(Op op, int a, int b, Field field) {
                    switch(op) {
                        case SPUT:
                        case SPUT_BOOLEAN:
                        case SPUT_BYTE:
                        case SPUT_CHAR:
                        case SPUT_OBJECT:
                        case SPUT_SHORT:
                        case SPUT_WIDE:
                            if (field.getOwner().equals(classNode.className)) {
                                String key = field.getName() + ":" + field.getType();
                                fs.remove(key);
                                DexFieldNode dn = shouldNotBeAssigned.get(key);
                                if (dn != null) {
                                    //System.out.println(field.getName() + ":" + field.getType());
                                    dn.cst = null;
                                }
                            }
                            break;
                        default:
                            // ignored
                            break;
                    }
                }
            });
        } else {
            // has init but no code
            return;
        }
    }
    for (DexFieldNode fn : fs.values()) {
        fn.cst = getDefaultValueOfType(fn.field.getType().charAt(0));
    }
}
Also used : Op(com.googlecode.d2j.reader.Op) Field(com.googlecode.d2j.Field) HashMap(java.util.HashMap) DexFieldNode(com.googlecode.d2j.node.DexFieldNode) DexMethodNode(com.googlecode.d2j.node.DexMethodNode) DexCodeVisitor(com.googlecode.d2j.visitors.DexCodeVisitor)

Example 2 with DexMethodNode

use of com.googlecode.d2j.node.DexMethodNode in project dex2jar by pxb1988.

the class BaksmaliBaseDexExceptionHandler method dumpTxt0.

private void dumpTxt0(BufferedWriter writer, String[] originalArgs) throws IOException {
    dumpSummary(originalArgs, writer);
    int i = 0;
    for (Map.Entry<DexMethodNode, Exception> e : exceptionMap.entrySet()) {
        DexMethodNode dexMethodNode = e.getKey();
        Exception ex = e.getValue();
        writer.newLine();
        writer.write("================= " + i++ + " ===================");
        writer.newLine();
        dumpMethod(writer, dexMethodNode, ex);
    }
}
Also used : DexMethodNode(com.googlecode.d2j.node.DexMethodNode) IOException(java.io.IOException)

Example 3 with DexMethodNode

use of com.googlecode.d2j.node.DexMethodNode in project dex2jar by pxb1988.

the class DexWeaver method wrap.

public DexClassVisitor wrap(final String classNameDesc, final DexClassVisitor dcv) {
    return dcv == null ? null : new DexClassVisitor(dcv) {

        Map<MtdInfo, Method> cache = new HashMap<>();

        @Override
        public DexMethodVisitor visitMethod(final int accessFlags, Method method) {
            final DexMethodVisitor dmv = superVisitDexMethod(accessFlags, method);
            final MtdInfo mapTo = findDefinedTargetMethod(method.getOwner(), method.getName(), method.getDesc());
            if (mapTo != null) {
                final Method t = new Method(method.getOwner(), buildMethodAName(method.getName()), method.getParameterTypes(), method.getReturnType());
                final Method src = method;
                return new DexMethodNode(accessFlags, method) {

                    @Override
                    public void visitEnd() {
                        super.visitEnd();
                        DexCodeNode code = this.codeNode;
                        this.codeNode = null;
                        accept(dmv);
                        Op opcode;
                        if (Modifier.isStatic(access)) {
                            opcode = Op.INVOKE_STATIC_RANGE;
                        } else {
                            opcode = Op.INVOKE_VIRTUAL_RANGE;
                        }
                        generateMtdACode(opcode, t, mapTo, dmv, src);
                        // make sure public
                        int newAccess = (access & ~(DexConstants.ACC_PRIVATE | DexConstants.ACC_PROTECTED)) | DexConstants.ACC_PUBLIC;
                        code.accept(wrap(superVisitDexMethod(newAccess, t), dcv));
                    }
                };
            } else {
                return wrap(dmv, dcv);
            }
        }

        private DexMethodVisitor wrap(DexMethodVisitor dmv, final DexClassVisitor classVisitor) {
            return dmv == null ? null : new DexMethodVisitor(dmv) {

                @Override
                public DexCodeVisitor visitCode() {
                    return wrap(super.visitCode(), classVisitor);
                }
            };
        }

        private DexCodeVisitor wrap(DexCodeVisitor dcv, final DexClassVisitor classVisitor) {
            return dcv == null ? null : new DexCodeVisitor(dcv) {

                @Override
                public void visitMethodStmt(Op op, int[] args, Method method) {
                    MtdInfo mapTo = findTargetMethod(method.getOwner(), method.getName(), method.getDesc());
                    if (mapTo != null) {
                        Method methodA = cache.get(buildKey(method.getOwner(), method.getName(), method.getDesc()));
                        if (methodA == null) {
                            if (isStatic(op)) {
                                methodA = new Method(classNameDesc, buildMethodAName(method.getName()), method.getParameterTypes(), method.getReturnType());
                            } else {
                                methodA = new Method(classNameDesc, buildMethodAName(method.getName()), join(method.getOwner(), method.getParameterTypes()), method.getReturnType());
                            }
                            DexMethodVisitor dmv = classVisitor.visitMethod(DexConstants.ACC_PRIVATE | DexConstants.ACC_STATIC, methodA);
                            generateMtdACode(op, method, mapTo, dmv, method);
                            dmv.visitEnd();
                            cache.put(buildKey(method.getOwner(), method.getName(), method.getDesc()), methodA);
                        }
                        super.visitMethodStmt(isRange(op) ? Op.INVOKE_STATIC_RANGE : Op.INVOKE_STATIC, args, methodA);
                    } else {
                        super.visitMethodStmt(op, args, method);
                    }
                }
            };
        }

        private void generateMtdACode(Op opcode, Method t, MtdInfo mapTo, DexMethodVisitor dmv, Method src) {
            DexCodeVisitor dcv = dmv.visitCode();
            int countArge = countArgs(t);
            boolean haveThis = haveThis(opcode);
            int registers = 4 + (haveThis ? 1 : 0) + countArge;
            dcv.visitRegister(registers);
            int argStart = 4;
            if (haveThis) {
                dcv.visitStmt2R(Op.MOVE_OBJECT, 0, argStart);
                argStart++;
            } else {
                dcv.visitConstStmt(Op.CONST_4, 0, 0);
            }
            if (t.getParameterTypes().length == 0) {
                dcv.visitConstStmt(Op.CONST_4, 1, 0);
            } else {
                dcv.visitConstStmt(Op.CONST, 1, t.getParameterTypes().length);
                dcv.visitTypeStmt(Op.NEW_ARRAY, 1, 1, "[Ljava/lang/Object;");
                for (int i = 0; i < t.getParameterTypes().length; i++) {
                    char type = t.getParameterTypes()[i].charAt(0);
                    dcv.visitConstStmt(Op.CONST, 2, i);
                    box(type, argStart, 3, dcv);
                    dcv.visitStmt3R(Op.APUT_OBJECT, 3, 1, 2);
                    if (type == 'J' || type == 'D') {
                        argStart += 2;
                    } else {
                        argStart += 1;
                    }
                }
            }
            int nextIdx = callbacks.size();
            dcv.visitConstStmt(Op.CONST, 2, nextIdx);
            String miTypeDesc = "L" + getCurrentInvocationName() + ";";
            dcv.visitTypeStmt(Op.NEW_INSTANCE, 3, 0, miTypeDesc);
            dcv.visitMethodStmt(Op.INVOKE_DIRECT, new int[] { 3, 0, 1, 2 }, new Method(miTypeDesc, "<init>", new String[] { "Ljava/lang/Object;", "[Ljava/lang/Object;", "I" }, "V"));
            Method call = build(mapTo);
            dcv.visitMethodStmt(Op.INVOKE_STATIC, new int[] { 3 }, call);
            if (!"V".equals(t.getReturnType())) {
                switch(call.getReturnType().charAt(0)) {
                    case '[':
                    case 'L':
                        dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
                        break;
                    case 'J':
                    case 'D':
                        dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, 0);
                        break;
                    default:
                        dcv.visitStmt1R(Op.MOVE_RESULT, 0);
                        break;
                }
                unbox(t.getReturnType(), 0, dcv);
                switch(t.getReturnType().charAt(0)) {
                    case '[':
                    case 'L':
                        dcv.visitStmt1R(Op.RETURN_OBJECT, 0);
                        break;
                    case 'J':
                    case 'D':
                        dcv.visitStmt1R(Op.RETURN_WIDE, 0);
                        break;
                    default:
                        dcv.visitStmt1R(Op.RETURN, 0);
                        break;
                }
            } else {
                dcv.visitStmt0R(Op.RETURN_VOID);
            }
            Callback cb = new Callback();
            cb.idx = nextIdx;
            cb.callback = newMethodCallback(opcode, t);
            cb.target = src;
            cb.isSpecial = isSuper(opcode);
            cb.isStatic = isStatic(opcode);
            callbacks.add(cb);
        }

        private Method newMethodCallback(Op opcode, Method t) {
            boolean isStatic = !haveThis(opcode);
            boolean isSuper = isSuper(opcode);
            Method m;
            if (isSuper || isStatic) {
                m = new Method(t.getOwner(), buildCallbackMethodName(t.getName()), new String[] { "[Ljava/lang/Object;" }, "Ljava/lang/Object;");
            } else {
                m = new Method(t.getOwner(), buildCallbackMethodName(t.getName()), new String[] { "Ljava/lang/Object;", "[Ljava/lang/Object;" }, "Ljava/lang/Object;");
            }
            DexMethodVisitor dmv = superVisitDexMethod(DexConstants.ACC_PUBLIC | (isSuper ? 0 : DexConstants.ACC_STATIC), m);
            DexCodeVisitor dcv = dmv.visitCode();
            int totalRegs;
            int argStart;
            if (isStatic) {
                totalRegs = 1 + countArgs(t) + 1;
                argStart = totalRegs - 1;
            } else {
                totalRegs = 1 + countArgs(t) + 2;
                argStart = totalRegs - 2;
            }
            dcv.visitRegister(totalRegs);
            int[] args = new int[countArgs(t) + (isStatic ? 0 : 1)];
            int args_index = 0;
            int i = 1;
            if (!isStatic) {
                if (i != argStart) {
                    dcv.visitStmt2R(Op.MOVE_OBJECT, i, argStart);
                }
                if (!isSuper) {
                    dcv.visitTypeStmt(Op.CHECK_CAST, i, -1, t.getOwner());
                }
                args[args_index++] = i;
                i++;
                argStart++;
            }
            String[] parameterTypes = t.getParameterTypes();
            for (int i1 = 0; i1 < parameterTypes.length; i1++) {
                String argType = parameterTypes[i1];
                dcv.visitConstStmt(Op.CONST, 0, i1);
                dcv.visitStmt3R(Op.AGET_OBJECT, i, argStart, 0);
                unbox(argType, i, dcv);
                args[args_index++] = i;
                if (argType.charAt(0) == 'J' || argType.charAt(0) == 'D') {
                    args[args_index++] = i + 1;
                    i += 2;
                } else {
                    i += 1;
                }
            }
            dcv.visitMethodStmt(opcode, args, t);
            if ("V".equals(t.getReturnType())) {
                dcv.visitConstStmt(Op.CONST, 0, 0);
            } else {
                switch(t.getReturnType().charAt(0)) {
                    case '[':
                    case 'L':
                        dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
                        break;
                    case 'J':
                    case 'D':
                        dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, 0);
                        break;
                    default:
                        dcv.visitStmt1R(Op.MOVE_RESULT, 0);
                        break;
                }
                box(t.getReturnType().charAt(0), 0, 0, dcv);
            }
            dcv.visitStmt1R(Op.RETURN_OBJECT, 0);
            return m;
        }

        private DexMethodVisitor superVisitDexMethod(int accessFlags, Method method) {
            return super.visitMethod(accessFlags, method);
        }
    };
}
Also used : Op(com.googlecode.d2j.reader.Op) HashMap(java.util.HashMap) Method(com.googlecode.d2j.Method) DexCodeNode(com.googlecode.d2j.node.DexCodeNode) DexMethodNode(com.googlecode.d2j.node.DexMethodNode) DexCodeVisitor(com.googlecode.d2j.visitors.DexCodeVisitor) DexClassVisitor(com.googlecode.d2j.visitors.DexClassVisitor) DexMethodVisitor(com.googlecode.d2j.visitors.DexMethodVisitor)

Example 4 with DexMethodNode

use of com.googlecode.d2j.node.DexMethodNode in project dex2jar by pxb1988.

the class Dex2jar method doTranslate.

private void doTranslate(final Path dist) throws IOException {
    DexFileNode fileNode = new DexFileNode();
    try {
        reader.accept(fileNode, readerConfig | DexFileReader.IGNORE_READ_EXCEPTION);
    } catch (Exception ex) {
        exceptionHandler.handleFileException(ex);
    }
    ClassVisitorFactory cvf = new ClassVisitorFactory() {

        @Override
        public ClassVisitor create(final String name) {
            return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {

                @Override
                public void visitEnd() {
                    super.visitEnd();
                    ClassWriter cw = (ClassWriter) super.cv;
                    byte[] data;
                    try {
                        // FIXME handle 'java.lang.RuntimeException: Method code too large!'
                        data = cw.toByteArray();
                    } catch (Exception ex) {
                        System.err.println(String.format("ASM fail to generate .class file: %s", name));
                        exceptionHandler.handleFileException(ex);
                        return;
                    }
                    try {
                        Path dist1 = dist.resolve(name + ".class");
                        Path parent = dist1.getParent();
                        if (parent != null && !Files.exists(parent)) {
                            Files.createDirectories(parent);
                        }
                        Files.write(dist1, data);
                    } catch (IOException e) {
                        e.printStackTrace(System.err);
                    }
                }
            };
        }
    };
    new ExDex2Asm(exceptionHandler) {

        public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
            if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("<clinit>")) {
                // also skip clinit
                return;
            }
            super.convertCode(methodNode, mv);
        }

        @Override
        public void optimize(IrMethod irMethod) {
            T_cleanLabel.transform(irMethod);
            if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
            // T_topologicalSort.transform(irMethod);
            }
            T_deadCode.transform(irMethod);
            T_removeLocal.transform(irMethod);
            T_removeConst.transform(irMethod);
            T_zero.transform(irMethod);
            if (T_npe.transformReportChanged(irMethod)) {
                T_deadCode.transform(irMethod);
                T_removeLocal.transform(irMethod);
                T_removeConst.transform(irMethod);
            }
            T_new.transform(irMethod);
            T_fillArray.transform(irMethod);
            T_agg.transform(irMethod);
            T_multiArray.transform(irMethod);
            T_voidInvoke.transform(irMethod);
            if (0 != (v3Config & V3.PRINT_IR)) {
                int i = 0;
                for (Stmt p : irMethod.stmts) {
                    if (p.st == Stmt.ST.LABEL) {
                        LabelStmt labelStmt = (LabelStmt) p;
                        labelStmt.displayName = "L" + i++;
                    }
                }
                System.out.println(irMethod);
            }
            T_type.transform(irMethod);
            T_unssa.transform(irMethod);
            T_ir2jRegAssign.transform(irMethod);
            T_trimEx.transform(irMethod);
        }

        @Override
        public void ir2j(IrMethod irMethod, MethodVisitor mv) {
            new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
        }
    }.convertDex(fileNode, cvf);
}
Also used : Path(java.nio.file.Path) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) ClassVisitor(org.objectweb.asm.ClassVisitor) IOException(java.io.IOException) IrMethod(com.googlecode.dex2jar.ir.IrMethod) IOException(java.io.IOException) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt) DexMethodNode(com.googlecode.d2j.node.DexMethodNode) DexFileNode(com.googlecode.d2j.node.DexFileNode) IR2JConverter(com.googlecode.d2j.converter.IR2JConverter)

Example 5 with DexMethodNode

use of com.googlecode.d2j.node.DexMethodNode in project dex2jar by pxb1988.

the class ExDex2Asm method convertCode.

@Override
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
    if (!AsmBridge.isMethodWriter(mv)) {
        throw new RuntimeException("We use a MethodWriter tricky here!");
    }
    MethodNode mn = new MethodNode(Opcodes.ASM4, methodNode.access, methodNode.method.getName(), methodNode.method.getDesc(), null, null);
    try {
        super.convertCode(methodNode, mn);
    } catch (Exception ex) {
        if (exceptionHandler == null) {
            throw new DexException(ex, "fail convert code for %s", methodNode.method);
        } else {
            mn.instructions.clear();
            mn.tryCatchBlocks.clear();
            exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex);
        }
    }
    // code convert ok, copy to MethodWriter and check for Size
    mn.accept(mv);
    try {
        AsmBridge.sizeOfMethodWriter(mv);
    } catch (Exception ex) {
        mn.instructions.clear();
        mn.tryCatchBlocks.clear();
        exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex);
        AsmBridge.replaceMethodWriter(mv, mn);
    }
}
Also used : DexException(com.googlecode.d2j.DexException) MethodNode(org.objectweb.asm.tree.MethodNode) DexMethodNode(com.googlecode.d2j.node.DexMethodNode) DexException(com.googlecode.d2j.DexException)

Aggregations

DexMethodNode (com.googlecode.d2j.node.DexMethodNode)6 DexException (com.googlecode.d2j.DexException)2 Op (com.googlecode.d2j.reader.Op)2 DexCodeVisitor (com.googlecode.d2j.visitors.DexCodeVisitor)2 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 ClassWriter (org.objectweb.asm.ClassWriter)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 DirectClassFile (com.android.dx.cf.direct.DirectClassFile)1 StdAttributeFactory (com.android.dx.cf.direct.StdAttributeFactory)1 DexOptions (com.android.dx.dex.DexOptions)1 CfOptions (com.android.dx.dex.cf.CfOptions)1 Field (com.googlecode.d2j.Field)1 Method (com.googlecode.d2j.Method)1 IR2JConverter (com.googlecode.d2j.converter.IR2JConverter)1 ClassVisitorFactory (com.googlecode.d2j.dex.ClassVisitorFactory)1 Dex2Asm (com.googlecode.d2j.dex.Dex2Asm)1 DexCodeNode (com.googlecode.d2j.node.DexCodeNode)1 DexFieldNode (com.googlecode.d2j.node.DexFieldNode)1 DexFileNode (com.googlecode.d2j.node.DexFileNode)1