Protection of Agent Teamwork
Total Page:16
File Type:pdf, Size:1020Kb
Jeremy Hall Protection of Agent Teamwork Table of Contents Goal............................................................................................................................................................1 Overview....................................................................................................................................................1 Class Overview .........................................................................................................................................2 Javassisti.....................................................................................................................................................3 Usage..........................................................................................................................................................3 Limitations .................................................................................................................................................3 Java Limitations .........................................................................................................................................4 Changes made to Agent Teamwork...........................................................................................................4 Proxy Creation - Logical Flow...................................................................................................................4 Proxy Method Execution – Logical Flow..................................................................................................7 Conclusion .................................................................................................................................................8 I. Goal 1. The main goal of this project was to protect a Java program's logic by encrypting a Java class's methods. This is accomplished by first encrypting a Class, and then only decrypting the parts of that Class as they need to be used, after which they are thrown away. An additional goal was to have as little an impact as possible on existing code. This means that the project should require as little change in the classes that it protects as possible. A program using an encrypted class should also have minimal required changes to use the encrypted classes. II. Overview 1. The reason for protecting a Java program's logic is to prevent sophisticated attacks such as an attacker scanning the memory of a computer while its Java program is running. Another situation is forcing a memory dump to read the contents of a running Java program. 2. This project relies heavily on an open source Java library called Javassist. Javassist allows for manipulation of Java bytecode files, as well as run-time compilation of dynamically created classes. 3. For a class to be encrypted, its bytecode .class file must be loaded by a special classloader. In practice, this means using an instance of the ClassRipper class. 1 4. When a class is “ripped”, all of its methods are changed to forward their parameters to a single “Invoke” method. All of the class's real methods are encrypted, and stored inside of a class which knows how to decrypt and return an instance of a class that contains the required method ( In Java, a method cannot exist on its own, it must exist inside of a Class) . A one-time-use classloader is used to actually create the instance of the class containing the method. 5. The decrypted method is invoked, and all references to the instance of the class containing the method lose scope (including the class loader that loaded the class), so that the instance is garbage collected, and no unencrypted versions of the code remain. III. Class Overview 1. ClassRipper is the class that a program wishing to use an encrypted class will use. This class will “rip” a Java .class file, and return an instance of an object which contains the same public interface ( note that this does not literally mean a Java interface, but in fact means the returned class will have all the same methods, variables, interfaces, and inherited class ) as the Class stored in the .class file. 2. ProxyCreator is the class which holds all the actual steps for generating a new encrypted Class from the original Class representation. I refer to the modified classes as proxies. 1. There are two slightly different proxy types that need to be created. The first is the Class whose instance will be returned to the user. This class contains none of the method information from the original class. It just has skeleton methods which forward all information to an “Invoke” method. 2. For every method that existed in the original class, a separate Class must be created to store said method. This is the second type of proxy. This proxy actually contains a method from the original class in it for execution. In addition to containing a real method, however, it must also contain skeleton methods just like the first type of proxy. This is because the method that this proxy contains may reference another method inside the original class. 3. ClassServer is essentially a wrapper around a Hashtable. ClassServer accepts a method name, and returns the correct Class wrapped method for a proxy to use. ClassServer uses the method name as a key into the Hashtable, decrypts the Class that is returned to it, and then instantiates an instance of that Class to return to the proxy. 2 4. DisposableClassLoader is a ClassLoader which is to be used with only one class. ClassServer uses this class to instantiate the Class returned to it from the Hashtable. This is because for the class definition to be garbage collected, the ClassLoader that loaded it must be dereferenced as well. 5. The Crypto class provides the methods to encrypt and decrypt. It also handles the generation of the secret key. Its encryption implementation is a symmetrical cipher. 6. ByteEncrypt extends Crypto and is used specifically to handle the encryption of bytes. This class is used by ClassRipper to encrypt the individual class wrapped methods which are inserted into the Hashtable. IV. Javassisti 1. As mentioned earlier, Javassist allows for the manipulation of bytecode, and the run-time creation of classes. Before modifying a class with Javassist, the class must be loaded into one of Javassist's own class types. Most of the Javassist code is in the ProxyCreator class. This project loads the class from a .class file from the filesystem. This is loaded into a CtClass, which is a Javassist representation of a Class. CtMethod is Javassist's representation of a Java Method. 2. CtClass allows for the direct manipulation of all of a Class's internal members. CtMethods can be created, added to a CtClass, removed from a CtClass, and modified. CtFields are representations of Java Fields, and can be modified similarly to CtMethods. V. Usage 1. To create an encrypted class, the first thing one must do is to instantiate an instance of ClassRipper. 2. Call the method Object ClassRipper.StartRip( String location ). The parameter points to the .class file of the Class which should be encrypted. The returned object is an instance of an encrypted version of the class. If the Class to be encrypted needs to have arguments passed to its constructor, then use Object ClassRipper.StartRip( String location, Object[] args ) instead, and pass an Object array holding the constructor arguments along with the .class file location. VI. Limitations 1. One major limitation placed on a Class which wants to be encrypted is that the constructor may not reference another method in the class. This is because of the order in which the 3 constructor is called, and the ClassServer which contains the encrypted methods is passed to the proxy. When the encrypted version of the class is created at runtime, one of the methods added to it is called “_setClassServer” and its meant to accept the ClassServer so that the proxy can retrieve its methods. This method must by definition be called after the constructor, which means that if the constructor references another method in the class, the proxy won't have its ClassServer yet so it cannot retrieve the method and an exception will be thrown. 2. Encrypted classes are not threadsafe. This is because there is a mechanism to send and retrieve class variables each time a method is called, and this portion has not been synchronized (although it probably wouldn't be hard to do). VII. Java Limitations 1. There are certain limitations in Java which have made the project harder to implement. One of the biggest limitations is that once a Class has been loaded by a Java ClassLoader, it cannot be replaced, or removed individually. To get rid of a Class, the entire ClassLoader must be garbage collected. 2. Methods must be wrapped inside of a Class, they cannot exist on their own. 3. Once a Class has been loaded into Java, it cannot be modified (there actually is a way to allow this, but it can only be done by running Java in debug mode). 4. Unless the class being encrypted belongs to an interface, the only way to access the methods of the encrypted class is through reflection (unless you cast the object as its superclass). This is because the actual class isn't created until run-time. 5. In Java, its very difficult to remove all traces of something from memory. This is because garbage collection is nondeterministic. Its impossible to know when it will happen, and it's impossible to force it to happen. This means that unencrypted versions of methods can be floating in memory for some time before being removed, thus reducing the