Search in sources :

Example 1 with DexClassVisitor

use of com.googlecode.d2j.visitors.DexClassVisitor in project dex2jar by pxb1988.

the class DexWeaver method buildInvocationClz.

public String buildInvocationClz(DexFileVisitor dfv) {
    String typeName = getCurrentInvocationName();
    String typeNameDesc = "L" + typeName + ";";
    DexClassVisitor dcv = dfv.visit(DexConstants.ACC_PUBLIC, typeNameDesc, "Ljava/lang/Object;", new String[] { invocationInterfaceDesc });
    dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"), null).visitEnd();
    dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"), null).visitEnd();
    dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL, new Field(typeNameDesc, "idx", "I"), null).visitEnd();
    {
        DexMethodVisitor mv = dcv.visitMethod(DexConstants.ACC_PUBLIC | DexConstants.ACC_CONSTRUCTOR, new Method(typeNameDesc, "<init>", new String[] { "Ljava/lang/Object;", "[Ljava/lang/Object;", "I" }, "V"));
        DexCodeVisitor codeVisitor = mv.visitCode();
        codeVisitor.visitRegister(4);
        codeVisitor.visitFieldStmt(Op.IPUT_OBJECT, 1, 0, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
        codeVisitor.visitFieldStmt(Op.IPUT_OBJECT, 2, 0, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
        codeVisitor.visitFieldStmt(Op.IPUT, 3, 0, new Field(typeNameDesc, "idx", "I"));
        codeVisitor.visitStmt0R(Op.RETURN_VOID);
        codeVisitor.visitEnd();
        mv.visitEnd();
    }
    {
        genSwitchMethod(dcv, typeNameDesc, "getMethodOwner", new CB() {

            @Override
            public String getKey(Method mtd) {
                return toInternal(mtd.getOwner());
            }
        });
        genSwitchMethod(dcv, typeNameDesc, "getMethodName", new CB() {

            @Override
            public String getKey(Method mtd) {
                return mtd.getName();
            }
        });
        genSwitchMethod(dcv, typeNameDesc, "getMethodDesc", new CB() {

            @Override
            public String getKey(Method mtd) {
                return mtd.getDesc();
            }
        });
    }
    {
        DexMethodVisitor mv = dcv.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "getArguments", new String[0], "[Ljava/lang/Object;"));
        DexCodeVisitor code = mv.visitCode();
        code.visitRegister(2);
        code.visitFieldStmt(Op.IGET, 0, 1, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
        code.visitStmt1R(Op.RETURN_OBJECT, 0);
        code.visitEnd();
        mv.visitEnd();
    }
    {
        DexMethodVisitor mv = dcv.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "getThis", new String[0], "Ljava/lang/Object;"));
        DexCodeVisitor code = mv.visitCode();
        code.visitRegister(2);
        code.visitFieldStmt(Op.IGET, 0, 1, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
        code.visitStmt1R(Op.RETURN_OBJECT, 0);
        code.visitEnd();
        mv.visitEnd();
    }
    {
        DexMethodVisitor mv = dcv.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "proceed", new String[0], "Ljava/lang/Object;"));
        DexCodeVisitor code = mv.visitCode();
        code.visitRegister(4);
        code.visitFieldStmt(Op.IGET, 0, 3, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
        code.visitFieldStmt(Op.IGET, 1, 3, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
        code.visitFieldStmt(Op.IGET, 2, 3, new Field(typeNameDesc, "idx", "I"));
        DexLabel[] labels = new DexLabel[callbacks.size()];
        for (int i = 0; i < labels.length; i++) {
            labels[i] = new DexLabel();
        }
        code.visitPackedSwitchStmt(Op.PACKED_SWITCH, 2, 0, labels);
        code.visitTypeStmt(Op.NEW_INSTANCE, 0, 0, "Ljava/lang/RuntimeException;");
        code.visitConstStmt(Op.CONST_STRING, 1, "invalid idx");
        code.visitMethodStmt(Op.INVOKE_DIRECT, new int[] { 0, 1 }, new Method("Ljava/lang/RuntimeException;", "<init>", new String[] { "Ljava/lang/String;" }, "V"));
        code.visitStmt1R(Op.THROW, 0);
        for (int i = 0; i < labels.length; i++) {
            code.visitLabel(labels[i]);
            Callback callback = callbacks.get(i);
            Method mCallback = (Method) callback.callback;
            if (callback.isStatic) {
                code.visitMethodStmt(Op.INVOKE_STATIC, new int[] { 1 }, mCallback);
            } else if (callback.isSpecial) {
                code.visitTypeStmt(Op.CHECK_CAST, 0, -1, mCallback.getOwner());
                code.visitMethodStmt(Op.INVOKE_VIRTUAL, new int[] { 0, 1 }, mCallback);
            } else {
                code.visitMethodStmt(Op.INVOKE_STATIC, new int[] { 0, 1 }, mCallback);
            }
            code.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
            code.visitStmt1R(Op.RETURN_OBJECT, 0);
        }
        code.visitEnd();
        mv.visitEnd();
    }
    dcv.visitEnd();
    return typeName;
}
Also used : Field(com.googlecode.d2j.Field) DexCodeVisitor(com.googlecode.d2j.visitors.DexCodeVisitor) DexLabel(com.googlecode.d2j.DexLabel) Method(com.googlecode.d2j.Method) DexClassVisitor(com.googlecode.d2j.visitors.DexClassVisitor) DexMethodVisitor(com.googlecode.d2j.visitors.DexMethodVisitor)

Example 2 with DexClassVisitor

use of com.googlecode.d2j.visitors.DexClassVisitor in project dex2jar by pxb1988.

the class AsmfierTest method test.

@Test
public void test() {
    ASMifierFileV fv = new ASMifierFileV(new File("target/asmftest").toPath(), "a.b");
    DexClassVisitor cv = fv.visit(ACC_PUBLIC, "La/f;", "Ljava/lang/Object;", null);
    DexFieldVisitor f2v = cv.visitField(ACC_PUBLIC, new Field("La/f;", "abc", "I"), null);
    f2v.visitEnd();
    DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La/f;", "zz", new String[0], "I"));
    DexAnnotationAble pv = mv.visitParameterAnnotation(2);
    DexAnnotationVisitor dav = pv.visitAnnotation("Leeeff;", Visibility.BUILD);
    dav.visitEnd();
    DexCodeVisitor dcv = mv.visitCode();
    dcv.visitConstStmt(Op.FILL_ARRAY_DATA, 0, new int[] { 1, 2, 3 });
    dcv.visitStmt0R(Op.RETURN_VOID);
    dcv.visitEnd();
    mv.visitEnd();
    cv.visitEnd();
    fv.visitEnd();
}
Also used : Field(com.googlecode.d2j.Field) ASMifierFileV(com.googlecode.d2j.util.ASMifierFileV) DexAnnotationAble(com.googlecode.d2j.visitors.DexAnnotationAble) DexFieldVisitor(com.googlecode.d2j.visitors.DexFieldVisitor) DexAnnotationVisitor(com.googlecode.d2j.visitors.DexAnnotationVisitor) DexCodeVisitor(com.googlecode.d2j.visitors.DexCodeVisitor) Method(com.googlecode.d2j.Method) DexClassVisitor(com.googlecode.d2j.visitors.DexClassVisitor) File(java.io.File) DexMethodVisitor(com.googlecode.d2j.visitors.DexMethodVisitor) Test(org.junit.Test)

Example 3 with DexClassVisitor

use of com.googlecode.d2j.visitors.DexClassVisitor in project dex2jar by pxb1988.

the class DexWeaverCmd method doCommandLine.

@Override
protected void doCommandLine() throws Exception {
    if (remainingArgs.length == 0) {
        throw new HelpException("no odex");
    }
    final Map<String, Method> map = new HashMap<>();
    for (String ln : Files.readAllLines(config, StandardCharsets.UTF_8)) {
        if (ln.startsWith("#") || ln.length() == 0) {
            continue;
        }
        String[] x = ln.split("=");
        map.put(x[0], parseMethod(x[1]));
    }
    DexFileWriter out = new DexFileWriter();
    DexFileVisitor fv = new DexFileVisitor(out) {

        @Override
        public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) {
            DexClassVisitor dcv = super.visit(access_flags, className, superClass, interfaceNames);
            if (dcv != null) {
                return new DexClassVisitor(dcv) {

                    @Override
                    public DexMethodVisitor visitMethod(int accessFlags, Method method) {
                        DexMethodVisitor dmv = super.visitMethod(accessFlags, method);
                        if (dmv != null) {
                            return new DexMethodVisitor(dmv) {

                                @Override
                                public DexCodeVisitor visitCode() {
                                    DexCodeVisitor code = super.visitCode();
                                    if (code != null) {
                                        return new DexCodeVisitor(code) {

                                            @Override
                                            public void visitMethodStmt(Op op, int[] args, Method method) {
                                                Method replaceTo = map.get(method.toString());
                                                if (replaceTo != null) {
                                                    switch(op) {
                                                        case INVOKE_DIRECT:
                                                        case INVOKE_INTERFACE:
                                                        case INVOKE_STATIC:
                                                        case INVOKE_SUPER:
                                                        case INVOKE_VIRTUAL:
                                                            super.visitMethodStmt(Op.INVOKE_STATIC, args, replaceTo);
                                                            break;
                                                        case INVOKE_DIRECT_RANGE:
                                                        case INVOKE_INTERFACE_RANGE:
                                                        case INVOKE_STATIC_RANGE:
                                                        case INVOKE_SUPER_RANGE:
                                                        case INVOKE_VIRTUAL_RANGE:
                                                            super.visitMethodStmt(Op.INVOKE_STATIC_RANGE, args, replaceTo);
                                                            break;
                                                        default:
                                                    }
                                                } else {
                                                    super.visitMethodStmt(op, args, method);
                                                }
                                            }
                                        };
                                    }
                                    return code;
                                }
                            };
                        }
                        return dmv;
                    }
                };
            }
            return dcv;
        }

        @Override
        public void visitEnd() {
        }
    };
    for (String f : remainingArgs) {
        byte[] data = ZipUtil.readDex(new File(f).toPath());
        DexFileReader r = new DexFileReader(data);
        r.accept(fv);
    }
    if (stub != null) {
        byte[] data = ZipUtil.readDex(stub);
        DexFileReader r = new DexFileReader(data);
        r.accept(new DexFileVisitor(out) {

            @Override
            public void visitEnd() {
            }
        });
    }
    out.visitEnd();
    byte[] data = out.toByteArray();
    Files.write(output, data);
}
Also used : Op(com.googlecode.d2j.reader.Op) HashMap(java.util.HashMap) DexFileWriter(com.googlecode.d2j.dex.writer.DexFileWriter) DexFileReader(com.googlecode.d2j.reader.DexFileReader) Method(com.googlecode.d2j.Method) DexFileVisitor(com.googlecode.d2j.visitors.DexFileVisitor) DexCodeVisitor(com.googlecode.d2j.visitors.DexCodeVisitor) DexClassVisitor(com.googlecode.d2j.visitors.DexClassVisitor) File(java.io.File) DexMethodVisitor(com.googlecode.d2j.visitors.DexMethodVisitor)

Example 4 with DexClassVisitor

use of com.googlecode.d2j.visitors.DexClassVisitor 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 5 with DexClassVisitor

use of com.googlecode.d2j.visitors.DexClassVisitor in project dex2jar by pxb1988.

the class DexClassNode method accept.

public void accept(DexFileVisitor dfv) {
    DexClassVisitor dcv = dfv.visit(access, className, superClass, interfaceNames);
    if (dcv != null) {
        accept(dcv);
        dcv.visitEnd();
    }
}
Also used : DexClassVisitor(com.googlecode.d2j.visitors.DexClassVisitor)

Aggregations

DexClassVisitor (com.googlecode.d2j.visitors.DexClassVisitor)5 Method (com.googlecode.d2j.Method)4 DexCodeVisitor (com.googlecode.d2j.visitors.DexCodeVisitor)4 DexMethodVisitor (com.googlecode.d2j.visitors.DexMethodVisitor)4 Field (com.googlecode.d2j.Field)2 Op (com.googlecode.d2j.reader.Op)2 File (java.io.File)2 HashMap (java.util.HashMap)2 DexLabel (com.googlecode.d2j.DexLabel)1 DexFileWriter (com.googlecode.d2j.dex.writer.DexFileWriter)1 DexCodeNode (com.googlecode.d2j.node.DexCodeNode)1 DexMethodNode (com.googlecode.d2j.node.DexMethodNode)1 DexFileReader (com.googlecode.d2j.reader.DexFileReader)1 ASMifierFileV (com.googlecode.d2j.util.ASMifierFileV)1 DexAnnotationAble (com.googlecode.d2j.visitors.DexAnnotationAble)1 DexAnnotationVisitor (com.googlecode.d2j.visitors.DexAnnotationVisitor)1 DexFieldVisitor (com.googlecode.d2j.visitors.DexFieldVisitor)1 DexFileVisitor (com.googlecode.d2j.visitors.DexFileVisitor)1 Test (org.junit.Test)1