From 9cf03f48a4a72ddb6fed07c82567ffcee6f2f0cb Mon Sep 17 00:00:00 2001 From: yelochick Date: Fri, 26 Apr 2024 00:09:53 +0800 Subject: [PATCH] init --- .gitignore | 38 ++++ pom.xml | 71 +++++++ readme.md | 6 + .../java/com/yelochick/ActivationPlugin.java | 24 +++ .../java/com/yelochick/SafeClassWriter.java | 176 ++++++++++++++++++ .../com/yelochick/SmartInputTransformer.java | 56 ++++++ 6 files changed, 371 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 readme.md create mode 100644 src/main/java/com/yelochick/ActivationPlugin.java create mode 100644 src/main/java/com/yelochick/SafeClassWriter.java create mode 100644 src/main/java/com/yelochick/SmartInputTransformer.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb2df64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +.idea/ +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5bcb25b --- /dev/null +++ b/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.yelochick + plugin-activation + 1.0.0 + + + 8 + 8 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 8 + 8 + UTF-8 + -XDignore.symbol.file + true + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.0.0 + + false + + jar-with-dependencies + + + + true + + + YeloChick + com.yelochick.ActivationPlugin + + + activation + + + + make-assembly + package + + single + + + + + + + + + com.ja-netfilter + ja-netfilter + 2.0.1 + provided + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..214ac12 --- /dev/null +++ b/readme.md @@ -0,0 +1,6 @@ +plugin-activation +A plugin for the ja-netfilter + +Use the `mvn clean package` command to compile and use activation.jar file! + +懂的都懂,无需多言 diff --git a/src/main/java/com/yelochick/ActivationPlugin.java b/src/main/java/com/yelochick/ActivationPlugin.java new file mode 100644 index 0000000..cc3257e --- /dev/null +++ b/src/main/java/com/yelochick/ActivationPlugin.java @@ -0,0 +1,24 @@ +package com.yelochick; + +import com.janetfilter.core.plugin.MyTransformer; +import com.janetfilter.core.plugin.PluginEntry; + +import java.util.Collections; +import java.util.List; + +public class ActivationPlugin implements PluginEntry { + @Override + public String getName() { + return "ACTIVATION"; + } + + @Override + public String getAuthor() { + return "YeloChick"; + } + + @Override + public List getTransformers() { + return Collections.singletonList(new SmartInputTransformer()); + } +} diff --git a/src/main/java/com/yelochick/SafeClassWriter.java b/src/main/java/com/yelochick/SafeClassWriter.java new file mode 100644 index 0000000..6daa303 --- /dev/null +++ b/src/main/java/com/yelochick/SafeClassWriter.java @@ -0,0 +1,176 @@ +/*** + * 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.yelochick; + + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + +import java.io.IOException; +import java.io.InputStream; + + +/** + * 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 (String s : itfs) { + if (s.equals(itf)) { + return true; + } + } + for (String s : itfs) { + if (typeImplements(s, typeInfo(s), 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/yelochick/SmartInputTransformer.java b/src/main/java/com/yelochick/SmartInputTransformer.java new file mode 100644 index 0000000..fa925f7 --- /dev/null +++ b/src/main/java/com/yelochick/SmartInputTransformer.java @@ -0,0 +1,56 @@ +package com.yelochick; + +import com.janetfilter.core.plugin.MyTransformer; +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.*; + +/** + * @author yelochick + */ +public class SmartInputTransformer implements MyTransformer { + + @Override + public String getHookClassName() { + return "com/xxxtai/smartinputintellij/model/LicenseInfo"; + } + + @Override + public byte[] transform(String className, byte[] classBytes, int order) throws Exception { + ClassReader reader = new ClassReader(classBytes); + ClassNode node = new ClassNode(ASM5); + reader.accept(node, 0); + for (MethodNode m : node.methods) { + if ("enableLicense".equals(m.name)) { + InsnList list = new InsnList(); + list.add(new LdcInsnNode("")); + list.add(new VarInsnNode(ALOAD, 1)); + list.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false)); + LabelNode labelNode = new LabelNode(); + list.add(new JumpInsnNode(IFNE, labelNode)); + list.add(new VarInsnNode(ALOAD, 0)); + list.add(new VarInsnNode(ALOAD, 1)); + list.add(new FieldInsnNode(PUTFIELD, "com/xxxtai/smartinputintellij/model/LicenseInfo", "license", "Ljava/lang/String;")); + list.add(new VarInsnNode(ALOAD, 0)); + list.add(new LdcInsnNode(4102415999000L)); + list.add(new MethodInsnNode(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false)); + list.add(new FieldInsnNode(PUTFIELD, "com/xxxtai/smartinputintellij/model/LicenseInfo", "expireTimestamp", "Ljava/lang/Long;")); + list.add(new InsnNode(ICONST_1)); + list.add(new InsnNode(IRETURN)); + list.add(labelNode); + m.instructions.insert(list); + } else if ("isOffline".equals(m.name)) { + m.instructions.clear(); + InsnList list = new InsnList(); + list.add(new InsnNode(ICONST_1)); + list.add(new InsnNode(IRETURN)); + m.instructions.insert(list); + } + } + SafeClassWriter writer = new SafeClassWriter(null, null, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + node.accept(writer); + return writer.toByteArray(); + } +}