From 3a71d9649de3982b9ae62594b9076b536674b6ab Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 9 Feb 1999 18:05:31 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@252 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/bytecode/BinaryInfo.java | 4 + jode/jode/flow/SpecialBlock.java | 8 +- jode/jode/obfuscator/ClassBundle.java | 5 + jode/jode/obfuscator/ClassIdentifier.java | 311 +++++++--- jode/jode/obfuscator/FieldIdentifier.java | 59 +- jode/jode/obfuscator/Identifier.java | 11 +- jode/jode/obfuscator/MethodIdentifier.java | 652 ++++++++++++++++++-- jode/jode/obfuscator/PackageIdentifier.java | 36 +- 8 files changed, 933 insertions(+), 153 deletions(-) diff --git a/jode/jode/bytecode/BinaryInfo.java b/jode/jode/bytecode/BinaryInfo.java index 781d463..08f98a1 100644 --- a/jode/jode/bytecode/BinaryInfo.java +++ b/jode/jode/bytecode/BinaryInfo.java @@ -43,6 +43,10 @@ public class BinaryInfo { return null; } + public AttributeInfo[] getAttributes() { + return attributes; + } + protected void skipAttributes(DataInputStream input) throws IOException { int count = input.readUnsignedShort(); for (int i=0; i< count; i++) { diff --git a/jode/jode/flow/SpecialBlock.java b/jode/jode/flow/SpecialBlock.java index 532d11f..b64b466 100644 --- a/jode/jode/flow/SpecialBlock.java +++ b/jode/jode/flow/SpecialBlock.java @@ -146,6 +146,9 @@ public class SpecialBlock extends StructuredBlock { if (last.outer instanceof SequentialBlock && last.outer.getSubBlocks()[0] instanceof InstructionBlock) { + if (jump != null && jump.destination == null) + return false; + InstructionBlock prev = (InstructionBlock) last.outer.getSubBlocks()[0]; Expression instr = prev.getInstruction(); @@ -193,9 +196,8 @@ public class SpecialBlock extends StructuredBlock { (new CompareBinaryOperator(instr.getType(), Operator.EQUALS_OP), new Expression[] { previnstr, instr }); - ConditionalBlock newIfThen = new ConditionalBlock(newCond); - newIfThen.moveDefinitions(last.outer.outer, newIfThen); - newIfThen.trueBlock.copyJump(jump); + IfThenElseBlock newIfThen = new IfThenElseBlock(newCond); + newIfThen.setThenBlock(new EmptyBlock()); newIfThen.moveJump(jump); if (this == last) { newIfThen.replace(last.outer.outer); diff --git a/jode/jode/obfuscator/ClassBundle.java b/jode/jode/obfuscator/ClassBundle.java index 4301372..5311dae 100644 --- a/jode/jode/obfuscator/ClassBundle.java +++ b/jode/jode/obfuscator/ClassBundle.java @@ -90,6 +90,11 @@ public class ClassBundle { } public void storeClasses(String destination) { + File directory = new File(destination); + if (!directory.exists()) { + Obfuscator.err.println("Destination directory " + +directory.getPath()+" doesn't exists."); + } basePackage.storeClasses(new File(destination)); } } diff --git a/jode/jode/obfuscator/ClassIdentifier.java b/jode/jode/obfuscator/ClassIdentifier.java index 6c8983e..a44f850 100644 --- a/jode/jode/obfuscator/ClassIdentifier.java +++ b/jode/jode/obfuscator/ClassIdentifier.java @@ -19,9 +19,7 @@ package jode.obfuscator; import jode.Obfuscator; -import jode.bytecode.ClassInfo; -import jode.bytecode.FieldInfo; -import jode.bytecode.MethodInfo; +import jode.bytecode.*; import java.lang.reflect.Modifier; import java.util.*; import java.io.*; @@ -31,8 +29,13 @@ public class ClassIdentifier extends Identifier { PackageIdentifier pack; String name; ClassInfo info; + boolean willStrip; int preserveRule; + int fieldCount; + /* The first fieldCount are of type FieldIdentifier, the remaining + * are MethodIdentifier + */ Identifier[] identifiers; Vector knownSubClasses = new Vector(); Vector virtualReachables = new Vector(); @@ -65,7 +68,7 @@ public class ClassIdentifier extends Identifier { for (int i=0; i< identifiers.length; i++) { if (identifiers[i].getName().equals(name) && (typeSig == null - || identifiers[i] .getType().equals(typeSig))) + || identifiers[i].getType().equals(typeSig))) identifiers[i].setPreserved(); } } @@ -115,21 +118,20 @@ public class ClassIdentifier extends Identifier { ClassIdentifier superident = (ClassIdentifier) bundle.getIdentifier(superclass.getName()); if (superident != null) { - for (int i=0; i < superident.identifiers.length; i++) - if (superident.identifiers[i] - instanceof MethodIdentifier) { - MethodIdentifier mid = (MethodIdentifier) - superident.identifiers[i]; - // all virtual methods in superclass must be chained. - int modif = mid.info.getModifiers(); - if (((Modifier.PRIVATE - | Modifier.STATIC - | Modifier.FINAL) & modif) == 0 - && !(mid.getName().equals(""))) { - // chain the preserved/same name lists. - chainIdentifier(superident.identifiers[i]); - } + for (int i=superident.fieldCount; + i < superident.identifiers.length; i++) { + MethodIdentifier mid = (MethodIdentifier) + superident.identifiers[i]; + // all virtual methods in superclass must be chained. + int modif = mid.info.getModifiers(); + if (((Modifier.PRIVATE + | Modifier.STATIC + | Modifier.FINAL) & modif) == 0 + && !(mid.getName().equals(""))) { + // chain the preserved/same name lists. + chainIdentifier(superident.identifiers[i]); } + } } else { // all methods and fields in superclass are preserved! MethodInfo[] topmethods = superclass.getMethods(); @@ -159,15 +161,20 @@ public class ClassIdentifier extends Identifier { } public void setSingleReachable() { - info.loadInfo(info.FULLINFO); - + super.setSingleReachable(); if (Obfuscator.isVerbose) - Obfuscator.err.println(this); + Obfuscator.err.println("Reachable: "+this); + reachableIdentifier("", "()V", false); + } + + public void initClass() { + info.loadInfo(info.FULLINFO); FieldInfo[] finfos = info.getFields(); MethodInfo[] minfos = info.getMethods(); + fieldCount = finfos.length; identifiers = new Identifier[finfos.length + minfos.length]; - for (int i=0; i< finfos.length; i++) { + for (int i=0; i< fieldCount; i++) { identifiers[i] = new FieldIdentifier(this, finfos[i]); if ((preserveRule & (finfos[i].getModifiers() ^ Modifier.PRIVATE)) != 0) { @@ -176,7 +183,7 @@ public class ClassIdentifier extends Identifier { } } for (int i=0; i< minfos.length; i++) { - identifiers[finfos.length + i] + identifiers[fieldCount + i] = new MethodIdentifier(this, minfos[i]); if ((preserveRule & (minfos[i].getModifiers() ^ Modifier.PRIVATE)) != 0) { @@ -192,7 +199,6 @@ public class ClassIdentifier extends Identifier { ClassIdentifier ifaceident = (ClassIdentifier) bundle.getIdentifier(ifaces[i].getName()); if (ifaceident != null) { - ifaceident.setReachable(); ifaceident.addSubClass(this); } initSuperClasses(ifaces[i]); @@ -202,49 +208,152 @@ public class ClassIdentifier extends Identifier { ClassIdentifier superident = (ClassIdentifier) bundle.getIdentifier(info.getSuperclass().getName()); if (superident != null) { - superident.setReachable(); superident.addSubClass(this); } initSuperClasses(info.getSuperclass()); } preserveIdentifier("", "()V"); + preserveIdentifier("", null); } public void strip() { - int newLength = 0; - for (int i=0; i < identifiers.length; i++) { - if (identifiers[i].isReachable()) - newLength++; - else { - if (Obfuscator.isDebugging) + willStrip = true; + if (Obfuscator.isDebugging) { + for (int i=0; i < identifiers.length; i++) { + if (!identifiers[i].isReachable()) Obfuscator.err.println(identifiers[i].toString() + " is stripped"); } } - Identifier[] newIdents = new Identifier[newLength]; - int index = 0; - for (int i=0; i < identifiers.length; i++) { - if (identifiers[i].isReachable()) - newIdents[index++] = identifiers[i]; - } - identifiers = newIdents; } public void buildTable(int renameRule) { super.buildTable(renameRule); for (int i=0; i < identifiers.length; i++) - identifiers[i].buildTable(renameRule); + if (!willStrip || identifiers[i].isReachable()) + identifiers[i].buildTable(renameRule); } public void writeTable(PrintWriter out) throws IOException { if (getName() != getAlias()) out.println("" + getFullAlias() + " = " + getName()); for (int i=0; i < identifiers.length; i++) - identifiers[i].writeTable(out); + if (!willStrip || identifiers[i].isReachable()) + identifiers[i].writeTable(out); } - public void storeClass(OutputStream out) throws IOException { - /*XXX*/ + public void addIfaces(Vector result, ClassInfo[] ifaces) { + for (int i=0; i < ifaces.length; i++) { + ClassIdentifier ifaceident = (ClassIdentifier) + bundle.getIdentifier(ifaces[i].getName()); + if (ifaceident != null) { + if (ifaceident.isReachable()) + result.addElement(ifaceident.getFullAlias()); + else + addIfaces(result, ifaceident.info.getInterfaces()); + } else + result.addElement(ifaces[i].getName()); + } + } + + /** + * Generates the new super class and interfaces, removing super + * classes and interfaces that are not reachable. + * @return an array of class names (full qualified, dot separated) + * where the first entry is the super class (may be null) and the + * other entries are the interfaces. + */ + public String[] getSuperIfaces() { + /* First generate Ifaces and superclass infos */ + Vector newSuperIfaces = new Vector(); + addIfaces(newSuperIfaces, info.getInterfaces()); + String superName = null; + ClassInfo superClass = info.getSuperclass(); + while (superClass != null) { + ClassIdentifier superident = (ClassIdentifier) + bundle.getIdentifier(superClass.getName()); + if (superident != null) { + if (superident.isReachable()) { + superName = superident.getFullAlias(); + break; + } else { + addIfaces(newSuperIfaces, superClass.getInterfaces()); + superClass = superClass.getSuperclass(); + } + } else { + superName = superClass.getName(); + break; + } + } + newSuperIfaces.insertElementAt(superName, 0); + String[] result = new String[newSuperIfaces.size()]; + newSuperIfaces.copyInto(result); + return result; + } + + public void storeClass(DataOutputStream out) throws IOException { + GrowableConstantPool gcp = new GrowableConstantPool(); + + for (int i=fieldCount; i < identifiers.length; i++) + if (!willStrip || identifiers[i].isReachable()) + ((MethodIdentifier)identifiers[i]).reserveSmallConstants(gcp); + + int[] hierarchyInts; + { + String[] hierarchy = getSuperIfaces(); + hierarchyInts = new int[hierarchy.length]; + for (int i=0; i< hierarchy.length; i++) { + if (hierarchy[i] != null) + hierarchyInts[i] = gcp.putClassRef(hierarchy[i]); + else + hierarchyInts[i] = 0; + } + hierarchy = null; + } + int nameIndex = gcp.putClassRef(getFullAlias()); + + int fields = 0; + int methods = 0; + + for (int i=0; i= clName.length() || clName.charAt(i) != 'L') + break; + int index = clName.indexOf(';', i); + if (index != clName.length()-1) + break; + clName = clName.substring(i+1, index); + } + clazz.bundle.reachableIdentifier(clName, false); + addr += 3; + if (opcode == opc_multianewarray) { + stream.skip(1); + addr ++; + } + break; + } + case opc_invokespecial: + case opc_invokestatic: + case opc_invokeinterface: + case opc_invokevirtual: { + int ref = stream.readUnsignedShort(); + String[] names = cp.getRef(ref); + clazz.bundle.reachableIdentifier + (names[0].replace('/','.')+"."+names[1]+"."+names[2], + opcode == opc_invokevirtual + || opcode == opc_invokeinterface); + addr += 3; + + if (opcode == opc_invokeinterface) { + stream.skip(2); + addr += 2; + } + break; + } + + default: + if (opcode == opc_newarray + || (opcode >= opc_bipush && opcode <= opc_aload) + || (opcode >= opc_istore && opcode <= opc_astore)) { + stream.skip(1); + addr += 2; + } else if (opcode >= opc_ifeq && opcode <= opc_jsr) { + stream.skip(2); + addr += 3; + } else if (opcode == opc_xxxunusedxxx + || opcode >= opc_breakpoint) + throw new ClassFormatError("Invalid opcode "+opcode); + else + addr++; + } + } + } + + public void readExceptions(AttributeInfo exceptionsattr) + throws IOException { + byte[] content = exceptionsattr.getContents(); + DataInputStream input = new DataInputStream + (new ByteArrayInputStream(content)); + ConstantPool cp = clazz.info.getConstantPool(); + + int count = input.readUnsignedShort(); + exceptions = new String[count]; + for (int i=0; i< count; i++) { + exceptions[i] + = cp.getClassName(input.readUnsignedShort()).replace('/','.'); + clazz.bundle.reachableIdentifier(exceptions[i], false); + } } public void setSingleReachable() { @@ -53,53 +204,28 @@ public class MethodIdentifier extends Identifier { if (Obfuscator.isDebugging) Obfuscator.err.println("Reachable: "+this); - ConstantPool cp = clazz.info.getConstantPool(); + String type = getType(); + int index = type.indexOf('L'); + while (index != -1) { + int end = type.indexOf(';', index); + clazz.bundle.reachableIdentifier(type.substring(index+1, end) + , false); + index = type.indexOf('L', end); + } + AttributeInfo codeattr = info.findAttribute("Code"); - if (codeattr == null) - return; + AttributeInfo exceptionsattr = info.findAttribute("Exceptions"); - DataInputStream stream = new DataInputStream - (new ByteArrayInputStream(codeattr.getContents())); - CodeInfo codeinfo = new CodeInfo(); try { - codeinfo.read(clazz.info.getConstantPool(), stream); - Vector references = analyzeCode(codeinfo); - Enumeration enum = references.elements(); - while (enum.hasMoreElements()) { - int[] ref = (int[]) enum.nextElement(); - int tag = cp.getTag(ref[0]); - switch (tag) { - case ConstantPool.FIELDREF: - case ConstantPool.METHODREF: - case ConstantPool.INTERFACEMETHODREF: { - String[] names = cp.getRef(ref[0]); - clazz.bundle.reachableIdentifier - (names[0].replace('/','.')+"."+names[1]+"."+names[2], - ref[1] == 1); - break; - } - case ConstantPool.CLASS: { - String clName = cp.getClassName(ref[0]).replace('/','.'); - if (clName.charAt(0) == '[') { - int i; - for (i=0; i< clName.length(); i++) - if (clName.charAt(i) != '[') - break; - if (i >= clName.length() || clName.charAt(i) != 'L') - break; - int index = clName.indexOf(';', i); - if (index != clName.length()-1) - break; - clName = clName.substring(i+1, index); - } - clazz.bundle.reachableIdentifier(clName, false); - break; - } - default: - throw new jode.AssertError - ("Unknown reference: "+ref+" tag: "+tag); - } + if (codeattr != null) { + DataInputStream stream = new DataInputStream + (new ByteArrayInputStream(codeattr.getContents())); + codeinfo = new CodeInfo(); + codeinfo.read(clazz.info.getConstantPool(), stream); + analyzeCode(); } + if (exceptionsattr != null) + readExceptions(exceptionsattr); } catch (IOException ex) { ex.printStackTrace(); } @@ -112,6 +238,10 @@ public class MethodIdentifier extends Identifier { + " = " + getName()); } + public Identifier getParent() { + return clazz; + } + public String getFullName() { return clazz.getFullName() + "." + getName(); } @@ -131,11 +261,419 @@ public class MethodIdentifier extends Identifier { public boolean conflicting(String newAlias) { String type = getType(); String paramType = type.substring(0, type.indexOf(')')+1); - return clazz.containsMethod(newAlias, paramType) - || clazz.containsField(newAlias); + return clazz.getMethod(newAlias, paramType) != null + || clazz.containFieldAlias(newAlias, ""); } public String toString() { return "MethodIdentifier "+getFullName()+"."+getType(); } + + int nameIndex; + int descriptorIndex; + int codeIndex; + byte[] code; + int exceptionsIndex; + int[] excIndices; + + static byte[] buff = new byte[10]; + static void copy(DataInputStream in, DataOutputStream out, int length) + throws IOException { + if (buff.length < length) + buff = new byte[length]; + in.readFully(buff, 0, length); + out.write(buff, 0, length); + } + + public void transformCode(GrowableConstantPool gcp) { + ConstantPool cp = clazz.info.getConstantPool(); + byte[] origcode = codeinfo.getCode(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream output = new DataOutputStream(baos); + DataInputStream input = new DataInputStream + (new ByteArrayInputStream(origcode)); + try { + output.writeShort(codeinfo.getMaxStack()); + output.writeShort(codeinfo.getMaxLocals()); + output.writeInt(origcode.length); + int addr = 0; + while (input.available() > 0) { + int opcode = input.readUnsignedByte(); + switch (opcode) { + case opc_wide: { + output.writeByte(opcode); + int wideopcode = input.readUnsignedByte(); + switch (wideopcode) { + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + case opc_ret: + output.writeByte(wideopcode); + copy(input, output, 2); + addr+=4; + break; + + case opc_iinc: + output.writeByte(wideopcode); + copy(input, output, 4); + addr+=6; + break; + default: + throw new ClassFormatError("Invalid wide opcode " + +wideopcode); + } + break; + } + case opc_ret: + output.writeByte(opcode); + copy(input, output, 1); + addr+=2; + break; + + case opc_ldc: { + int index = input.readUnsignedByte(); + int newIndex = gcp.copyConstant(cp, index); + output.writeByte(opcode); + output.writeByte(newIndex); + addr+=2; + break; + } + case opc_ldc_w: + case opc_ldc2_w: { + int index = input.readUnsignedShort(); + int newIndex = gcp.copyConstant(cp, index); + output.writeByte(opcode); + output.writeShort(newIndex); + addr += 3; + break; + } + + case opc_sipush: + case opc_iinc: + case opc_ifnull: case opc_ifnonnull: + output.writeByte(opcode); + copy(input, output, 2); + addr+=3; + break; + case opc_jsr_w: + case opc_goto_w: + output.writeByte(opcode); + copy(input, output, 4); + addr+=5; + break; + case opc_tableswitch: { + output.writeByte(opcode); + int length = 7-(addr % 4); + copy(input, output, length); + int low = input.readInt(); + output.writeInt(low); + int high = input.readInt(); + output.writeInt(high); + copy(input, output, 4*(high-low+1)); + addr += 9 + length + 4*(high-low+1); + break; + } + case opc_lookupswitch: { + output.writeByte(opcode); + int length = 7-(addr % 4); + copy(input, output, length); + int npairs = input.readInt(); + output.writeInt(npairs); + copy(input, output, 8*npairs); + addr += 5 + length + 8*npairs; + break; + } + + case opc_getstatic: + case opc_getfield: + case opc_putstatic: + case opc_putfield: { + int ref = input.readUnsignedShort(); + String[] names = cp.getRef(ref); + ClassIdentifier ci = (ClassIdentifier) + clazz.bundle.getIdentifier(names[0].replace('/','.')); + + if (ci != null) { + names[0] = ci.getFullAlias(); + Identifier fi = ci.getIdentifier(names[1], names[2]); + if (fi instanceof FieldIdentifier) { + if (!((FieldIdentifier)fi).isReachable()) { + if (opcode != opc_putfield + && opcode != opc_putstatic) + throw new jode.AssertError + ("reading not reachable field"); + int stacksize = + (opcode == opc_putstatic) ? 0 : 1; + stacksize += jode.Type.tType + (names[2]).stackSize(); + if (stacksize == 3) { + output.writeByte(opc_pop2); + output.writeByte(opc_pop); + output.writeByte(opc_nop); + } else if (stacksize == 2) { + output.writeByte(opc_pop2); + output.writeByte(opc_nop); + output.writeByte(opc_nop); + } else { + output.writeByte(opc_pop); + output.writeByte(opc_nop); + output.writeByte(opc_nop); + } + addr += 3; + break; + } + names[1] = ((FieldIdentifier) fi).getAlias(); + } + } + names[2] = clazz.bundle.getTypeAlias(names[2]); + output.writeByte(opcode); + output.writeShort(gcp.putRef(cp.getTag(ref), names)); + addr += 3; + break; + } + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + case opc_multianewarray: { + int ref = input.readUnsignedShort(); + String clName = cp.getClassName(ref).replace('/','.'); + if (clName.charAt(0) == '[') { + clName = clazz.bundle.getTypeAlias(clName); + } else { + ClassIdentifier ci = (ClassIdentifier) + clazz.bundle.getIdentifier(clName); + if (ci != null) + clName = ci.getFullAlias(); + } + int newRef = gcp.putClassRef(clName); + output.writeByte(opcode); + output.writeShort(newRef); + addr += 3; + if (opcode == opc_multianewarray) { + copy(input, output, 1); + addr ++; + } + break; + } + case opc_invokespecial: + case opc_invokestatic: + case opc_invokeinterface: + case opc_invokevirtual: { + int ref = input.readUnsignedShort(); + String[] names = cp.getRef(ref); + ClassIdentifier ci = (ClassIdentifier) + clazz.bundle.getIdentifier(names[0].replace('/','.')); + + if (ci != null) { + names[0] = ci.getFullAlias(); + Identifier mi = ci.getIdentifier(names[1], names[2]); + if (mi instanceof MethodIdentifier) { + names[1] = ((MethodIdentifier)mi).getAlias(); + } + } + names[2] = clazz.bundle.getTypeAlias(names[2]); + output.writeByte(opcode); + output.writeShort(gcp.putRef(cp.getTag(ref), names)); + addr += 3; + if (opcode == opc_invokeinterface) { + copy(input, output, 2); + addr += 2; + } + break; + } + + default: + output.writeByte(opcode); + if (opcode == opc_newarray + || (opcode >= opc_bipush && opcode <= opc_aload) + || (opcode >= opc_istore && opcode <= opc_astore)) { + copy(input, output, 1); + addr += 2; + } else if (opcode >= opc_ifeq && opcode <= opc_jsr) { + copy(input, output, 2); + addr += 3; + } else if (opcode == opc_xxxunusedxxx + || opcode >= opc_breakpoint) + throw new ClassFormatError("Invalid opcode "+opcode); + else + addr++; + } + } + + int[] handlers = codeinfo.getExceptionHandlers(); + output.writeShort(handlers.length / 4); + for (int i=0; i< handlers.length; i += 4) { + output.writeShort(handlers[i]); + output.writeShort(handlers[i+1]); + output.writeShort(handlers[i+2]); + String clName + = cp.getClassName(handlers[i+3]).replace('/','.'); + ClassIdentifier ci = (ClassIdentifier) + clazz.bundle.getIdentifier(clName); + if (ci != null) + clName = ci.getFullAlias(); + output.writeShort(gcp.putClassRef(clName)); + } + output.writeShort(0); // No Attributes; + output.close(); + } catch (IOException ex) { + ex.printStackTrace(); + code = null; + return; + } + code = baos.toByteArray(); + } + + public void reserveSmallConstants(GrowableConstantPool gcp) { + if (codeinfo != null) { + ConstantPool cp = clazz.info.getConstantPool(); + byte[] code = codeinfo.getCode(); + DataInputStream stream = + new DataInputStream(new ByteArrayInputStream(code)); + try { + int addr = 0; + while (stream.available() > 0) { + int opcode = stream.readUnsignedByte(); + switch (opcode) { + + case opc_ldc: { + int index = stream.readUnsignedByte(); + gcp.copyConstant(cp, index); + break; + } + + case opc_wide: { + switch (opcode = stream.readUnsignedByte()) { + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + case opc_ret: + stream.skip(2); + addr+=4; + break; + + case opc_iinc: + stream.skip(4); + addr+=6; + break; + default: + throw new ClassFormatError("Invalid wide opcode "+opcode); + } + } + case opc_tableswitch: { + int length = 7-(addr % 4); + stream.skip(length); + int low = stream.readInt(); + int high = stream.readInt(); + stream.skip(4*(high-low+1)); + addr += 9 + length + 4*(high-low+1); + break; + } + case opc_lookupswitch: { + int length = 7-(addr % 4); + stream.skip(length); + int npairs = stream.readInt(); + stream.skip(8*npairs); + addr += 5 + length + 8*npairs; + break; + } + case opc_ret: + stream.skip(1); + addr+=2; + break; + case opc_sipush: + case opc_ldc2_w: + case opc_iinc: + case opc_ifnull: case opc_ifnonnull: + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + stream.skip(2); + addr+=3; + break; + case opc_multianewarray: + stream.skip(3); + addr += 4; + break; + case opc_jsr_w: + case opc_goto_w: + case opc_invokeinterface: + stream.skip(4); + addr+=5; + break; + default: + if (opcode == opc_newarray + || (opcode >= opc_bipush && opcode <= opc_aload) + || (opcode >= opc_istore && opcode <= opc_astore)) { + stream.skip(1); + addr += 2; + } else if (opcode >= opc_ifeq && opcode <= opc_jsr + || opcode >= opc_getstatic && opcode <= opc_invokestatic) { + stream.skip(2); + addr += 3; + } else if (opcode == opc_xxxunusedxxx + || opcode >= opc_breakpoint) + throw new ClassFormatError("Invalid opcode "+opcode); + else + addr++; + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + + public void fillConstantPool(GrowableConstantPool gcp) { + nameIndex = gcp.putUTF(getAlias()); + descriptorIndex = gcp.putUTF(clazz.bundle.getTypeAlias(getType())); + AttributeInfo codeattr = info.findAttribute("Code"); + codeIndex = 0; + if (codeinfo != null) { + transformCode(gcp); + if (code != null) + codeIndex = gcp.putUTF("Code"); + } + if (exceptions != null) { + exceptionsIndex = gcp.putUTF("Exceptions"); + excIndices = new int[exceptions.length]; + for (int i=0; i< exceptions.length; i++) { + ClassIdentifier ci = (ClassIdentifier) + clazz.bundle.getIdentifier(exceptions[i]); + if (ci != null) + excIndices[i] = gcp.putClassRef(ci.getFullAlias()); + else + excIndices[i] = gcp.putClassRef(exceptions[i]); + } + } + } + + public void write(DataOutputStream out) throws IOException { + out.writeShort(info.getModifiers()); + out.writeShort(nameIndex); + out.writeShort(descriptorIndex); + int attrCount = 0; + if (code != null) + attrCount++; + if (excIndices != null) + attrCount++; + out.writeShort(attrCount); + if (code != null) { + out.writeShort(codeIndex); + out.writeInt(code.length); + out.write(code); + } + if (excIndices != null) { + out.writeShort(exceptionsIndex); + out.writeInt(excIndices.length*2+2); + out.writeShort(excIndices.length); + for (int i=0; i< excIndices.length; i++) + out.writeShort(excIndices[i]); + } + } } + diff --git a/jode/jode/obfuscator/PackageIdentifier.java b/jode/jode/obfuscator/PackageIdentifier.java index de40912..c6fed9e 100644 --- a/jode/jode/obfuscator/PackageIdentifier.java +++ b/jode/jode/obfuscator/PackageIdentifier.java @@ -31,6 +31,7 @@ public class PackageIdentifier extends Identifier { PackageIdentifier parent; String name; + boolean willStrip = false; boolean loadOnDemand; Hashtable loadedClasses; @@ -70,14 +71,16 @@ public class PackageIdentifier extends Identifier { String fullname = getFullName() + name; if (ClassInfo.isPackage(fullname)) { ident = new PackageIdentifier(bundle, this, name, true); + loadedClasses.put(name, ident); } else if (!ClassInfo.exists(fullname)) { throw new IllegalArgumentException ("Can't find class"+fullname); } else { ident = new ClassIdentifier(bundle, this, name, ClassInfo.forName(fullname)); + loadedClasses.put(name, ident); + ((ClassIdentifier) ident).initClass(); } - loadedClasses.put(name, ident); } return ident; } else { @@ -121,7 +124,6 @@ public class PackageIdentifier extends Identifier { if (ident == null) return; - ident.setReachable(); if (index == -1) return; @@ -210,12 +212,11 @@ public class PackageIdentifier extends Identifier { } public void strip() { - Hashtable ht = new Hashtable(); + willStrip = true; Enumeration enum = loadedClasses.elements(); while (enum.hasMoreElements()) { Identifier ident = (Identifier) enum.nextElement(); if (ident.isReachable()) { - ht.put(ident.getName(), ident); if (ident instanceof ClassIdentifier) { ((ClassIdentifier) ident).strip(); } else @@ -227,7 +228,6 @@ public class PackageIdentifier extends Identifier { + " is not reachable"); } } - loadedClasses = ht; } public void buildTable(int renameRule) { @@ -248,10 +248,16 @@ public class PackageIdentifier extends Identifier { + " = " + getName()); Enumeration enum = loadedClasses.elements(); while (enum.hasMoreElements()) { - ((Identifier)enum.nextElement()).writeTable(out); + Identifier ident = (Identifier) enum.nextElement(); + if (!willStrip || ident.isReachable()) + ident.writeTable(out); } } + public Identifier getParent() { + return parent; + } + public String getName() { return name; } @@ -262,16 +268,30 @@ public class PackageIdentifier extends Identifier { public void storeClasses(File destination) { File newDest = (parent == null) ? destination - : new File(destination, getName()); + : new File(destination, getAlias()); + if (!newDest.exists() && !newDest.mkdir()) { + Obfuscator.err.println("Could not create directory " + +newDest.getPath()+", check permissions."); + } Enumeration enum = loadedClasses.elements(); while (enum.hasMoreElements()) { Identifier ident = (Identifier) enum.nextElement(); + if (willStrip && !ident.isReachable()) + continue; if (ident instanceof PackageIdentifier) ((PackageIdentifier) ident) .storeClasses(newDest); else { try { - ((ClassIdentifier) ident).storeClass(null); + File file = new File(newDest, ident.getAlias()+".class"); + if (file.exists()) { + Obfuscator.err.println + ("Refuse to overwrite existing class file " + +file.getPath()+". Remove it first."); + } + DataOutputStream out = new DataOutputStream + (new FileOutputStream(file)); + ((ClassIdentifier) ident).storeClass(out); } catch (java.io.IOException ex) { Obfuscator.err.println("Can't write Class " + ident.getName());