修改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();
  }
}

 

转载于:https://www.cnblogs.com/li-ran/p/6846141.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ClassLoaderJava中用于加载类文件的机制,可以通过在运行时动态加载新的类文件,实现热部署的功能。以下是一个简单的ClassLoader实现热部署的示例: ```java public class HotSwapClassLoader extends ClassLoader { public HotSwapClassLoader() { super(HotSwapClassLoader.class.getClassLoader()); } public Class loadClass(String className, boolean resolve) throws ClassNotFoundException { Class clazz = findLoadedClass(className); if (clazz == null) { try { clazz = findClass(className); } catch (ClassNotFoundException e) { clazz = super.loadClass(className, resolve); } } if (resolve) { resolveClass(clazz); } return clazz; } public Class loadByte(byte[] classBytes) { return defineClass(null, classBytes, 0, classBytes.length); } } ``` 这个HotSwapClassLoader类继承了JavaClassLoader类,重写loadClass方法来实现热部署的功能。在loadClass方法中,先检查是否已经加载了该类,如果没有则自己尝试加载,如果还是找不到则交给父ClassLoader来加载。在loadByte方法中,通过字节流加载新的类文件。 使用这个HotSwapClassLoader类,可以在运行时动态地加载新的类文件,实现热部署的功能。例如,可以创建一个测试类: ```java public class Test { public void hello() { System.out.println("Hello World!"); } } ``` 然后在另外一个类中,使用HotSwapClassLoader来加载这个类,并调用它的hello方法: ```java public class Main { public static void main(String[] args) throws Exception { HotSwapClassLoader loader = new HotSwapClassLoader(); Class clazz = loader.loadClass("Test", false); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("hello", null); method.invoke(obj, null); } } ``` 这个程序会输出"Hello World!",然后可以修改Test类的代码,重新编译,再运行Main类,就可以看到新的代码被加载并执行了,实现了热部署的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值