zoukankan      html  css  js  c++  java
  • 修改spring源码重写classloader实现项目加密

     

    (一)操作方法和spring源码添加修改部分

    事先说明:spring源码要下载好,会有修改spring的源码操作,本文和本作者所依赖的spring项目的版本是3.1.1,spring4及以上源码对应的类路径可能有所改变,需要自己找到要修改的类哦,类名应该是不会变的。望理解~~

    操作步骤: ~具体说明看类文件注释~

    1.运行ProduceKey.java的main方法 生成 key.key文件

    2.ClassesEncryption类中,修改项目路径,修改key文件路径

    3.执行ClassesEncryption的main方法加密文件

    4.将OverrideClassLoader项目生成jar包,放在tomcat/lib下(自己网上看操作)

    5.在tomcat/conf/context.xml 中Context 节点中添加
      <Loader loaderClass="com.loader.ReBuildClassLoader" delegate="false"></Loader>

    6. 替换tomcat的文件,比如com/ 下的除了(com/webapp/entity)下所有文件

    7.启动tomcat

    加密修改spring 源码

    1.org.springframework.context-3.1.1.RELEASE.jar
    2.org.springframework.core-3.1.1.RELEASE.jar

    其中org.springframework.context-3.1.1.RELEASE.jar 修改类

    (1)ClassPathScanningCandidateComponentProvider.java

    line:230 加入
    packageSearchPath = packageSearchPath.replace(".class", ".zdywjmjw");
    System.out.println("packageSearchPath"+packageSearchPath);
    Resource[] resourcesZdywjmjw = this.resourcePatternResolver.getResources(packageSearchPath);
    Resource[] resources = new Resource[resourcesClass.length+resourcesZdywjmjw.length];
    System.arraycopy(resourcesClass, 0, resources, 0, resourcesClass.length); 
    System.arraycopy(resourcesZdywjmjw, 0, resources, resourcesClass.length, resourcesZdywjmjw.length);

    其中org.springframework.core-3.1.1.RELEASE.jar 修改类

    (1)ClassPathResource.java

    在类下面添加下列方法

    private static boolean isWindowsOS() {
    boolean isWindowsOS = false;
    String osName = System.getProperty("os.name");
    if (osName.toLowerCase().indexOf("windows") > -1) {
    isWindowsOS = true;
    }
    return isWindowsOS;
    }

    // 把文件读入byte数组
    private byte[] readFile(String filename) throws IOException {
    File file = new File(filename);
    long len = file.length();
    byte data[] = new byte[(int) len];
    FileInputStream fin = new FileInputStream(file);
    int r = fin.read(data);
    if (r != len)
    throw new IOException("Only read " + r + " of " + len + " for " + file);
    fin.close();
    return data;
    }

    // 把byte数组写出到文件
    private void writeFile(String filename, byte data[]) throws IOException {
    FileOutputStream fout = new FileOutputStream(filename);
    fout.write(data);
    fout.close();
    }

    line 168行 修改
    String basepath =this.getClass().getResource("/").getPath();
    if(isWindowsOS()){
    basepath = basepath.substring(1,basepath.length());//window下增加
    }
    String reloadedClass = basepath+this.path.replace(".class", ".zdywjmjw");
    File file = new File(reloadedClass);
    if (file.exists()) {
    // 下面是定制部分
      try {
        String keyFilename = basepath+"key.key";
        // 读取密匙
        String algorithm = "DES";
        byte rawKey[] = readFile(keyFilename);
        DESKeySpec dks = new DESKeySpec(rawKey);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
        SecretKey key = keyFactory.generateSecret(dks);
        SecureRandom sr = new SecureRandom();
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, key, sr);
        // 读取经过加密的类文件
        byte classData[] = readFile(pclass);
        if (classData != null) {
          byte decryptedClassData[] = cipher.doFinal(classData); // 解密
          InputStream sbs = new ByteArrayInputStream(decryptedClassData); 
          return sbs;
        }
      } catch (Exception fnfe) {

      }
    }

    (2).SimpleMetadataReader.java

    添加方法
    private static boolean isWindowsOS() {
      boolean isWindowsOS = false;
      String osName = System.getProperty("os.name");
      if (osName.toLowerCase().indexOf("windows") > -1) {
        isWindowsOS = true;
      }
      return isWindowsOS;
    }

    public static byte[] readFile(String filename) throws IOException {
      File file = new File(filename);
      long len = file.length();
      byte data[] = new byte[(int) len];
      FileInputStream fin = new FileInputStream(file);
      int r = fin.read(data);
      if (r != len)
      throw new IOException("Only read " + r + " of " + len + " for " + file);
      fin.close();
      return data;
    }

    修改构造类

    SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException {
      InputStream is = resource.getInputStream();
      ClassReader classReader = null;
      try {
        String filename = ""; 
        if (resource.getURI().toString().indexOf("jar:file") == -1 ) {
          String checkPath="";
          if(isWindowsOS()){
          checkPath = "classes\com";
        }else{
          checkPath = "classes/com";
        }
        if(resource.getFile().getAbsolutePath().indexOf(checkPath)!=-1){
          filename = resource.getFile().getAbsolutePath().replace(".class", ".zdywjmjw"); 
          File file = new File(filename);
          if(file.exists()){
          //进行解密
          String basepath =this.getClass().getResource("/").getPath();
          if(isWindowsOS()){
            basepath = basepath.substring(1,basepath.length());
          }
          String keyFilename = basepath+"key.key";
          String algorithm = "DES";
          try{
            // 生成密匙
            SecureRandom sr = new SecureRandom();
            byte rawKey[] = readFile(keyFilename);
            DESKeySpec dks = new DESKeySpec(rawKey);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
            SecretKey key = keyFactory.generateSecret(dks);

            // 创建用于实际加密操作的Cipher对象
            Cipher cipher = Cipher.getInstance(algorithm);
            cipher.init(Cipher.DECRYPT_MODE, key, sr);
            byte classData[] = readFile(name);
            byte decryptedClassData[] = cipher.doFinal(classData);
            classReader = new ClassReader(decryptedClassData);
          } catch(NoSuchAlgorithmException e){
            e.printStackTrace();
          } catch (InvalidKeyException e) {
            e.printStackTrace();
          } catch (InvalidKeySpecException e) {
            e.printStackTrace();
          } catch (NoSuchPaddingException e) {
            e.printStackTrace();
          } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
          } catch (BadPaddingException e) {
            e.printStackTrace();
          }
        }else{
          classReader = new ClassReader(is);
        }
       }else{
        classReader = new ClassReader(is);
       }
      }else{
        classReader = new ClassReader(is);
      }
      }finally {
        is.close();
      }

      AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
      classReader.accept(visitor, true);

      this.annotationMetadata = visitor;
      // (since AnnotationMetadataReader extends ClassMetadataReadingVisitor)
      this.classMetadata = visitor;
      this.resource = resource;
    }

    (3)LocalVariableTableParameterNameDiscoverer.java

    line 103 行修改
    String cName = clazz.getResource("/").getPath()+clazz.getName().replace(".", "/")+".class";
    is = clazz.getClassLoader().getResourceAsStream(cName);
    if(is == null){
      // We couldn't load the class file, which is not fatal as it
      // simply means this method of discovering parameter names won't work.
      if (logger.isDebugEnabled()) {
        logger.debug("Cannot find '.class' file for class [" + clazz
        + "] - unable to determine constructors/methods parameter names");
      }
      return NO_DEBUG_INFO_MAP;
    }

    (二)项目相关

    项目名称:OverrideClassLoader

    项目打包方式:jar,是普通Java工程

    项目结构:

    com.key

    com.loader

    com.util

    其中 key包下面文件有:ClassesEncryption.java、ProduceKey.java、GenerateEncryptedClassMain

    loader包下面有文件:ReBuildClassLoader.java 

    util包下面有文件:FileUtil.java

    (1)ProduceKey.java

    package com.key;

    import java.security.SecureRandom;

    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;

    import com.util.FileUtil;
    /**
    * 生成key文件类
    * @author win7
    *
    */
    public class ProduceKey {

      public static void main(String args[]) throws Exception {

        String keyFilename = null;
        boolean windowsOS = isWindowsOS();//检查是否是window系统
        System.out.println(windowsOS);
        if (windowsOS) {
          keyFilename = "D://developer/apache-tomcat7/webapps/项目名称/WEB-INF/classes/key.key";//是本地开发的项目,tomcat的路径
        } else {
          keyFilename = "/usr/local/tomcat/webapps/项目名称/WEB-INF/classes/key.key";
        }

        String algorithm = "DES";

        // 生成密匙
        SecureRandom sr = new SecureRandom();
        KeyGenerator kg = KeyGenerator.getInstance(algorithm);
        kg.init(sr);
        SecretKey key = kg.generateKey();

        // 把密匙数据保存到文件,放入指定位置
        FileUtil.writeFile(keyFilename, key.getEncoded());
      }

      private static boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
          isWindowsOS = true;
        }
        return isWindowsOS;
      }

    }

    (2)ClassesEncryption.java

    package com.key;

    import java.io.File;
    import java.security.SecureRandom;
    import java.util.ArrayList;
    import java.util.List;

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;

    import com.util.FileUtil;
    /**
    * class文件加密类
    * @author win7
    *
    */
    public class ClassesEncryption {
      public static List<File> filelist = new ArrayList<>();

      public static void main(String[] args) throws Exception {
      System.out.println("search start");

      // 得到要加密的项目下com目录下的class文件
      getFileList("D://developer/apache-tomcat7/webapps/项目名称/WEB-INF/classes/com");

      System.out.println("文件数量" + filelist.size());

      // 获取文件名秘钥
      String keyFilename = "D://developer/apache-tomcat7/webapps/项目名称/WEB-INF/classes/key.key";
      // 算法
      String algorithm = "DES";

      // -------下面开始生成密匙-------
      // 强加密随机数生成器
      SecureRandom sr = new SecureRandom();
      // 将加密后的key.key转成字节数组
      byte rawKey[] = FileUtil.readFile(keyFilename);
      // 创建一个 DESKeySpec 对象,使用 rawKey 中的前 8 个字节作为 DES 密钥的密钥内容。
      DESKeySpec dks = new DESKeySpec(rawKey);
      // 得到转换指定算法的秘密密钥的SecretKeyFactory对象。
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
      // 根据提供的密钥规范(密钥材料)生成 SecretKey 对象
      SecretKey key = keyFactory.generateSecret(dks);

      // 创建用于实际加密操作的Cipher对象 , Cipher:此类为加密和解密提供密码功能
      Cipher ecipher = Cipher.getInstance(algorithm);
      // 参数:加密的常量,加密密钥, 算法参数
      ecipher.init(Cipher.ENCRYPT_MODE, key, sr);

        // 加密命令行中指定的每一个类
        for (int i = 0; i < filelist.size(); i++) {
          String filename = filelist.get(i).getAbsolutePath();
          byte classData[] = FileUtil.readFile(filename); // 读入类文件
          byte encryptedClassData[] = ecipher.doFinal(classData); // 加密
          String projectFile = filename.replace(".class", ".zdywjmjw");//zdyljzq:自定义文件名结尾
          FileUtil.writeFile(projectFile, encryptedClassData); // 保存加密后的内容
          System.out.println("Encrypted " + projectFile);

          File classFile = new File(filename);
          classFile.delete();
        }
      }

      public static void encrypt(String tomcat_home) throws Exception {
        System.out.println("search start");
        getFileList(tomcat_home + "webapps/项目名称/WEB-INF/classes/com");

        System.out.println("文件数量" + filelist.size());

        String keyFilename = tomcat_home + "webapps/项目名称/WEB-INF/classes/key.key";
        String algorithm = "DES";// 算法

        // -------下面开始生成密匙-------
        // 强加密随机数生成器
        SecureRandom sr = new SecureRandom();
        // 将加密后的key.key转成字节数组
        byte rawKey[] = FileUtil.readFile(keyFilename);
        // 创建一个 DESKeySpec 对象,使用 rawKey 中的前 8 个字节作为 DES 密钥的密钥内容。
        DESKeySpec dks = new DESKeySpec(rawKey);
        // 得到转换指定算法的秘密密钥的SecretKeyFactory对象。
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
        // 根据提供的密钥规范(密钥材料)生成 SecretKey 对象
        SecretKey key = keyFactory.generateSecret(dks);

        // 创建用于实际加密操作的Cipher对象 , Cipher:此类为加密和解密提供密码功能
        Cipher ecipher = Cipher.getInstance(algorithm);
        // 参数:加密的常量,加密密钥, 算法参数
        ecipher.init(Cipher.ENCRYPT_MODE, key, sr);

        // 加密命令行中指定的每一个类
        for (int i = 0; i < filelist.size(); i++) {
          String filename = filelist.get(i).getAbsolutePath();
          byte classData[] = FileUtil.readFile(filename); // 读入类文件
          byte encryptedClassData[] = ecipher.doFinal(classData); // 加密
          String projectFile = filename.replace(".class", ".zdywjmjw");//zdyljzq:自定义文件名结尾
          FileUtil.writeFile(projectFile, encryptedClassData); // 保存加密后的内容
          System.out.println("Encrypted " + projectFile);

          File classFile = new File(filename);
          classFile.delete();

        }
      }

    /**
    * 注意:加密的时候不能加密实体,要不然项目就启动不成功或者异常
    * @param strPath
    * @return
    */
       public static List<File> getFileList(String strPath) {
          File dir = new File(strPath);
          File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
          if (files != null) {
            for (int i = 0; i < files.length; i++) {
              String fileName = files[i].getName();
              if (files[i].isDirectory()) { // 判断是文件还是文件夹
                getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
              } else if (fileName.endsWith(".class")) { // 判断文件名是否以.class结尾
                String strFileName = files[i].getAbsolutePath();
                // System.out.println("---" + strFileName);
                if (isWindowsOS()) {
                  if (strFileName.indexOf("com\项目名称\webapp\entity") == -1) {
                    filelist.add(files[i]);
                  }
                } else {
                  if (strFileName.indexOf("com/项目名称/webapp/entity") == -1) {
                  filelist.add(files[i]);
                }
              }

              } else {
              continue;
            }
          }

        }
        return filelist;
      }

      public static boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
          isWindowsOS = true;
        }
        return isWindowsOS;
      }
    }

    (3)GenerateEncryptedClassMain.java

    package com.key;

    import java.util.Scanner;
    /**
    * main方法生成加密class文件
    * @author win7
    *
    */
    public class GenerateEncryptedClassMain {
      public static void main(String[] args) {
        try {
          Scanner s = new Scanner(System.in);
          String str = null;
          System.out.println("请tomcat路径以'/'结尾:");//如: /usr/local/tomcat/
          str = s.next();
          if (str == null || str.trim().equals("")) {
            System.out.println("tomcat路径不能为空");
            return;
          }
          String tomcat_home = str;
          ClassesEncryption.encrypt(tomcat_home);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    (4)ReBuildClassLoader.java

    package com.loader;

    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.GeneralSecurityException;
    import java.security.SecureRandom;

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;

    import org.apache.catalina.loader.WebappClassLoader;

    import com.util.FileUtil;

    /**
    * 自定义类加载器
    * WebappClassLoader:是tomcat的jar包提供,所以要添加 tomcat server Runtime
    * 
    * @author win7
    *
    */
    public class ReBuildClassLoader extends WebappClassLoader {
      // 这些对象在构造函数中设置,以后loadClass()方法将利用它们解密类
      private SecretKey key;
      private Cipher cipher;

      public ReBuildClassLoader() {
        super();
      }

      public ReBuildClassLoader(ClassLoader parent) {
        super(parent);
      }

      @Override
      public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        try {
          // 要创建的Class对象
          Class clasz = null;

          // 必需的步骤1:如果类已经在系统缓冲之中,不必再次装入它
          clasz = findLoadedClass(name);

          if (clasz != null)
            return clasz;

            // 下面是定制部分
          try {
            String basepath = "";
            if (isWindowsOS()) {
              basepath = "D://developer/apache-tomcat7/webapps/项目名称/WEB-INF/classes/";// 项目物理地址
            } else {
              basepath = "/usr/local/tomcat/webapps/项目名称/WEB-INF/classes/";
            }
            String cname = basepath + name.replace('.', '/') + ".zdywjmjw";
            File file = new File(cname);
            if (file.exists()) {
              String keyFilename = basepath + "key.key";
              // 读取密匙
              String algorithm = "DES";
              // System.err.println("[DecryptStart: reading key]");
              byte rawKey[] = FileUtil.readFile(keyFilename);
              DESKeySpec dks = new DESKeySpec(rawKey);
              SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
              key = keyFactory.generateSecret(dks);
              SecureRandom sr = new SecureRandom();
              // System.err.println("[DecryptStart: creating cipher]");
              cipher = Cipher.getInstance(algorithm);
              cipher.init(Cipher.DECRYPT_MODE, key, sr);
              // 读取经过加密的类文件
              byte classData[] = FileUtil.readFile(cname);
              if (classData != null) {
                byte decryptedClassData[] = cipher.doFinal(classData); // 解密
                clasz = defineClass(name, decryptedClassData, 0, decryptedClassData.length); // 再把它转换成一个类
                // System.err.println("[DecryptStart: decrypting class + name + "]");
              }
            }
          } catch (FileNotFoundException fnfe) {

          }

          // 必需的步骤2:如果上面没有成功
          // 尝试用默认的ClassLoader装入它
          if (clasz == null)
            return super.loadClass(name, resolve);

            // 必需的步骤3:如有必要,则装入相关的类
            if (resolve && clasz != null)
              resolveClass(clasz);

              return clasz;// 把类返回给调用者

            } catch (IOException ie) {
              throw new ClassNotFoundException(ie.toString());
            } catch (GeneralSecurityException gse) {
              throw new ClassNotFoundException(gse.toString());
            }
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
          return super.loadClass(name);
        }

        @Override
        public InputStream getResourceAsStream(String arg0) {
          String pclass = arg0.replace(".class", ".zdywjmjw");
          File file = new File(pclass);
          if (file.exists()) {
          // 下面是定制部分
          try {
            String basepath = "";
            if (isWindowsOS()) {
              basepath = "D://developer/apache-tomcat7/webapps/项目名称/WEB-INF/classes/";// 项目物理地址
            } else {
              basepath = "/usr/local/tomcat/webapps/项目名称/WEB-INF/classes/";
            }
            String keyFilename = basepath + "key.key";
            // 读取密匙
            String algorithm = "DES";
            byte rawKey[] = FileUtil.readFile(keyFilename);
            DESKeySpec dks = new DESKeySpec(rawKey);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
            key = keyFactory.generateSecret(dks);
            SecureRandom sr = new SecureRandom();
            cipher = Cipher.getInstance(algorithm);
            cipher.init(Cipher.DECRYPT_MODE, key, sr);
            // 读取经过加密的类文件
            byte classData[] = FileUtil.readFile(pclass);
            if (classData != null) {
              byte decryptedClassData[] = cipher.doFinal(classData); // 解密
              InputStream sbs = new ByteArrayInputStream(decryptedClassData);
              return sbs;
              }
            } catch (Exception fnfe) {

            }
          }
          return super.getResourceAsStream(arg0);
        }

      private boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
          isWindowsOS = true;
        }
          return isWindowsOS;
        }

      }

    FileUtil.java

    package com.util;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;

    public class FileUtil {
      // 把文件读入byte数组
      static public byte[] readFile(String filename) throws IOException {
      File file = new File(filename);
      long len = file.length();
      byte data[] = new byte[(int) len];
      FileInputStream fin = new FileInputStream(file);
      int r = fin.read(data);
      if (r != len)
        throw new IOException("Only read " + r + " of " + len + " for " + file);
        fin.close();
        return data;
      }

      // 把byte数组写出到文件
      static public void writeFile(String filename, byte data[]) throws IOException {
        FileOutputStream fout = new FileOutputStream(filename);
        fout.write(data);
        fout.close();
      }
    }

  • 相关阅读:
    linux basename 和 dirname 获取当前路径
    灵活的装饰器
    ubuntu 20version install wechat
    git pull 总提示让输入merge 信息
    Linux脚本中$#、$0、$1、$@、$*、$$、$?
    ansible
    MMD讲解
    再生希尔伯特空间与核函数讲解
    流形学习
    聚类
  • 原文地址:https://www.cnblogs.com/li-ran/p/6846141.html
Copyright © 2011-2022 走看看