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 ());
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 classesfrom 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);
if (c == null) { try { // OK, either 'c' was loaded by the system (not the bootstrap // or extension) loader (in which case I want to ignore that // definition) or the parent failed altogether; either way I // attempt to define my own version: c = findClass (name); } catch (ClassNotFoundException ignore) { // If that failed, fall back on the parent's version // [which could be null at this point]: c = parentsVersion; } } }
if (c == null) throw new ClassNotFoundException (name);
if (resolve) resolveClass (c);
return c; }
/** * Overrides java.new.URLClassLoader.defineClass() to * be able to call crypt() before defining a class. */ protected Class findClass (final String name) throws ClassNotFoundException { if(TRACE) System.out.println("findClass(" + name + ")");
//.class files are not guaranteed to be loadable as resources; // but if Sun's code does it, so perhaps can mine... final String classResource = name.replace ('.', '/') + ".class"; final URL classURL = getResource (classResource);
if (classURL == null) throw new ClassNotFoundException (name); else { InputStream in = null; try { in = classURL.openStream ();
final byte [] classBytes = readFully (in);
// "decrypt": crypt (classBytes); if (TRACE) System.out.println ("decrypted [" +