lots of bugs fixed

git-svn-id: https://svn.code.sf.net/p/jode/code/branches/stable@1052 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 25 years ago
parent 4ae713d9a6
commit 20d93c44fe
  1. 6
      jode/jode/obfuscator/ClassBundle.java
  2. 164
      jode/jode/obfuscator/ClassIdentifier.java
  3. 16
      jode/jode/obfuscator/ConstantAnalyzer.java
  4. 2
      jode/jode/obfuscator/FieldIdentifier.java
  5. 5
      jode/jode/obfuscator/Identifier.java
  6. 2
      jode/jode/obfuscator/Main.java
  7. 19
      jode/jode/obfuscator/ModifierMatcher.java
  8. 106
      jode/jode/obfuscator/SimpleAnalyzer.java

@ -139,8 +139,10 @@ public class ClassBundle {
analyze(); analyze();
} }
public void analyzeIdentifier(Identifier i) { public void analyzeIdentifier(Identifier ident) {
toAnalyze.add(i); if (ident == null)
throw new NullPointerException();
toAnalyze.add(ident);
} }
public void analyze() { public void analyze() {

@ -40,6 +40,7 @@ import jode.util.Iterator;
import jode.util.List; import jode.util.List;
import jode.util.LinkedList; import jode.util.LinkedList;
import jode.util.Map; import jode.util.Map;
import jode.util.UnsupportedOperationException;
///#endif ///#endif
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -57,7 +58,6 @@ public class ClassIdentifier extends Identifier {
String superName; String superName;
String[] ifaceNames; String[] ifaceNames;
List identifiers;
List fieldIdents, methodIdents; List fieldIdents, methodIdents;
List knownSubClasses = new LinkedList(); List knownSubClasses = new LinkedList();
List virtualReachables = new LinkedList(); List virtualReachables = new LinkedList();
@ -82,6 +82,7 @@ public class ClassIdentifier extends Identifier {
String fullName = getFullName() + "."; String fullName = getFullName() + ".";
for (Iterator i = getChilds(); i.hasNext(); ) { for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next(); Identifier ident = (Identifier) i.next();
System.err.println("checking "+ident);
if (wildcard.matches(fullName + ident.getName()) if (wildcard.matches(fullName + ident.getName())
|| wildcard.matches(fullName + ident.getName() || wildcard.matches(fullName + ident.getName()
+ "." +ident.getType())) { + "." +ident.getType())) {
@ -94,8 +95,24 @@ public class ClassIdentifier extends Identifier {
} }
} }
public void preserveIdentifier(String name, String typeSig) { private FieldIdentifier findField(String name, String typeSig) {
preserveMatchingIdentifier(new WildCard(name+"."+typeSig)); for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier) i.next();
if (ident.getName().equals(name)
&& ident.getType().equals(typeSig))
return ident;
}
return null;
}
private MethodIdentifier findMethod(String name, String typeSig) {
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
MethodIdentifier ident = (MethodIdentifier) i.next();
if (ident.getName().equals(name)
&& ident.getType().equals(typeSig))
return ident;
}
return null;
} }
public void reachableIdentifier(String name, String typeSig, public void reachableIdentifier(String name, String typeSig,
@ -109,6 +126,20 @@ public class ClassIdentifier extends Identifier {
found = true; found = true;
} }
} }
if (!found) {
// This means that the method is inherited from parent and
// must be marked as reachable there, (but not virtual).
// Consider following:
// A method in Collection and AbstractCollection is not reachable
// but it is reachable in Set and not implemented in AbstractSet
// In that case the method must be marked reachable in
// AbstractCollection.
ClassIdentifier superIdent = Main.getClassBundle()
.getClassIdentifier(info.getSuperclass().getName());
if (superIdent != null)
superIdent.reachableIdentifier(name, typeSig, false);
}
if (isVirtual) { if (isVirtual) {
for (Iterator i = knownSubClasses.iterator(); i.hasNext(); ) for (Iterator i = knownSubClasses.iterator(); i.hasNext(); )
((ClassIdentifier)i.next()) ((ClassIdentifier)i.next())
@ -117,13 +148,13 @@ public class ClassIdentifier extends Identifier {
} }
} }
public void chainIdentifier(Identifier chainIdent) { public void chainMethodIdentifier(Identifier chainIdent) {
String name = chainIdent.getName(); String name = chainIdent.getName();
String typeSig = chainIdent.getType(); String typeSig = chainIdent.getType();
for (Iterator i = getChilds(); i.hasNext(); ) { for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next(); Identifier ident = (Identifier) i.next();
if (ident.getName().equals(ident.getName()) if (ident.getName().equals(name)
&& (ident.getType().equals(typeSig))) && ident.getType().equals(typeSig))
chainIdent.addShadow(ident); chainIdent.addShadow(ident);
} }
} }
@ -246,33 +277,28 @@ public class ClassIdentifier extends Identifier {
* a compatible class. * a compatible class.
*/ */
public void preserveSerializable() { public void preserveSerializable() {
preserveIdentifier("writeObject", "(Ljava.io.ObjectOutputStream)V"); Identifier method
preserveIdentifier("readObject", "(Ljava.io.ObjectOutputStream)V"); = findMethod("writeObject", "(Ljava.io.ObjectOutputStream)V");
if (method != null)
method.setPreserved();
method = findMethod("readObject", "(Ljava.io.ObjectInputStream)V");
if (method != null)
method.setPreserved();
if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) { if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) {
setPreserved(); setPreserved();
boolean hasSerialUID = false; Identifier UIDident = findField("serialVersionUID", "J");
for (Iterator i = getFieldIdents().iterator(); i.hasNext(); ) { if (UIDident == null) {
Identifier ident = (Identifier) i.next();
if ("serialVersionUID".equals(ident.getName())
&& "J".equals(ident.getType())) {
ident.setReachable();
ident.setPreserved();
hasSerialUID = true;
break;
}
}
if (!hasSerialUID) {
/* add a field serializableVersionUID if not existent */ /* add a field serializableVersionUID if not existent */
long serialVersion = calcSerialVersionUID(); long serialVersion = calcSerialVersionUID();
FieldInfo UIDField = new FieldInfo FieldInfo UIDField = new FieldInfo
(info, "serialVersionUID", "J", (info, "serialVersionUID", "J",
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL); Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
UIDField.setConstant(new Long(serialVersion)); UIDField.setConstant(new Long(serialVersion));
FieldIdentifier fident = new FieldIdentifier(this, UIDField); UIDident = new FieldIdentifier(this, UIDField);
fident.setPreserved(); fieldIdents.add(UIDident);
fident.setReachable();
fieldIdents.add(fident);
} }
UIDident.setReachable();
UIDident.setPreserved();
for (Iterator i=getFieldIdents().iterator(); i.hasNext(); ) { for (Iterator i=getFieldIdents().iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier) i.next(); FieldIdentifier ident = (FieldIdentifier) i.next();
if ((ident.info.getModifiers() if ((ident.info.getModifiers()
@ -358,7 +384,7 @@ public class ClassIdentifier extends Identifier {
| Modifier.FINAL) & modif) == 0 | Modifier.FINAL) & modif) == 0
&& !(mid.getName().equals("<init>"))) { && !(mid.getName().equals("<init>"))) {
// chain the preserved/same name lists. // chain the preserved/same name lists.
chainIdentifier(mid); chainMethodIdentifier(mid);
} }
} }
} else { } else {
@ -371,8 +397,10 @@ public class ClassIdentifier extends Identifier {
if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL) if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
& modif) == 0 & modif) == 0
&& !topmethods[i].getName().equals("<init>")) { && !topmethods[i].getName().equals("<init>")) {
preserveIdentifier Identifier method = findMethod
(topmethods[i].getName(), topmethods[i].getType()); (topmethods[i].getName(), topmethods[i].getType());
if (method != null)
method.setPreserved();
} }
} }
} }
@ -393,10 +421,8 @@ public class ClassIdentifier extends Identifier {
Collections.shuffle(Arrays.asList(finfos), rand); Collections.shuffle(Arrays.asList(finfos), rand);
Collections.shuffle(Arrays.asList(minfos), rand); Collections.shuffle(Arrays.asList(minfos), rand);
} }
identifiers = new ArrayList(finfos.length + minfos.length); fieldIdents = new ArrayList(finfos.length);
fieldIdents = identifiers.subList(0, 0); methodIdents = new ArrayList(minfos.length);
methodIdents = identifiers.subList(0, 0);
identifiers = Collections.unmodifiableList(identifiers);
for (int i=0; i< finfos.length; i++) for (int i=0; i< finfos.length; i++)
fieldIdents.add(new FieldIdentifier(this, finfos[i])); fieldIdents.add(new FieldIdentifier(this, finfos[i]));
@ -665,36 +691,30 @@ public class ClassIdentifier extends Identifier {
transformSuperIfaces(); transformSuperIfaces();
transformInnerClasses(); transformInnerClasses();
int newFieldCount = 0, newMethodCount = 0; Collection newFields = new ArrayList(fieldIdents.size());
if ((Main.stripping & Main.STRIP_UNREACH) != 0) { Collection newMethods = new ArrayList(methodIdents.size());
for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (!ident.isReachable())
i.remove();
}
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (!ident.isReachable())
i.remove();
}
}
FieldInfo[] newFields = new FieldInfo[fieldIdents.size()];
MethodInfo[] newMethods = new MethodInfo[methodIdents.size()];
newFieldCount = newMethodCount = 0;
for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) { for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier)i.next(); FieldIdentifier ident = (FieldIdentifier)i.next();
ident.doTransformations(); if ((Main.stripping & Main.STRIP_UNREACH) == 0
newFields[newFieldCount++] = ident.info; || ident.isReachable()) {
ident.doTransformations();
newFields.add(ident.info);
}
} }
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
MethodIdentifier ident = (MethodIdentifier)i.next(); MethodIdentifier ident = (MethodIdentifier)i.next();
ident.doTransformations(); if ((Main.stripping & Main.STRIP_UNREACH) == 0
newMethods[newMethodCount++] = ident.info; || ident.isReachable()) {
ident.doTransformations();
newMethods.add(ident.info);
}
} }
info.setFields(newFields); info.setFields((FieldInfo[]) newFields.toArray
info.setMethods(newMethods); (new FieldInfo[newFields.size()]));
info.setMethods((MethodInfo[]) newMethods.toArray
(new MethodInfo[newMethods.size()]));
} }
public void storeClass(DataOutputStream out) throws IOException { public void storeClass(DataOutputStream out) throws IOException {
@ -702,7 +722,7 @@ public class ClassIdentifier extends Identifier {
GlobalOptions.err.println("Writing "+this); GlobalOptions.err.println("Writing "+this);
info.write(out); info.write(out);
info = null; info = null;
identifiers = null; fieldIdents = methodIdents = null;
} }
public Identifier getParent() { public Identifier getParent() {
@ -746,7 +766,28 @@ public class ClassIdentifier extends Identifier {
} }
public Iterator getChilds() { public Iterator getChilds() {
return identifiers.iterator(); final Iterator fieldIter = fieldIdents.iterator();
final Iterator methodIter = methodIdents.iterator();
return new Iterator() {
boolean fieldsNext = fieldIter.hasNext();
public boolean hasNext() {
return fieldsNext ? true : methodIter.hasNext();
}
public Object next() {
if (fieldsNext) {
Object result = fieldIter.next();
fieldsNext = fieldIter.hasNext();
return result;
}
return methodIter.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
} }
public String toString() { public String toString() {
@ -754,24 +795,13 @@ public class ClassIdentifier extends Identifier {
} }
public Identifier getIdentifier(String fieldName, String typeSig) { public Identifier getIdentifier(String fieldName, String typeSig) {
for (Iterator i = identifiers.iterator(); i.hasNext(); ) { for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next(); Identifier ident = (Identifier) i.next();
if (ident.getName().equals(fieldName) if (ident.getName().equals(fieldName)
&& ident.getType().startsWith(typeSig)) && ident.getType().startsWith(typeSig))
return ident; return ident;
} }
for (int i=0; i < ifaceNames.length; i++) {
ClassIdentifier ifaceident = Main.getClassBundle()
.getClassIdentifier(ifaceNames[i]);
if (ifaceident != null) {
Identifier ident
= ifaceident.getIdentifier(fieldName, typeSig);
if (ident != null)
return ident;
}
}
if (superName != null) { if (superName != null) {
ClassIdentifier superident = Main.getClassBundle() ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superName); .getClassIdentifier(superName);

@ -448,10 +448,17 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
(clName.substring(1, clName.length()-1) (clName.substring(1, clName.length()-1)
.replace('/','.')); .replace('/','.'));
} }
while (clazz != null if (instr.opcode >= opc_invokevirtual) {
&& clazz.findMethod(ref.getName(), while (clazz != null
ref.getType()) == null) && clazz.findMethod(ref.getName(),
clazz = clazz.getSuperclass(); ref.getType()) == null)
clazz = clazz.getSuperclass();
} else {
while (clazz != null
&& clazz.findField(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
}
if (clazz == null) { if (clazz == null) {
GlobalOptions.err.println("WARNING: Can't find reference: " GlobalOptions.err.println("WARNING: Can't find reference: "
@ -1371,6 +1378,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
public void analyzeCode(MethodIdentifier listener, BytecodeInfo bytecode) { public void analyzeCode(MethodIdentifier listener, BytecodeInfo bytecode) {
this.listener = listener;
this.bytecode = bytecode; this.bytecode = bytecode;
working = true; working = true;
if (constInfos == null) if (constInfos == null)

@ -111,6 +111,8 @@ public class FieldIdentifier extends Identifier{
} }
public void addFieldListener(Identifier ident) { public void addFieldListener(Identifier ident) {
if (ident == null)
throw new NullPointerException();
if (!fieldListeners.contains(ident)) if (!fieldListeners.contains(ident))
fieldListeners.add(ident); fieldListeners.add(ident);
} }

@ -179,14 +179,13 @@ public abstract class Identifier {
if (GlobalOptions.verboseLevel > 4) if (GlobalOptions.verboseLevel > 4)
GlobalOptions.err.println(toString() + " is preserved"); GlobalOptions.err.println(toString() + " is preserved");
} else { } else {
Identifier rep = getRepresentative(); Identifier rep = getRepresentative();
if (rep.wasAliased) if (rep.wasAliased)
return; return;
rep.wasAliased = true; rep.wasAliased = true;
// set alias to empty string, so it won't conflict! // set alias to empty string, so it won't conflict!
alias = ""; rep.alias = "";
String newAlias = null; String newAlias = null;
next_alias: next_alias:
for (;;) { for (;;) {
@ -198,7 +197,7 @@ public abstract class Identifier {
ptr = ptr.right; ptr = ptr.right;
} }
setAlias(newAlias.toString()); setAlias(newAlias.toString());
return; break;
} }
} }
for (Iterator i = getChilds(); i.hasNext(); ) for (Iterator i = getChilds(); i.hasNext(); )

@ -184,7 +184,7 @@ public class Main {
} }
public static CodeAnalyzer createCodeAnalyzer() { public static CodeAnalyzer createCodeAnalyzer() {
return new ConstantAnalyzer() /*XXX*/; return new SimpleAnalyzer() /*XXX*/;
} }
static CodeTransformer[] codeTransformers = { static CodeTransformer[] codeTransformers = {

@ -107,7 +107,7 @@ public class ModifierMatcher implements IdentifierMatcher, Cloneable {
if (implies(and, xor, andMasks[i], xorMasks[i])) if (implies(and, xor, andMasks[i], xorMasks[i]))
continue next_i; continue next_i;
for (int j=0; j<andMasks.length; j++) { for (int j=0; j < andMasks.length; j++) {
if (j != i if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j], && implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i])) andMasks[i], xorMasks[i]))
@ -120,12 +120,21 @@ public class ModifierMatcher implements IdentifierMatcher, Cloneable {
int[] ands = new int[newCount]; int[] ands = new int[newCount];
int[] xors = new int[newCount]; int[] xors = new int[newCount];
int index = 0; int index = 0;
next_i:
for (int i=0; i < newCount; i++) { for (int i=0; i < newCount; i++) {
int bothAnd = andMasks[i] & and; if (implies(and, xor, andMasks[i], xorMasks[i]))
if ((xorMasks[i] & bothAnd) == (and & bothAnd)) { continue next_i;
ands[index++] = andMasks[i] | and;
xors[index++] = xorMasks[i] | xor; for (int j=0; j < andMasks.length; j++) {
if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i]))
continue next_i;
} }
ands[index] = andMasks[i] | and;
xors[index] = xorMasks[i] | xor;
index++;
} }
return new ModifierMatcher(ands, xors); return new ModifierMatcher(ands, xors);
} }

@ -18,10 +18,69 @@
*/ */
package jode.obfuscator; package jode.obfuscator;
import jode.bytecode.*; import jode.bytecode.Handler;
import jode.bytecode.Opcodes;
import jode.bytecode.ClassInfo;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.Instruction;
import jode.bytecode.Reference;
import jode.GlobalOptions;
import jode.type.Type; import jode.type.Type;
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
public Identifier canonizeReference(Instruction instr) {
Reference ref = (Reference) instr.objData;
Identifier ident = Main.getClassBundle().getIdentifier(ref);
String clName = ref.getClazz();
String realClazzName;
if (ident != null) {
ClassIdentifier clazz = (ClassIdentifier)ident.getParent();
realClazzName = "L" + (clazz.getFullName()
.replace('.', '/')) + ";";
} else {
/* We have to look at the ClassInfo's instead, to
* point to the right method.
*/
ClassInfo clazz;
if (clName.charAt(0) == '[') {
/* Arrays don't define new methods (well clone(),
* but that can be ignored).
*/
clazz = ClassInfo.javaLangObject;
} else {
clazz = ClassInfo.forName
(clName.substring(1, clName.length()-1)
.replace('/','.'));
}
if (instr.opcode >= opc_invokevirtual) {
while (clazz != null
&& clazz.findMethod(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
} else {
while (clazz != null
&& clazz.findField(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
}
if (clazz == null) {
GlobalOptions.err.println("WARNING: Can't find reference: "
+ref);
realClazzName = clName;
} else
realClazzName = "L" + clazz.getName().replace('.', '/') + ";";
}
if (!realClazzName.equals(ref.getClazz())) {
ref = Reference.getReference(realClazzName,
ref.getName(), ref.getType());
instr.objData = ref;
}
return ident;
}
/** /**
* Reads the opcodes out of the code info and determine its * Reads the opcodes out of the code info and determine its
* references * references
@ -54,52 +113,21 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
/* fall through */ /* fall through */
case opc_getstatic: case opc_getstatic:
case opc_getfield: { case opc_getfield: {
Reference ref = (Reference) instr.objData; Identifier ident = canonizeReference(instr);
Identifier ident = Main.getClassBundle().getIdentifier(ref);
String clName = ref.getClazz();
String realClazzName;
if (ident != null) { if (ident != null) {
ClassIdentifier clazz = (ClassIdentifier)ident.getParent();
realClazzName = "L" + (clazz.getFullName()
.replace('.', '/')) + ";";
if (instr.opcode == opc_putstatic if (instr.opcode == opc_putstatic
|| instr.opcode == opc_putfield) { || instr.opcode == opc_putfield) {
FieldIdentifier fi = (FieldIdentifier) ident; FieldIdentifier fi = (FieldIdentifier) ident;
if (fi != null && !fi.isNotConstant()) if (fi != null && !fi.isNotConstant())
fi.setNotConstant(); fi.setNotConstant();
} else if (instr.opcode == opc_invokevirtual
|| instr.opcode == opc_invokeinterface) {
((ClassIdentifier) ident.getParent())
.reachableIdentifier(ident.getName(),
ident.getType(), true);
} else { } else {
clazz.reachableIdentifier ident.setReachable();
(ref.getName(), ref.getType(),
instr.opcode == opc_invokevirtual
|| instr.opcode == opc_invokeinterface);
} }
} else {
/* We have to look at the ClassInfo's instead, to
* point to the right method.
*/
ClassInfo clazz;
if (clName.charAt(0) == '[') {
/* Arrays don't define new methods (well clone(),
* but that can be ignored).
*/
clazz = ClassInfo.javaLangObject;
} else {
clazz = ClassInfo.forName
(clName.substring(1, clName.length()-1)
.replace('/','.'));
}
while (clazz != null
&& clazz.findMethod(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
realClazzName = (clazz != null) ? clName
: "L" + clazz.getName().replace('.', '/') + ";";
}
if (!realClazzName.equals(ref.getClazz())) {
ref = Reference.getReference(realClazzName,
ref.getName(), ref.getType());
instr.objData = ref;
} }
break; break;
} }

Loading…
Cancel
Save