Initial commit from SVN.

This commit is contained in:
wcrisman
2014-05-30 10:31:51 -07:00
commit b45e56b890
1968 changed files with 370949 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import com.common.debug.Debug;
import com.common.io.StreamSupport;
import com.common.util.*;
import java.io.*;
import java.lang.reflect.Array;
import java.util.Arrays;
/*
* A runnable class that will read in class files, mangle them, and output them to another location.
*/
public class Main {
/**
* Main constructor.
*/
private Main() {
}//Main()//
/**
* Mangles a class file.
* @param args Four arguments are expected: <br>
* args[0]: Whether to mangle the source file name.
* args[1]: The input directory.
* args[2]: The output directory for the classes in the previous input directory.
* args[3]: The semi-colon separated package names to exclude. Package names must use '/' and not '.' as a separator. A value of ';' can be used if nothing is being passed.
* args[4]: The semi-colon separated package names to include (exclusions are applied first). Package names must use '/' and not '.' as a separator.
* args[5]: The external jar directory (containing jars used during the obfuscation but not obfuscated).
* args[6]: The optional metadata file name (assumes the metadata file is located directly in the input directory).
* args[7]: The optional metadata file output name (assumes the metadata file is located directly in the input directory).
*/
public static void main(String[] args) {
/*
ClassLoader loader = new ClassLoader() {
private File root = new File("c:/data/workspace-deploy/archives/temp/contents_temp/");
protected Class findClass(String name) throws ClassNotFoundException {
File file = new File(root, name.replace('.', '/') + ".class");
Class result = null;
if(file.exists() && file.canRead()) {
byte[] bytes = null;
try {
bytes = StreamSupport.readBytes(file);
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
if(bytes != null) {
result = defineClass(name, bytes, 0, bytes.length);
}//if//
}//if//
return result != null ? result : super.findClass(name);
}//findClass()//
public Class loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}//loadClass()//
};
try {
loader.loadClass("java.lang.String");
Debug.log("Loaded String");
}catch(Throwable e) {Debug.log(e);}
try {
//loader.loadClass("java.lang.String[]");
Class.forName("[Ljava.lang.String;");
Debug.log("Loaded String[]");
}catch(Throwable e) {Debug.log(e);}
try {
loader.loadClass("com.de22.release.interfaces.IReleaseServerConnection");
Class.forName("[Lcom.de22.release.interfaces.IReleaseServerConnection;");
Debug.log("Loaded IProxyInterfaceLoader[]");
}catch(Throwable e) {Debug.log(e);}
*/
boolean printInstructions = false;
try {
if(args.length < 5) {
printInstructions = true;
}//if//
else {
boolean mangleSourceFileNames = Boolean.parseBoolean(args[0]);
File inputDirectory = new File(args[1]);
File outputDirectory = new File(args[2]);
String exclusionsText = args[3].trim();
IList exclusions = exclusionsText.length() == 0 || (exclusionsText.length() == 1 && exclusionsText.charAt(0) == ';') ? LiteList.EMPTY_LIST : new LiteList(exclusionsText.split(";"));
IList inclusions = new LiteList(args[4].trim().split(";"));
File mapping = new File(outputDirectory, "mapping.txt");
DevelopmentMangler mangler = new DevelopmentMangler(exclusions, inclusions, inputDirectory, outputDirectory, args.length > 5 ? new File(args[5]) : null, args.length > 6 ? args[6] : null, args.length > 7 ? args[7] : null, mangleSourceFileNames);
mangler.mangleClasses();
StreamSupport.writeText(mangler.getPairings(), mapping, "UTF8");
}//else//
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
if(printInstructions) {
Debug.log("Process was passed these arguments:");
for(int index = 0; index < args.length; index++) {
Debug.log("arg[" + index + "]: '" + args[index] + "'");
}//for//
Debug.log("Usage:\r\n arg[0]: Whether source file references should be obfuscated.\r\n arg[1]: The input directory (or file).\r\n arg[2]: The output directory.\r\n arg[3]: The semi-colon separated package names to exclude. Package names must use '/' and not '.' as a separator. A single semi-colon can be used for an empty set.\r\n arg[4]: The semi-colon separated package names to include (exclusions are applied first). Package names must use '/' and not '.' as a separator.\r\n arg[5]: The optional directory containing jars that won't be mangled, but will be used to load classes during mangling.\r\n arg[6]: The optional input metadata file name and extension (no path - assumes that it is directly in the input directory).\r\n arg[7]: The optional ouput metadata file name and extension (no path - assumes that it is directly in the input directory).");
}//if//
}//main()//
}//Main//

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import com.common.util.IList;
public class MangleSupport {
public static final String PROXY_POSTPEND = "__SZProxy";
/**
* MangleSupport constructor.
*/
private MangleSupport() {
}//MangleSupport()//
/**
* Mangles the given class name.
* <p>NOTE: Copied from BaseMangler.</p>
* @param name The name of the class to be mangled. (com/test/ClassName$InnerClassName)
* @return The managled name.
*/
public static String mangleClassName(String name) {
String result = null;
if(name.indexOf('$') != -1) {
String[] names = name.split("\\$");
StringBuffer buffer = new StringBuffer(16 * names.length + names.length - 1);
//Warning: If this changes, it may require an update to RuntimeMangler's isMangled(String) method, and BaseMangler's mangleClassName(..) method.//
for(int index = 0; index < names.length; index++) {
if(index != 0) {
buffer.append('$');
}//if//
//Don't mangle annoymous class names (they are always pure numbers).//
if(Character.isDigit(names[index].charAt(0))) {
buffer.append(names[index]);
}//if//
else {
int lastSlashIndex = names[index].lastIndexOf('/');
//Give special treatment to proxy classes, allowing the ORB to find the proxy class given a proxied interface class.//
if(names[index].endsWith(PROXY_POSTPEND)) {
String newName = names[index].substring(0, names[index].length() - PROXY_POSTPEND.length());
if(!(name.length() <= lastSlashIndex + 2 || name.charAt(lastSlashIndex + 1) != 'I' || !Character.isUpperCase(name.charAt(lastSlashIndex + 2)))) {
newName = lastSlashIndex == -1 ? newName.substring(1) : newName.substring(0, lastSlashIndex + 1) + newName.substring(lastSlashIndex + 2);
}//if//
buffer.append(hashString64(newName, (byte) 11));
}//if//
//Detect interface names that might be used by the ORB when finding the interface to proxy from a given object.//
else if(names[index].length() <= lastSlashIndex + 2 || names[index].charAt(lastSlashIndex + 1) != 'I' || !Character.isUpperCase(names[index].charAt(lastSlashIndex + 2))) {
buffer.append(hashString64(names[index], (byte) 12));
}//if//
else {
String newName = lastSlashIndex == -1 ? names[index].substring(1) : names[index].substring(0, lastSlashIndex + 1) + names[index].substring(lastSlashIndex + 1);
//Use the name without the 'I' so that it matches the class name.//
buffer.append(hashString64(newName, (byte) 10));
}//else//
}//else//
}//for//
result = buffer.toString();
}//if//
else {
int lastSlashIndex = name.lastIndexOf('/');
//Give special treatment to proxy classes, allowing the ORB to find the proxy class given a proxied interface class.//
if(name.endsWith(PROXY_POSTPEND)) {
String newName = name.substring(0, name.length() - PROXY_POSTPEND.length());
if(!(name.length() <= lastSlashIndex + 2 || name.charAt(lastSlashIndex + 1) != 'I' || !Character.isUpperCase(name.charAt(lastSlashIndex + 2)))) {
newName = lastSlashIndex == -1 ? newName.substring(1) : newName.substring(0, lastSlashIndex + 1) + newName.substring(lastSlashIndex + 2);
}//if//
result = hashString64(newName, (byte) 11);
}//if//
//Detect interface names that might be used by the ORB when finding the interface to proxy from a given object.//
else if(name.length() <= lastSlashIndex + 2 || name.charAt(lastSlashIndex + 1) != 'I' || !Character.isUpperCase(name.charAt(lastSlashIndex + 2))) {
result = hashString64(name, (byte) 12);
}//if//
else {
String newName = lastSlashIndex == -1 ? name.substring(1) : name.substring(0, lastSlashIndex + 1) + name.substring(lastSlashIndex + 2);
//Use the name without the 'I' so that it matches the class name.//
result = hashString64(newName, (byte) 10);
}//else//
}//else//
return result;
}//mangleClassName()//
/**
* Hashes the given text into a 60 bit value and a 4 bit prefix.
* <p>NOTE: Copied from BaseMangler.</p>
* @param name The text to be hashed.
* @param firstFourBits The first four bits to use in the hashed value (corresponds to the first hex character in the result).
* @return The hex hash value.
*/
public static String hashString64(String text, byte firstFourBits) {
long number = (((long) text.length()) << 28);
int firstBitPosition = 60;
//Set the highest four bits.//
number |= ((long) (firstFourBits & 0xFF)) << 60;
for(int index = 0; index < text.length(); index++) {
long next = (long) (text.charAt(index) & 0xFFFF);
if(firstBitPosition - 16 >= 0) {
number ^= (next << (firstBitPosition - 16));
}//if//
else {
long wrappedBits = next;
int wrappedBitCount = 16 - firstBitPosition;
//Kill the lower N bits that must be wrapped to the top of the long value.//
next >>= wrappedBitCount;
//Kill the top bits that won't be wrapped to the top of the long value.//
wrappedBits <<= (64 - wrappedBitCount);
//Shift the wrapped bits to appear at the top of the long (after the first four bits).//
wrappedBits >>>= 4;
//Apply the wrapped & unwrapped bits.//
number ^= (next | wrappedBits);
}//else//
firstBitPosition -= 16;
if(firstBitPosition < 0) {
firstBitPosition += 60;
}//if//
}//for//
return Long.toHexString(number);
}//hashString64()//
/**
* Determines whether the given class name is a mangled name. If the name is an inner class then just the inner class is tested.
* @param name The name to test.
* @return Whether the name has been mangled.
*/
public static boolean isMangled(String name) {
boolean result = name.indexOf('/') == -1;
String[] nameParts = name.split("$");
//for(int partIndex = 0; result && partIndex < nameParts.length; partIndex++) {
String namePart = nameParts[nameParts.length - 1];
if(!Character.isDigit(namePart.charAt(0))) {
result = namePart.length() == 16;
for(int characterIndex = 0; result && characterIndex < namePart.length(); characterIndex++) {
char ch = namePart.charAt(characterIndex);
result = (ch >= 'a' && ch <= 'f') || Character.isDigit(ch);
}//for//
}//if//
else {
result = false;
}//else//
//}//for//
return result;
}//isMangled()//
/**
* Attempts to match the qualified class name to the metadata that need mangling.
* @param name The qualified class name to test. Must be in the form: "com.test.ClassName$InnerClassName".
* @param excludedPackages The collection of packages to not be mangled (superceeds the included packages).
* @param includedPackages The collection of packages to be mangled.
* @return Whether the class name should be mangled.
*/
public static boolean matches(String name, IList excludedPackages, IList includedPackages) {
for(int index = 0; index < excludedPackages.getSize(); index++) {
if(name.startsWith((String) excludedPackages.get(index))) {
return false;
}//if//
}//for//
for(int index = 0; index < includedPackages.getSize(); index++) {
if(name.startsWith((String) includedPackages.get(index))) {
return true;
}//if//
}//for//
return false;
}//matches()//
}//MangleSupport//

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import com.common.util.IList;
public class ManglerClassLoader extends ClassLoader {
/** The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match. */
private IList excludedPackages = null;
/** The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded. */
private IList includedPackages = null;
/**
* ManglerClassLoader constructor.
* @param excludedPackages The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match.
* @param includedPackages The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded.
*/
public ManglerClassLoader(IList excludedPackages, IList includedPackages) {
this.excludedPackages = excludedPackages;
this.includedPackages = includedPackages;
}//ManglerClassLoader()//
/**
* ManglerClassLoader constructor.
* @param parent The parent class loader which gets first crack and loading the classes.
* @param excludedPackages The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match.
* @param includedPackages The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded.
*/
public ManglerClassLoader(ClassLoader parent, IList excludedPackages, IList includedPackages) {
super(parent);
this.excludedPackages = excludedPackages;
this.includedPackages = includedPackages;
}//ManglerClassLoader()//
/**
* Attempts to match the qualified class name to the metadata that need mangling.
* <p>NOTE: Copied from BaseMangler.</p>
* @param name The qualified class name to test. Must be in the form: "com.test.ClassName$InnerClassName".
* @param metadata The package metadata used to determine if a type name should be mangled.
* @return Whether the class name should be mangled.
*/
private boolean matches(String name) {
for(int index = 0; index < excludedPackages.getSize(); index++) {
if(name.startsWith((String) excludedPackages.get(index))) {
return false;
}//if//
}//for//
for(int index = 0; index < includedPackages.getSize(); index++) {
if(name.startsWith((String) includedPackages.get(index))) {
return true;
}//if//
}//for//
return false;
}//matches()//
/**
* Mangles the given class name.
* <p>NOTE: Copied from BaseMangler.</p>
* @param name The name of the class to be mangled. (com/test/ClassName$InnerClassName)
* @return The managled name.
*/
private String mangleClassName(String name) {
return MangleSupport.mangleClassName(name);
}//mangleClassName()//
/**
* Hashes the given text into a 60 bit value and a 4 bit prefix.
* <p>NOTE: Copied from BaseMangler.</p>
* @param name The text to be hashed.
* @param firstFourBits The first four bits to use in the hashed value (corresponds to the first hex character in the result).
* @return The hex hash value.
*/
protected String hashString64(String text, byte firstFourBits) {
return MangleSupport.hashString64(text, firstFourBits);
}//hashString64()//
/* (non-Javadoc)
* @see java.lang.ClassLoader#findClass(java.lang.String)
*/
protected Class findClass(String name) throws ClassNotFoundException {
String className = name.replace('.', '/');
if(matches(className)) {
className = mangleClassName(className);
return loadClass(className);
}//if//
return super.findClass(name);
}//findClass()//
}//ManglerClassLoader//

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import com.common.util.IHashMap;
import com.common.util.IList;
import com.de22.orb.IProxyInterfaceLoader;
public class ProxyInterfaceLoader implements IProxyInterfaceLoader {
/** The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match. */
private IList excludedPackages = null;
/** The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded. */
private IList includedPackages = null;
/** The optional map of normal class names indexed by the mangled name. This is useful for removing mangling when sending serialized data or proxies to the remote process via the orb. */
private IHashMap demangleMap = null;
/**
* ProxyInterfaceLoader constructor.
* @param excludedPackages The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match.
* @param includedPackages The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded.
* @param demangleMap The optional map of normal class names indexed by the mangled name. This is useful for removing mangling when sending serialized data or proxies to the remote process via the orb.
*/
public ProxyInterfaceLoader(IList excludedPackages, IList includedPackages, IHashMap demangleMap) {
this.excludedPackages = excludedPackages;
this.includedPackages = includedPackages;
this.demangleMap = demangleMap;
}//ProxyInterfaceLoader()//
/* (non-Javadoc)
* @see com.de22.orb.IProxyInterfaceLoader#loadDefaultProxyInterface(java.lang.Object, java.lang.ClassLoader)
*/
public Class loadDefaultProxyInterface(Object proxiedObject, ClassLoader classLoader) throws ClassNotFoundException {
String proxiedClassName = proxiedObject.getClass().getName();
//TODO: Do we need to handle interfaces that are inner classes?
if(MangleSupport.isMangled(proxiedClassName)) {
proxiedClassName = 'a' + proxiedClassName.substring(1);
}//if//
else {
proxiedClassName = 'I' + proxiedClassName;
}//else//
return classLoader != null ? classLoader.loadClass(proxiedClassName) : Class.forName(proxiedClassName);
}//loadDefaultProxyInterface()//
/* (non-Javadoc)
* @see com.de22.orb.IProxyInterfaceLoader#loadProxyClass(java.lang.Class, java.lang.ClassLoader)
*/
public Class loadProxyClass(Class interfaceClass, ClassLoader classLoader) throws ClassNotFoundException {
String proxyClassName = interfaceClass.getName();
//TODO: Do we need to handle interfaces that are inner classes?
if(MangleSupport.isMangled(proxyClassName)) {
proxyClassName = 'b' + proxyClassName.substring(1);
}//if//
else if(MangleSupport.matches(proxyClassName, excludedPackages, includedPackages)) {
proxyClassName = MangleSupport.mangleClassName(proxyClassName);
}//else if//
else if(!proxyClassName.endsWith(MangleSupport.PROXY_POSTPEND)) {
proxyClassName = proxyClassName + MangleSupport.PROXY_POSTPEND;
}//else//
//Debug.log("Converted " + interfaceClass.getName() + " to " + proxyClassName);
return classLoader != null ? classLoader.loadClass(proxyClassName) : Class.forName(proxyClassName);
}//loadProxyClass()//
/* (non-Javadoc)
* @see com.de22.orb.IProxyInterfaceLoader#mangleClassName(java.lang.String)
*/
public String mangleClassName(String className) {
if(!MangleSupport.isMangled(className) && MangleSupport.matches(className, excludedPackages, includedPackages)) {
className = MangleSupport.mangleClassName(className);
}//else if//
return className;
}//mangleClassName()//
/* (non-Javadoc)
* @see com.de22.orb.IProxyInterfaceLoader#demangleClassName(java.lang.String)
*/
public String demangleClassName(String className) {
String result = null;
if(demangleMap != null) {
result = (String) demangleMap.get(className);
}//if//
return result == null ? className : result;
}//demangleClassName()//
}//ProxyInterfaceLoader//

View File

@@ -0,0 +1,885 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipOutputStream;
import com.common.comparison.Comparator;
import com.common.debug.Debug;
import com.common.io.ByteArrayOutputStream;
import com.common.io.ObjectInputStream;
import com.common.io.ObjectOutputStream;
import com.common.io.StreamSupport;
import com.common.io.SymmetricOutputStream;
import com.common.security.ISymmetricAlgorithm;
import com.common.util.IHashMap;
import com.common.util.IHashSet;
import com.common.util.IIterator;
import com.common.util.IList;
import com.common.util.ISet;
import com.common.util.LiteHashMap;
import com.common.util.LiteHashSet;
import com.common.util.LiteList;
import com.de22.javabytecode.Field;
import com.de22.javabytecode.Method;
import com.de22.javabytecode.Type;
import com.de22.javabytecode.constant.ConstantUtf8;
import com.de22.obfuscation.BaseMangler.FieldMetadata;
import com.de22.obfuscation.BaseMangler.FieldRefConstantMetadata;
import com.de22.obfuscation.BaseMangler.MethodMetadata;
import com.de22.obfuscation.BaseMangler.NameAndTypeConstantMetadata;
/**
* Performs a mangling on java class files (also has some functionality for java source and text files).
* This will prevent reverse engineering the name from the mangled name, and it will allow dynamic loading of code that depends on the mangled code base.
*/
public class RuntimeMangler extends BaseMangler {
/** The mapping of TypeMetadata objects indexed by the type name (com/test/ClassName$InnerClassName). */
private LiteHashMap metadataMap = new LiteHashMap(100, Comparator.getLogicalComparator(), Comparator.getIdentityComparator());
/** The hash map of unmangled type names indexed by the mangled name. This is used by the user of this code to reverse the manglings in any generated source. */
private IHashMap mangleTypeMap;
public static final void main(String[] args) {
//File controlPath = new File("c:/data/workspace-test/Test/controls/");
//LiteList jars = new LiteList(40, 20);
File[] jarFiles = null;
// //Collect all the jars in the control directories.//
// File[] files = controlPath.listFiles();
//
// for(int fileIndex = 0; fileIndex < files.length; fileIndex++) {
// File nextFile = files[fileIndex];
//
// if(nextFile.isFile() && nextFile.canRead() && nextFile.getName().endsWith(".jar") && !nextFile.getName().equalsIgnoreCase("Builder.jar")) {
// jars.add(nextFile);
// }//if//
// }//for//
//
// //Mangle the component jars (generating zjar files).//
// jars.toArray(jarFiles = new File[jars.getSize()]);
//jarFiles = new File[] {new File("c:/data/workspace-test/Test/controls/window.jar")};
//jarFiles = new File[] {new File("c:/data/workspace-test/Test/controls/window.jar"), new File("c:/data/workspace-test/Test/controls/frame.jar"), new File("c:/data/workspace-test/Test/controls/container.jar"), new File("c:/data/workspace-test/Test/controls/scrollable-component.jar"), new File("c:/data/workspace-test/Test/controls/component.jar"), new File("c:/data/workspace-test/Test/controls/abstract.jar")};
RuntimeMangler mangler = new RuntimeMangler(new File[] {new File("c:/data/workspace-iwc2/Pman/controls/Builder.jar")}, new LiteList(new String[] {"com/foundation/view/swt/builder", "com/foundation/tcv/swt/builder"}), new LiteList(new String[] {"com/de22", "com/common", "com/foundation", "com/declarativeengineering"}), null);
jarFiles = new File[] {
new File("C:/Data/workspace-iwc2/Pman/controls/abstract.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/button.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/card-layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-button.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-combo.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-container.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-date-time.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-panel.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-progress.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cell-text.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/collection-component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/combo.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/container.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cool-bar.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/cool-item.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/date-time.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/enhanced-list.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/expand-bar.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/fill-layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/font-combo.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/form-layout-data.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/form-layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/frame.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/grid-layout-data.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/grid-layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/group.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/hyperlink.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/label.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/layout-data.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/list.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/menu.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/panel-viewer.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/panel.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/progress.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/row-layout-data.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/row-layout.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/sash-form.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/sash.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/scrollable-component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/simple-table.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/simple-tree-table.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/slider.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/spinner.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/stack-viewer.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/styled-text.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tab-panel.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/table-component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/table.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/text.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tool-bar.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tool-item.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tray-item.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tree-component.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/tree.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/value-holder.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/view-container.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/window.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/wizard.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/de22.date-picker.builder.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/de22.picture-viewer.builder.jar"),
// new File("C:/Data/workspace-iwc2/Pman/controls/de22.opengl.builder.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/novocode.custom-separator.builder.jar"),
new File("C:/Data/workspace-iwc2/Pman/controls/novocode.hyperlink.builder.jar")
};
// RuntimeMangler mangler = new RuntimeMangler(new File[] {new File("c:/data/workspace-test/Test/controls/Builder.jar")}, new LiteList(new String[] {"com/foundation/view/swt/builder", "com/foundation/tcv/swt/builder"}), new LiteList(new String[] {"com/de22", "com/common", "com/foundation", "com/declarativeengineering"}), null);
//
// jarFiles = new File[] {
// new File("C:/Data/workspace-test/Test/controls/abstract.jar"),
// new File("C:/Data/workspace-test/Test/controls/button.jar"),
// new File("C:/Data/workspace-test/Test/controls/card-layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-button.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-combo.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-component.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-container.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-date-time.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-panel.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-progress.jar"),
// new File("C:/Data/workspace-test/Test/controls/cell-text.jar"),
// new File("C:/Data/workspace-test/Test/controls/collection-component.jar"),
// new File("C:/Data/workspace-test/Test/controls/combo.jar"),
// new File("C:/Data/workspace-test/Test/controls/component.jar"),
// new File("C:/Data/workspace-test/Test/controls/container.jar"),
// new File("C:/Data/workspace-test/Test/controls/cool-bar.jar"),
// new File("C:/Data/workspace-test/Test/controls/cool-item.jar"),
// new File("C:/Data/workspace-test/Test/controls/date-time.jar"),
// new File("C:/Data/workspace-test/Test/controls/enhanced-list.jar"),
// new File("C:/Data/workspace-test/Test/controls/expand-bar.jar"),
// new File("C:/Data/workspace-test/Test/controls/fill-layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/font-combo.jar"),
// new File("C:/Data/workspace-test/Test/controls/form-layout-data.jar"),
// new File("C:/Data/workspace-test/Test/controls/form-layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/frame.jar"),
// new File("C:/Data/workspace-test/Test/controls/grid-layout-data.jar"),
// new File("C:/Data/workspace-test/Test/controls/grid-layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/group.jar"),
// new File("C:/Data/workspace-test/Test/controls/hyperlink.jar"),
// new File("C:/Data/workspace-test/Test/controls/label.jar"),
// new File("C:/Data/workspace-test/Test/controls/layout-data.jar"),
// new File("C:/Data/workspace-test/Test/controls/layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/list.jar"),
// new File("C:/Data/workspace-test/Test/controls/menu.jar"),
// new File("C:/Data/workspace-test/Test/controls/panel-viewer.jar"),
// new File("C:/Data/workspace-test/Test/controls/panel.jar"),
// new File("C:/Data/workspace-test/Test/controls/progress.jar"),
// new File("C:/Data/workspace-test/Test/controls/row-layout-data.jar"),
// new File("C:/Data/workspace-test/Test/controls/row-layout.jar"),
// new File("C:/Data/workspace-test/Test/controls/sash-form.jar"),
// new File("C:/Data/workspace-test/Test/controls/sash.jar"),
// new File("C:/Data/workspace-test/Test/controls/scrollable-component.jar"),
// new File("C:/Data/workspace-test/Test/controls/simple-table.jar"),
// new File("C:/Data/workspace-test/Test/controls/simple-tree-table.jar"),
// new File("C:/Data/workspace-test/Test/controls/slider.jar"),
// new File("C:/Data/workspace-test/Test/controls/spinner.jar"),
// new File("C:/Data/workspace-test/Test/controls/stack-viewer.jar"),
// new File("C:/Data/workspace-test/Test/controls/styled-text.jar"),
// new File("C:/Data/workspace-test/Test/controls/tab-panel.jar"),
// new File("C:/Data/workspace-test/Test/controls/table-component.jar"),
// new File("C:/Data/workspace-test/Test/controls/table.jar"),
// new File("C:/Data/workspace-test/Test/controls/text.jar"),
// new File("C:/Data/workspace-test/Test/controls/tool-bar.jar"),
// new File("C:/Data/workspace-test/Test/controls/tool-item.jar"),
// new File("C:/Data/workspace-test/Test/controls/tray-item.jar"),
// new File("C:/Data/workspace-test/Test/controls/tree-component.jar"),
// new File("C:/Data/workspace-test/Test/controls/tree.jar"),
// new File("C:/Data/workspace-test/Test/controls/value-holder.jar"),
// new File("C:/Data/workspace-test/Test/controls/view-container.jar"),
// new File("C:/Data/workspace-test/Test/controls/window.jar"),
// new File("C:/Data/workspace-test/Test/controls/wizard.jar"),
// new File("C:/Data/workspace-test/Test/controls/de22.color-picker.builder.jar"),
// new File("C:/Data/workspace-test/Test/controls/de22.date-picker.builder.jar"),
// new File("C:/Data/workspace-test/Test/controls/de22.picture-viewer.builder.jar"),
// new File("C:/Data/workspace-test/Test/controls/de22.resource-editor.builder.jar")
// };
try {
mangler.mangleJars(jarFiles, null);
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
}//main()//
/**
* RuntimeMangler constructor.
* @param codebaseJars The jar file references to any jars that are pre-mangled. This does not need to include jars that have never been mangled, and shouldn't include jars that might need mangling to work with the mangled code.
* @param excludedPackages The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match.
* @param includedPackages The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded.
* @param mangleMap The map that will be filled with unmangled qualified class names (com.test.ClassName$InnerClassName) indexed by the mangled name.
*/
public RuntimeMangler(File[] codebaseJars, IList excludedPackages, IList includedPackages, IHashMap mangleMap) {
super(excludedPackages, includedPackages, false);
this.mangleTypeMap = mangleMap;
//Iterate over the codebase jar file references and load the metadata for them. This should not include the JDK jars or any other unmangled jars. */
for(int index = 0; index < codebaseJars.length; index++) {
File next = codebaseJars[index];
JarFile jar = null;
try {
Enumeration iterator;
jar = new JarFile(next);
iterator = jar.entries();
while(iterator.hasMoreElements()) {
JarEntry entry = (JarEntry) iterator.nextElement();
if(entry.getName().endsWith(".class")) {
InputStream in = jar.getInputStream(entry);
try {
ObjectInputStream oin = new ObjectInputStream(in, null, null);
Type type = new Type();
TypeMetadata metadata;
type.readExternal(oin);
metadata = new TypeMetadata(type, true);
metadataMap.put(metadata.getName(), metadata);
}//try//
catch(Throwable e) {
Debug.log("Caught while reading the class: " + entry.getName(), e);
}//catch//
finally {
in.close();
}//finally//
}//if//
}//while//
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
finally {
if(jar != null) {try {jar.close();}catch(Throwable e) {}}
}//finally//
}//for//
}//RuntimeMangler()//
/**
* Provides runtime mangling of a jar's class files so they work against pre-mangled class files.
* <p>This routine doesn't perform any mangling of code that is already mangled, it just updates the class files in the jar to reference the mangled class, attribute, and method names in the already mangled code base.</p>
* <p>The method outputs a .zjar file for each .jar input - placed in the same directory as the .jar input.</p>
* @param jarFiles All the jar files that may need mangling.
* @param algorithm The optional algorithm for encrypting the resulting class files inside the zjar output.
*/
public void mangleJars(File[] jarFiles, ISymmetricAlgorithm algorithm) throws ClassNotFoundException, IOException {
LiteList modifiedTypeMetadata = new LiteList(100, 1000);
LiteList[] typeMetadataCollections = new LiteList[jarFiles.length];
//First collect metadata.//
for(int index = 0; index < jarFiles.length; index++) {
File next = jarFiles[index];
JarFile jar = null;
try {
Enumeration iterator;
jar = new JarFile(next);
iterator = jar.entries();
typeMetadataCollections[index] = new LiteList(jar.size(), 20);
while(iterator.hasMoreElements()) {
JarEntry entry = (JarEntry) iterator.nextElement();
if(entry.getName().endsWith(".class")) {
InputStream in = jar.getInputStream(entry);
try {
ObjectInputStream oin = new ObjectInputStream(in, null, null);
Type type = new Type();
TypeMetadata metadata;
type.readExternal(oin);
metadata = new TypeMetadata(type, false);
metadataMap.put(metadata.getName(), metadata);
modifiedTypeMetadata.add(metadata);
typeMetadataCollections[index].add(metadata);
}//try//
catch(Throwable e) {
Debug.log("Caught while post-mangle processing the class: " + entry.getName(), e);
}//catch//
finally {
in.close();
}//finally//
}//if//
}//while//
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
finally {
if(jar != null) {try {jar.close();}catch(Throwable e) {}}
}//finally//
}//for//
//Mangle the metadata.//
for(int typeIndex = 0; typeIndex < modifiedTypeMetadata.getSize(); typeIndex++) {
TypeMetadata nextType = (TypeMetadata) modifiedTypeMetadata.get(typeIndex);
ConstantCollection constantCollection = nextType.getConstantCollection();
Type type = nextType.getType();
LiteList nameConstants = new LiteList(constantCollection.getConstantMetadata().getSize());
LiteHashSet superTypeSet = new LiteHashSet(30, LiteHashSet.DEFAULT_LOAD_FACTOR, Comparator.getLogicalComparator(), LiteHashSet.STYLE_NO_DUPLICATES);
int constantsSize = constantCollection.getConstantMetadata().getSize();
//Collect all the super classes and interfaces. Will be used later when testing whether to mangle methods and fields.//
collectSuperTypes(type, superTypeSet);
//Setup the back references between the constant and the metadata that references it.//
constantCollection.initializeConstantReferences();
//Iterate over each constant looking for UTF8 constants, determine the type, and add to the correct collection for later processing.//
for(int constantIndex = 0; constantIndex < constantsSize; constantIndex++) {
ConstantMetadata next = (ConstantMetadata) constantCollection.getConstantMetadata().get(constantIndex);
if(next instanceof Utf8ConstantMetadata) {
Utf8ConstantMetadata constant = (Utf8ConstantMetadata) next;
IList referencingMetadata = constant.getReferencingMetadata();
int constantType = UTF8_CONSTANT_TYPE_TEXT;
//Determine the format for the UTF8 based on what is referencing it.//
for(int referenceIndex = 0; referenceIndex < referencingMetadata.getSize(); referenceIndex++) {
Metadata nextReference = (Metadata) referencingMetadata.get(referenceIndex);
if((nextReference instanceof TypeConstantMetadata) ||
((nextReference instanceof NameAndTypeConstantMetadata) && (((NameAndTypeConstantMetadata) nextReference).getReferencingMetadata().getSize() > 0) && (((NameAndTypeConstantMetadata) nextReference).getReferencingMetadata().getFirst() instanceof FieldRefConstantMetadata) && (((NameAndTypeConstantMetadata) nextReference).descriptor == constant)) ||
((nextReference instanceof FieldMetadata) && (((FieldMetadata) nextReference).descriptor == constant))) {
if(constantType != UTF8_CONSTANT_TYPE_TEXT && constantType != UTF8_CONSTANT_TYPE_TYPE) {
Debug.log(new RuntimeException("Invalid constant type state: " + constantType + " Expecting text or type. Caught while processing: " + nextType.getName()));
}//if//
constantType = UTF8_CONSTANT_TYPE_TYPE;
}//if//
else if(nextReference instanceof InnerClassesMetadata) {
int innerClassIndex = ((InnerClassesMetadata) nextReference).getInnerClassIndex(constant);
if(innerClassIndex == -1) {
//Do nothing.. the inner class metadata references the UTF8 because it is the code attribute's name.//
}//if//
else {
//For some odd reason the class file declares InnerClasses, referencing the fully qualified inner class name, fully qualified outer class name, and the unqualified inner class name.//
//Here we are mangling the unqualified inner class name which would not otherwise be identified as a class name.//
if(matches(((InnerClassesMetadata) nextReference).innerClassInfos[innerClassIndex].originalValue)) {
Utf8ConstantMetadata nameConstant = new Utf8ConstantMetadata(type, mangleClassName(constant));
constantCollection.addConstant(nameConstant);
((InnerClassesMetadata) nextReference).innerClassNames[innerClassIndex] = nameConstant;
}//if//
}//else//
}//else if//
else if(((nextReference instanceof NameAndTypeConstantMetadata) && (((NameAndTypeConstantMetadata) nextReference).name == constant)) ||
((nextReference instanceof MethodMetadata) && (((MethodMetadata) nextReference).name == constant)) ||
((nextReference instanceof FieldMetadata) && (((FieldMetadata) nextReference).name == constant))) {
if(constantType != UTF8_CONSTANT_TYPE_TEXT && constantType != UTF8_CONSTANT_TYPE_NAME) {
Debug.log(new RuntimeException("Invalid constant type state: " + constantType + " Expecting text or name. Caught while processing: " + nextType.getName()));
}//if//
constantType = UTF8_CONSTANT_TYPE_NAME;
}//else if//
else if(((nextReference instanceof NameAndTypeConstantMetadata) && (((NameAndTypeConstantMetadata) nextReference).getReferencingMetadata().getSize() > 0) && (!(((NameAndTypeConstantMetadata) nextReference).getReferencingMetadata().getFirst() instanceof FieldRefConstantMetadata)) && (((NameAndTypeConstantMetadata) nextReference).descriptor == constant)) ||
((nextReference instanceof MethodMetadata) && (((MethodMetadata) nextReference).descriptor == constant))) {
if(constantType != UTF8_CONSTANT_TYPE_TEXT && constantType != UTF8_CONSTANT_TYPE_DESCRIPTOR) {
Debug.log(new RuntimeException("Invalid constant type state: " + constantType + " Expecting text or descriptor. Caught while processing: " + nextType.getName()));
}//if//
constantType = UTF8_CONSTANT_TYPE_DESCRIPTOR;
}//else if//
}//for//
//Based on the text's type, perform the correct mangling as required.//
switch(constantType) {
case UTF8_CONSTANT_TYPE_TEXT: {
//Mangle the text if it conforms to a dot separated class name and matches the packages to be mangled.//
constant.value = mangleText(constant);
break;
}//case//
case UTF8_CONSTANT_TYPE_TYPE: {
//Mangle the class name if it matches the packages to be mangled.//
constant.value = mangleClassName(constant);
break;
}//case//
case UTF8_CONSTANT_TYPE_NAME: {
//Delay the processing of the name constants so that the types and signatures are all properly mangled.//
nameConstants.add(constant);
break;
}//case//
case UTF8_CONSTANT_TYPE_DESCRIPTOR: {
//Mangle the descriptor as needed based on whether the types in the descriptor match the packages to be mangled.//
constant.value = mangleSignature(type, constant);
break;
}//case//
}//switch//
}//if//
}//for//
//Process the name constants last so that the signatures and types are all mangled as necessary.//
for(int index = 0; index < nameConstants.getSize(); index++) {
Utf8ConstantMetadata constant = (Utf8ConstantMetadata) nameConstants.get(index);
IList referencingMetadata = constant.getReferencingMetadata();
//Ignore constructor or class constructor method names.//
if(!(constant.value.equals("<init>") || constant.value.equals("<clinit>"))) {
//Modify the name & type, method, and field references to point to the new constant(s) as needed. Don't modify the current constant.
for(int referenceIndex = 0; referenceIndex < referencingMetadata.getSize(); referenceIndex++) {
Metadata nextReference = (Metadata) referencingMetadata.get(referenceIndex);
if(nextReference instanceof NameAndTypeConstantMetadata) {
NameAndTypeConstantMetadata nameAndType = (NameAndTypeConstantMetadata) nextReference;
//For each referencing field or method ref.//
for(int nameAndTypeReferenceIndex = 0; nameAndTypeReferenceIndex < nameAndType.getReferencingMetadata().getSize(); nameAndTypeReferenceIndex++) {
Metadata nameAndTypeReference = (Metadata) nameAndType.getReferencingMetadata().get(nameAndTypeReferenceIndex);
TypeConstantMetadata declaringType = null;
boolean isField = false;
if(nameAndTypeReference instanceof FieldRefConstantMetadata) {
declaringType = ((FieldRefConstantMetadata) nameAndTypeReference).type;
isField = true;
}//if//
else if(nameAndTypeReference instanceof MethodRefConstantMetadata) {
declaringType = ((MethodRefConstantMetadata) nameAndTypeReference).type;
}//else if//
else if(nameAndTypeReference instanceof InterfaceMethodRefConstantMetadata) {
declaringType = ((InterfaceMethodRefConstantMetadata) nameAndTypeReference).type;
}//else if//
else {
throw new RuntimeException("Unexpected reference to a name and type constant: " + nameAndTypeReference.getClass().getName());
}//else//
if(isField) {
String mangledName = mangleFieldName(constant.value);
//Determine if the field name should be mangled based on whether the first accessable field in the class inheritance chain from the declaring type is mangled or not (or none was found in which case don't mangle).//
if(shouldMangleField(constant.value, mangledName, declaringType.name.value, constantCollection.getThisType().type.name.value, superTypeSet)) {
Utf8ConstantMetadata nameConstant = new Utf8ConstantMetadata(type, mangledName);
NameAndTypeConstantMetadata nameAndTypeConstant = new NameAndTypeConstantMetadata(type, nameConstant, nameAndType.descriptor);
createMapping(constant.value, mangledName, TYPE_FIELD);
constantCollection.addConstant(nameConstant);
constantCollection.addConstant(nameAndTypeConstant);
((FieldRefConstantMetadata) nameAndTypeReference).nameAndType = nameAndTypeConstant;
}//if//
}//if//
else {
String mangledName = mangleMethodName(constant.value);
//Determine if the method name should be mangled based on whether there is a mangled method with the correct signature in any of the pre-mangled code in the defining class's hierarchy.//
if(shouldMangleMethod(mangledName, ((NameAndTypeConstantMetadata) nextReference).descriptor.value, declaringType.name.value, constantCollection.getThisType().type.name.value, superTypeSet)) {
Utf8ConstantMetadata nameConstant = new Utf8ConstantMetadata(type, mangledName);
NameAndTypeConstantMetadata nameAndTypeConstant = new NameAndTypeConstantMetadata(type, nameConstant, nameAndType.descriptor);
createMapping(constant.value, mangledName, TYPE_METHOD);
constantCollection.addConstant(nameConstant);
constantCollection.addConstant(nameAndTypeConstant);
if(nameAndTypeReference instanceof MethodRefConstantMetadata) {
((MethodRefConstantMetadata) nameAndTypeReference).nameAndType = nameAndTypeConstant;
}//else if//
else {
((InterfaceMethodRefConstantMetadata) nameAndTypeReference).nameAndType = nameAndTypeConstant;
}//else//
}//if//
}//else//
}//for//
}//if//
else if(nextReference instanceof MethodMetadata) {
MethodMetadata method = (MethodMetadata) nextReference;
String mangledName = mangleMethodName(constant.value);
//Determine if any class or interface in the pre-mangled parts (classes and interfaces loaded in the constructor) of this type's hierarchy have a method with the correct signature and the mangled name.//
if(shouldMangleMethod(mangledName, method.descriptor.value, constantCollection.getThisType().type.name.value, constantCollection.getThisType().type.name.value, superTypeSet)) {
Utf8ConstantMetadata nameConstant = new Utf8ConstantMetadata(type, mangledName);
createMapping(constant.value, mangledName, TYPE_METHOD);
constantCollection.addConstant(nameConstant);
method.name = nameConstant;
}//if//
}//else if//
//else if(nextReference instanceof FieldMetadata) {
//FieldMetadata field = (FieldMetadata) nextReference;
//DON"T MANGLE THIS - The field is declared in this class, otherwise it would be a FieldRef. This class shouldn't mangle the field.
//TODO: Determine if any class in the post-mangled parts (classes loaded in this method) of this type's hierarchy have the unmangled name.
//Determine if any class in the pre-mangled parts (classes loaded in the constructor) of this type's hierarchy have the mangled name.
//If no mangled or unmangled field found then leave it unmangled.
//}//else if//
}//for//
}//if//
}//for//
//Apply the changes to the constants, fields, methods, interfaces, super, and this references.//
constantCollection.applyConstants();
}//for//
//Write the mangled data into new jars.//
for(int index = 0; index < jarFiles.length; index++) {
LiteList typeMetadata = typeMetadataCollections[index];
//Ignore any jars that contain no class files.//
if(typeMetadata.getSize() > 0) {
File nextFile = jarFiles[index];
String nextPath = nextFile.getCanonicalPath();
File modifiedNext = new File(nextPath.substring(0, nextPath.length() - 3) + "zjar");
FileOutputStream fout = null;
try {
JarOutputStream jout;
fout = new FileOutputStream(modifiedNext);
jout = new JarOutputStream(fout);
if(algorithm != null) {
ByteArrayOutputStream bout = new ByteArrayOutputStream(10000, true);
jout.setLevel(0);
for(int typeIndex = 0; typeIndex < typeMetadata.getSize(); typeIndex++) {
TypeMetadata next = (TypeMetadata) typeMetadata.get(typeIndex);
JarEntry entry = new JarEntry(next.getName() + ".class");
SymmetricOutputStream sout = new SymmetricOutputStream(bout, algorithm);
ZipOutputStream zout = new ZipOutputStream(sout);
ObjectOutputStream oout = new ObjectOutputStream(zout, null);
jout.putNextEntry(entry);
next.getType().writeExternal(oout);
oout.flush();
zout.finish();
zout.flush();
sout.flush();
jout.write(bout.getBuffer(), 0, bout.getSize());
bout.reset();
jout.closeEntry();
}//for//
}//if//
else {
ObjectOutputStream oout;
oout = new ObjectOutputStream(jout, null);
jout.setLevel(9);
for(int typeIndex = 0; typeIndex < typeMetadata.getSize(); typeIndex++) {
TypeMetadata next = (TypeMetadata) typeMetadata.get(typeIndex);
JarEntry entry = new JarEntry(next.getName() + ".class");
jout.putNextEntry(entry);
next.getType().writeExternal(oout);
jout.closeEntry();
}//for//
}//else//
jout.close();
fout = null;
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
finally {
if(fout != null) {try {fout.close();}catch(Throwable e) {}}
}//finally//
}//if//
}//for//
/*
//Debug Output.//
IIterator iterator = mangleTypeMap.keyIterator();
File output = new File(jarFiles[0].getParent(), "output.txt");
StringBuffer buffer = new StringBuffer(10000);
while(iterator.hasNext()) {
String mangledName = (String) iterator.next();
String name = (String) mangleTypeMap.get(mangledName);
buffer.append(mangledName);
buffer.append(' ');
buffer.append(name);
buffer.append('\r');
buffer.append('\n');
}
StreamSupport.writeText(buffer.toString(), output, "UTF8");
*/
}//mangleJars()//
/* (non-Javadoc)
* @see com.de22.obfuscation.BaseMangler#createMapping(java.lang.String, java.lang.String, int)
*/
protected void createMapping(String name, String mangledName, int type) {
if(mangleTypeMap != null) {
mangleTypeMap.put(mangledName, name);
}//if//
}//createMapping()//
/**
* Recursively collects the super class and interface names (class file format: com/test/TestClass$Inner) for a given type (includes the given type).
* @param type The type to start with.
* @param set The set of type names found.
*/
private void collectSuperTypes(Type type, IHashSet set) {
String typeName = getConstantUtf8(type, type.getConstant(type.getThisReference())).getValue();
if(!set.containsValue(typeName)) {
String parentTypeName = getConstantUtf8(type, type.getConstant(type.getParentReference())).getValue();
TypeMetadata parentTypeMetadata = (TypeMetadata) metadataMap.get(parentTypeName);
set.add(typeName);
for(int interfaceIndex = 1; interfaceIndex <= type.getInterfaceCount(); interfaceIndex++) {
String interfaceTypeName = getConstantUtf8(type, type.getConstant(type.getInterface((short) interfaceIndex).getClassIndex())).getValue();
TypeMetadata interfaceTypeMetadata = (TypeMetadata) metadataMap.get(interfaceTypeName);
if(interfaceTypeMetadata != null) {
collectSuperTypes(interfaceTypeMetadata.getType(), set);
}//if//
}//for//
if(parentTypeMetadata != null) {
collectSuperTypes(parentTypeMetadata.getType(), set);
}//if//
}//if//
}//collectSuperTypes()//
/**
* Determines whether the field name should be mangled.
* Searches the class (no interfaces) hierarchy for the first visible declaration of the field with either the mangled or non-mangled name.
* @param fieldName The unmangled name for the field.
* @param mangledFieldName The mangled name for the field.
* @param typeName The class to use as a starting point for the field declaration search.
* @param referencingClassName The name of the class (com/test/ClassName$Inner) referencing the field, used to ensure visibility of the located field.
* @param referencingClassHierarchy The set of all classes in the referencing class's hierarchy.
* @return Whether the field name should be mangled.
*/
private boolean shouldMangleField(String fieldName, String mangledFieldName, String typeName, String referencingClassName, ISet referencingClassHierarchy) {
Boolean result = null;
if(fieldName.indexOf('$') == -1) {
int searchableClassNamesIndex = 0;
LiteList searchableClassNames = new LiteList(100, 1000);
LiteHashSet searchedClassNames = new LiteHashSet(100, LiteHashSet.DEFAULT_LOAD_FACTOR, Comparator.getLogicalComparator(), LiteHashSet.STYLE_NO_DUPLICATES);
String referencingClassPackage = referencingClassName.lastIndexOf('/') != -1 ? referencingClassName.substring(0, referencingClassName.lastIndexOf('/')) : "";
searchableClassNames.add(typeName);
//Note: We are using the searchableClassNames list to avoid a recursive method.//
//Search for the mangled and unmangled field name in the hierarchy using a breadth first search of parent classes and interfaces. Ignore any not found in the metadataMap.//
while(searchableClassNames.getSize() > searchableClassNamesIndex && result == null) {
String nextTypeName = (String) searchableClassNames.get(searchableClassNamesIndex++);
TypeMetadata next = (TypeMetadata) metadataMap.get(nextTypeName);
searchedClassNames.add(nextTypeName);
//The type metadata would be null if the type is not one of the pre-mangled or post-mangled classes (all we have access to here). For example java.lang.Object would not be included.//
if(next != null) {
Type type = next.getType();
ConstantUtf8 parentNameConstant = getConstantUtf8(type, type.getConstant(type.getParentReference()));
//Search each of the class/interface fields (interfaces can have static fields which must be searched).//
for(int index = 1; index <= next.getType().getFieldCount(); index++) {
Field field = next.getType().getField((short) index);
ConstantUtf8 fieldNameConstant = getConstantUtf8(next.getType(), next.getType().getConstant(field.getFieldNameIndex()));
if(fieldNameConstant != null) {
//Check the field's name first.//
if(fieldNameConstant.getValue().equals(fieldName) || fieldNameConstant.getValue().equals(mangledFieldName)) {
int modifiers = field.getAccessFlags() & 0xFFFF;
String fieldClass = next.getName();
String fieldClassPackage = fieldClass.lastIndexOf('/') != -1 ? fieldClass.substring(0, fieldClass.lastIndexOf('/')) : "";
String outerFieldClass = fieldClass.indexOf('$') == -1 ? fieldClass : fieldClass.substring(0, fieldClass.indexOf('$'));
String outerReferencingClass = referencingClassName.indexOf('$') == -1 ? referencingClassName : referencingClassName.substring(0, referencingClassName.indexOf('$'));
//Figure out if the field is public, or package/protected and in the same package as the referencing class, or protected and the field's class is a super class or interface of the field's class.//
if(Modifier.isPublic(modifiers) || (!Modifier.isPrivate(modifiers) && Comparator.equals(referencingClassPackage, fieldClassPackage)) || (Modifier.isProtected(modifiers) && referencingClassHierarchy.containsValue(fieldClass)) || (Modifier.isPrivate(modifiers) && Comparator.equals(outerFieldClass, outerReferencingClass))) {
result = fieldNameConstant.getValue().equals(mangledFieldName) ? Boolean.TRUE : Boolean.FALSE;
}//if//
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//for//
//If the field was not found then add the super interfaces and class to the list to be processed.//
if(result == null) {
for(int index = 1; index <= type.getInterfaceCount(); index++) {
ConstantUtf8 nextInterfaceConstant = getConstantUtf8(type, type.getConstant(type.getInterface((short) index).getClassIndex()));
if(nextInterfaceConstant != null) {
if(!searchedClassNames.containsValue(nextInterfaceConstant.getValue())) {
searchableClassNames.add(nextInterfaceConstant.getValue());
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//for//
if(parentNameConstant != null) {
if(!searchedClassNames.containsValue(parentNameConstant.getValue())) {
searchableClassNames.add(parentNameConstant.getValue());
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//if//
}//if//
}//while//
}//if//
return result == null ? false : result.booleanValue();
}//shouldMangleField()//
/**
* Determines whether the method name should be mangled.
* Searches through the pre-mangled code for a method with the mangled name and signature. If found, the method must be mangled, otherwise it is not.
* @param mangledMethodName The mangled name for the method.
* @param methodSignature The mangled signature for the method.
* @param typeName The class or interface to use as a starting point for the method declaration search.
* @param referencingClassName The name of the class (com/test/ClassName$Inner) referencing the method, used to ensure visibility of the located method.
* @param referencingClassHierarchy The set of all classes in the referencing class's hierarchy.
* @return Whether the field name should be mangled.
*/
private boolean shouldMangleMethod(String mangledMethodName, String methodSignature, String typeName, String referencingClassName, ISet referencingClassHierarchy) {
boolean result = false;
int searchableClassNamesIndex = 0;
LiteList searchableClassNames = new LiteList(100, 1000);
LiteHashSet searchedClassNames = new LiteHashSet(100, LiteHashSet.DEFAULT_LOAD_FACTOR, Comparator.getLogicalComparator(), LiteHashSet.STYLE_NO_DUPLICATES);
String referencingClassPackage = referencingClassName.lastIndexOf('/') != -1 ? referencingClassName.substring(0, referencingClassName.lastIndexOf('/')) : "";
searchableClassNames.add(typeName);
//Note: We are using the searchableClassNames list to avoid a recursive method.//
//Search for the mangled method name in the hierarchy using a breadth first search of parent classes and interfaces. Ignore any not found in the metadataMap.//
while(searchableClassNames.getSize() > searchableClassNamesIndex && !result) {
String nextTypeName = (String) searchableClassNames.get(searchableClassNamesIndex++);
TypeMetadata next = (TypeMetadata) metadataMap.get(nextTypeName);
searchedClassNames.add(nextTypeName);
//The type metadata would be null if the type is not one of the pre-mangled or post-mangled classes (all we have access to here). For example java.lang.Object would not be included.//
if(next != null) {
Type type = next.getType();
ConstantUtf8 parentNameConstant = getConstantUtf8(type, type.getConstant(type.getParentReference()));
if(matches(nextTypeName.replace('/', '.')) || isMangled(nextTypeName)) {
for(int index = 1; !result && index <= type.getMethodCount(); index++) {
Method method = type.getMethod((short) index);
ConstantUtf8 methodNameConstant = getConstantUtf8(type, type.getConstant(method.getNameIndex()));
ConstantUtf8 methodDescriptorConstant = getConstantUtf8(type, type.getConstant(method.getDescriptorIndex()));
if(methodNameConstant != null && methodDescriptorConstant != null) {
if(Comparator.equals(methodNameConstant.getValue(), mangledMethodName) && Comparator.equals(methodDescriptorConstant.getValue(), methodSignature)) {
int modifiers = method.getAccessFlags() & 0xFFFF;
String methodClass = next.getName();
String methodClassPackage = methodClass.lastIndexOf('/') != -1 ? methodClass.substring(0, methodClass.lastIndexOf('/')) : "";
String outerMethodClass = methodClass.indexOf('$') == -1 ? methodClass : methodClass.substring(0, methodClass.indexOf('$'));
String outerReferencingClass = referencingClassName.indexOf('$') == -1 ? referencingClassName : referencingClassName.substring(0, referencingClassName.indexOf('$'));
//Figure out if the method is public, or package/protected and in the same package as the referencing class, or protected and the method's class is a super class or interface of the field's class.//
if(Modifier.isPublic(modifiers) || (!Modifier.isPrivate(modifiers) && Comparator.equals(referencingClassPackage, methodClassPackage)) || (Modifier.isProtected(modifiers) && referencingClassHierarchy.containsValue(methodClass)) || (Modifier.isPrivate(modifiers) && Comparator.equals(outerMethodClass, outerReferencingClass))) {
result = true;
}//if//
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//for//
}//if//
//If the method was not found then add the super interfaces and class to the list for processing.//
if(!result) {
for(int index = 1; index <= type.getInterfaceCount(); index++) {
ConstantUtf8 nextInterfaceConstant = getConstantUtf8(type, type.getConstant(type.getInterface((short) index).getClassIndex()));
if(nextInterfaceConstant != null) {
String name = nextInterfaceConstant.getValue();
if(matches(name)) {
String mangledName = mangleClassName(name);
createMapping(name, mangledName, TYPE_CLASS);
name = mangledName;
}//if//
if(!searchedClassNames.containsValue(name)) {
searchableClassNames.add(name);
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//for//
if(parentNameConstant != null) {
String name = parentNameConstant.getValue();
if(matches(name)) {
String mangledName = mangleClassName(name);
createMapping(name, mangledName, TYPE_CLASS);
name = mangledName;
}//if//
if(!searchedClassNames.containsValue(name)) {
searchableClassNames.add(name);
}//if//
}//if//
else {
Debug.log(new RuntimeException());
}//else//
}//if//
}//if//
}//while//
return result;
}//shouldMangleMethod()//
/**
* De-mangles the given source code.
* <p>Thread Safe</p>
* @param source The source code containing fully qualified mangled class references.
* @param mangleMap The optional mapping of mangled name to unmangled names.
* @return The de-mangled source code.
*/
public static String demangleSource(String source, IHashMap mangleMap) {
StringBuffer buffer = new StringBuffer(source);
IIterator iterator = mangleMap.keyIterator();
//Iterate over each mangled/unmangled name pairing.//
while(iterator.hasNext()) {
String mangledName = (String) iterator.next();
String name = (String) mangleMap.get(mangledName);
int startIndex = buffer.indexOf(mangledName);
name = name.replace('/', '.');
//Iterate over each reference to the mangled name and replace it.//
while(startIndex != -1) {
buffer.replace(startIndex, mangledName.length() + startIndex, name);
startIndex = buffer.indexOf(mangledName, startIndex + name.length());
}//while//
}//while//
return buffer.toString();
}//demangleSource()//
/**
* Determines whether the given class name is a mangled name. If the name is an inner class then just the inner class is tested.
* @param name The name to test.
* @return Whether the name has been mangled.
*/
protected boolean isMangled(String name) {
return MangleSupport.isMangled(name);
}//isMangled()//
}//Mangler//

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation.test;
public class Base {
public String text = "";
public void doSomething() {
}
}

View File

@@ -0,0 +1,12 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation.test;
public interface ITest {
public ITest getTest(Base base);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation.test;
public class Test extends Base implements ITest {
private static final String IDENTIFIER = "abc";
private static final String IDENTIFIER2 = "abc".replace('a', 'b');
private static final String IDENTIFIER3;
static {
IDENTIFIER3 = "abc";
}//static//
private String text = "Hello";
public class MyInnerClass {
public boolean equals(Object value) {
return true;
}
public String getText() {
String result = "a";
result += "b";
return result;
}
}
/**
* @param args
*/
public static void main(String[] args) {
new Test().doSomething();
new Base().doSomething();
}
public Test() {
((Base) this).text = "2";
text = "Hello";
}
public void doSomething() {
System.out.println(((Base) this).text);
System.out.println(text);
System.out.println("text");
System.out.println("doSomething");
System.out.println(IDENTIFIER);
Test.class.getName();
}
public boolean equals(Object value) {
return false;
}
public ITest getTest(Base base) {
return (ITest) base;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation.test2;
import com.common.util.LiteList;
public class Main {
public static class Inner1 {
public static class Inner1_1 {
private String x = "x";
}
}
public class Inner2 {
}
/**
* @param args
*/
public static void main(String[] args) {
LiteList result = new LiteList(10, 20);
result.add(Inner1.class);
result.add(Inner1.Inner1_1.class);
result.add(Inner2.class);
result.add(Peer1.class);
result.add(Peer1.PeerInner.class);
for(int index = 0; index < result.getSize(); index++) {
Class d = ((Class) result.get(index)).getDeclaringClass();
Class e = ((Class) result.get(index)).getEnclosingClass();
System.out.println("" + index + " Declaring Class: " + (d == null ? "null" : d.getName()) + " Enclosing Class: " + (e == null ? "null" : e.getName()));
}
}
}
class Peer1 {
private String x = "x";
public class PeerInner {
}
}