diff --git a/jode/jode/obfuscator/MethodIdentifier.java b/jode/jode/obfuscator/MethodIdentifier.java
index fa35295..24ac403 100644
--- a/jode/jode/obfuscator/MethodIdentifier.java
+++ b/jode/jode/obfuscator/MethodIdentifier.java
@@ -28,12 +28,16 @@ import java.util.Hashtable;
public class MethodIdentifier extends Identifier implements Opcodes {
ClassIdentifier clazz;
MethodInfo info;
- CodeInfo codeinfo;
/**
* The exceptions that can be thrown by this method
*/
String[] exceptions;
+ /**
+ * The byte code of this method, or null if there isn't any.
+ */
+ BytecodeInfo bytecode;
+
public MethodIdentifier(ClassIdentifier clazz, MethodInfo info) {
super(info.getName());
this.clazz = clazz;
@@ -46,8 +50,8 @@ public class MethodIdentifier extends Identifier implements Opcodes {
if (codeattr != null) {
DataInputStream stream = new DataInputStream
(new ByteArrayInputStream(codeattr.getContents()));
- codeinfo = new CodeInfo();
- codeinfo.read(clazz.info.getConstantPool(), stream);
+ bytecode = new BytecodeInfo();
+ bytecode.read(clazz.info.getConstantPool(), stream);
}
if (exceptionsattr != null)
readExceptions(exceptionsattr);
@@ -63,110 +67,21 @@ public class MethodIdentifier extends Identifier implements Opcodes {
}
}
- /**
- * Skips the specified number of bytes in the input stream. This calls
- * skip as long until the bytes are all skipped.
- * @param is the inputstream to skip.
- * @param count the number of bytes to skip.
- */
- private final static void skip(InputStream is, long count)
- throws IOException {
- while (count > 0) {
- long skipped = is.skip(count);
- if (skipped == 0)
- throw new EOFException("Can't skip.");
- count -= skipped;
- }
- }
-
/**
* Reads the opcodes out of the code info and determine its
* references
* @return an enumeration of the references.
*/
- public void analyzeCode() throws IOException{
- ConstantPool cp = clazz.info.getConstantPool();
- byte[] code = codeinfo.getCode();
- DataInputStream stream =
- new DataInputStream(new ByteArrayInputStream(code));
- int addr = 0;
- while (stream.available() > 0) {
- int opcode = stream.readUnsignedByte();
- switch (opcode) {
- 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:
- skip(stream, 2);
- addr+=4;
- break;
-
- case opc_iinc:
- skip(stream, 4);
- addr+=6;
- break;
- default:
- throw new ClassFormatError("Invalid wide opcode "+opcode);
- }
- break;
- }
- case opc_ret:
- skip(stream, 1);
- addr+=2;
- break;
- case opc_sipush:
- case opc_ldc_w:
- case opc_ldc2_w:
- case opc_iinc:
- case opc_ifnull: case opc_ifnonnull:
- case opc_putstatic:
- case opc_putfield:
- skip(stream, 2);
- addr+=3;
- break;
- case opc_jsr_w:
- case opc_goto_w:
- skip(stream, 4);
- addr+=5;
- break;
- case opc_tableswitch: {
- int length = 7-(addr % 4);
- skip(stream, length);
- int low = stream.readInt();
- int high = stream.readInt();
- skip(stream, 4*(high-low+1));
- addr += 9 + length + 4*(high-low+1);
- break;
- }
- case opc_lookupswitch: {
- int length = 7-(addr % 4);
- skip(stream, length);
- int npairs = stream.readInt();
- skip(stream, 8*npairs);
- addr += 5 + length + 8*npairs;
- break;
- }
-
- case opc_getstatic:
- case opc_getfield: {
- int ref = stream.readUnsignedShort();
- String[] names = cp.getRef(ref);
- clazz.bundle.reachableIdentifier
- (names[0].replace('/','.')+"."+names[1]+"."+names[2],
- false);
- addr += 3;
- break;
- }
+ public void analyzeCode() throws IOException {
+ for (Instruction instr = bytecode.getFirstInstr();
+ instr != null; instr = instr.nextByAddr) {
+ switch (instr.opcode) {
case opc_new:
case opc_anewarray:
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray: {
- int ref = stream.readUnsignedShort();
- String clName = cp.getClassName(ref).replace('/','.');
+ String clName = (String) instr.objData;
if (clName.charAt(0) == '[') {
int i;
for (i=0; i< clName.length(); i++)
@@ -180,46 +95,21 @@ public class MethodIdentifier extends Identifier implements Opcodes {
clName = clName.substring(i+1, index);
}
clazz.bundle.reachableIdentifier(clName, false);
- addr += 3;
- if (opcode == opc_multianewarray) {
- skip(stream, 1);
- addr ++;
- }
break;
}
+ case opc_getstatic:
+ case opc_getfield:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
case opc_invokevirtual: {
- int ref = stream.readUnsignedShort();
- String[] names = cp.getRef(ref);
+ String[] names = (String[]) instr.objData;
clazz.bundle.reachableIdentifier
(names[0].replace('/','.')+"."+names[1]+"."+names[2],
- opcode == opc_invokevirtual
- || opcode == opc_invokeinterface);
- addr += 3;
-
- if (opcode == opc_invokeinterface) {
- skip(stream, 2);
- addr += 2;
- }
+ instr.opcode == opc_invokevirtual
+ || instr.opcode == opc_invokeinterface);
break;
}
-
- default:
- if (opcode == opc_newarray
- || (opcode >= opc_bipush && opcode <= opc_aload)
- || (opcode >= opc_istore && opcode <= opc_astore)) {
- skip(stream, 1);
- addr += 2;
- } else if (opcode >= opc_ifeq && opcode <= opc_jsr) {
- skip(stream, 2);
- addr += 3;
- } else if (opcode == opc_xxxunusedxxx
- || opcode >= opc_breakpoint)
- throw new ClassFormatError("Invalid opcode "+opcode);
- else
- addr++;
}
}
}
@@ -254,7 +144,7 @@ public class MethodIdentifier extends Identifier implements Opcodes {
index = type.indexOf('L', end);
}
- if (codeinfo != null) {
+ if (bytecode != null) {
try {
analyzeCode();
} catch (IOException ex) {
@@ -334,152 +224,95 @@ public class MethodIdentifier extends Identifier implements Opcodes {
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;
+ /**
+ * This method does the code transformation. This include
+ *
- new slot distribution for locals
+ * - obfuscating transformation of flow
+ * - renaming field, method and class references
+ *
+ */
+ public void doCodeTransformations(GrowableConstantPool gcp) {
+ if (bytecode != null) {
+ /* XXX This should be in a if (Obfuscator.distributeLocals) */
+ LocalOptimizer localOpt = new LocalOptimizer(bytecode);
+ localOpt.calcLocalInfo();
+ localOpt.distributeLocals();
+ if (Obfuscator.isDebugging)
+ localOpt.dumpLocals();
+
+ for (Instruction instr = bytecode.getFirstInstr();
+ instr != null; instr = instr.nextByAddr) {
+ switch (instr.opcode) {
+ case opc_ldc:
+ gcp.reserveConstant(instr.objData);
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);
+ case opc_invokespecial:
+ case opc_invokestatic:
+ case opc_invokeinterface:
+ case opc_invokevirtual: {
+ String[] names = (String[]) instr.objData;
+ ClassIdentifier ci = (ClassIdentifier)
+ clazz.bundle.getIdentifier(names[0].replace('/','.'));
+
+ if (ci != null) {
+ names[0] = ci.getFullAlias();
+ names[1] =
+ ((MethodIdentifier)
+ ci.getIdentifier(names[1], names[2])).getAlias();
+ }
+ names[2] = clazz.bundle.getTypeAlias(names[2]);
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;
+ case opc_getstatic:
+ case opc_getfield: {
+ String[] names = (String[]) instr.objData;
+ ClassIdentifier ci = (ClassIdentifier)
+ clazz.bundle.getIdentifier(names[0].replace('/','.'));
+ if (ci != null) {
+ FieldIdentifier fi = (FieldIdentifier)
+ ci.getIdentifier(names[1], names[2]);
+ names[0] = ci.getFullAlias();
+ names[1] = fi.getAlias();
+ }
+ names[2] = clazz.bundle.getTypeAlias(names[2]);
break;
}
-
- case opc_getstatic:
- case opc_getfield:
case opc_putstatic:
case opc_putfield: {
- int ref = input.readUnsignedShort();
- String[] names = cp.getRef(ref);
+ String[] names = (String[]) instr.objData;
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 (Obfuscator.shouldStrip
- && !((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;
+ FieldIdentifier fi = (FieldIdentifier)
+ ci.getIdentifier(names[1], names[2]);
+ if (Obfuscator.shouldStrip && !fi.isReachable()) {
+ /* Replace instruction with pop opcodes. */
+ int stacksize =
+ (instr.opcode
+ == Instruction.opc_putstatic) ? 0 : 1;
+ stacksize += jode.Type.tType(names[2]).stackSize();
+ if (stacksize == 3) {
+ /* Add a pop instruction after this opcode. */
+ Instruction second = new Instruction();
+ second.length = 1;
+ second.opcode = Instruction.opc_pop;
+ second.nextByAddr = instr.nextByAddr;
+ instr.nextByAddr = second;
+ second.nextByAddr.preds.removeElement(instr);
+ second.nextByAddr.preds.addElement(second);
+ stacksize--;
}
- names[1] = ((FieldIdentifier) fi).getAlias();
+ instr.objData = null;
+ instr.intData = 0;
+ instr.opcode = Instruction.opc_pop - 1 + stacksize;
+ instr.length = 1;
+ } else {
+ names[0] = ci.getFullAlias();
+ names[1] = 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:
@@ -487,200 +320,29 @@ public class MethodIdentifier extends Identifier implements Opcodes {
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray: {
- int ref = input.readUnsignedShort();
- String clName = cp.getClassName(ref).replace('/','.');
+ String clName = (String) instr.objData;
if (clName.charAt(0) == '[') {
clName = clazz.bundle.getTypeAlias(clName);
} else {
- ClassIdentifier ci = (ClassIdentifier)
+ 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;
- }
+ instr.objData = clName;
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]);
- if (handlers[i+3] == 0)
- output.writeShort(0);
- else {
- String clName
- = cp.getClassName(handlers[i+3]).replace('/','.');
- ClassIdentifier ci = (ClassIdentifier)
- clazz.bundle.getIdentifier(clName);
+
+ Handler[] handlers = bytecode.getExceptionHandlers();
+ for (int i=0; i< handlers.length; i++) {
+ if (handlers[i].type != null) {
+ ClassIdentifier ci = (ClassIdentifier)
+ clazz.bundle.getIdentifier(handlers[i].type);
if (ci != null)
- clName = ci.getFullAlias();
- output.writeShort(gcp.putClassRef(clName));
- }
- }
- output.writeShort(0); // No Attributes;
- output.close();
- } catch (IOException ex) {
- ex.printStackTrace(Obfuscator.err);
- 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);
- addr += 2;
- 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:
- skip(stream, 2);
- addr+=4;
- break;
-
- case opc_iinc:
- skip(stream, 4);
- addr+=6;
- break;
- default:
- throw new ClassFormatError("Invalid wide opcode "+opcode);
- }
- break;
- }
- case opc_tableswitch: {
- int length = 7-(addr % 4);
- skip(stream, length);
- int low = stream.readInt();
- int high = stream.readInt();
- skip(stream, 4*(high-low+1));
- addr += 9 + length + 4*(high-low+1);
- break;
- }
- case opc_lookupswitch: {
- int length = 7-(addr % 4);
- skip(stream, length);
- int npairs = stream.readInt();
- skip(stream, 8*npairs);
- addr += 5 + length + 8*npairs;
- break;
- }
- case opc_ret:
- skip(stream, 1);
- addr+=2;
- break;
- case opc_sipush:
- case opc_ldc_w:
- 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:
- skip(stream, 2);
- addr+=3;
- break;
- case opc_multianewarray:
- skip(stream, 3);
- addr += 4;
- break;
- case opc_jsr_w:
- case opc_goto_w:
- case opc_invokeinterface:
- skip(stream, 4);
- addr+=5;
- break;
- default:
- if (opcode == opc_newarray
- || (opcode >= opc_bipush && opcode <= opc_aload)
- || (opcode >= opc_istore && opcode <= opc_astore)) {
- skip(stream, 1);
- addr += 2;
- } else if (opcode >= opc_ifeq && opcode <= opc_jsr
- || opcode >= opc_getstatic && opcode <= opc_invokestatic) {
- skip(stream, 2);
- addr += 3;
- } else if (opcode == opc_xxxunusedxxx
- || opcode >= opc_breakpoint)
- throw new ClassFormatError("Invalid opcode "+opcode);
- else
- addr++;
- }
+ handlers[i].type = ci.getFullAlias();
}
- } catch (IOException ex) {
- ex.printStackTrace(Obfuscator.err);
}
}
}
@@ -690,10 +352,20 @@ public class MethodIdentifier extends Identifier implements Opcodes {
descriptorIndex = gcp.putUTF(clazz.bundle.getTypeAlias(getType()));
codeIndex = 0;
- if (codeinfo != null) {
- transformCode(gcp);
- if (code != null)
+ if (bytecode != null) {
+
+
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream output = new DataOutputStream(baos);
+ try {
+ bytecode.writeCode(gcp, clazz.bundle, output);
+ output.close();
+ code = baos.toByteArray();
codeIndex = gcp.putUTF("Code");
+ } catch (IOException ex) {
+ code = null;
+ }
}
if (exceptions != null) {
exceptionsIndex = gcp.putUTF("Exceptions");