public class Main { public static void main (final String [] args) { System.out.println ("secret result = " + MySecretClass.mySecretAlgorithm ()); }
} // End of class
package my.secret.code;
import java.util.Random;
public class MySecretClass { /** * Guess what, the secret algorithm just uses a random number generator... */ public static int mySecretAlgorithm () { return (int) s_random.nextInt (); }
private static final Random s_random = new Random (System.currentTimeMillis ());
} // End of class 我想通过加密相关的class文件并在运行期解密来隐藏my.secret.code.MySecretClass的执行。用下面这个工具可以达到效果(你可以到这里下载Resources):
public class EncryptedClassLoader extends URLClassLoader { public static void main (final String [] args) throws Exception { if ("-run".equals (args [0]) && (args.length >= 3)) { // Create a custom loader that will use the current loader as // delegation parent: final ClassLoader appLoader = new EncryptedClassLoader (EncryptedClassLoader.class.getClassLoader (), new File (args [1]));
// Thread context loader must be adjusted as well: Thread.currentThread ().setContextClassLoader (appLoader);
final Class app = appLoader.loadClass (args [2]);
final Method appmain = app.getMethod ("main", new Class [] {String [].class}); final String [] appargs = new String [args.length - 3]; System.arraycopy (args, 3, appargs, 0, appargs.length);
appmain.invoke (null, new Object [] {appargs}); } else if ("-encrypt".equals (args [0]) && (args.length >= 3)) { ... encrypt specified classes ... } else throw new IllegalArgumentException (USAGE); }
/** * Overrides java.lang.ClassLoader.loadClass() to change the usual parent-child * delegation rules just enough to be able to "snatch" application classes * from under system classloader's nose. */ public Class loadClass (final String name, final boolean resolve) throws ClassNotFoundException { if (TRACE) System.out.println ("loadClass (" + name + ", " + resolve + ")");
Class c = null;
// First, check if this class has already been defined by this classloader // instance: c = findLoadedClass (name);
if (c == null) { Class parentsVersion = null; try { // This is slightly unorthodox: do a trial load via the // parent loader and note whether the parent delegated or not; // what this accomplishes is proper delegation for all core // and extension classes without my having to filter on class name: parentsVersion = getParent ().loadClass (name);