Search in sources :

Example 6 with Op

use of com.googlecode.d2j.reader.Op 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 7 with Op

use of com.googlecode.d2j.reader.Op in project dex2jar by pxb1988.

the class Dex2IRConverter method fixExceptionHandlers.

/**
     * issue 63
     * <pre>
     * L1:
     *    STMTs
     * L2:
     *    RETURN
     * L1~L2 > L2 Exception
     * </pre>
     * <p/>
     * fix to
     * <p/>
     * <pre>
     * L1:
     *    STMTs
     * L2:
     *    RETURN
     * L3:
     *    goto L2
     * L1~L2 > L3 Exception
     * </pre>
     */
private void fixExceptionHandlers() {
    if (dexCodeNode.tryStmts == null) {
        return;
    }
    Queue<Integer> q = new LinkedList<>();
    Set<Integer> handlers = new TreeSet<>();
    for (TryCatchNode tcb : dexCodeNode.tryStmts) {
        for (DexLabel h : tcb.handler) {
            int index = indexOf(h);
            // add the next insn after label
            q.add(index + 1);
            handlers.add(index);
        }
    }
    q.add(0);
    Map<Integer, DexLabel> needChange = new HashMap<>();
    BitSet access = new BitSet(insnList.size());
    while (!q.isEmpty()) {
        Integer key = q.poll();
        int index = key;
        if (access.get(index)) {
            continue;
        } else {
            access.set(index);
        }
        if (handlers.contains(key)) {
            // the cfg goes to a exception handler
            needChange.put(key, null);
        }
        DexStmtNode node = insnList.get(key);
        if (node.op == null) {
            q.add(index + 1);
        } else {
            Op op = node.op;
            if (op.canContinue()) {
                q.add(index + 1);
            }
            if (op.canBranch()) {
                JumpStmtNode jump = (JumpStmtNode) node;
                q.add(indexOf(jump.label));
            }
            if (op.canSwitch()) {
                for (DexLabel dexLabel : ((BaseSwitchStmtNode) node).labels) {
                    q.add(indexOf(dexLabel));
                }
            }
        }
    }
    if (needChange.size() > 0) {
        for (TryCatchNode tcb : dexCodeNode.tryStmts) {
            DexLabel[] handler = tcb.handler;
            for (int i = 0; i < handler.length; i++) {
                DexLabel h = handler[i];
                int index = indexOf(h);
                if (needChange.containsKey(index)) {
                    DexLabel n = needChange.get(index);
                    if (n == null) {
                        n = new DexLabel();
                        needChange.put(index, n);
                        DexLabelStmtNode dexStmtNode = new DexLabelStmtNode(n);
                        dexStmtNode.__index = insnList.size();
                        insnList.add(dexStmtNode);
                        labelMap.put(n, dexStmtNode);
                        JumpStmtNode jumpStmtNode = new JumpStmtNode(Op.GOTO, 0, 0, h);
                        jumpStmtNode.__index = insnList.size();
                        insnList.add(jumpStmtNode);
                    }
                    handler[i] = n;
                }
            }
        }
    }
}
Also used : Op(com.googlecode.d2j.reader.Op) TryCatchNode(com.googlecode.d2j.node.TryCatchNode) DexLabel(com.googlecode.d2j.DexLabel)

Example 8 with Op

use of com.googlecode.d2j.reader.Op in project dex2jar by pxb1988.

the class Dex2IRConverter method dfs.

private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, DvmInterpreter<DvmValue> interpreter) {
    currentEmit = preEmit;
    Dex2IrFrame first = initFirstFrame(dexCodeNode, target);
    if (parentCount[0] > 1) {
        merge(first, 0);
    } else {
        frames[0] = first;
    }
    Stack<DexStmtNode> stack = new Stack<>();
    stack.push(insnList.get(0));
    Dex2IrFrame tmp = new Dex2IrFrame(dexCodeNode.totalRegister);
    while (!stack.isEmpty()) {
        DexStmtNode p = stack.pop();
        int index = p.__index;
        if (!access.get(index)) {
            access.set(index);
        } else {
            continue;
        }
        Dex2IrFrame frame = frames[index];
        setCurrentEmit(index);
        if (p instanceof DexLabelStmtNode) {
            emit(getLabel(((DexLabelStmtNode) p).label));
            if (handlers.get(index)) {
                Local ex = newLocal();
                emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;")));
                frame.setTmp(new DvmValue(ex));
            }
        }
        BitSet ex = exBranch[index];
        if (ex != null) {
            for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) {
                merge(frame, i);
                stack.push(insnList.get(i));
            }
        }
        tmp.init(frame);
        try {
            if (p.op != null) {
                switch(p.op) {
                    case RETURN_VOID:
                        emit(nReturnVoid());
                        break;
                    case GOTO:
                    case GOTO_16:
                    case GOTO_32:
                        emit(nGoto(getLabel(((JumpStmtNode) p).label)));
                        break;
                    case NOP:
                        emit(nNop());
                        break;
                    case BAD_OP:
                        emit(nThrow(nInvokeNew(new Value[] { nString("bad dex opcode") }, new String[] { "Ljava/lang/String;" }, "Ljava/lang/VerifyError;")));
                        break;
                    default:
                        tmp.execute(p, interpreter);
                        break;
                }
            }
        } catch (Exception exception) {
            throw new RuntimeException("Fail on Op " + p.op + " index " + index, exception);
        }
        if (p.op != null) {
            Op op = p.op;
            if (op.canBranch()) {
                JumpStmtNode jump = (JumpStmtNode) p;
                int targetIndex = indexOf(jump.label);
                stack.push(insnList.get(targetIndex));
                merge(tmp, targetIndex);
            }
            if (op.canSwitch()) {
                BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p;
                for (DexLabel label : switchStmtNode.labels) {
                    int targetIndex = indexOf(label);
                    stack.push(insnList.get(targetIndex));
                    merge(tmp, targetIndex);
                }
            }
            if (op.canContinue()) {
                stack.push(insnList.get(index + 1));
                merge(tmp, index + 1);
            }
        } else {
            stack.push(insnList.get(index + 1));
            merge(tmp, index + 1);
        }
        // cleanup frame it is useless
        if (parentCount[index] <= 1) {
            frames[index] = null;
        }
    }
}
Also used : Op(com.googlecode.d2j.reader.Op) Local(com.googlecode.dex2jar.ir.expr.Local) DexLabel(com.googlecode.d2j.DexLabel)

Aggregations

Op (com.googlecode.d2j.reader.Op)8 DexCodeVisitor (com.googlecode.d2j.visitors.DexCodeVisitor)4 HashMap (java.util.HashMap)4 DexLabel (com.googlecode.d2j.DexLabel)3 Method (com.googlecode.d2j.Method)3 Field (com.googlecode.d2j.Field)2 DexMethodNode (com.googlecode.d2j.node.DexMethodNode)2 DexClassVisitor (com.googlecode.d2j.visitors.DexClassVisitor)2 DexMethodVisitor (com.googlecode.d2j.visitors.DexMethodVisitor)2 Local (com.googlecode.dex2jar.ir.expr.Local)2 DexType (com.googlecode.d2j.DexType)1 DexFileWriter (com.googlecode.d2j.dex.writer.DexFileWriter)1 DexCodeNode (com.googlecode.d2j.node.DexCodeNode)1 DexFieldNode (com.googlecode.d2j.node.DexFieldNode)1 TryCatchNode (com.googlecode.d2j.node.TryCatchNode)1 DvmInterpreter (com.googlecode.d2j.node.analysis.DvmInterpreter)1 DexFileReader (com.googlecode.d2j.reader.DexFileReader)1 SmaliBaseVisitor (com.googlecode.d2j.smali.antlr4.SmaliBaseVisitor)1 SmaliParser (com.googlecode.d2j.smali.antlr4.SmaliParser)1 DexFileVisitor (com.googlecode.d2j.visitors.DexFileVisitor)1