Przeglądaj źródła

禁用gHotSpotVMStructs函数,避免使用sa-jdi HSDB 来dump class,提高代码安全性

wang 2 lat temu
rodzic
commit
e4553c3ee9

+ 11 - 11
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/Reverses.java

@@ -3,15 +3,7 @@ package winter.com.ideaaedi.classwinter;
 import winter.com.ideaaedi.classwinter.author.JustryDeng;
 import winter.com.ideaaedi.classwinter.exception.ClassWinterException;
 import winter.com.ideaaedi.classwinter.executor.DecryptExecutor;
-import winter.com.ideaaedi.classwinter.util.Cache;
-import winter.com.ideaaedi.classwinter.util.Constant;
-import winter.com.ideaaedi.classwinter.util.ExceptionUtil;
-import winter.com.ideaaedi.classwinter.util.IOUtil;
-import winter.com.ideaaedi.classwinter.util.JarUtil;
-import winter.com.ideaaedi.classwinter.util.JavaagentCmdArgs;
-import winter.com.ideaaedi.classwinter.util.Logger;
-import winter.com.ideaaedi.classwinter.util.Pair;
-import winter.com.ideaaedi.classwinter.util.StrUtil;
+import winter.com.ideaaedi.classwinter.util.*;
 
 import java.io.File;
 import java.io.IOException;
@@ -66,7 +58,15 @@ public class Reverses {
             // 是否启动debug,同步给Logger
             Logger.ENABLE_DEBUG.set(javaagentCmdArgs.isDebug());
         }
-        
+        // 禁用gHotSpotVMStructs函数,避免使用sa-jdi HSDB 来dump class,提高代码安全性
+        try {
+            long structs = JVMUtil.getSymbol("gHotSpotVMStructs");
+            JVMUtil.putAddress(structs, 0);
+            Logger.debug(Reverses.class, "Disabled VM Structs");
+        } catch (Exception e) {
+            Logger.error(Reverses.class, ExceptionUtil.getStackTraceMessage(e));
+            exit(null);
+        }
         // 要忽略的解密处理逻辑的项目路径(ProtectionDomain.getCodeSource().getLocation().getPath())
         Set<String> skipProjectPathPrefixSet = new HashSet<>();
         String skipProjectPathPrefix = javaagentCmdArgs.getSkipProjectPathPrefix();
@@ -227,7 +227,7 @@ public class Reverses {
                             return null;
                         }
                     }
-                    
+
                     /// ============================================ 处理class文件
                     // 判断是否应该解密
                     if (DecryptExecutor.checklistContain(projectPath, className) && DecryptExecutor.verifySeal(projectPath, classfileBuffer)) {

+ 25 - 0
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/exception/JVMException.java

@@ -0,0 +1,25 @@
+package winter.com.ideaaedi.classwinter.exception;
+
+
+/**
+ * JVM异常
+ *
+ * @author wang
+ */
+public class JVMException extends RuntimeException {
+
+    public JVMException() {
+    }
+
+    public JVMException(String message) {
+        super(message);
+    }
+
+    public JVMException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public JVMException(Throwable cause) {
+        super(cause);
+    }
+}

+ 122 - 0
class-winter-core/src/main/java/winter/com/ideaaedi/classwinter/util/JVMUtil.java

@@ -0,0 +1,122 @@
+package winter.com.ideaaedi.classwinter.util;
+
+import sun.misc.Unsafe;
+import winter.com.ideaaedi.classwinter.exception.JVMException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.NoSuchElementException;
+
+/**
+ * JVM 工具类,用于处理 JVM 相关操作。
+ *
+ * @author wang
+ */
+public class JVMUtil {
+
+    /**
+     * 用于查找本地库中的符号的反射方法。
+     */
+    private static final Method findNative;
+
+    /**
+     * 用于加载本地库的类加载器。
+     */
+    private static final ClassLoader classLoader;
+
+    /**
+     * Unsafe 类的实例,用于执行底层的内存操作。
+     */
+    public static final Unsafe unsafe = getUnsafe();
+
+    static {
+        // 检测操作系统类型
+        String os = System.getProperty("os.name").toLowerCase();
+        if (os.contains("windows")) {
+            // 在 Windows 操作系统上加载相应的 jvm.dll
+            String vmName = System.getProperty("java.vm.name");
+            String dll = vmName.contains("Client VM") ? "/bin/client/jvm.dll" : "/bin/server/jvm.dll";
+            try {
+                System.load(System.getProperty("java.home") + dll);
+            } catch (UnsatisfiedLinkError e) {
+                throw new JVMException("Cannot find jvm.dll. Unsupported JVM?");
+            }
+            classLoader = JVMUtil.class.getClassLoader();
+        } else {
+            classLoader = null;
+        }
+        try {
+            // 获取 ClassLoader 类的 findNative 方法并设置访问权限
+            findNative = ClassLoader.class.getDeclaredMethod("findNative", ClassLoader.class, String.class);
+            findNative.setAccessible(true);
+        } catch (NoSuchMethodException e) {
+            throw new JVMException("Method ClassLoader.findNative not found");
+        }
+    }
+
+    /**
+     * 获取指定符号的地址。
+     *
+     * @param name 符号名称
+     * @return 符号的地址
+     * @throws NoSuchElementException 如果找不到指定符号
+     */
+    public static long getSymbol(String name) {
+        long address = JVMUtil.lookup(name);
+        if (address == 0) {
+            throw new NoSuchElementException("No such symbol: " + name);
+        }
+        return getLong(address);
+    }
+
+    /**
+     * 从指定地址读取 long 类型的值。
+     *
+     * @param addr 地址
+     * @return 读取的 long 值
+     */
+    public static long getLong(long addr) {
+        return unsafe.getLong(addr);
+    }
+
+    /**
+     * 将指定值写入指定地址。
+     *
+     * @param addr 地址
+     * @param val  要写入的值
+     */
+    public static void putAddress(long addr, long val) {
+        unsafe.putAddress(addr, val);
+    }
+
+    /**
+     * 查找本地库中指定名称的符号的地址。
+     *
+     * @param name 符号名称
+     * @return 符号的地址
+     */
+    public static long lookup(String name) {
+        try {
+            return (Long) findNative.invoke(null, classLoader, name);
+        } catch (InvocationTargetException e) {
+            throw new JVMException(e.getTargetException());
+        } catch (IllegalAccessException e) {
+            throw new JVMException(e);
+        }
+    }
+
+    /**
+     * 获取 Unsafe 类的实例。
+     *
+     * @return Unsafe 类的实例
+     */
+    private static Unsafe getUnsafe() {
+        try {
+            java.lang.reflect.Field f = Unsafe.class.getDeclaredField("theUnsafe");
+            f.setAccessible(true);
+            return (Unsafe) f.get(null);
+        } catch (Exception e) {
+            throw new JVMException("Unable to get Unsafe", e);
+        }
+    }
+}