`
tiantian911
  • 浏览: 226921 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

自定义classloader加密java程序

阅读更多
大概想法是这样的:
1. 生成密钥用于在des算法中加密。
2. classloader类中动态的解密class,并且通过反射机制执行main方法。
3. 对classloader类进行高质量的混淆。

首先需要生成des算法中的key:


import java.io.File;
import java.io.FileOutputStream;
import java.security.SecureRandom;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

class Key {

	private String keyName;

	public Key() {

	}

	public Key(String keyName) {
		this.keyName = keyName;
	}

	public void createKey(String keyName) throws Exception {

		SecureRandom sr = new SecureRandom();
		KeyGenerator kg = KeyGenerator.getInstance("DES");
		kg.init(sr);
		SecretKey key = kg.generateKey();
		System.out.println(key.toString());
		byte rawKeyData[] = key.getEncoded();
		FileOutputStream fo = new FileOutputStream(new File(keyName));
		fo.write(rawKeyData);
		fo.close();
	}

	public static void main(String args[]) {
		try {
			new Key("").createKey("d:/key.txt");

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}



有了key之后就可以对class进行加密了:
package com.hitachi.crypt;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.SecureRandom;

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

public class Crypt {

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

        SecureRandom sr = new SecureRandom();
        FileInputStream fi = new FileInputStream(new File("d:/key.txt"));
        byte rawKeyData[] = new byte[fi.available()];
        fi.read(rawKeyData);
        fi.close();
        DESKeySpec dks = new DESKeySpec(rawKeyData);
        SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, key, sr);
        FileInputStream fi2 = new FileInputStream(new File("d:/HelloWorld.class"));
        byte data[] = new byte[fi2.available()];
        fi2.read(data);
        fi2.close();
        byte encryptedData[] = cipher.doFinal(data);
        FileOutputStream fo = new FileOutputStream(new File("d:/HelloWorld.class"));
        fo.write(encryptedData);
        fo.close();
    }
}


然后还是关键的classloader类:
package com.hitachi.classloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class MyClassLoader extends ClassLoader {

	private static String myClasspath = new String("");
	private static Hashtable<String, Class<?>> loadClassHashTable = new Hashtable<String, Class<?>>();
	private static Hashtable<String, Long> loadClassTime = new Hashtable<String, Long>();

	public MyClassLoader() {

	}

	/** */
	/**
	 * create a classloader and specify a classpath.
	 * 
	 * @param myClasspath
	 *            the specified classpath name.
	 */
	public MyClassLoader(String myClasspath) {
		if (!myClasspath.endsWith("\\")) {
			myClasspath = myClasspath + "\\";
		}
		MyClassLoader.myClasspath = myClasspath;
	}

	/** */
	/**
	 * set the classpath
	 * 
	 * @param myClasspath
	 *            the specified classpath name
	 */
	public void SetmyClasspath(String myClasspath) {
		if (!myClasspath.endsWith("\\")) {
			myClasspath = myClasspath + "\\";
		}
		MyClassLoader.myClasspath = myClasspath;
	}

	/** */
	/**
	 * Loads the class with the specified binary name. This method searches for
	 * classes in the same manner as the loadClass(String, boolean) method.
	 * Invoking this method is equivalent to invoking {loadClass(name,false)}.
	 * 
	 * @param className
	 *            The binary name of the class.
	 * 
	 * @return The resulting <tt>Class</tt> object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class was not found.
	 */
	@SuppressWarnings("unchecked")
	public Class loadClass(String className) throws ClassNotFoundException {
		return loadClass(className, false);
	}

	/** */
	/**
	 * Loads the class with the specified binary name. The default
	 * implementation of this method searches for classes in the following
	 * order:
	 * 
	 * Invoke {findLoadedClass(String)} to check if the class has already been
	 * loaded.
	 * 
	 * Invoke {findSystemClass(String)} to load the system class.
	 * 
	 * Invoke the {findClass(String)} method to find the class.
	 * 
	 * If the class was found using the above steps, and the resolve flag is
	 * true, this method will then invoke the {resolveClass(Class)} method on
	 * the resulting Class object.
	 * 
	 * @param name
	 *            The binary name of the class.
	 * 
	 * @param resolve
	 *            If true then resolve the class.
	 * 
	 * @return The resulting Class object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class could not be found.
	 */
	@SuppressWarnings("unchecked")
	protected Class loadClass(String name, boolean resolve)
			throws ClassNotFoundException {

		try {
			Class foundClass = findLoadedClass(name);

			// check if the class has already been loaded.
			if (foundClass != null) {
				System.out.println("Complete to load the class: " + name);
				return foundClass;
			}

			// if the class is systemClass, load the system class by system
			if (name.startsWith("java.")) {
				foundClass = findSystemClass(name);
				loadClassHashTable.put(name, foundClass);
				System.out.println("System is loading the class: " + name);
				return foundClass;
			}

			// invoke the findClass() method to load the class
			try {
				foundClass = findClass(name);
			} catch (Exception fnfe) {
			}

			if (resolve && (foundClass != null)) {
				resolveClass(foundClass);
			}
			return foundClass;
		} catch (Exception e) {
			throw new ClassNotFoundException(e.toString());
		}
	}

	/** */
	/**
	 * Finds the class with the specified binary name.The default implementation
	 * throws a ClassNotFoundException.
	 * 
	 * @param className
	 *            The binary name of the class.
	 * 
	 * @return The resulting Class object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class could not be found.
	 */
	@SuppressWarnings("unchecked")
	public Class findClass(String className) {

		byte[] classData = null;
		try {
			classData = loadClassData(className);
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (classData == null) {
			return null;
		}

		System.out.println("MyClassLoader is loading : " + className + "");
		Class c = defineClass(className, classData, 0, classData.length);
		MyClassLoader.loadClassHashTable.put(className, c);
		System.out.println("Complete to load the class :" + className);
		return c;
	}

	/** */
	/**
	 * Loads the classData with the specified binary name. This method searches
	 * for classes in the specified classpath as
	 * searchFile(myClasspath,className) method.
	 * 
	 * @param name
	 *            The binary name of the class
	 * 
	 * @return The resulting the classData of the class object by byte[]
	 * 
	 * @throws IOException
	 *             if have some failed or interrupted I/O operations.
	 */
	private byte[] loadClassData(String className) throws IOException {

		String filePath = searchFile(myClasspath, className + ".class");

		if (!(filePath == null || filePath == "")) {

			System.out.println("It have found the file : " + className
					+ ".  Begin to read the data and load the class。");
			FileInputStream inFile = new FileInputStream(filePath);
			byte[] classData = new byte[inFile.available()];
			inFile.read(classData);
			inFile.close();
			loadClassTime.put(className, new File(filePath).lastModified());
			return classData;
		} else {

			filePath = searchFile(myClasspath, className + ".java");
			if (!(filePath == null || filePath == "")) {
				System.out.println("It have found the file : " + filePath
						+ ".  Begin to translate");
				Runtime.getRuntime().exec("javac " + filePath);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("Translate it over : " + filePath);
				return loadClassData(className);
			} else {
				System.out
						.println("Haven't found the file, and fail to read the classData!");
				return null;
			}
		}
	}

	/** */
	/**
	 * Loads the class with the specified binary name.The default implementation
	 * throws a ClassNotFoundException.
	 * 
	 * @param classData
	 *            The data of the class.
	 * @param className
	 *            The binary name of the class.
	 * 
	 * @return The resulting Class object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class could not be found.
	 */
	public Class loadClass(byte[] classData, String className)
			throws ClassNotFoundException {

		System.out.println("MyClassLoader is loading : " + className + "");
		Class c = defineClass(className, classData, 0, classData.length);
		loadClassHashTable.put(className, c);
		System.out.println("Complete to load the class :" + className);

		return c;
	}

	/** */
	/**
	 * Loads the class with the specified binary name.The default implementation
	 * throws a ClassNotFoundException.
	 * 
	 * @param className
	 *            The binary name of the class.
	 * @param jarName
	 *            The binary name of the jar that search the class from it.
	 * 
	 * @return The resulting Class object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class could not be found.
	 */
	protected Class loadClass(String className, String jarName)
			throws ClassNotFoundException {

		String jarPath = searchFile(myClasspath, jarName + ".jar");
		JarInputStream in = null;

		if (!(jarPath == null || jarPath == "")) {

			try {
				in = new JarInputStream(new FileInputStream(jarPath));
				JarEntry entry;
				while ((entry = in.getNextJarEntry()) != null) {
					String outFileName = entry.getName().substring(
							entry.getName().lastIndexOf("/") + 1,
							entry.getName().length());
					if (outFileName.equals(className + ".class")) {
						if (entry.getSize() == -1) {
							System.err.println("error : can't read the file!");
							return null;
						}
						byte[] classData = new byte[(int) entry.getSize()];
						System.out
								.println("It have found the file : "
										+ className
										+ ".  Begin to read the data and load the class。");
						in.read(classData);
						return loadClass(classData, className);
					}
				}
				System.out.println("Haven't found the file " + className
						+ " in " + jarName + ".jar.");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} else {
			System.out.println("Haven't found the jarFile: " + jarName
					+ ".jar.");
			return null;
		}
		return null;
	}

	/** */
	/**
	 * Reloads the class with the specified binary name. Needn't have to restart
	 * JVM then reload the class.
	 * 
	 * @param className
	 *            The binary name of the class need to reload .
	 * 
	 * @return The resulting Class object.
	 * 
	 * @throws ClassNotFoundException
	 *             If the class was not found.
	 */
	public Class reload(String fileName) {

		String filePath = searchFile(myClasspath, fileName + ".class");
		Long a = new File(filePath).lastModified();

		if (!a.equals(loadClassTime.get(fileName))) {
			loadClassHashTable.remove(fileName);
			loadClassTime.remove(fileName);
			try {
				MyClassLoader mc2 = new MyClassLoader(myClasspath);
				mc2.loadClass(fileName);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		} else {
			System.out
					.println("The class is the newest version , needn't reloading.");
		}
		return null;
	}

	/** */
	/**
	 * search the file with the specified binary name. Needn't have to restart
	 * JVM then reload the class.
	 * 
	 * @param classpath
	 *            the specified path where we search.
	 * @param fileName
	 *            The binary name of the file that want to search.
	 * 
	 * @return The resulting file path.
	 */
	public String searchFile(String classpath, String fileName) {

		String cut = fileName.substring(fileName.lastIndexOf('.'), fileName
				.length());
		String path = fileName.substring(0, fileName.lastIndexOf('.')).replace(
				'.', '/')
				+ cut;

		File f = new File(classpath + path);
		if (f.isFile()) {
			return f.getPath();
		} else {
			String objects[] = new File(classpath).list();
			for (int i = 0; i < objects.length; i++) {
				if (new File(classpath + File.separator + objects[i])
						.isDirectory()) {
					String s = searchFile(classpath + objects[i]
							+ File.separator, fileName);
					if (s == null || s == "") {
						continue;
					} else {
						return s;
					}
				}
			}
		}
		return null;
	};

}




最后解密,并且通过反射机制执行:
package com.hitachi.crypt;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.security.SecureRandom;

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

import com.hitachi.classloader.MyClassLoader;
public class Decrypt {

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

		SecureRandom sr = new SecureRandom();
		FileInputStream fi = new FileInputStream(new File("d:/key.txt"));
		byte rawKeyData[] = new byte[fi.available()];
		fi.read(rawKeyData);
		fi.close();
		DESKeySpec dks = new DESKeySpec(rawKeyData);
		SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
		Cipher cipher = Cipher.getInstance("DES");
		cipher.init(Cipher.DECRYPT_MODE, key, sr);
		FileInputStream fi2 = new FileInputStream(new File(
				"D:/HelloWorld.class"));
		byte encryptedData[] = new byte[fi2.available()];
		fi2.read(encryptedData);
		fi2.close();
		byte decryptedData[] = cipher.doFinal(encryptedData);
		MyClassLoader mcl = new MyClassLoader("D:/");
		Class cl = mcl.loadClass(decryptedData, "HelloWorld");
		Method mainMethod = cl.getMethod("sayHello");
		mainMethod.invoke(null, null);
	}
}


其中源文件是这样的:

public class HelloWorld {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("Hello world");
	}

	public static void sayHello() {
		System.out.println("Hello");
	}

}


就可以了。
2
0
分享到:
评论
4 楼 lzj0470 2011-12-24  
这种方式,带来的问题很大。如:返回一个对象,然后再调用一些办法
3 楼 qskm 2010-07-22  
这个怎么用呢?楼主没说清楚啊,
1、 加密的话该怎么加密?直接执行Crypt类,一个一个加密class文件还是怎么整?
2、 加载class的classloader类是放在哪里?需要配置还是如何调用的?
3、 基于ssh的系统能用不?
4、 ???
2 楼 thxg 2009-11-08  
博主好,请教一个classloader相关的问题,我用classloader加载了一个jar文件,用完之后希望可以跟据用户意愿删掉这个jar文件,但据说VM不退出,就不会释放,就无法删除,有什么好办法解决这个问题吗?参考问答模块的链接:
http://www.iteye.com/problems/28854
1 楼 雁行 2009-06-12  
好复杂啊
参考一下

相关推荐

    自定义classloader的使用

    自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨自定义Classloader的使用。 一、Classloader的工作原理 Java的类加载机制遵循双亲...

    classloader 加密解密应用程序 ,反编译class

    在程序运行时,通过自定义的`ClassLoader`,在加载类之前先解密这些加密的字节码,然后再交给JVM执行。这样可以增加逆向工程的难度,防止代码被恶意分析或篡改。加密解密的过程通常涉及到对字节码的操作,例如使用...

    Understanding the Java ClassLoader

    ### Java ClassLoader理解详解 ...自定义ClassLoader不仅能够扩展JVM的功能,还能够在实际项目中解决特定问题,如动态加载远程资源、加密类文件等。希望这篇教程能为你提供足够的背景知识,以便在实践中应用这些技术。

    加密Java源代码

    加密Java源代码 ,使用自定义classloader加载器和加密解密技术实现

    JAVA加密研究.doc

    本文主要探讨了两种常见的Java加密策略:自定义ClassLoader加密和混淆技术。 首先,我们关注自定义ClassLoader的加密方法。Java的类加载机制允许开发者创建自己的ClassLoader子类,通过这个机制可以实现对类的加密...

    如何有效防止Java程序源码被人偷窥.doc

    【如何有效防止Java程序源码被人偷窥】 Java程序的源代码保护是一个重要的议题,因为一旦源码被窃取,可能会导致知识产权的流失,甚至可能导致安全风险。在Java中,由于其字节码的可读性,源码很容易通过反编译器被...

    防止Java程序被反编译

    2. **Class文件加密**:对敏感的Class文件进行加密,然后在运行时通过自定义ClassLoader解密并加载。虽然这增加了反编译的难度,但自定义ClassLoader本身可能会成为攻击目标,一旦解密密钥或算法被破解,加密的Class...

    ClassLoader 详解.doc

    自定义ClassLoader是Java平台的一大特色,开发人员可以根据需要创建自己的类加载器,例如实现模块化、热部署或者加密解密类等高级功能。自定义ClassLoader通常需要重写findClass()或loadClass()方法,以控制类的加载...

    运用加密技术保护Java源代码

    下面将通过一个简单的示例来展示如何使用自定义ClassLoader来实现Java源代码的加密与解密。 1. **创建自定义ClassLoader**: - 自定义ClassLoader需要重写`findClass`方法来处理加密后的类文件。 - 在`findClass`...

    ClassLoader小例子

    - 在某些特殊情况下,我们可能需要自定义ClassLoader来实现特定的加载逻辑,例如从网络、数据库或加密文件中加载类。 - 自定义ClassLoader通常需要重写`loadClass()`方法,该方法在找不到类时调用`findClass()`...

    Java类加密程序

    例如,本加密工具安装在c:\hideasoft\java_protect,执行加密后的CLASS文件的命令行如下: java -agentlib:c:\hideasoft\java_protect\hidea &lt;您的CLASS类及参数&gt; 应用场合 独立的应用程序(Application,...

    Java SE: ClassLoader in depth

    - 应用程序沙箱:在沙箱环境中运行应用程序,通过自定义ClassLoader来控制加载的类的安全性。 - 模块化/插件化:对于需要模块化或插件化的应用程序,可以通过自定义ClassLoader实现模块的热加载或动态卸载。 深入...

    ava的ClassLoader介绍.doc

    不同于C或C++程序,Java程序由多个独立的类文件组成,每个文件对应一个Java类。ClassLoader的工作机制允许Java程序在运行时动态加载类,从而提供了更大的灵活性和扩展性。 Java的ClassLoader分为几个层次,包括...

    java classloader讲义-淘宝网

    通过对Java ClassLoader的深入了解,我们可以更好地理解Java类的加载机制以及如何通过自定义ClassLoader来满足特定的应用需求。淘宝网的成功实践为我们提供了宝贵的参考案例,展示了ClassLoaders在实际项目中的重要...

    防止Java程序源码被人盗用的应用实例.doc

    - 尽管加密和自定义ClassLoader可以增加安全性,但是Java的JVM本身可能存在安全漏洞,允许黑客绕过这些保护措施。因此,还需要结合使用Java的安全管理器和策略文件,限制代码的执行权限,防止恶意代码对系统资源的...

    ClassLoader总结

    总之,ClassLoader是Java运行时环境中的关键组件,理解其工作原理和如何自定义ClassLoader对于提高开发者的技术深度和解决问题的能力具有重要意义。通过阅读源码和实践,我们可以更深入地掌握这一领域,从而在实际...

    浅析ClassLoader

    1. 自定义需求:在某些场景下,如动态加载插件、加密类文件等,开发者可能需要自定义ClassLoader。自定义ClassLoader需要继承java.lang.ClassLoader并重写findClass()方法。 2. 实现步骤:创建类加载器实例,读取类...

    深入Java虚拟机_ClassLoader

    《深入Java虚拟机_ClassLoader》是一本专注于Java虚拟机(JVM)中ClassLoader部分的专著,旨在帮助读者深入理解Java程序如何加载、链接和初始化类。ClassLoader是Java平台核心特性的一部分,它负责查找和加载类到JVM...

    JAVA数据加密方面的资料

    在这个主题中,我们将深入探讨三个关键知识点:Java中的类加载器(ClassLoader)在加密解密中的应用、常见的加密算法以及Java提供的加密技术。 首先,让我们来看看Java的类加载器如何在加密解密中发挥作用。类加载...

Global site tag (gtag.js) - Google Analytics