├── .gitignore ├── LICENSE ├── README.md ├── accepted-words.dic ├── pom.xml └── src └── main └── java ├── lsieun ├── annotation │ └── todo │ │ └── ToDo.java ├── asm │ ├── analysis │ │ ├── ControlFlowAnalyzer.java │ │ ├── ControlFlowAnalyzer2.java │ │ ├── ControlFlowEdgeAnalyzer.java │ │ ├── ControlFlowEdgeAnalyzer2.java │ │ ├── ControlFlowGraphAnalyzer.java │ │ ├── DataFlowAnalyzer.java │ │ ├── InsnText.java │ │ ├── MockAnalyzer.java │ │ ├── RemoveDeadCodeNode.java │ │ ├── RemoveDeadCodeVisitor.java │ │ ├── RemoveUnusedCastNode.java │ │ ├── RemoveUnusedCastVisitor.java │ │ ├── cc │ │ │ ├── CyclomaticComplexity.java │ │ │ ├── CyclomaticComplexityAnalyzer.java │ │ │ └── CyclomaticComplexityFrame.java │ │ ├── cfg │ │ │ ├── ControlFlowBuilder.java │ │ │ ├── ControlFlowGraph.java │ │ │ ├── Edge.java │ │ │ ├── EdgeCreator.java │ │ │ ├── FramelessAnalyzer.java │ │ │ └── SimpleEdgeCreator.java │ │ ├── diagnosis │ │ │ ├── DeadCodeDiagnosis.java │ │ │ ├── NullDereferenceDiagnosis.java │ │ │ ├── NullabilityDiagnosis.java │ │ │ ├── RedundantVariableDiagnosis.java │ │ │ ├── RelatedInstructionDiagnosis.java │ │ │ └── ReverseEngineerMethodArgumentsDiagnosis.java │ │ ├── graph │ │ │ ├── InsnBlock.java │ │ │ ├── TextBox.java │ │ │ └── TextGraph.java │ │ ├── nullability │ │ │ ├── NullDeferenceInterpreter.java │ │ │ ├── Nullability.java │ │ │ ├── NullabilityAnalyzer.java │ │ │ ├── NullabilityFrame.java │ │ │ ├── NullabilityInterpreter.java │ │ │ └── NullabilityValue.java │ │ ├── state │ │ │ ├── StateInterpreter.java │ │ │ ├── StateType.java │ │ │ └── StateValue.java │ │ └── transition │ │ │ └── DestinationInterpreter.java │ ├── commons │ │ ├── ClassRemapperExample01.java │ │ ├── ClassRemapperExample02.java │ │ ├── ClassRemapperExample03.java │ │ ├── GeneratorAdapterExample01.java │ │ ├── InstructionAdapterExample01.java │ │ ├── MethodStackMapFrame02Visitor.java │ │ ├── MethodStackMapFrameVisitor.java │ │ ├── SerialVersionUIDAdderExample01.java │ │ └── StaticInitMergerExample01.java │ ├── core │ │ ├── ChangeURLVisitor.java │ │ ├── ClassChangeVersionVisitor.java │ │ ├── ClassCloneVisitor.java │ │ ├── ClassDecompileVisitor.java │ │ ├── ClassListMemberVisitor.java │ │ ├── ClassRemoveAttributeVisitor.java │ │ ├── MethodAroundVisitor.java │ │ ├── MethodAroundVisitor2.java │ │ ├── MethodEmptyBodyVisitor.java │ │ ├── MethodEnterVisitor.java │ │ ├── MethodExitVisitor.java │ │ ├── MethodFindInvokeVisitor.java │ │ ├── MethodFindRefVisitor.java │ │ ├── MethodParameterVisitor.java │ │ ├── MethodParameterVisitor2.java │ │ ├── MethodPatternAdapter.java │ │ ├── MethodRemoveAddZeroVisitor.java │ │ ├── MethodRemoveGetFieldPutFieldVisitor.java │ │ ├── MethodRemoveNopVisitor.java │ │ ├── MethodRemovePrintVisitor.java │ │ ├── MethodReplaceInvokeVisitor.java │ │ ├── MethodTimerVisitor.java │ │ ├── MethodTimerVisitor2.java │ │ ├── MethodTimerVisitor3.java │ │ ├── MethodTimerVisitor4.java │ │ ├── SuperPackageAttribute.java │ │ ├── counter │ │ │ ├── ClassCounterVisitor.java │ │ │ └── MethodCounterAdapter.java │ │ ├── empty │ │ │ ├── EmptyAnnotationVisitor.java │ │ │ ├── EmptyClassVisitor.java │ │ │ ├── EmptyFieldVisitor.java │ │ │ ├── EmptyMethodVisitor.java │ │ │ ├── EmptyModuleVisitor.java │ │ │ └── EmptyRecordComponentVisitor.java │ │ ├── info │ │ │ ├── InfoClassVisitor.java │ │ │ ├── InfoFieldVisitor.java │ │ │ └── InfoMethodVisitor.java │ │ └── timer │ │ │ ├── ClassTimerVisitor.java │ │ │ └── MethodTimerAdapter.java │ ├── template │ │ ├── CheckMethodAnnotationVisitor.java │ │ ├── ClassAddAnnotationVisitor.java │ │ ├── ClassAddCustomAttributeVisitor.java │ │ ├── ClassAddFieldVisitor.java │ │ ├── ClassAddInterfaceVisitor.java │ │ ├── ClassAddMethodVisitor.java │ │ ├── ClassGetAttributeContentVisitor.java │ │ ├── ClassMergeVisitor.java │ │ ├── ClassMergeVisitorRun.java │ │ ├── ClassPrintAnnotationVisitor.java │ │ ├── ClassPrintParameterVisitor.java │ │ ├── ClassRemoveFieldVisitor.java │ │ ├── ClassRemoveMethodVisitor.java │ │ ├── ClassRenameAdapter.java │ │ ├── ClassRenameAdapterRun.java │ │ ├── ClassReplaceMethodBodyVisitor.java │ │ ├── CustomAttribute.java │ │ ├── FieldAccessAdapter.java │ │ ├── FieldAccessAdapterRun.java │ │ ├── FieldAccessConverter.java │ │ ├── Info.java │ │ ├── MethodCallAdapter.java │ │ ├── MethodCallAdapterRun.java │ │ ├── MethodCallConverter.java │ │ ├── MethodEnteringAdapter.java │ │ ├── MethodEnteringVisitor.java │ │ ├── MethodEnteringVisitorRun.java │ │ ├── MethodExitingAdapter.java │ │ ├── MethodExitingAdapterRun.java │ │ ├── MethodExitingConverter.java │ │ ├── MethodFinallyAdapter.java │ │ ├── MethodFinallyAdapterRun.java │ │ ├── MethodFinallyConverter.java │ │ ├── MethodPrintInstructionAdapter.java │ │ ├── MethodPrintInstructionVisitor.java │ │ ├── MethodWithSameTryCatchLogicVisitor.java │ │ ├── MethodWithWholeTryCatchVisitor.java │ │ ├── RefRenameAdapter.java │ │ └── RemoveSyntheticVisitor.java │ ├── tree │ │ ├── ChangeMemberNameBasedOnAnnotationNode.java │ │ ├── ChangeThisNode.java │ │ ├── ClassAddCustomAttributeNode.java │ │ ├── ClassAddFieldNode.java │ │ ├── ClassAddMethodNode.java │ │ ├── ClassAddTimerNode.java │ │ ├── ClassRemoveFieldNode.java │ │ ├── ClassRemoveMethodNode.java │ │ ├── MixCore2TreeVisitor.java │ │ ├── MixTree2CoreNode.java │ │ ├── OptimizeJumpNode.java │ │ ├── RemoveGetFieldPutFieldNode.java │ │ ├── my │ │ │ ├── MyClassNode.java │ │ │ ├── MyClassVisitor.java │ │ │ ├── MyMethodAdapter.java │ │ │ └── MyMethodNode.java │ │ └── transformer │ │ │ ├── ClassTransformer.java │ │ │ └── MethodTransformer.java │ └── util │ │ ├── CheckClassAdapterExample01Generate.java │ │ ├── CheckClassAdapterExample02Generate.java │ │ ├── CodeUtils.java │ │ ├── TraceClassVisitorExample01Generate.java │ │ ├── TraceClassVisitorExample02Transform.java │ │ ├── TraceClassVisitorExample03.java │ │ └── TreePrinter.java ├── classfile │ ├── CPInfo.java │ ├── ClassFile.java │ └── InsnRaw.java ├── cst │ └── Const.java ├── drawing │ ├── canvas │ │ ├── Box.java │ │ ├── Canvas.java │ │ ├── Drawable.java │ │ ├── TextAlign.java │ │ ├── TextDirection.java │ │ └── TextPixel.java │ └── theme │ │ ├── line │ │ └── ContinuousLine.java │ │ ├── shape │ │ ├── Rectangle.java │ │ └── RectangleWithText.java │ │ ├── table │ │ ├── AbstractTable.java │ │ ├── FixedWidthOneLineTable.java │ │ └── OneLineTable.java │ │ └── text │ │ └── PlainText.java ├── trove │ ├── HashFunctions.java │ ├── PrimeFinder.java │ ├── THash.java │ ├── TIntArrayList.java │ ├── TIntFunction.java │ ├── TIntHash.java │ ├── TIntHashingStrategy.java │ ├── TIntIntHashMap.java │ ├── TIntIntIterator.java │ ├── TIntIntProcedure.java │ ├── TIntProcedure.java │ ├── TIterator.java │ ├── TPrimitiveHash.java │ ├── TPrimitiveIterator.java │ └── package-info.java └── utils │ ├── ASMUtilsCore.java │ ├── ASMUtilsTree.java │ ├── BoxDrawingUtils.java │ ├── ByteArrayClassLoader.java │ ├── ByteUtils.java │ ├── DescriptorUtils.java │ ├── FileUtils.java │ ├── FrameUtils.java │ ├── HexFormat.java │ ├── HexUtils.java │ ├── IOUtils.java │ ├── JarUtils.java │ ├── OpcodeConst.java │ ├── ReadUtils.java │ ├── StringUtils.java │ └── ValueUtils.java ├── run ├── ASMPrint.java ├── BoxDrawingRun.java ├── BytecodeRun.java ├── ControlFlowGraphRun.java ├── ControlFlowGraphType.java ├── HelloWorldAnalysisCore.java ├── HelloWorldAnalysisTree.java ├── HelloWorldFrameCore.java ├── HelloWorldFrameCore02.java ├── HelloWorldFrameTree.java ├── HelloWorldGenerateCore.java ├── HelloWorldGenerateTree.java ├── HelloWorldRun.java ├── HelloWorldTransformCore.java ├── HelloWorldTransformTree.java ├── MockAnalyzerRun.java ├── PrintASMCodeCore.java ├── PrintASMCodeTree.java ├── PrintASMTextClass.java ├── PrintASMTextLambda.java ├── PrintOpcodeTable.java └── jar │ ├── CompareTwoJarFile.java │ └── FindJarClassItem.java └── sample ├── HelloWorld.java └── ParameterUtils.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # IDEA 26 | 27 | .idea/ 28 | *.iml 29 | *.kotlin_module 30 | target/ 31 | lib/ 32 | build/ 33 | dist/ 34 | .* 35 | *.data 36 | !.gitignore 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 lsieun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /accepted-words.dic: -------------------------------------------------------------------------------- 1 | bilibili 2 | gitee 3 | insn 4 | lsieun 5 | -------------------------------------------------------------------------------- /src/main/java/lsieun/annotation/todo/ToDo.java: -------------------------------------------------------------------------------- 1 | package lsieun.annotation.todo; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | import java.lang.annotation.Target; 6 | 7 | import static java.lang.annotation.ElementType.*; 8 | 9 | @Retention(RetentionPolicy.SOURCE) 10 | @Target({ 11 | TYPE, 12 | FIELD, 13 | CONSTRUCTOR, 14 | METHOD, 15 | PARAMETER, 16 | LOCAL_VARIABLE, 17 | ANNOTATION_TYPE, 18 | PACKAGE, 19 | TYPE_PARAMETER, 20 | TYPE_USE, 21 | // MODULE, 22 | // RECORD_COMPONENT, 23 | }) 24 | public @interface ToDo { 25 | String[] value(); 26 | } -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/RemoveDeadCodeNode.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis; 2 | 3 | import lsieun.asm.tree.transformer.MethodTransformer; 4 | import org.objectweb.asm.ClassVisitor; 5 | import org.objectweb.asm.tree.AbstractInsnNode; 6 | import org.objectweb.asm.tree.ClassNode; 7 | import org.objectweb.asm.tree.LabelNode; 8 | import org.objectweb.asm.tree.MethodNode; 9 | import org.objectweb.asm.tree.analysis.*; 10 | 11 | public class RemoveDeadCodeNode extends ClassNode { 12 | public RemoveDeadCodeNode(int api, ClassVisitor cv) { 13 | super(api); 14 | this.cv = cv; 15 | } 16 | 17 | @Override 18 | public void visitEnd() { 19 | // 首先,处理自己的代码逻辑 20 | MethodTransformer mt = new MethodRemoveDeadCodeTransformer(name, null); 21 | for (MethodNode mn : methods) { 22 | mt.transform(mn); 23 | } 24 | 25 | // 其次,调用父类的方法实现 26 | super.visitEnd(); 27 | 28 | // 最后,向后续ClassVisitor传递 29 | if (cv != null) { 30 | accept(cv); 31 | } 32 | } 33 | 34 | private static class MethodRemoveDeadCodeTransformer extends MethodTransformer { 35 | private final String owner; 36 | 37 | public MethodRemoveDeadCodeTransformer(String owner, MethodTransformer mt) { 38 | super(mt); 39 | this.owner = owner; 40 | } 41 | 42 | @Override 43 | public void transform(MethodNode mn) { 44 | // 首先,处理自己的代码逻辑 45 | Analyzer analyzer = new Analyzer<>(new BasicInterpreter()); 46 | try { 47 | analyzer.analyze(owner, mn); 48 | Frame[] frames = analyzer.getFrames(); 49 | AbstractInsnNode[] insnNodes = mn.instructions.toArray(); 50 | for (int i = 0; i < frames.length; i++) { 51 | if (frames[i] == null && !(insnNodes[i] instanceof LabelNode)) { 52 | mn.instructions.remove(insnNodes[i]); 53 | } 54 | } 55 | } 56 | catch (AnalyzerException ex) { 57 | ex.printStackTrace(); 58 | } 59 | 60 | // 其次,调用父类的方法实现 61 | super.transform(mn); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cc/CyclomaticComplexity.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cc; 2 | 3 | import org.objectweb.asm.tree.MethodNode; 4 | import org.objectweb.asm.tree.analysis.*; 5 | 6 | public class CyclomaticComplexity { 7 | public static int getCyclomaticComplexity(String owner, MethodNode mn) throws AnalyzerException { 8 | // 第一步,获取Frame信息 9 | Analyzer analyzer = new CyclomaticComplexityAnalyzer<>(new BasicInterpreter()); 10 | Frame[] frames = analyzer.analyze(owner, mn); 11 | 12 | // 第二步,计算复杂度 13 | int edges = 0; 14 | int nodes = 0; 15 | for (Frame frame : frames) { 16 | if (frame != null) { 17 | edges += ((CyclomaticComplexityFrame) frame).successors.size(); 18 | nodes += 1; 19 | } 20 | } 21 | return edges - nodes + 2; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cc/CyclomaticComplexityAnalyzer.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cc; 2 | 3 | import org.objectweb.asm.tree.analysis.*; 4 | 5 | public class CyclomaticComplexityAnalyzer extends Analyzer { 6 | public CyclomaticComplexityAnalyzer(Interpreter interpreter) { 7 | super(interpreter); 8 | } 9 | 10 | @Override 11 | protected Frame newFrame(int numLocals, int numStack) { 12 | return new CyclomaticComplexityFrame<>(numLocals, numStack); 13 | } 14 | 15 | @Override 16 | protected Frame newFrame(Frame frame) { 17 | return new CyclomaticComplexityFrame<>(frame); 18 | } 19 | 20 | @Override 21 | protected void newControlFlowEdge(int insnIndex, int successorIndex) { 22 | CyclomaticComplexityFrame frame = (CyclomaticComplexityFrame) getFrames()[insnIndex]; 23 | frame.successors.add((CyclomaticComplexityFrame) getFrames()[successorIndex]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cc/CyclomaticComplexityFrame.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cc; 2 | 3 | import org.objectweb.asm.tree.analysis.Frame; 4 | import org.objectweb.asm.tree.analysis.Value; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class CyclomaticComplexityFrame extends Frame { 10 | public Set> successors = new HashSet<>(); 11 | 12 | public CyclomaticComplexityFrame(int numLocals, int numStack) { 13 | super(numLocals, numStack); 14 | } 15 | 16 | public CyclomaticComplexityFrame(Frame frame) { 17 | super(frame); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cfg/ControlFlowBuilder.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cfg; 2 | 3 | import org.objectweb.asm.tree.MethodNode; 4 | import org.objectweb.asm.tree.analysis.AnalyzerException; 5 | 6 | import static org.objectweb.asm.Opcodes.ACC_ABSTRACT; 7 | import static org.objectweb.asm.Opcodes.ACC_NATIVE; 8 | 9 | public final class ControlFlowBuilder { 10 | public static ControlFlowGraph buildCFG(String className, MethodNode methodNode) throws AnalyzerException { 11 | if ((methodNode.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { 12 | throw new RuntimeException("method body is empty"); 13 | } 14 | 15 | int size = methodNode.instructions.size(); 16 | SimpleEdgeCreator edgeCreator = new SimpleEdgeCreator(size); 17 | FramelessAnalyzer myAnalyzer = new FramelessAnalyzer(edgeCreator); 18 | myAnalyzer.analyze(methodNode); 19 | 20 | 21 | int[][] transitions = new int[edgeCreator.transitions.length][]; 22 | for (int i = 0; i < transitions.length; i++) { 23 | transitions[i] = edgeCreator.transitions[i].toNativeArray(); 24 | } 25 | int[][] errorTransitions = new int[edgeCreator.errorTransitions.length][]; 26 | for (int i = 0; i < errorTransitions.length; i++) { 27 | errorTransitions[i] = edgeCreator.errorTransitions[i].toNativeArray(); 28 | } 29 | 30 | return new ControlFlowGraph(transitions, errorTransitions); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cfg/ControlFlowGraph.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cfg; 2 | 3 | import java.util.Arrays; 4 | import java.util.Formatter; 5 | 6 | public final class ControlFlowGraph { 7 | public final int[][] transitions; 8 | public final int[][] errorTransitions; 9 | 10 | public ControlFlowGraph(int[][] transitions, int[][] errorTransitions) { 11 | this.transitions = transitions; 12 | this.errorTransitions = errorTransitions; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | StringBuilder sb = new StringBuilder(); 18 | Formatter fm = new Formatter(sb); 19 | fm.format("ControlFlowGraph%n"); 20 | 21 | fm.format("Normal Transitions%n"); 22 | int normalLength = transitions.length; 23 | for (int i = 0; i < normalLength; i++) { 24 | int[] array = transitions[i]; 25 | fm.format("%03d %s%n", i, Arrays.toString(array)); 26 | } 27 | 28 | fm.format("Error Transitions%n"); 29 | int errorLength = transitions.length; 30 | for (int i = 0; i < errorLength; i++) { 31 | int[] array = errorTransitions[i]; 32 | fm.format("%03d %s%n", i, Arrays.toString(array)); 33 | } 34 | return sb.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cfg/Edge.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cfg; 2 | 3 | public final class Edge { 4 | public final int from; 5 | public final int to; 6 | 7 | public Edge(int from, int to) { 8 | this.from = from; 9 | this.to = to; 10 | } 11 | 12 | @Override 13 | public boolean equals(Object obj) { 14 | if (this == obj) return true; 15 | if (!(obj instanceof Edge)) { 16 | return false; 17 | } 18 | Edge edge = (Edge) obj; 19 | return (from == edge.from) && (to == edge.to); 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return 31 * from + to; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cfg/EdgeCreator.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cfg; 2 | 3 | public interface EdgeCreator { 4 | void newControlFlowEdge(int insn, int successor); 5 | 6 | void newControlFlowExceptionEdge(int insn, int successor, boolean npe); 7 | } -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/cfg/SimpleEdgeCreator.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.cfg; 2 | 3 | import lsieun.trove.TIntArrayList; 4 | 5 | public class SimpleEdgeCreator implements EdgeCreator { 6 | public final TIntArrayList[] transitions; 7 | public final TIntArrayList[] errorTransitions; 8 | 9 | public SimpleEdgeCreator(int size) { 10 | this.transitions = new TIntArrayList[size]; 11 | this.errorTransitions = new TIntArrayList[size]; 12 | for (int i = 0; i < transitions.length; i++) { 13 | this.transitions[i] = new TIntArrayList(); 14 | this.errorTransitions[i] = new TIntArrayList(); 15 | } 16 | } 17 | 18 | @Override 19 | public void newControlFlowEdge(int insn, int successor) { 20 | if (!transitions[insn].contains(successor)) { 21 | transitions[insn].add(successor); 22 | } 23 | } 24 | 25 | @Override 26 | public void newControlFlowExceptionEdge(int insn, int successor, boolean npe) { 27 | if (!errorTransitions[insn].contains(successor)) { 28 | errorTransitions[insn].add(successor); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/diagnosis/DeadCodeDiagnosis.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.diagnosis; 2 | 3 | import lsieun.asm.analysis.ControlFlowAnalyzer; 4 | import lsieun.trove.TIntArrayList; 5 | import org.objectweb.asm.tree.InsnList; 6 | import org.objectweb.asm.tree.MethodNode; 7 | import org.objectweb.asm.tree.analysis.AnalyzerException; 8 | 9 | public class DeadCodeDiagnosis { 10 | public static int[] diagnose(String className, MethodNode mn) throws AnalyzerException { 11 | InsnList instructions = mn.instructions; 12 | int size = instructions.size(); 13 | 14 | boolean[] flags = new boolean[size]; 15 | ControlFlowAnalyzer analyzer = new ControlFlowAnalyzer() { 16 | @Override 17 | protected void newControlFlowEdge(int insnIndex, int successorIndex) { 18 | // 首先,处理自己的代码逻辑 19 | flags[insnIndex] = true; 20 | flags[successorIndex] = true; 21 | 22 | // 其次,调用父类的实现 23 | super.newControlFlowEdge(insnIndex, successorIndex); 24 | } 25 | }; 26 | analyzer.analyze(className, mn); 27 | 28 | 29 | TIntArrayList intArrayList = new TIntArrayList(); 30 | for (int i = 0; i < size; i++) { 31 | boolean flag = flags[i]; 32 | if (!flag) { 33 | intArrayList.add(i); 34 | } 35 | } 36 | 37 | return intArrayList.toNativeArray(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/diagnosis/NullDereferenceDiagnosis.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.diagnosis; 2 | 3 | import lsieun.asm.analysis.nullability.NullDeferenceInterpreter; 4 | import lsieun.trove.TIntArrayList; 5 | import org.objectweb.asm.Type; 6 | import org.objectweb.asm.tree.AbstractInsnNode; 7 | import org.objectweb.asm.tree.InsnList; 8 | import org.objectweb.asm.tree.MethodInsnNode; 9 | import org.objectweb.asm.tree.MethodNode; 10 | import org.objectweb.asm.tree.analysis.*; 11 | 12 | import java.util.Arrays; 13 | 14 | import static org.objectweb.asm.Opcodes.*; 15 | 16 | public class NullDereferenceDiagnosis { 17 | public static int[] diagnose(String owner, MethodNode mn) throws AnalyzerException { 18 | // 第一步,获取Frame信息 19 | Analyzer analyzer = new Analyzer<>(new NullDeferenceInterpreter(ASM9)); 20 | Frame[] frames = analyzer.analyze(owner, mn); 21 | 22 | // 第二步,判断是否为null或maybe-null,收集数据 23 | TIntArrayList intArrayList = new TIntArrayList(); 24 | InsnList instructions = mn.instructions; 25 | int size = instructions.size(); 26 | for (int i = 0; i < size; i++) { 27 | AbstractInsnNode insn = instructions.get(i); 28 | if (frames[i] != null) { 29 | Value value = getTarget(insn, frames[i]); 30 | if (value == NullDeferenceInterpreter.NULL_VALUE || value == NullDeferenceInterpreter.MAYBE_NULL_VALUE) { 31 | intArrayList.add(i); 32 | } 33 | } 34 | } 35 | 36 | // 第三步,将结果转换成int[]形式 37 | int[] array = intArrayList.toNativeArray(); 38 | Arrays.sort(array); 39 | return array; 40 | } 41 | 42 | private static BasicValue getTarget(AbstractInsnNode insn, Frame frame) { 43 | int opcode = insn.getOpcode(); 44 | switch (opcode) { 45 | case GETFIELD: 46 | case ARRAYLENGTH: 47 | case MONITORENTER: 48 | case MONITOREXIT: 49 | return getStackValue(frame, 0); 50 | case PUTFIELD: 51 | return getStackValue(frame, 1); 52 | case INVOKEVIRTUAL: 53 | case INVOKESPECIAL: 54 | case INVOKEINTERFACE: 55 | String desc = ((MethodInsnNode) insn).desc; 56 | return getStackValue(frame, Type.getArgumentTypes(desc).length); 57 | 58 | } 59 | return null; 60 | } 61 | 62 | private static BasicValue getStackValue(Frame frame, int index) { 63 | int top = frame.getStackSize() - 1; 64 | return index <= top ? frame.getStack(top - index) : null; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/diagnosis/RedundantVariableDiagnosis.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.diagnosis; 2 | 3 | import lsieun.trove.TIntArrayList; 4 | import org.objectweb.asm.Opcodes; 5 | import org.objectweb.asm.tree.AbstractInsnNode; 6 | import org.objectweb.asm.tree.InsnList; 7 | import org.objectweb.asm.tree.MethodNode; 8 | import org.objectweb.asm.tree.VarInsnNode; 9 | import org.objectweb.asm.tree.analysis.*; 10 | 11 | import java.util.Arrays; 12 | 13 | public class RedundantVariableDiagnosis { 14 | public static int[] diagnose(String className, MethodNode mn) throws AnalyzerException { 15 | // 第一步,准备工作。使用SimpleVerifier进行分析,得到frames信息 16 | Analyzer analyzer = new Analyzer<>(new SimpleVerifier()); 17 | Frame[] frames = analyzer.analyze(className, mn); 18 | 19 | // 第二步,利用frames信息,查看local variable当中哪些slot数据出现了冗余 20 | TIntArrayList localIndexList = new TIntArrayList(); 21 | for (Frame f : frames) { 22 | int locals = f.getLocals(); 23 | for (int i = 0; i < locals; i++) { 24 | BasicValue val1 = f.getLocal(i); 25 | if (val1 == BasicValue.UNINITIALIZED_VALUE) { 26 | continue; 27 | } 28 | for (int j = i + 1; j < locals; j++) { 29 | BasicValue val2 = f.getLocal(j); 30 | if (val2 == BasicValue.UNINITIALIZED_VALUE) { 31 | continue; 32 | } 33 | if (val1 == val2) { 34 | if (!localIndexList.contains(j)) { 35 | localIndexList.add(j); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | // 第三步,将slot的索引值(local index)转换成instruction的索引值(insn index) 43 | TIntArrayList insnIndexList = new TIntArrayList(); 44 | InsnList instructions = mn.instructions; 45 | int size = instructions.size(); 46 | for (int i = 0; i < size; i++) { 47 | AbstractInsnNode node = instructions.get(i); 48 | int opcode = node.getOpcode(); 49 | if (opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE) { 50 | VarInsnNode varInsnNode = (VarInsnNode) node; 51 | if (localIndexList.contains(varInsnNode.var)) { 52 | if (!insnIndexList.contains(i)) { 53 | insnIndexList.add(i); 54 | } 55 | } 56 | } 57 | } 58 | 59 | // 第四步,将insnIndexList转换成int[]形式 60 | int[] array = insnIndexList.toNativeArray(); 61 | Arrays.sort(array); 62 | return array; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/graph/InsnBlock.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class InsnBlock { 7 | // 文字信息 8 | public final List lines = new ArrayList<>(); 9 | 10 | // 关联关系 11 | public final List nextBlockList = new ArrayList<>(); 12 | public final List jumpBlockList = new ArrayList<>(); 13 | 14 | public void addLines(List list) { 15 | lines.addAll(list); 16 | } 17 | 18 | public void addNext(InsnBlock item) { 19 | if (!nextBlockList.contains(item)) { 20 | nextBlockList.add(item); 21 | } 22 | } 23 | 24 | public void addJump(InsnBlock item) { 25 | if (!jumpBlockList.contains(item)) { 26 | jumpBlockList.add(item); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/graph/TextBox.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.graph; 2 | 3 | public class TextBox { 4 | public final int row; 5 | public final int col; 6 | public final int width; 7 | public final int height; 8 | 9 | public TextBox(int row, int col, int width, int height) { 10 | this.row = row; 11 | this.col = col; 12 | this.width = width; 13 | this.height = height; 14 | } 15 | 16 | public static TextBox valueOf(int row, int col, int width, int height) { 17 | return new TextBox(row, col, width, height); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/nullability/NullDeferenceInterpreter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.nullability; 2 | 3 | import org.objectweb.asm.Type; 4 | import org.objectweb.asm.tree.AbstractInsnNode; 5 | import org.objectweb.asm.tree.analysis.AnalyzerException; 6 | import org.objectweb.asm.tree.analysis.BasicInterpreter; 7 | import org.objectweb.asm.tree.analysis.BasicValue; 8 | import org.objectweb.asm.tree.analysis.Value; 9 | 10 | public class NullDeferenceInterpreter extends BasicInterpreter { 11 | public final static BasicValue NULL_VALUE = new BasicValue(NULL_TYPE); 12 | public final static BasicValue MAYBE_NULL_VALUE = new BasicValue(Type.getObjectType("may-be-null")); 13 | 14 | public NullDeferenceInterpreter(int api) { 15 | super(api); 16 | } 17 | 18 | @Override 19 | public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException { 20 | if (insn.getOpcode() == ACONST_NULL) { 21 | return NULL_VALUE; 22 | } 23 | return super.newOperation(insn); 24 | } 25 | 26 | @Override 27 | public BasicValue merge(BasicValue value1, BasicValue value2) { 28 | if (isRef(value1) && isRef(value2) && value1 != value2) { 29 | return MAYBE_NULL_VALUE; 30 | } 31 | return super.merge(value1, value2); 32 | } 33 | 34 | private boolean isRef(Value value) { 35 | return value == BasicValue.REFERENCE_VALUE || value == NULL_VALUE || value == MAYBE_NULL_VALUE; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/nullability/Nullability.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.nullability; 2 | 3 | public enum Nullability { 4 | UNKNOWN(0), 5 | NOT_NULL(1), 6 | NULL(1), 7 | NULLABLE(2); 8 | 9 | public final int priority; 10 | 11 | Nullability(int priority) { 12 | this.priority = priority; 13 | } 14 | 15 | public static Nullability merge(Nullability value1, Nullability value2) { 16 | // 第一种情况,两者相等,则直接返回一个 17 | if (value1 == value2) { 18 | return value1; 19 | } 20 | 21 | // 第二种情况,两者不相等,比较优先级大小,谁大返回谁 22 | int priority1 = value1.priority; 23 | int priority2 = value2.priority; 24 | if (priority1 > priority2) { 25 | return value1; 26 | } 27 | else if (priority1 < priority2) { 28 | return value2; 29 | } 30 | 31 | // 第三种情况,两者不相等,但优先级相等,则一个是NOT_NULL,另一个是NULL 32 | return NULLABLE; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/nullability/NullabilityAnalyzer.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.nullability; 2 | 3 | import org.objectweb.asm.tree.analysis.Analyzer; 4 | import org.objectweb.asm.tree.analysis.Frame; 5 | import org.objectweb.asm.tree.analysis.Interpreter; 6 | 7 | public class NullabilityAnalyzer extends Analyzer { 8 | public NullabilityAnalyzer(Interpreter interpreter) { 9 | super(interpreter); 10 | } 11 | 12 | @Override 13 | protected Frame newFrame(Frame frame) { 14 | return new NullabilityFrame((NullabilityFrame) frame); 15 | } 16 | 17 | @Override 18 | protected Frame newFrame(int numLocals, int numStack) { 19 | return new NullabilityFrame(numLocals, numStack); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/nullability/NullabilityFrame.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.nullability; 2 | 3 | import org.objectweb.asm.Opcodes; 4 | import org.objectweb.asm.tree.LabelNode; 5 | import org.objectweb.asm.tree.analysis.Frame; 6 | 7 | public class NullabilityFrame extends Frame { 8 | public NullabilityFrame(int numLocals, int numStack) { 9 | super(numLocals, numStack); 10 | } 11 | 12 | public NullabilityFrame(NullabilityFrame frame) { 13 | super(frame); 14 | } 15 | 16 | @Override 17 | public void initJumpTarget(int opcode, LabelNode target) { 18 | // 首先,处理自己的代码逻辑 19 | int stackIndex = getStackSize(); 20 | NullabilityValue oldValue = getStack(stackIndex); 21 | switch (opcode) { 22 | case Opcodes.IFNULL: { 23 | if (target == null) { 24 | updateFrame(oldValue, Nullability.NOT_NULL); 25 | } 26 | else { 27 | updateFrame(oldValue, Nullability.NULL); 28 | } 29 | break; 30 | } 31 | case Opcodes.IFNONNULL: { 32 | if (target == null) { 33 | updateFrame(oldValue, Nullability.NULL); 34 | } 35 | else { 36 | updateFrame(oldValue, Nullability.NOT_NULL); 37 | } 38 | break; 39 | } 40 | } 41 | 42 | // 其次,调用父类的方法实现 43 | super.initJumpTarget(opcode, target); 44 | } 45 | 46 | private void updateFrame(NullabilityValue oldValue, Nullability newState) { 47 | NullabilityValue newValue = new NullabilityValue(oldValue.getType(), newState); 48 | int numLocals = getLocals(); 49 | for (int i = 0; i < numLocals; i++) { 50 | NullabilityValue currentValue = getLocal(i); 51 | if (oldValue == currentValue) { 52 | setLocal(i, newValue); 53 | } 54 | } 55 | 56 | int numStack = getMaxStackSize(); 57 | for (int i = 0; i < numStack; i++) { 58 | NullabilityValue currentValue = getStack(i); 59 | if (oldValue == currentValue) { 60 | setStack(i, newValue); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/nullability/NullabilityValue.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.nullability; 2 | 3 | import org.objectweb.asm.Type; 4 | import org.objectweb.asm.tree.analysis.Value; 5 | 6 | public class NullabilityValue implements Value { 7 | private final Type type; 8 | private Nullability state; 9 | 10 | public NullabilityValue(Type type) { 11 | this(type, Nullability.UNKNOWN); 12 | } 13 | 14 | public NullabilityValue(Type type, Nullability state) { 15 | this.type = type; 16 | this.state = state; 17 | } 18 | 19 | public Type getType() { 20 | return type; 21 | } 22 | 23 | public void setState(Nullability state) { 24 | this.state = state; 25 | } 26 | 27 | public Nullability getState() { 28 | return state; 29 | } 30 | 31 | @Override 32 | public int getSize() { 33 | return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1; 34 | } 35 | 36 | public boolean isReference() { 37 | return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY); 38 | } 39 | 40 | @Override 41 | public boolean equals(final Object value) { 42 | if (value == this) { 43 | return true; 44 | } 45 | else if (value instanceof NullabilityValue) { 46 | NullabilityValue another = (NullabilityValue) value; 47 | if (type == null) { 48 | return ((NullabilityValue) value).type == null; 49 | } 50 | else { 51 | return type.equals(((NullabilityValue) value).type) && state == another.state; 52 | } 53 | } 54 | else { 55 | return false; 56 | } 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return type == null ? 0 : type.hashCode(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/state/StateInterpreter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.state; 2 | 3 | import org.objectweb.asm.Opcodes; 4 | import org.objectweb.asm.Type; 5 | import org.objectweb.asm.tree.AbstractInsnNode; 6 | import org.objectweb.asm.tree.analysis.AnalyzerException; 7 | import org.objectweb.asm.tree.analysis.Interpreter; 8 | 9 | import java.util.List; 10 | 11 | public class StateInterpreter extends Interpreter implements Opcodes { 12 | public StateInterpreter() { 13 | super(ASM9); 14 | if (getClass() != StateInterpreter.class) { 15 | throw new IllegalStateException(); 16 | } 17 | } 18 | 19 | public StateInterpreter(int api) { 20 | super(api); 21 | } 22 | 23 | @Override 24 | public StateValue newValue(Type type) { 25 | return null; 26 | } 27 | 28 | @Override 29 | public StateValue newOperation(AbstractInsnNode insn) throws AnalyzerException { 30 | return null; 31 | } 32 | 33 | @Override 34 | public StateValue copyOperation(AbstractInsnNode insn, StateValue value) throws AnalyzerException { 35 | return null; 36 | } 37 | 38 | @Override 39 | public StateValue unaryOperation(AbstractInsnNode insn, StateValue value) throws AnalyzerException { 40 | return null; 41 | } 42 | 43 | @Override 44 | public StateValue binaryOperation(AbstractInsnNode insn, StateValue value1, StateValue value2) throws AnalyzerException { 45 | return null; 46 | } 47 | 48 | @Override 49 | public StateValue ternaryOperation(AbstractInsnNode insn, StateValue value1, StateValue value2, StateValue value3) throws AnalyzerException { 50 | return null; 51 | } 52 | 53 | @Override 54 | public StateValue naryOperation(AbstractInsnNode insn, List values) throws AnalyzerException { 55 | return null; 56 | } 57 | 58 | @Override 59 | public void returnOperation(AbstractInsnNode insn, StateValue value, StateValue expected) throws AnalyzerException { 60 | 61 | } 62 | 63 | @Override 64 | public StateValue merge(StateValue value1, StateValue value2) { 65 | return null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/state/StateType.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.state; 2 | 3 | public enum StateType { 4 | DEFAULT, // default 5 | TOP, 6 | INT, 7 | FLOAT, 8 | LONG, 9 | DOUBLE, 10 | NULL, 11 | 12 | CP, // constant pool 13 | HEAP; // 从堆内存上分配的对象 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/analysis/state/StateValue.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.analysis.state; 2 | 3 | import org.objectweb.asm.tree.analysis.Value; 4 | 5 | public class StateValue implements Value { 6 | public final int size; 7 | 8 | public StateValue(int size) { 9 | this.size = size; 10 | } 11 | 12 | @Override 13 | public int getSize() { 14 | return size; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/ClassRemapperExample01.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassReader; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.ClassWriter; 7 | import org.objectweb.asm.commons.ClassRemapper; 8 | import org.objectweb.asm.commons.Remapper; 9 | import org.objectweb.asm.commons.SimpleRemapper; 10 | 11 | public class ClassRemapperExample01 { 12 | public static void main(String[] args) { 13 | String origin_name = "sample/HelloWorld"; 14 | String target_name = "sample/GoodChild"; 15 | String origin_filepath = getFilePath(origin_name); 16 | byte[] bytes1 = FileUtils.readBytes(origin_filepath); 17 | 18 | //(1)构建ClassReader 19 | ClassReader cr = new ClassReader(bytes1); 20 | 21 | //(2)构建ClassWriter 22 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 23 | 24 | //(3)串连ClassVisitor 25 | Remapper remapper = new SimpleRemapper(origin_name, target_name); 26 | ClassVisitor cv = new ClassRemapper(cw, remapper); 27 | 28 | //(4)两者进行结合 29 | int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES; 30 | cr.accept(cv, parsingOptions); 31 | 32 | //(5)重新生成Class 33 | byte[] bytes2 = cw.toByteArray(); 34 | 35 | String target_filepath = getFilePath(target_name); 36 | FileUtils.writeBytes(target_filepath, bytes2); 37 | } 38 | 39 | public static String getFilePath(String internalName) { 40 | String relative_path = String.format("%s.class", internalName); 41 | return FileUtils.getFilePath(relative_path); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/ClassRemapperExample02.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassReader; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.ClassWriter; 7 | import org.objectweb.asm.commons.ClassRemapper; 8 | import org.objectweb.asm.commons.Remapper; 9 | import org.objectweb.asm.commons.SimpleRemapper; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class ClassRemapperExample02 { 15 | public static void main(String[] args) { 16 | String origin_name = "sample/HelloWorld"; 17 | String target_name = "sample/GoodChild"; 18 | String origin_filepath = getFilePath(origin_name); 19 | byte[] bytes1 = FileUtils.readBytes(origin_filepath); 20 | 21 | //(1)构建ClassReader 22 | ClassReader cr = new ClassReader(bytes1); 23 | 24 | //(2)构建ClassWriter 25 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 26 | 27 | //(3)串连ClassVisitor 28 | Map mapping = new HashMap<>(); 29 | mapping.put(origin_name, target_name); 30 | mapping.put(origin_name + ".intValue", "a"); 31 | mapping.put(origin_name + ".test()V", "b"); 32 | Remapper mapper = new SimpleRemapper(mapping); 33 | ClassVisitor cv = new ClassRemapper(cw, mapper); 34 | 35 | //(4)两者进行结合 36 | int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES; 37 | cr.accept(cv, parsingOptions); 38 | 39 | //(5)重新生成Class 40 | byte[] bytes2 = cw.toByteArray(); 41 | 42 | String target_filepath = getFilePath(target_name); 43 | FileUtils.writeBytes(target_filepath, bytes2); 44 | } 45 | 46 | public static String getFilePath(String internalName) { 47 | String relative_path = String.format("%s.class", internalName); 48 | return FileUtils.getFilePath(relative_path); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/ClassRemapperExample03.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassReader; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.ClassWriter; 7 | import org.objectweb.asm.commons.ClassRemapper; 8 | import org.objectweb.asm.commons.Remapper; 9 | import org.objectweb.asm.commons.SimpleRemapper; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class ClassRemapperExample03 { 15 | public static void main(String[] args) { 16 | Map mapping = new HashMap<>(); 17 | mapping.put("sample/HelloWorld", "sample/AAA"); 18 | mapping.put("sample/GoodChild", "sample/BBB"); 19 | mapping.put("sample/HelloWorld.test()V", "a"); 20 | mapping.put("sample/GoodChild.study()V", "b"); 21 | obfuscate("sample/HelloWorld", "sample/AAA", mapping); 22 | obfuscate("sample/GoodChild", "sample/BBB", mapping); 23 | } 24 | 25 | public static void obfuscate(String origin_name, String target_name, Map mapping) { 26 | String origin_filepath = getFilePath(origin_name); 27 | byte[] bytes1 = FileUtils.readBytes(origin_filepath); 28 | 29 | //(1)构建ClassReader 30 | ClassReader cr = new ClassReader(bytes1); 31 | 32 | //(2)构建ClassWriter 33 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 34 | 35 | //(3)串连ClassVisitor 36 | Remapper mapper = new SimpleRemapper(mapping); 37 | ClassVisitor cv = new ClassRemapper(cw, mapper); 38 | 39 | //(4)两者进行结合 40 | int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES; 41 | cr.accept(cv, parsingOptions); 42 | 43 | //(5)重新生成Class 44 | byte[] bytes2 = cw.toByteArray(); 45 | 46 | String target_filepath = getFilePath(target_name); 47 | FileUtils.writeBytes(target_filepath, bytes2); 48 | } 49 | 50 | public static String getFilePath(String internalName) { 51 | String relative_path = String.format("%s.class", internalName); 52 | return FileUtils.getFilePath(relative_path); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/GeneratorAdapterExample01.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.objectweb.asm.Type; 6 | import org.objectweb.asm.commons.GeneratorAdapter; 7 | import org.objectweb.asm.commons.Method; 8 | import org.objectweb.asm.util.TraceClassVisitor; 9 | 10 | import java.io.PrintStream; 11 | import java.io.PrintWriter; 12 | 13 | import static org.objectweb.asm.Opcodes.*; 14 | 15 | public class GeneratorAdapterExample01 { 16 | public static void main(String[] args) throws Exception { 17 | String relative_path = "sample/HelloWorld.class"; 18 | String filepath = FileUtils.getFilePath(relative_path); 19 | 20 | // (1) 生成byte[]内容 21 | byte[] bytes = dump(); 22 | 23 | // (2) 保存byte[]到文件 24 | FileUtils.writeBytes(filepath, bytes); 25 | } 26 | 27 | public static byte[] dump() throws Exception { 28 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 29 | PrintWriter printWriter = new PrintWriter(System.out); 30 | TraceClassVisitor cv = new TraceClassVisitor(cw, printWriter); 31 | 32 | cv.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", null); 33 | 34 | { 35 | Method m1 = Method.getMethod("void ()"); 36 | GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m1, null, null, cv); 37 | mg.loadThis(); 38 | mg.invokeConstructor(Type.getType(Object.class), m1); 39 | mg.returnValue(); 40 | mg.endMethod(); 41 | } 42 | 43 | { 44 | Method m2 = Method.getMethod("void main (String[])"); 45 | GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m2, null, null, cv); 46 | mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); 47 | mg.push("Hello world!"); 48 | mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); 49 | mg.returnValue(); 50 | mg.endMethod(); 51 | } 52 | 53 | cv.visitEnd(); 54 | 55 | return cw.toByteArray(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/InstructionAdapterExample01.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.Type; 7 | import org.objectweb.asm.commons.InstructionAdapter; 8 | 9 | import static org.objectweb.asm.Opcodes.*; 10 | 11 | public class InstructionAdapterExample01 { 12 | public static void main(String[] args) throws Exception { 13 | String relative_path = "sample/HelloWorld.class"; 14 | String filepath = FileUtils.getFilePath(relative_path); 15 | 16 | // (1) 生成byte[]内容 17 | byte[] bytes = dump(); 18 | 19 | // (2) 保存byte[]到文件 20 | FileUtils.writeBytes(filepath, bytes); 21 | } 22 | 23 | public static byte[] dump() throws Exception { 24 | // (1) 创建ClassWriter对象 25 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 26 | 27 | // (2) 调用visitXxx()方法 28 | cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", 29 | null, "java/lang/Object", null); 30 | 31 | { 32 | MethodVisitor mv1 = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); 33 | InstructionAdapter ia = new InstructionAdapter(mv1); 34 | ia.visitCode(); 35 | ia.load(0, InstructionAdapter.OBJECT_TYPE); 36 | ia.invokespecial("java/lang/Object", "", "()V", false); 37 | ia.areturn(Type.VOID_TYPE); 38 | ia.visitMaxs(1, 1); 39 | ia.visitEnd(); 40 | } 41 | 42 | { 43 | MethodVisitor mv2 = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null); 44 | InstructionAdapter ia = new InstructionAdapter(mv2); 45 | ia.visitCode(); 46 | ia.getstatic("java/lang/System", "out", "Ljava/io/PrintStream;"); 47 | ia.aconst("Hello World"); 48 | ia.invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 49 | ia.areturn(Type.VOID_TYPE); 50 | ia.visitMaxs(2, 1); 51 | ia.visitEnd(); 52 | } 53 | 54 | cw.visitEnd(); 55 | 56 | // (3) 调用toByteArray()方法 57 | return cw.toByteArray(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/commons/SerialVersionUIDAdderExample01.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.commons; 2 | 3 | import lsieun.utils.FileUtils; 4 | import org.objectweb.asm.ClassReader; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.ClassWriter; 7 | import org.objectweb.asm.Opcodes; 8 | import org.objectweb.asm.commons.SerialVersionUIDAdder; 9 | 10 | public class SerialVersionUIDAdderExample01 { 11 | public static void main(String[] args) { 12 | String relative_path = "sample/HelloWorld.class"; 13 | String filepath = FileUtils.getFilePath(relative_path); 14 | byte[] bytes1 = FileUtils.readBytes(filepath); 15 | 16 | //(1)构建ClassReader 17 | ClassReader cr = new ClassReader(bytes1); 18 | 19 | //(2)构建ClassWriter 20 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 21 | 22 | //(3)串连ClassVisitor 23 | int api = Opcodes.ASM9; 24 | ClassVisitor cv = new SerialVersionUIDAdder(cw); 25 | 26 | //(4)结合ClassReader和ClassVisitor 27 | int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES; 28 | cr.accept(cv, parsingOptions); 29 | 30 | //(5)生成byte[] 31 | byte[] bytes2 = cw.toByteArray(); 32 | 33 | FileUtils.writeBytes(filepath, bytes2); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ChangeURLVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import lsieun.annotation.todo.ToDo; 4 | import org.objectweb.asm.ClassVisitor; 5 | import org.objectweb.asm.Label; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Opcodes; 8 | import org.objectweb.asm.commons.AdviceAdapter; 9 | 10 | @ToDo("Remove") 11 | public class ChangeURLVisitor extends ClassVisitor { 12 | public ChangeURLVisitor(ClassVisitor classVisitor) { 13 | super(Opcodes.ASM9, classVisitor); 14 | } 15 | 16 | @Override 17 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 18 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 19 | if (mv != null && "".equals(name) && "(Ljava/net/URL;Ljava/lang/String;Ljava/net/URLStreamHandler;)V".equals(descriptor)) { 20 | mv = new ChangeURLAdapter(mv, access, name, descriptor); 21 | } 22 | return mv; 23 | } 24 | 25 | public class ChangeURLAdapter extends AdviceAdapter { 26 | protected ChangeURLAdapter(MethodVisitor methodVisitor, int access, String name, String descriptor) { 27 | super(Opcodes.ASM9, methodVisitor, access, name, descriptor); 28 | } 29 | 30 | @Override 31 | protected void onMethodEnter() { 32 | super.visitVarInsn(ALOAD, 2); 33 | Label elseLabel = new Label(); 34 | super.visitJumpInsn(IFNULL, elseLabel); 35 | super.visitVarInsn(ALOAD, 2); 36 | super.visitLdcInsn("/lservice/rpc/validateKey.action"); 37 | super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "contains", "(Ljava/lang/CharSequence;)Z", false); 38 | super.visitJumpInsn(IFEQ, elseLabel); 39 | super.visitTypeInsn(NEW, "java/net/MalformedURLException"); 40 | super.visitInsn(DUP); 41 | super.visitMethodInsn(INVOKESPECIAL, "java/net/MalformedURLException", "", "()V", false); 42 | super.visitInsn(ATHROW); 43 | super.visitLabel(elseLabel); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ClassChangeVersionVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.Opcodes; 5 | 6 | public class ClassChangeVersionVisitor extends ClassVisitor { 7 | public ClassChangeVersionVisitor(int api, ClassVisitor classVisitor) { 8 | super(api, classVisitor); 9 | } 10 | 11 | @Override 12 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 13 | super.visit(Opcodes.V1_7, access, name, signature, superName, interfaces); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ClassCloneVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | 5 | public class ClassCloneVisitor extends ClassVisitor { 6 | public ClassCloneVisitor(int api, ClassVisitor cw) { 7 | super(api, cw); 8 | } 9 | 10 | @Override 11 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 12 | super.visit(version, access, name, signature, superName, new String[]{"java/lang/Cloneable"}); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ClassDecompileVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.*; 4 | 5 | public class ClassDecompileVisitor extends ClassVisitor { 6 | 7 | public ClassDecompileVisitor() { 8 | super(Opcodes.ASM9); 9 | } 10 | 11 | @Override 12 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 13 | System.out.println(name + " extends " + superName + " {"); 14 | } 15 | 16 | @Override 17 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 18 | System.out.println(" " + descriptor + " " + name); 19 | return null; 20 | } 21 | 22 | @Override 23 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 24 | System.out.println(" " + name + " " + descriptor); 25 | return null; 26 | } 27 | 28 | @Override 29 | public void visitEnd() { 30 | System.out.println("}"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ClassListMemberVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | import java.util.Arrays; 8 | import java.util.Formatter; 9 | 10 | public class ClassListMemberVisitor extends ClassVisitor { 11 | private final Formatter fm = new Formatter(); 12 | 13 | public ClassListMemberVisitor(int api) { 14 | super(api); 15 | } 16 | 17 | public ClassListMemberVisitor(int api, ClassVisitor classVisitor) { 18 | super(api, classVisitor); 19 | } 20 | 21 | @Override 22 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 23 | fm.format("%s extends %s implements %s {%n", name, superName, Arrays.toString(interfaces)); 24 | } 25 | 26 | @Override 27 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 28 | fm.format(" %s: %s%n", name, descriptor); 29 | return null; 30 | } 31 | 32 | @Override 33 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 34 | fm.format(" %s: %s%n", name, descriptor); 35 | return null; 36 | } 37 | 38 | @Override 39 | public void visitEnd() { 40 | fm.format("}"); 41 | } 42 | 43 | public String getText() { 44 | return fm.toString(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/ClassRemoveAttributeVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | 5 | public class ClassRemoveAttributeVisitor extends ClassVisitor { 6 | public ClassRemoveAttributeVisitor(int api, ClassVisitor cv) { 7 | super(api, cv); 8 | } 9 | 10 | @Override 11 | public void visitSource(String source, String debug) { 12 | // do nothing 13 | } 14 | 15 | @Override 16 | public void visitOuterClass(String owner, String name, String descriptor) { 17 | // do nothing 18 | } 19 | 20 | @Override 21 | public void visitInnerClass(String name, String outerName, String innerName, int access) { 22 | // do nothing 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodAroundVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | import static org.objectweb.asm.Opcodes.*; 8 | 9 | public class MethodAroundVisitor extends ClassVisitor { 10 | public MethodAroundVisitor(int api, ClassVisitor classVisitor) { 11 | super(api, classVisitor); 12 | } 13 | 14 | @Override 15 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 16 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 17 | if (mv != null && !"".equals(name)) { 18 | boolean isAbstractMethod = (access & Opcodes.ACC_ABSTRACT) == Opcodes.ACC_ABSTRACT; 19 | boolean isNativeMethod = (access & Opcodes.ACC_NATIVE) == Opcodes.ACC_NATIVE; 20 | if (!isAbstractMethod && !isNativeMethod) { 21 | mv = new MethodAroundAdapter(api, mv); 22 | } 23 | } 24 | return mv; 25 | } 26 | 27 | private static class MethodAroundAdapter extends MethodVisitor { 28 | public MethodAroundAdapter(int api, MethodVisitor methodVisitor) { 29 | super(api, methodVisitor); 30 | } 31 | 32 | @Override 33 | public void visitCode() { 34 | // 首先,处理自己的代码逻辑 35 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 36 | super.visitLdcInsn("Method Enter..."); 37 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 38 | 39 | // 其次,调用父类的方法实现 40 | super.visitCode(); 41 | } 42 | 43 | @Override 44 | public void visitInsn(int opcode) { 45 | // 首先,处理自己的代码逻辑 46 | if (opcode == ATHROW || (opcode >= IRETURN && opcode <= RETURN)) { 47 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 48 | super.visitLdcInsn("Method Exit..."); 49 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 50 | } 51 | 52 | // 其次,调用父类的方法实现 53 | super.visitInsn(opcode); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodAroundVisitor2.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | import static org.objectweb.asm.Opcodes.*; 8 | 9 | public class MethodAroundVisitor2 extends ClassVisitor { 10 | public MethodAroundVisitor2(int api, ClassVisitor classVisitor) { 11 | super(api, classVisitor); 12 | } 13 | 14 | @Override 15 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 16 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 17 | if (mv != null && !"".equals(name)) { 18 | boolean isAbstractMethod = (access & Opcodes.ACC_ABSTRACT) == Opcodes.ACC_ABSTRACT; 19 | boolean isNativeMethod = (access & Opcodes.ACC_NATIVE) == Opcodes.ACC_NATIVE; 20 | if (!isAbstractMethod && !isNativeMethod) { 21 | mv = new MethodAroundAdapter(api, mv); 22 | } 23 | } 24 | return mv; 25 | } 26 | 27 | private static class MethodAroundAdapter extends MethodVisitor { 28 | public MethodAroundAdapter(int api, MethodVisitor methodVisitor) { 29 | super(api, methodVisitor); 30 | } 31 | 32 | @Override 33 | public void visitCode() { 34 | // 首先,处理自己的代码逻辑 35 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 36 | super.visitLdcInsn("Method Enter222"); 37 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 38 | 39 | // 其次,调用父类的方法实现 40 | super.visitCode(); 41 | } 42 | 43 | @Override 44 | public void visitInsn(int opcode) { 45 | // 首先,处理自己的代码逻辑 46 | if (opcode == ATHROW || (opcode >= IRETURN && opcode <= RETURN)) { 47 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 48 | super.visitLdcInsn("Method Exit222"); 49 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 50 | } 51 | 52 | // 其次,调用父类的方法实现 53 | super.visitInsn(opcode); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodEnterVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.Label; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.Opcodes; 7 | 8 | import static org.objectweb.asm.Opcodes.*; 9 | 10 | public class MethodEnterVisitor extends ClassVisitor { 11 | public MethodEnterVisitor(int api, ClassVisitor classVisitor) { 12 | super(api, classVisitor); 13 | } 14 | 15 | @Override 16 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 17 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 18 | if (mv != null && !"".equals(name)) { 19 | mv = new MethodEnterAdapter(api, mv); 20 | } 21 | return mv; 22 | } 23 | 24 | private static class MethodEnterAdapter extends MethodVisitor { 25 | public MethodEnterAdapter(int api, MethodVisitor methodVisitor) { 26 | super(api, methodVisitor); 27 | } 28 | 29 | @Override 30 | public void visitCode() { 31 | // 首先,处理自己的代码逻辑 32 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 33 | super.visitLdcInsn("Method Enter..."); 34 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 35 | 36 | // 其次,调用父类的方法实现 37 | super.visitCode(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodExitVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | public class MethodExitVisitor extends ClassVisitor { 8 | public MethodExitVisitor(int api, ClassVisitor classVisitor) { 9 | super(api, classVisitor); 10 | } 11 | 12 | @Override 13 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 14 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 15 | if (mv != null && !"".equals(name)) { 16 | mv = new MethodExitAdapter(api, mv); 17 | } 18 | return mv; 19 | } 20 | 21 | private static class MethodExitAdapter extends MethodVisitor { 22 | public MethodExitAdapter(int api, MethodVisitor methodVisitor) { 23 | super(api, methodVisitor); 24 | } 25 | 26 | @Override 27 | public void visitInsn(int opcode) { 28 | // 首先,处理自己的代码逻辑 29 | if (opcode == Opcodes.ATHROW || (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) { 30 | super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 31 | super.visitLdcInsn("Method Exit..."); 32 | super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 33 | } 34 | 35 | // 其次,调用父类的方法实现 36 | super.visitInsn(opcode); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodFindInvokeVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.util.Printer; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class MethodFindInvokeVisitor extends ClassVisitor { 11 | private final String methodName; 12 | private final String methodDesc; 13 | 14 | public MethodFindInvokeVisitor(int api, ClassVisitor classVisitor, String methodName, String methodDesc) { 15 | super(api, classVisitor); 16 | this.methodName = methodName; 17 | this.methodDesc = methodDesc; 18 | } 19 | 20 | @Override 21 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 22 | if (methodName.equals(name) && methodDesc.equals(descriptor)) { 23 | return new MethodFindInvokeAdapter(api, null); 24 | } 25 | return null; 26 | } 27 | 28 | private static class MethodFindInvokeAdapter extends MethodVisitor { 29 | private final List list = new ArrayList<>(); 30 | 31 | public MethodFindInvokeAdapter(int api, MethodVisitor methodVisitor) { 32 | super(api, methodVisitor); 33 | } 34 | 35 | @Override 36 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { 37 | // 首先,处理自己的代码逻辑 38 | String info = String.format("%s %s.%s%s", Printer.OPCODES[opcode], owner, name, descriptor); 39 | if (!list.contains(info)) { 40 | list.add(info); 41 | } 42 | 43 | // 其次,调用父类的方法实现 44 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 45 | } 46 | 47 | @Override 48 | public void visitEnd() { 49 | // 首先,处理自己的代码逻辑 50 | for (String item : list) { 51 | System.out.println(item); 52 | } 53 | 54 | // 其次,调用父类的方法实现 55 | super.visitEnd(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodRemoveAddZeroVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import static org.objectweb.asm.Opcodes.*; 7 | 8 | public class MethodRemoveAddZeroVisitor extends ClassVisitor { 9 | public MethodRemoveAddZeroVisitor(int api, ClassVisitor classVisitor) { 10 | super(api, classVisitor); 11 | } 12 | 13 | @Override 14 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 15 | MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); 16 | if (mv != null && !"".equals(name) && !"".equals(name)) { 17 | boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0; 18 | boolean isNativeMethod = (access & ACC_NATIVE) != 0; 19 | if (!isAbstractMethod && !isNativeMethod) { 20 | mv = new MethodRemoveAddZeroAdapter(api, mv); 21 | } 22 | } 23 | return mv; 24 | } 25 | 26 | private static class MethodRemoveAddZeroAdapter extends MethodPatternAdapter { 27 | private static final int SEEN_ICONST_0 = 1; 28 | 29 | public MethodRemoveAddZeroAdapter(int api, MethodVisitor methodVisitor) { 30 | super(api, methodVisitor); 31 | } 32 | 33 | @Override 34 | public void visitInsn(int opcode) { 35 | // 第一,对于感兴趣的状态进行处理 36 | switch (state) { 37 | case SEEN_NOTHING: 38 | if (opcode == ICONST_0) { 39 | state = SEEN_ICONST_0; 40 | return; 41 | } 42 | break; 43 | case SEEN_ICONST_0: 44 | if (opcode == IADD) { 45 | state = SEEN_NOTHING; 46 | return; 47 | } 48 | else if (opcode == ICONST_0) { 49 | mv.visitInsn(ICONST_0); 50 | return; 51 | } 52 | break; 53 | } 54 | 55 | // 第二,对于不感兴趣的状态,交给父类进行处理 56 | super.visitInsn(opcode); 57 | } 58 | 59 | @Override 60 | protected void visitInsn() { 61 | if (state == SEEN_ICONST_0) { 62 | mv.visitInsn(ICONST_0); 63 | } 64 | state = SEEN_NOTHING; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/MethodRemoveNopVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import static org.objectweb.asm.Opcodes.*; 7 | 8 | public class MethodRemoveNopVisitor extends ClassVisitor { 9 | public MethodRemoveNopVisitor(int api, ClassVisitor classVisitor) { 10 | super(api, classVisitor); 11 | } 12 | 13 | @Override 14 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 15 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 16 | if (mv != null && !"".equals(name) && !"".equals(name)) { 17 | boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0; 18 | boolean isNativeMethod = (access & ACC_NATIVE) != 0; 19 | if (!isAbstractMethod && !isNativeMethod) { 20 | mv = new MethodRemoveNopAdapter(api, mv); 21 | } 22 | 23 | } 24 | return mv; 25 | } 26 | 27 | private static class MethodRemoveNopAdapter extends MethodVisitor { 28 | public MethodRemoveNopAdapter(int api, MethodVisitor methodVisitor) { 29 | super(api, methodVisitor); 30 | } 31 | 32 | @Override 33 | public void visitInsn(int opcode) { 34 | if (opcode != NOP) { 35 | super.visitInsn(opcode); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/SuperPackageAttribute.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core; 2 | 3 | import org.objectweb.asm.*; 4 | 5 | public class SuperPackageAttribute extends Attribute { 6 | public String name; 7 | 8 | public SuperPackageAttribute() { 9 | super("Superpackage"); 10 | } 11 | 12 | public SuperPackageAttribute(String name) { 13 | this(); 14 | this.name = name; 15 | } 16 | 17 | @Override 18 | protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) { 19 | String name = classReader.readUTF8(offset, charBuffer); 20 | return new SuperPackageAttribute(name); 21 | } 22 | 23 | @Override 24 | protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) { 25 | int index = classWriter.newUTF8(name); 26 | return new ByteVector().putShort(index); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return String.format("%s {name='%s'}", type, name); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/counter/ClassCounterVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.counter; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | import static org.objectweb.asm.Opcodes.*; 8 | 9 | public class ClassCounterVisitor extends ClassVisitor { 10 | private String owner; 11 | private boolean isInterface; 12 | 13 | public ClassCounterVisitor(int api, ClassVisitor cv) { 14 | super(api, cv); 15 | } 16 | 17 | @Override 18 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 19 | super.visit(version, access, name, signature, superName, interfaces); 20 | owner = name; 21 | isInterface = (access & ACC_INTERFACE) != 0; 22 | } 23 | 24 | @Override 25 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 26 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 27 | if (!isInterface && mv != null && !name.equals("")) { 28 | String fieldName = name + "_count"; 29 | mv = new MethodCounterAdapter(api, mv, owner, fieldName); 30 | 31 | FieldVisitor fv = super.visitField(ACC_PUBLIC | ACC_STATIC, fieldName, "I", null, null); 32 | if (fv != null) { 33 | fv.visitEnd(); 34 | } 35 | } 36 | return mv; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/counter/MethodCounterAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.counter; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | 5 | import static org.objectweb.asm.Opcodes.*; 6 | 7 | public class MethodCounterAdapter extends MethodVisitor { 8 | private final String owner; 9 | private final String fieldName; 10 | 11 | public MethodCounterAdapter(int api, MethodVisitor mv, String owner, String fieldName) { 12 | super(api, mv); 13 | this.owner = owner; 14 | this.fieldName = fieldName; 15 | } 16 | 17 | @Override 18 | public void visitCode() { 19 | super.visitFieldInsn(GETSTATIC, owner, fieldName, "I"); 20 | super.visitInsn(ICONST_1); 21 | super.visitInsn(IADD); 22 | super.visitFieldInsn(PUTSTATIC, owner, fieldName, "I"); 23 | super.visitCode(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyAnnotationVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.AnnotationVisitor; 4 | 5 | public class EmptyAnnotationVisitor extends AnnotationVisitor { 6 | public EmptyAnnotationVisitor(int api, AnnotationVisitor annotationVisitor) { 7 | super(api, annotationVisitor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyClassVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.*; 4 | 5 | public class EmptyClassVisitor extends ClassVisitor { 6 | public EmptyClassVisitor(int api, ClassVisitor classVisitor) { 7 | super(api, classVisitor); 8 | } 9 | 10 | @Override 11 | public ModuleVisitor visitModule(String name, int access, String version) { 12 | ModuleVisitor mv = super.visitModule(name, access, version); 13 | return new EmptyModuleVisitor(api, mv); 14 | } 15 | 16 | @Override 17 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { 18 | AnnotationVisitor av = super.visitAnnotation(descriptor, visible); 19 | return new EmptyAnnotationVisitor(api, av); 20 | } 21 | 22 | @Override 23 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { 24 | AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, descriptor, visible); 25 | return new EmptyAnnotationVisitor(api, av); 26 | } 27 | 28 | @Override 29 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) { 30 | RecordComponentVisitor rcv = super.visitRecordComponent(name, descriptor, signature); 31 | return new EmptyRecordComponentVisitor(api, rcv); 32 | } 33 | 34 | @Override 35 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 36 | FieldVisitor fv = super.visitField(access, name, descriptor, signature, value); 37 | return new EmptyFieldVisitor(api, fv); 38 | } 39 | 40 | @Override 41 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 42 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 43 | return new EmptyMethodVisitor(api, mv); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.FieldVisitor; 4 | 5 | public class EmptyFieldVisitor extends FieldVisitor { 6 | public EmptyFieldVisitor(int api, FieldVisitor fieldVisitor) { 7 | super(api, fieldVisitor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyMethodVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | 5 | public class EmptyMethodVisitor extends MethodVisitor { 6 | public EmptyMethodVisitor(int api, MethodVisitor methodVisitor) { 7 | super(api, methodVisitor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyModuleVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.ModuleVisitor; 4 | 5 | public class EmptyModuleVisitor extends ModuleVisitor { 6 | public EmptyModuleVisitor(int api, ModuleVisitor moduleVisitor) { 7 | super(api, moduleVisitor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/empty/EmptyRecordComponentVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.empty; 2 | 3 | import org.objectweb.asm.RecordComponentVisitor; 4 | 5 | public class EmptyRecordComponentVisitor extends RecordComponentVisitor { 6 | public EmptyRecordComponentVisitor(int api, RecordComponentVisitor recordComponentVisitor) { 7 | super(api, recordComponentVisitor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/info/InfoFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.info; 2 | 3 | import org.objectweb.asm.FieldVisitor; 4 | 5 | public class InfoFieldVisitor extends FieldVisitor { 6 | public InfoFieldVisitor(int api, FieldVisitor fieldVisitor) { 7 | super(api, fieldVisitor); 8 | } 9 | 10 | @Override 11 | public void visitEnd() { 12 | String line = String.format(" FieldVisitor.visitEnd();"); 13 | System.out.println(line); 14 | super.visitEnd(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/timer/ClassTimerVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.timer; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | import static org.objectweb.asm.Opcodes.*; 8 | 9 | public class ClassTimerVisitor extends ClassVisitor { 10 | private String owner; 11 | private boolean isInterface; 12 | 13 | public ClassTimerVisitor(int api, ClassVisitor cv) { 14 | super(api, cv); 15 | } 16 | 17 | @Override 18 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 19 | super.visit(version, access, name, signature, superName, interfaces); 20 | owner = name; 21 | isInterface = (access & ACC_INTERFACE) != 0; 22 | } 23 | 24 | @Override 25 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 26 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 27 | if (!isInterface && mv != null && !name.equals("")) { 28 | mv = new MethodTimerAdapter(api, mv, owner); 29 | } 30 | return mv; 31 | } 32 | 33 | @Override 34 | public void visitEnd() { 35 | if (!isInterface) { 36 | FieldVisitor fv = super.visitField(ACC_PUBLIC | ACC_STATIC, "timer", "J", null, null); 37 | if (fv != null) { 38 | fv.visitEnd(); 39 | } 40 | } 41 | super.visitEnd(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/core/timer/MethodTimerAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.core.timer; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | 5 | import static org.objectweb.asm.Opcodes.*; 6 | 7 | public class MethodTimerAdapter extends MethodVisitor { 8 | private final String owner; 9 | 10 | public MethodTimerAdapter(int api, MethodVisitor mv, String owner) { 11 | super(api, mv); 12 | this.owner = owner; 13 | } 14 | 15 | @Override 16 | public void visitCode() { 17 | super.visitCode(); 18 | super.visitFieldInsn(GETSTATIC, owner, "timer", "J"); 19 | super.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false); 20 | super.visitInsn(LSUB); 21 | super.visitFieldInsn(PUTSTATIC, owner, "timer", "J"); 22 | } 23 | 24 | @Override 25 | public void visitInsn(int opcode) { 26 | if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) { 27 | super.visitFieldInsn(GETSTATIC, owner, "timer", "J"); 28 | super.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false); 29 | super.visitInsn(LADD); 30 | super.visitFieldInsn(PUTSTATIC, owner, "timer", "J"); 31 | } 32 | super.visitInsn(opcode); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/CheckMethodAnnotationVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.AnnotationVisitor; 4 | import org.objectweb.asm.ClassVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class CheckMethodAnnotationVisitor extends ClassVisitor { 11 | // 需要处理的方法放到这里 12 | public List result = new ArrayList<>(); 13 | 14 | public CheckMethodAnnotationVisitor(int api, ClassVisitor classVisitor) { 15 | super(api, classVisitor); 16 | } 17 | 18 | @Override 19 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 20 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 21 | mv = new CheckMethodAnnotationAdapter(api, mv, name, descriptor); 22 | return mv; 23 | } 24 | 25 | private class CheckMethodAnnotationAdapter extends MethodVisitor { 26 | private final String methodName; 27 | private final String methodDesc; 28 | 29 | public CheckMethodAnnotationAdapter(int api, MethodVisitor methodVisitor, String methodName, String methodDesc) { 30 | super(api, methodVisitor); 31 | this.methodName = methodName; 32 | this.methodDesc = methodDesc; 33 | } 34 | 35 | @Override 36 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { 37 | // 在这里进行判断:是否需要对方法进行处理 38 | if (descriptor.equals("Lsample/MyTag;")) { 39 | String item = methodName + ":" + methodDesc; 40 | result.add(item); 41 | } 42 | return super.visitAnnotation(descriptor, visible); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassAddAnnotationVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.*; 4 | 5 | public class ClassAddAnnotationVisitor extends ClassVisitor { 6 | private final String annotationDesc; 7 | private boolean isAnnotationPresent; 8 | 9 | public ClassAddAnnotationVisitor(int api, ClassVisitor classVisitor, String annotationDesc) { 10 | super(api, classVisitor); 11 | this.annotationDesc = annotationDesc; 12 | } 13 | 14 | @Override 15 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { 16 | if (visible && descriptor.equals(annotationDesc)) { 17 | isAnnotationPresent = true; 18 | } 19 | return super.visitAnnotation(descriptor, visible); 20 | } 21 | 22 | @Override 23 | public void visitNestMember(String nestMember) { 24 | addAnnotation(); 25 | super.visitNestMember(nestMember); 26 | } 27 | 28 | @Override 29 | public void visitInnerClass(String name, String outerName, String innerName, int access) { 30 | addAnnotation(); 31 | super.visitInnerClass(name, outerName, innerName, access); 32 | } 33 | 34 | @Override 35 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) { 36 | addAnnotation(); 37 | return super.visitRecordComponent(name, descriptor, signature); 38 | } 39 | 40 | @Override 41 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 42 | addAnnotation(); 43 | return super.visitField(access, name, descriptor, signature, value); 44 | } 45 | 46 | @Override 47 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 48 | addAnnotation(); 49 | return super.visitMethod(access, name, descriptor, signature, exceptions); 50 | } 51 | 52 | @Override 53 | public void visitEnd() { 54 | addAnnotation(); 55 | super.visitEnd(); 56 | } 57 | 58 | private void addAnnotation() { 59 | if (!isAnnotationPresent) { 60 | AnnotationVisitor av = super.visitAnnotation(annotationDesc, true); 61 | if (av != null) { 62 | av.visitEnd(); 63 | } 64 | isAnnotationPresent = true; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassAddCustomAttributeVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.ByteUtils; 4 | import org.objectweb.asm.*; 5 | 6 | public class ClassAddCustomAttributeVisitor extends ClassVisitor { 7 | private final String attrName; 8 | private final String attrContent; 9 | private boolean isAttrPresent; 10 | 11 | public ClassAddCustomAttributeVisitor(int api, ClassVisitor classVisitor, String attrName, String attrContent) { 12 | super(api, classVisitor); 13 | this.attrName = attrName; 14 | this.attrContent = attrContent; 15 | this.isAttrPresent = false; 16 | } 17 | 18 | @Override 19 | public void visitAttribute(Attribute attribute) { 20 | if (attribute.type.equals(attrName)) { 21 | isAttrPresent = true; 22 | } 23 | super.visitAttribute(attribute); 24 | } 25 | 26 | @Override 27 | public void visitNestMember(String nestMember) { 28 | addAttribute(); 29 | super.visitNestMember(nestMember); 30 | } 31 | 32 | @Override 33 | public void visitInnerClass(String name, String outerName, String innerName, int access) { 34 | addAttribute(); 35 | super.visitInnerClass(name, outerName, innerName, access); 36 | } 37 | 38 | @Override 39 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) { 40 | addAttribute(); 41 | return super.visitRecordComponent(name, descriptor, signature); 42 | } 43 | 44 | @Override 45 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 46 | addAttribute(); 47 | return super.visitField(access, name, descriptor, signature, value); 48 | } 49 | 50 | @Override 51 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 52 | addAttribute(); 53 | return super.visitMethod(access, name, descriptor, signature, exceptions); 54 | } 55 | 56 | @Override 57 | public void visitEnd() { 58 | addAttribute(); 59 | super.visitEnd(); 60 | } 61 | 62 | private void addAttribute() { 63 | if (!isAttrPresent) { 64 | int hashCode = attrContent.hashCode(); 65 | byte[] info = ByteUtils.intToByteArray(hashCode); 66 | Attribute attr = new CustomAttribute(attrName, info); 67 | super.visitAttribute(attr); 68 | isAttrPresent = true; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassAddFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | 6 | public class ClassAddFieldVisitor extends ClassVisitor { 7 | private final int fieldAccess; 8 | private final String fieldName; 9 | private final String fieldDesc; 10 | private boolean isFieldPresent; 11 | 12 | public ClassAddFieldVisitor(int api, ClassVisitor classVisitor, int fieldAccess, String fieldName, String fieldDesc) { 13 | super(api, classVisitor); 14 | this.fieldAccess = fieldAccess; 15 | this.fieldName = fieldName; 16 | this.fieldDesc = fieldDesc; 17 | } 18 | 19 | @Override 20 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 21 | if (name.equals(fieldName)) { 22 | isFieldPresent = true; 23 | } 24 | return super.visitField(access, name, descriptor, signature, value); 25 | } 26 | 27 | @Override 28 | public void visitEnd() { 29 | if (!isFieldPresent) { 30 | FieldVisitor fv = super.visitField(fieldAccess, fieldName, fieldDesc, null, null); 31 | if (fv != null) { 32 | fv.visitEnd(); 33 | } 34 | } 35 | super.visitEnd(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassAddInterfaceVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class ClassAddInterfaceVisitor extends ClassVisitor { 10 | private final String[] newInterfaces; 11 | 12 | public ClassAddInterfaceVisitor(int api, ClassVisitor cv, String[] newInterfaces) { 13 | super(api, cv); 14 | this.newInterfaces = newInterfaces; 15 | } 16 | 17 | @Override 18 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 19 | Set set = new HashSet<>(); // 注意,这里使用Set是为了避免出现重复接口 20 | if (interfaces != null) { 21 | set.addAll(Arrays.asList(interfaces)); 22 | } 23 | if (newInterfaces != null) { 24 | set.addAll(Arrays.asList(newInterfaces)); 25 | } 26 | super.visit(version, access, name, signature, superName, set.toArray(new String[0])); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassAddMethodVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public abstract class ClassAddMethodVisitor extends ClassVisitor { 7 | private final int methodAccess; 8 | private final String methodName; 9 | private final String methodDesc; 10 | private final String methodSignature; 11 | private final String[] methodExceptions; 12 | private boolean isMethodPresent; 13 | 14 | public ClassAddMethodVisitor(int api, ClassVisitor cv, int methodAccess, String methodName, String methodDesc, 15 | String signature, String[] exceptions) { 16 | super(api, cv); 17 | this.methodAccess = methodAccess; 18 | this.methodName = methodName; 19 | this.methodDesc = methodDesc; 20 | this.methodSignature = signature; 21 | this.methodExceptions = exceptions; 22 | this.isMethodPresent = false; 23 | } 24 | 25 | @Override 26 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 27 | if (name.equals(methodName) && descriptor.equals(methodDesc)) { 28 | isMethodPresent = true; 29 | } 30 | return super.visitMethod(access, name, descriptor, signature, exceptions); 31 | } 32 | 33 | @Override 34 | public void visitEnd() { 35 | if (!isMethodPresent) { 36 | MethodVisitor mv = super.visitMethod(methodAccess, methodName, methodDesc, methodSignature, methodExceptions); 37 | if (mv != null) { 38 | // create method body 39 | generateMethodBody(mv); 40 | } 41 | } 42 | 43 | super.visitEnd(); 44 | } 45 | 46 | protected abstract void generateMethodBody(MethodVisitor mv); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassGetAttributeContentVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | public class ClassGetAttributeContentVisitor extends ClassVisitor { 8 | private final StringBuilder attr = new StringBuilder(); 9 | 10 | public ClassGetAttributeContentVisitor(int api, ClassVisitor classVisitor) { 11 | super(api, classVisitor); 12 | } 13 | 14 | @Override 15 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 16 | attr.append(name); 17 | super.visit(version, access, name, signature, superName, interfaces); 18 | } 19 | 20 | @Override 21 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 22 | attr.append(name); 23 | return super.visitField(access, name, descriptor, signature, value); 24 | } 25 | 26 | @Override 27 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 28 | attr.append(name); 29 | return super.visitMethod(access, name, descriptor, signature, exceptions); 30 | } 31 | 32 | public String getAttributeContent() { 33 | return attr.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassMergeVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.tree.ClassNode; 5 | import org.objectweb.asm.tree.FieldNode; 6 | import org.objectweb.asm.tree.MethodNode; 7 | 8 | import java.util.List; 9 | 10 | public class ClassMergeVisitor extends ClassVisitor { 11 | private final ClassNode anotherClass; 12 | 13 | public ClassMergeVisitor(int api, ClassVisitor classVisitor, ClassNode anotherClass) { 14 | super(api, classVisitor); 15 | this.anotherClass = anotherClass; 16 | } 17 | 18 | @Override 19 | public void visitEnd() { 20 | List fields = anotherClass.fields; 21 | for (FieldNode fn : fields) { 22 | fn.accept(this); 23 | } 24 | 25 | List methods = anotherClass.methods; 26 | for (MethodNode mn : methods) { 27 | String methodName = mn.name; 28 | if ("".equals(methodName)) { 29 | continue; 30 | } 31 | mn.accept(this); 32 | } 33 | super.visitEnd(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassRemoveFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | 6 | public class ClassRemoveFieldVisitor extends ClassVisitor { 7 | private final String fieldName; 8 | private final String fieldDesc; 9 | 10 | public ClassRemoveFieldVisitor(int api, ClassVisitor cv, String fieldName, String fieldDesc) { 11 | super(api, cv); 12 | this.fieldName = fieldName; 13 | this.fieldDesc = fieldDesc; 14 | } 15 | 16 | @Override 17 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 18 | if (name.equals(fieldName) && descriptor.equals(fieldDesc)) { 19 | return null; 20 | } 21 | else { 22 | return super.visitField(access, name, descriptor, signature, value); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassRemoveMethodVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public class ClassRemoveMethodVisitor extends ClassVisitor { 7 | private final String methodName; 8 | private final String methodDesc; 9 | 10 | public ClassRemoveMethodVisitor(int api, ClassVisitor cv, String methodName, String methodDesc) { 11 | super(api, cv); 12 | this.methodName = methodName; 13 | this.methodDesc = methodDesc; 14 | } 15 | 16 | @Override 17 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 18 | if (name.equals(methodName) && descriptor.equals(methodDesc)) { 19 | return null; 20 | } 21 | else { 22 | return super.visitMethod(access, name, descriptor, signature, exceptions); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassRenameAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.FieldVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | public class ClassRenameAdapter extends ClassVisitor { 8 | private final String oldOwner; 9 | private final String newOwner; 10 | 11 | public ClassRenameAdapter(int api, ClassVisitor classVisitor, String oldOwner, String newOwner) { 12 | super(api, classVisitor); 13 | this.oldOwner = oldOwner; 14 | this.newOwner = newOwner; 15 | } 16 | 17 | @Override 18 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 19 | if (name.equals(oldOwner)) { 20 | super.visit(version, access, newOwner, signature, superName, interfaces); 21 | } 22 | else { 23 | super.visit(version, access, name, signature, superName, interfaces); 24 | } 25 | } 26 | 27 | @Override 28 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { 29 | String oldDesc = getDescriptor(oldOwner); 30 | if (descriptor.contains(oldDesc)) { 31 | String newDesc = getDescriptor(newOwner); 32 | String desc = descriptor.replaceAll(oldDesc, newDesc); 33 | return super.visitField(access, name, desc, signature, value); 34 | } 35 | return super.visitField(access, name, descriptor, signature, value); 36 | } 37 | 38 | @Override 39 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 40 | String desc = descriptor; 41 | String oldDesc = getDescriptor(oldOwner); 42 | if (descriptor.contains(oldDesc)) { 43 | String newDesc = getDescriptor(newOwner); 44 | desc = descriptor.replaceAll(oldDesc, newDesc); 45 | } 46 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 47 | if (mv != null) { 48 | mv = new RefRenameAdapter(api, mv, oldOwner, newOwner); 49 | } 50 | return mv; 51 | } 52 | 53 | public String getDescriptor(String internalName) { 54 | return String.format("L%s;", internalName); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassRenameAdapterRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | public class ClassRenameAdapterRun { 11 | public static void main(String[] args) { 12 | String origin_name = "sample/HelloWorld"; 13 | String target_name = "sample/GoodChild"; 14 | String origin_filepath = getFilePath(origin_name); 15 | byte[] bytes1 = ReadUtils.readByPath(origin_filepath); 16 | 17 | //(1)构建ClassReader 18 | ClassReader cr = new ClassReader(bytes1); 19 | 20 | //(2)构建ClassWriter 21 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 22 | 23 | //(3)串连ClassVisitor 24 | ClassVisitor cv = new ClassRenameAdapter(Opcodes.ASM9, cw, origin_name, target_name); 25 | 26 | //(4)两者进行结合 27 | cr.accept(cv, 0); 28 | 29 | //(5)重新生成Class 30 | byte[] bytes2 = cw.toByteArray(); 31 | 32 | String target_filepath = getFilePath(target_name); 33 | FileUtils.writeBytes(target_filepath, bytes2); 34 | } 35 | 36 | public static String getFilePath(String internalName) { 37 | String relative_path = String.format("%s.class", internalName); 38 | return FileUtils.getFilePath(relative_path); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/ClassReplaceMethodBodyVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public abstract class ClassReplaceMethodBodyVisitor extends ClassVisitor { 7 | protected String owner; 8 | protected final String methodName; 9 | protected final String methodDesc; 10 | private final boolean keepOriginalMethod; 11 | 12 | public ClassReplaceMethodBodyVisitor(int api, ClassVisitor cv, String methodName, String methodDesc) { 13 | this(api, cv, methodName, methodDesc, true); 14 | } 15 | 16 | public ClassReplaceMethodBodyVisitor(int api, ClassVisitor cv, String methodName, String methodDesc, boolean keepOriginalMethod) { 17 | super(api, cv); 18 | this.methodName = methodName; 19 | this.methodDesc = methodDesc; 20 | this.keepOriginalMethod = keepOriginalMethod; 21 | } 22 | 23 | @Override 24 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 25 | super.visit(version, access, name, signature, superName, interfaces); 26 | this.owner = name; 27 | } 28 | 29 | @Override 30 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 31 | if (name.equals(methodName) && descriptor.equals(methodDesc)) { 32 | // 生成新方法(从抽象逻辑上来说,这是第二步;从代码角度来说,先执行) 33 | generateNewMethod(access, name, descriptor, signature, exceptions); 34 | 35 | if (keepOriginalMethod) { 36 | // 修改原来方法的名字(从抽象逻辑上来说,这是第一步;从代码角度来说,后执行) 37 | String newName = getNewName(name); 38 | return super.visitMethod(access, newName, descriptor, signature, exceptions); 39 | } 40 | else { 41 | // 删除原来的方法 42 | return null; 43 | } 44 | 45 | } 46 | return super.visitMethod(access, name, descriptor, signature, exceptions); 47 | } 48 | 49 | protected String getNewName(String name) { 50 | return String.format("orig$%s", name); 51 | } 52 | 53 | private void generateNewMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 54 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 55 | if (mv != null) { 56 | generateMethodBody(mv); 57 | } 58 | } 59 | 60 | protected abstract void generateMethodBody(MethodVisitor mv); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/CustomAttribute.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.ByteUtils; 4 | import lsieun.utils.HexFormat; 5 | import lsieun.utils.HexUtils; 6 | import org.objectweb.asm.*; 7 | 8 | public class CustomAttribute extends Attribute { 9 | private static final byte[] CODE_BLOB_BYTE_ARRAY = new byte[]{ 10 | (byte) 0xC0, (byte) 0xDE, (byte) 0xB1, 0x0B 11 | }; 12 | private static final int CODE_BLOB_INT_VALUE = 0xC0DEB10B; 13 | 14 | private final byte[] info; 15 | 16 | public CustomAttribute(String type, byte[] info) { 17 | super(type); 18 | this.info = info; 19 | } 20 | 21 | @Override 22 | protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) { 23 | int magic = classReader.readInt(offset); 24 | if (magic != CODE_BLOB_INT_VALUE) { 25 | throw new RuntimeException("magic is not right! expected: " + CODE_BLOB_INT_VALUE + ", actual: " + magic); 26 | } 27 | int value = classReader.readInt(offset + 4); 28 | byte[] info = ByteUtils.intToByteArray(value); 29 | return new CustomAttribute(CustomAttribute.class.getSimpleName(), info); 30 | } 31 | 32 | @Override 33 | protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) { 34 | ByteVector byteVector = new ByteVector(); 35 | byteVector.putByteArray(CODE_BLOB_BYTE_ARRAY, 0, CODE_BLOB_BYTE_ARRAY.length); 36 | byteVector.putByteArray(info, 0, info.length); 37 | return byteVector; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return String.format("%s {name='%s'}", type, HexUtils.format(info, HexFormat.FORMAT_FF_FF)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/FieldAccessAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import java.util.List; 7 | 8 | public class FieldAccessAdapter extends ClassVisitor { 9 | private final List list; 10 | 11 | public FieldAccessAdapter(int api, ClassVisitor cv, List list) { 12 | super(api, cv); 13 | this.list = list; 14 | } 15 | 16 | @Override 17 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 18 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 19 | if (mv != null) { 20 | mv = new FieldAccessConverter(api, mv, list); 21 | } 22 | return mv; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/FieldAccessAdapterRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class FieldAccessAdapterRun { 14 | public static void main(String[] args) { 15 | String relative_path = "sample/HelloWorld.class"; 16 | String filepath = FileUtils.getFilePath(relative_path); 17 | byte[] bytes1 = ReadUtils.readByPath(filepath); 18 | 19 | //(1)构建ClassReader 20 | ClassReader cr = new ClassReader(bytes1); 21 | 22 | //(2)构建ClassWriter 23 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 24 | 25 | //(3)串连ClassVisitor 26 | Info info1 = new Info(Opcodes.GETFIELD, "sample/HelloWorld", "intValue", "I", 27 | Opcodes.INVOKEVIRTUAL, "sample/HelloWorld", "getHour", "()I"); 28 | Info info2 = new Info(Opcodes.GETSTATIC, "sample/HelloWorld", "staticValue", "I", 29 | Opcodes.INVOKESTATIC, "sample/GoodChild", "getAge", "()I"); 30 | List list = new ArrayList<>(); 31 | list.add(info1); 32 | list.add(info2); 33 | ClassVisitor cv = new FieldAccessAdapter(Opcodes.ASM9, cw, list); 34 | 35 | //(4)两者进行结合 36 | cr.accept(cv, ClassReader.SKIP_FRAMES); 37 | 38 | //(5)重新生成Class 39 | byte[] bytes2 = cw.toByteArray(); 40 | 41 | FileUtils.writeBytes(filepath, bytes2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/FieldAccessConverter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class FieldAccessConverter extends MethodVisitor { 9 | private final List list; 10 | 11 | public FieldAccessConverter(int api, MethodVisitor mv, List list) { 12 | super(api, mv); 13 | if (list == null) { 14 | this.list = new ArrayList<>(); 15 | } 16 | else { 17 | this.list = list; 18 | } 19 | } 20 | 21 | @Override 22 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { 23 | Info info = matchingInfo(opcode, owner, name, descriptor); 24 | if (info != null) { 25 | super.visitMethodInsn(info.targetOpcode, info.targetOwner, info.targetName, info.targetDesc, false); 26 | return; 27 | } 28 | super.visitFieldInsn(opcode, owner, name, descriptor); 29 | } 30 | 31 | private Info matchingInfo(int opcode, String owner, String name, String descriptor) { 32 | for (Info info : list) { 33 | if (opcode == info.srcOpcode && 34 | owner.equals(info.srcOwner) && 35 | name.equals(info.srcName) && 36 | descriptor.equals(info.srcDesc)) { 37 | return info; 38 | } 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/Info.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | public class Info { 4 | public final int srcOpcode; 5 | public final String srcOwner; 6 | public final String srcName; 7 | public final String srcDesc; 8 | 9 | public final int targetOpcode; 10 | public final String targetOwner; 11 | public final String targetName; 12 | public final String targetDesc; 13 | 14 | public Info( 15 | int srcOpcode, String srcOwner, String srcName, String srcDesc, 16 | int targetOpcode, String targetOwner, String targetName, String targetDesc) { 17 | this.srcOpcode = srcOpcode; 18 | this.srcOwner = srcOwner; 19 | this.srcName = srcName; 20 | this.srcDesc = srcDesc; 21 | this.targetOpcode = targetOpcode; 22 | this.targetOwner = targetOwner; 23 | this.targetName = targetName; 24 | this.targetDesc = targetDesc; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodCallAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import java.util.List; 7 | 8 | public class MethodCallAdapter extends ClassVisitor { 9 | private final List list; 10 | 11 | public MethodCallAdapter(int api, ClassVisitor cv, List list) { 12 | super(api, cv); 13 | this.list = list; 14 | } 15 | 16 | @Override 17 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 18 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 19 | if (mv != null) { 20 | mv = new MethodCallConverter(api, mv, list); 21 | } 22 | return mv; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodCallAdapterRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class MethodCallAdapterRun { 14 | public static void main(String[] args) { 15 | String relative_path = "sample/HelloWorld.class"; 16 | String filepath = FileUtils.getFilePath(relative_path); 17 | byte[] bytes1 = ReadUtils.readByPath(filepath); 18 | 19 | //(1)构建ClassReader 20 | ClassReader cr = new ClassReader(bytes1); 21 | 22 | //(2)构建ClassWriter 23 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 24 | 25 | //(3)串连ClassVisitor 26 | Info info1 = new Info(Opcodes.INVOKEVIRTUAL, "sample/HelloWorld", "add", "(II)I", 27 | Opcodes.INVOKEVIRTUAL, "sample/HelloWorld", "sub", "(II)I"); 28 | List list = new ArrayList<>(); 29 | list.add(info1); 30 | ClassVisitor cv = new MethodCallAdapter(Opcodes.ASM9, cw, list); 31 | 32 | //(4)两者进行结合 33 | cr.accept(cv, ClassReader.SKIP_FRAMES); 34 | 35 | //(5)重新生成Class 36 | byte[] bytes2 = cw.toByteArray(); 37 | 38 | FileUtils.writeBytes(filepath, bytes2); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodCallConverter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class MethodCallConverter extends MethodVisitor { 9 | private final List list; 10 | 11 | public MethodCallConverter(int api, MethodVisitor mv, List list) { 12 | super(api, mv); 13 | if (list == null) { 14 | this.list = new ArrayList<>(); 15 | } 16 | else { 17 | this.list = list; 18 | } 19 | } 20 | 21 | @Override 22 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { 23 | Info info = matchingInfo(opcode, owner, name, descriptor); 24 | if (info != null) { 25 | super.visitMethodInsn(info.targetOpcode, info.targetOwner, info.targetName, info.targetDesc, false); 26 | return; 27 | } 28 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 29 | } 30 | 31 | private Info matchingInfo(int opcode, String owner, String name, String descriptor) { 32 | for (Info info : list) { 33 | if (opcode == info.srcOpcode && 34 | owner.equals(info.srcOwner) && 35 | name.equals(info.srcName) && 36 | descriptor.equals(info.srcDesc)) { 37 | return info; 38 | } 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodEnteringAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | import org.objectweb.asm.commons.AdviceAdapter; 5 | 6 | public class MethodEnteringAdapter extends AdviceAdapter { 7 | private final String methodName; 8 | 9 | public MethodEnteringAdapter(int api, MethodVisitor mv, int access, String name, String descriptor) { 10 | super(api, mv, access, name, descriptor); 11 | this.methodName = name; 12 | } 13 | 14 | @Override 15 | protected void onMethodEnter() { 16 | super.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 17 | super.visitLdcInsn("Entering " + methodName + " Method"); 18 | super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodEnteringVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public class MethodEnteringVisitor extends ClassVisitor { 7 | public MethodEnteringVisitor(int api, ClassVisitor cv) { 8 | super(api, cv); 9 | } 10 | 11 | @Override 12 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 13 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 14 | if (mv != null) { 15 | mv = new MethodEnteringAdapter(api, mv, access, name, descriptor); 16 | } 17 | return mv; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodEnteringVisitorRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | public class MethodEnteringVisitorRun { 11 | public static void main(String[] args) { 12 | String relative_path = "sample/HelloWorld.class"; 13 | String filepath = FileUtils.getFilePath(relative_path); 14 | byte[] bytes1 = ReadUtils.readByPath(filepath); 15 | 16 | //(1)构建ClassReader 17 | ClassReader cr = new ClassReader(bytes1); 18 | 19 | //(2)构建ClassWriter 20 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 21 | 22 | //(3)串连ClassVisitor 23 | ClassVisitor cv = new MethodEnteringVisitor(Opcodes.ASM9, cw); 24 | 25 | //(4)两者进行结合 26 | cr.accept(cv, 0); 27 | 28 | //(5)重新生成Class 29 | byte[] bytes2 = cw.toByteArray(); 30 | 31 | FileUtils.writeBytes(filepath, bytes2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodExitingAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public class MethodExitingAdapter extends ClassVisitor { 7 | public MethodExitingAdapter(int api, ClassVisitor cv) { 8 | super(api, cv); 9 | } 10 | 11 | @Override 12 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 13 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 14 | if (mv != null) { 15 | mv = new MethodExitingConverter(api, mv, access, name, descriptor); 16 | } 17 | return mv; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodExitingAdapterRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | public class MethodExitingAdapterRun { 11 | public static void main(String[] args) { 12 | String relative_path = "sample/HelloWorld.class"; 13 | String filepath = FileUtils.getFilePath(relative_path); 14 | byte[] bytes1 = ReadUtils.readByPath(filepath); 15 | 16 | //(1)构建ClassReader 17 | ClassReader cr = new ClassReader(bytes1); 18 | 19 | //(2)构建ClassWriter 20 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 21 | 22 | //(3)串连ClassVisitor 23 | ClassVisitor cv = new MethodExitingAdapter(Opcodes.ASM9, cw); 24 | 25 | //(4)两者进行结合 26 | cr.accept(cv, ClassReader.SKIP_FRAMES); 27 | 28 | //(5)重新生成Class 29 | byte[] bytes2 = cw.toByteArray(); 30 | 31 | FileUtils.writeBytes(filepath, bytes2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodExitingConverter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | import org.objectweb.asm.Opcodes; 5 | import org.objectweb.asm.commons.AdviceAdapter; 6 | 7 | public class MethodExitingConverter extends AdviceAdapter { 8 | private final String methodName; 9 | 10 | protected MethodExitingConverter(int api, MethodVisitor mv, int access, String name, String descriptor) { 11 | super(api, mv, access, name, descriptor); 12 | this.methodName = name; 13 | } 14 | 15 | @Override 16 | protected void onMethodExit(int opcode) { 17 | super.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 18 | if (opcode == Opcodes.ATHROW) { 19 | super.visitLdcInsn("Exiting on exception " + methodName + " Method"); 20 | } 21 | else { 22 | super.visitLdcInsn("Exiting " + methodName + " Method"); 23 | } 24 | 25 | super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodFinallyAdapter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | public class MethodFinallyAdapter extends ClassVisitor { 7 | public MethodFinallyAdapter(int api, ClassVisitor cv) { 8 | super(api, cv); 9 | } 10 | 11 | @Override 12 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 13 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 14 | if (mv != null && "main".equals(name)) { 15 | mv = new MethodFinallyConverter(api, mv, access, name, descriptor); 16 | } 17 | return mv; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodFinallyAdapterRun.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import lsieun.utils.FileUtils; 4 | import lsieun.utils.ReadUtils; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.Opcodes; 9 | 10 | public class MethodFinallyAdapterRun { 11 | public static void main(String[] args) { 12 | String relative_path = "sample/HelloWorld.class"; 13 | String filepath = FileUtils.getFilePath(relative_path); 14 | byte[] bytes1 = ReadUtils.readByPath(filepath); 15 | 16 | //(1)构建ClassReader 17 | ClassReader cr = new ClassReader(bytes1); 18 | 19 | //(2)构建ClassWriter 20 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 21 | 22 | //(3)串连ClassVisitor 23 | ClassVisitor cv = new MethodFinallyAdapter(Opcodes.ASM9, cw); 24 | 25 | //(4)两者进行结合 26 | cr.accept(cv, ClassReader.SKIP_FRAMES); 27 | 28 | //(5)重新生成Class 29 | byte[] bytes2 = cw.toByteArray(); 30 | 31 | FileUtils.writeBytes(filepath, bytes2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodFinallyConverter.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.Label; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | import org.objectweb.asm.commons.AdviceAdapter; 7 | 8 | public class MethodFinallyConverter extends AdviceAdapter { 9 | private final String methodName; 10 | private final Label tryLabel = new Label(); 11 | private final Label finallyLabel = new Label(); 12 | 13 | protected MethodFinallyConverter(int api, MethodVisitor mv, int access, String name, String descriptor) { 14 | super(api, mv, access, name, descriptor); 15 | this.methodName = name; 16 | } 17 | 18 | @Override 19 | public void visitCode() { 20 | super.visitCode(); 21 | super.visitLabel(tryLabel); 22 | } 23 | 24 | @Override 25 | public void visitMaxs(int maxStack, int maxLocals) { 26 | 27 | super.visitLabel(finallyLabel); 28 | super.visitTryCatchBlock(tryLabel, finallyLabel, finallyLabel, null); 29 | 30 | onFinally(); 31 | super.visitInsn(Opcodes.ATHROW); 32 | 33 | super.visitMaxs(maxStack, maxLocals); 34 | } 35 | 36 | @Override 37 | protected void onMethodExit(int opcode) { 38 | if (opcode != Opcodes.ATHROW) { 39 | onFinally(); 40 | } 41 | } 42 | 43 | private void onFinally() { 44 | super.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); 45 | super.visitLdcInsn("Exiting " + methodName + " Method"); 46 | super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodPrintInstructionVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import static org.objectweb.asm.Opcodes.ACC_ABSTRACT; 7 | import static org.objectweb.asm.Opcodes.ACC_NATIVE; 8 | 9 | public class MethodPrintInstructionVisitor extends ClassVisitor { 10 | public MethodPrintInstructionVisitor(int api, ClassVisitor classVisitor) { 11 | super(api, classVisitor); 12 | } 13 | 14 | @Override 15 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 16 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 17 | if (mv != null && !"".equals(name) && !"".equals(name)) { 18 | boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0; 19 | boolean isNativeMethod = (access & ACC_NATIVE) != 0; 20 | if (!isAbstractMethod && !isNativeMethod) { 21 | mv = new MethodPrintInstructionAdapter(api, mv, name, descriptor); 22 | } 23 | } 24 | return mv; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lsieun/asm/template/MethodWithSameTryCatchLogicVisitor.java: -------------------------------------------------------------------------------- 1 | package lsieun.asm.template; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.Label; 5 | import org.objectweb.asm.MethodVisitor; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static org.objectweb.asm.Opcodes.*; 11 | 12 | public class MethodWithSameTryCatchLogicVisitor extends ClassVisitor { 13 | public MethodWithSameTryCatchLogicVisitor(int api, ClassVisitor classVisitor) { 14 | super(api, classVisitor); 15 | } 16 | 17 | @Override 18 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 19 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 20 | if (mv != null) { 21 | boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0; 22 | boolean isNativeMethod = (access & ACC_NATIVE) != 0; 23 | if (!isAbstractMethod && !isNativeMethod) { 24 | mv = new MethodWithSameTryCatchLogicAdapter(api, mv); 25 | } 26 | } 27 | return mv; 28 | } 29 | 30 | 31 | private static class MethodWithSameTryCatchLogicAdapter extends MethodVisitor { 32 | private final List