@Override public void execute(AbstractInsnNode insn, Interpreter<JvmValue> interpreter) throws AnalyzerException { if (insn.getType() == AbstractInsnNode.FRAME || insn.getType() == AbstractInsnNode.LINE || insn.getType() == AbstractInsnNode.LABEL) { return; } if (insn.getOpcode() == Opcodes.RETURN) { interpreter.returnOperation(insn, null, null); } else if (insn.getOpcode() == Opcodes.GOTO) { interpreter.unaryOperation(insn, null); } else if (insn.getOpcode() == RET) { throw new RuntimeException("not support yet!"); } else { super.execute(insn, interpreter); } } }
@Override public void visitEnd() { try { Analyzer analyzer = new Analyzer(new SourceInterpreter()); Frame[] frames = analyzer.analyze(_classToAnalyze, this); int index = findMethodCall(this.instructions); if (index == -1) { return; } Frame f = frames[index]; String fieldDesc = ""; String methodDesc = ""; for (int j = 0; j < f.getStackSize(); ++j) { SourceValue stack = (SourceValue) f.getStack(j); Object insn = stack.insns.iterator().next(); if (insn instanceof FieldInsnNode) { FieldInsnNode fieldInstr = (FieldInsnNode) insn; fieldDesc = fieldInstr.name; } else if (insn instanceof TypeInsnNode) { fieldDesc = Util.getDescriptionForTypeInsnNode((TypeInsnNode) insn); } else if (insn instanceof MethodInsnNode) { methodDesc = Util.getDescriptionForMethodInsnNode((MethodInsnNode) insn); } } _inferredOperation = getInferredOperation(fieldDesc, methodDesc); } catch (AnalyzerException e) { System.out.println("Unable to analyze class, could not infer operation"); } }
@Override public void visitFile(Path file, String relative) throws IOException { if (file.getFileName().toString().endsWith(".class")) { ClassReader cr = new ClassReader(Files.readAllBytes(file)); ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG | ClassReader.EXPAND_FRAMES | ClassReader.SKIP_FRAMES); for (MethodNode method : cn.methods) { BasicVerifier verifier = new BasicVerifier(); Analyzer<BasicValue> a = new Analyzer<>(verifier); try { a.analyze(cn.name, method); } catch (Exception ex) { System.err.println("Error verify method " + cr.getClassName() + "." + method.name + " " + method.desc); if (detail) { ex.printStackTrace(System.err); printAnalyzerResult(method, a, new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8))); } } } } } });
static void printAnalyzerResult(MethodNode method, Analyzer a, final PrintWriter pw) throws IllegalArgumentException { Frame[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString()));
private Frame<BasicValue>[] analyse() throws AnalyzerException { final Analyzer<BasicValue> a = new Analyzer<BasicValue>(new SimpleVerifier()); a.analyze(className, this); return a.getFrames(); }
MethodNode method = (MethodNode) methods.get(i); if (method.instructions.size() > 0) { Analyzer a = new Analyzer(new SimpleVerifier()); try { a.analyze(ca.name, method); continue; } catch (Exception e) {
@Override public BasicValue newValue(Type type) { BasicValue basicValue = super.newValue(type); if (basicValue == BasicValue.REFERENCE_VALUE) { basicValue = new BasicValue(type); // record the exact type and not just "Ljava/lang/Object" } return basicValue; }
@Override public void returnOperation(final AbstractInsnNode insn, final BasicValue value, final BasicValue expected) throws AnalyzerException { if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, "Incompatible return type", expected, value); } }
/** * Constructs a new frame that is identical to the given frame. * * @param src * a frame. */ public Frame(final Frame<? extends V> src) { this(src.locals, src.values.length - src.locals); init(src); }
/** * Constructs a new frame with the given size. * * @param nLocals * the maximum number of local variables of the frame. * @param nStack * the maximum stack size of the frame. * @return the created frame. */ protected Frame<V> newFrame(final int nLocals, final int nStack) { return new Frame<V>(nLocals, nStack); }
return b(1, Exprs.nNewArray("D", local)); default: throw new AnalyzerException(insn, "Invalid array type");
@Override public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) { return new SourceValue(value.getSize(), insn); }
@Override public SourceValue ternaryOperation(final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2, final SourceValue value3) { return new SourceValue(1, insn); }
/** {@inheritDoc} */ @Override public BasicValue merge(BasicValue v, BasicValue w) { if (v == BOOLEAN_VALUE && w == BasicValue.INT_VALUE) return BasicValue.INT_VALUE; else if (w == BOOLEAN_VALUE && v == BasicValue.INT_VALUE) return BasicValue.INT_VALUE; else return super.merge(v, w); }
@Override public void visitEnd() { try { Analyzer analyzer = new Analyzer(new SourceInterpreter()); Frame[] frames = analyzer.analyze(_classToAnalyze, this); for (int j = 0; j < f.getStackSize(); ++j) { SourceValue stack = (SourceValue) f.getStack(j);
static void printAnalyzerResult(MethodNode method, Analyzer a, final PrintWriter pw) throws IllegalArgumentException, IllegalAccessException { Frame[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); String format = "%05d %-" + (method.maxStack + method.maxLocals + 6) + "s|%s"; for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame f = frames[j]; if (f == null) { s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())); } } pw.printf(format, j, s, buf.get(t)); // mv.text.get(j)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); pw.print(" " + buf.get(t)); } pw.println(); pw.flush(); }
@SuppressWarnings("rawtypes") public static void verify(final ClassReader cr, PrintWriter out) throws AnalyzerException, IllegalArgumentException, IllegalAccessException { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); List tryCatchBlocks = method.tryCatchBlocks; for (int j = 0; j < tryCatchBlocks.size(); j++) { TryCatchBlockNode tcn = (TryCatchBlockNode) tryCatchBlocks.get(j); if (tcn.start.equals(tcn.end)) { throw new DexException("try/catch block %d in %s has same start(%s) and end(%s)", j, method.name, tcn.start.getLabel(), tcn.end.getLabel()); } } BasicVerifier verifier = new BasicVerifier(); Analyzer a = new Analyzer(verifier); try { a.analyze(cn.name, method); } catch (Exception e) { out.println(cr.getClassName() + "." + method.name + method.desc); printAnalyzerResult(method, a, out); e.printStackTrace(out); out.flush(); throw new DexException("method " + method.name + " " + method.desc, e); } } }
@Override public BasicValue newValue(final Type type) { BasicValue basicValue = super.newValue(type); if (basicValue == BasicValue.REFERENCE_VALUE) // record the exact type and not just "Ljava/lang/Object" basicValue = new BasicValue(type); return basicValue; }
/** * Constructs a new frame that is identical to the given frame. * * @param src * a frame. * @return the created frame. */ protected Frame<V> newFrame(final Frame<? extends V> src) { return new Frame<V>(src); }
/** {@inheritDoc} */ @Override public BasicValue merge(BasicValue v, BasicValue w) { if (v == THIS_VALUE && w == BasicValue.REFERENCE_VALUE) return BasicValue.REFERENCE_VALUE; else if (w == THIS_VALUE && v == BasicValue.REFERENCE_VALUE) return BasicValue.REFERENCE_VALUE; else return super.merge(v, w); }