From 92b5ae69d1ab0e24182f88607b9ef870d294a833 Mon Sep 17 00:00:00 2001 From: "novice.li" Date: Sun, 25 Feb 2024 13:38:59 +0800 Subject: [PATCH] finish --- .../java/com/novitechie/LoadClassRule.java | 1 + .../PluginClassLoaderTransformer.java | 40 ++-- .../java/com/novitechie/PrivacyPlugin.java | 4 + .../java/com/novitechie/SafeClassWriter.java | 186 ++++++++++++++++++ .../java/com/novitechie/StackTraceRule.java | 1 + .../com/novitechie/VMOptionsTransformer.java | 42 ++-- 6 files changed, 229 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/novitechie/SafeClassWriter.java diff --git a/src/main/java/com/novitechie/LoadClassRule.java b/src/main/java/com/novitechie/LoadClassRule.java index 0979e22..0eb78bd 100644 --- a/src/main/java/com/novitechie/LoadClassRule.java +++ b/src/main/java/com/novitechie/LoadClassRule.java @@ -3,6 +3,7 @@ package com.novitechie; public class LoadClassRule { public static void check(String name) throws Exception { if (name.startsWith("com.janetfilter")) { + System.out.println("----------------------"+name); throw new ClassNotFoundException(name); } } diff --git a/src/main/java/com/novitechie/PluginClassLoaderTransformer.java b/src/main/java/com/novitechie/PluginClassLoaderTransformer.java index f372cb6..4dd616d 100644 --- a/src/main/java/com/novitechie/PluginClassLoaderTransformer.java +++ b/src/main/java/com/novitechie/PluginClassLoaderTransformer.java @@ -1,10 +1,11 @@ package com.novitechie; import com.janetfilter.core.plugin.MyTransformer; -import jdk.internal.org.objectweb.asm.*; -import jdk.internal.org.objectweb.asm.commons.AdviceAdapter; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.tree.*; -import static jdk.internal.org.objectweb.asm.Opcodes.ASM5; +import static jdk.internal.org.objectweb.asm.Opcodes.*; public class PluginClassLoaderTransformer implements MyTransformer { @Override @@ -14,24 +15,19 @@ public class PluginClassLoaderTransformer implements MyTransformer { @Override public byte[] transform(String className, byte[] classBytes, int order) throws Exception { - ClassReader cr = new ClassReader(classBytes); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); - cr.accept(new ClassVisitor(ASM5, cw) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (name.equals("loadClass")) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - return new AdviceAdapter(api, mv, access, name, desc) { - @Override - protected void onMethodEnter() { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, "com/novitechie/LoadClassRule", "check", "(Ljava/lang/String;)V", false); - } - }; - } - return super.visitMethod(access, name, desc, signature, exceptions); + ClassReader reader = new ClassReader(classBytes); + ClassNode node = new ClassNode(ASM5); + reader.accept(node, 0); + for (MethodNode m : node.methods) { + if ("loadClass".equals(m.name)) { + InsnList list = new InsnList(); + list.add(new VarInsnNode(ALOAD, 1)); + list.add(new MethodInsnNode(INVOKESTATIC, "com/novitechie/LoadClassRule", "check", "(Ljava/lang/String;)V", false)); + m.instructions.insert(list); } - }, 6); - return cw.toByteArray(); + } + ClassWriter writer = new SafeClassWriter(null,null,ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + node.accept(writer); + return writer.toByteArray(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/novitechie/PrivacyPlugin.java b/src/main/java/com/novitechie/PrivacyPlugin.java index 3e518b4..d476f53 100644 --- a/src/main/java/com/novitechie/PrivacyPlugin.java +++ b/src/main/java/com/novitechie/PrivacyPlugin.java @@ -7,6 +7,10 @@ import java.util.Arrays; import java.util.List; public class PrivacyPlugin implements PluginEntry { + + static { + System.out.println("-------------PrivacyPlugin------------------"); + } @Override public String getName() { return "PRIVACY"; diff --git a/src/main/java/com/novitechie/SafeClassWriter.java b/src/main/java/com/novitechie/SafeClassWriter.java new file mode 100644 index 0000000..875d1a4 --- /dev/null +++ b/src/main/java/com/novitechie/SafeClassWriter.java @@ -0,0 +1,186 @@ +/*** + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.novitechie; + + +import java.io.IOException; +import java.io.InputStream; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + + + +/** + * A ClassWriter that computes the common super class of two classes without + * actually loading them with a ClassLoader. + * + * @author Eric Bruneton + */ +public class SafeClassWriter extends ClassWriter { + + private final ClassLoader loader; + + + public SafeClassWriter(ClassReader cr, ClassLoader loader, final int flags) { + super(cr, flags); + this.loader = loader != null ? loader : ClassLoader.getSystemClassLoader(); + } + + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + try { + ClassReader info1 = typeInfo(type1); + ClassReader info2 = typeInfo(type2); + if ((info1.getAccess() & Opcodes.ACC_INTERFACE) != 0) { + if (typeImplements(type2, info2, type1)) { + return type1; + } else { + return "java/lang/Object"; + } + } + if ((info2.getAccess() & Opcodes.ACC_INTERFACE) != 0) { + if (typeImplements(type1, info1, type2)) { + return type2; + } else { + return "java/lang/Object"; + } + } + StringBuilder b1 = typeAncestors(type1, info1); + StringBuilder b2 = typeAncestors(type2, info2); + String result = "java/lang/Object"; + int end1 = b1.length(); + int end2 = b2.length(); + while (true) { + int start1 = b1.lastIndexOf(";", end1 - 1); + int start2 = b2.lastIndexOf(";", end2 - 1); + if (start1 != -1 && start2 != -1 + && end1 - start1 == end2 - start2) { + String p1 = b1.substring(start1 + 1, end1); + String p2 = b2.substring(start2 + 1, end2); + if (p1.equals(p2)) { + result = p1; + end1 = start1; + end2 = start2; + } else { + return result; + } + } else { + return result; + } + } + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + /** + * Returns the internal names of the ancestor classes of the given type. + * + * @param type + * the internal name of a class or interface. + * @param info + * the ClassReader corresponding to 'type'. + * @return a StringBuilder containing the ancestor classes of 'type', + * separated by ';'. The returned string has the following format: + * ";type1;type2 ... ;typeN", where type1 is 'type', and typeN is a + * direct subclass of Object. If 'type' is Object, the returned + * string is empty. + * @throws IOException + * if the bytecode of 'type' or of some of its ancestor class + * cannot be loaded. + */ + private StringBuilder typeAncestors(String type, ClassReader info) + throws IOException { + StringBuilder b = new StringBuilder(); + while (!"java/lang/Object".equals(type)) { + b.append(';').append(type); + type = info.getSuperName(); + info = typeInfo(type); + } + return b; + } + + /** + * Returns true if the given type implements the given interface. + * + * @param type + * the internal name of a class or interface. + * @param info + * the ClassReader corresponding to 'type'. + * @param itf + * the internal name of a interface. + * @return true if 'type' implements directly or indirectly 'itf' + * @throws IOException + * if the bytecode of 'type' or of some of its ancestor class + * cannot be loaded. + */ + private boolean typeImplements(String type, ClassReader info, String itf) + throws IOException { + while (!"java/lang/Object".equals(type)) { + String[] itfs = info.getInterfaces(); + for (int i = 0; i < itfs.length; ++i) { + if (itfs[i].equals(itf)) { + return true; + } + } + for (int i = 0; i < itfs.length; ++i) { + if (typeImplements(itfs[i], typeInfo(itfs[i]), itf)) { + return true; + } + } + type = info.getSuperName(); + info = typeInfo(type); + } + return false; + } + + /** + * Returns a ClassReader corresponding to the given class or interface. + * + * @param type + * the internal name of a class or interface. + * @return the ClassReader corresponding to 'type'. + * @throws IOException + * if the bytecode of 'type' cannot be loaded. + */ + private ClassReader typeInfo(final String type) throws IOException { + String resource = type + ".class"; + InputStream is = loader.getResourceAsStream(resource); + if (is == null) { + throw new IOException("Cannot create ClassReader for type " + type); + } + try { + return new ClassReader(is); + } finally { + is.close(); + } + } +} diff --git a/src/main/java/com/novitechie/StackTraceRule.java b/src/main/java/com/novitechie/StackTraceRule.java index 5abf63f..4d0b728 100644 --- a/src/main/java/com/novitechie/StackTraceRule.java +++ b/src/main/java/com/novitechie/StackTraceRule.java @@ -2,6 +2,7 @@ package com.novitechie; public class StackTraceRule { public static boolean check() { + System.out.println("------------------StackTraceRule"); RuntimeException e = new RuntimeException(); for (StackTraceElement stackTraceElement : e.getStackTrace()) { if (stackTraceElement.getFileName() == null) { diff --git a/src/main/java/com/novitechie/VMOptionsTransformer.java b/src/main/java/com/novitechie/VMOptionsTransformer.java index b1afc2b..6532dfe 100644 --- a/src/main/java/com/novitechie/VMOptionsTransformer.java +++ b/src/main/java/com/novitechie/VMOptionsTransformer.java @@ -3,8 +3,9 @@ package com.novitechie; import com.janetfilter.core.plugin.MyTransformer; import jdk.internal.org.objectweb.asm.*; import jdk.internal.org.objectweb.asm.commons.AdviceAdapter; +import jdk.internal.org.objectweb.asm.tree.*; -import static jdk.internal.org.objectweb.asm.Opcodes.ASM5; +import static jdk.internal.org.objectweb.asm.Opcodes.*; public class VMOptionsTransformer implements MyTransformer { @Override @@ -14,28 +15,23 @@ public class VMOptionsTransformer implements MyTransformer { @Override public byte[] transform(String className, byte[] classBytes, int order) throws Exception { - ClassReader cr = new ClassReader(classBytes); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); - cr.accept(new ClassVisitor(ASM5, cw) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (name.equals("getUserOptionsFile")) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - return new AdviceAdapter(api, mv, access, name, desc) { - @Override - protected void onMethodEnter() { - mv.visitMethodInsn(INVOKESTATIC, "com/novitechie/StackTraceRule", "check", "()Z", false); - Label l0 = new Label(); - mv.visitJumpInsn(IFEQ, l0); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l0); - } - }; - } - return super.visitMethod(access, name, desc, signature, exceptions); + ClassReader reader = new ClassReader(classBytes); + ClassNode node = new ClassNode(ASM5); + reader.accept(node, 0); + for (MethodNode m : node.methods) { + if ("getUserOptionsFile".equals(m.name)) { + InsnList list = new InsnList(); + list.add(new MethodInsnNode(INVOKESTATIC, "com/novitechie/StackTraceRule", "check", "()Z", false)); + LabelNode labelNode = new LabelNode(); + list.add(new JumpInsnNode(IFEQ,labelNode)); + list.add(new InsnNode(ACONST_NULL)); + list.add(new InsnNode(ARETURN)); + list.add(labelNode); + m.instructions.insert(list); } - }, 6); - return cw.toByteArray(); + } + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + node.accept(writer); + return writer.toByteArray(); } }