diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index 774c6f4d6e..73d4cb80bb 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -1,16 +1,6 @@ package info.sigterm.deob; -import info.sigterm.deob.deobfuscators.ConstantParameter; -import info.sigterm.deob.deobfuscators.IllegalStateExceptions; -import info.sigterm.deob.deobfuscators.MethodInliner; -import info.sigterm.deob.deobfuscators.MethodMover; -import info.sigterm.deob.deobfuscators.ModularArithmeticDeobfuscation; -import info.sigterm.deob.deobfuscators.RenameUnique; -import info.sigterm.deob.deobfuscators.RuntimeExceptions; -import info.sigterm.deob.deobfuscators.UnreachedCode; -import info.sigterm.deob.deobfuscators.UnusedFields; -import info.sigterm.deob.deobfuscators.UnusedMethods; -import info.sigterm.deob.deobfuscators.UnusedParameters; +import info.sigterm.deob.deobfuscators.FieldMover; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -45,66 +35,68 @@ public class Deob // bdur = System.currentTimeMillis() - bstart; // System.out.println("rename unique took " + bdur/1000L + " seconds"); - // remove except RuntimeException - bstart = System.currentTimeMillis(); - new RuntimeExceptions().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("runtime exception took " + bdur/1000L + " seconds"); - - // remove unused methods - bstart = System.currentTimeMillis(); - new UnusedMethods().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused methods took " + bdur/1000L + " seconds"); - - new UnreachedCode().run(group); - - // remove illegal state exceptions, frees up some parameters - bstart = System.currentTimeMillis(); - new IllegalStateExceptions().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("illegal state exception took " + bdur/1000L + " seconds"); - - // remove constant logically dead parameters - bstart = System.currentTimeMillis(); - new ConstantParameter().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("constant param took " + bdur/1000L + " seconds"); - - // remove unhit blocks - bstart = System.currentTimeMillis(); - new UnreachedCode().run(group); - //new UnusedBlocks().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused blocks took " + bdur/1000L + " seconds"); - - // remove unused parameters - bstart = System.currentTimeMillis(); - new UnusedParameters().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused params took " + bdur/1000L + " seconds"); - - // remove jump obfuscation - //new Jumps().run(group); - - // remove unused fields - bstart = System.currentTimeMillis(); - new UnusedFields().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused fields took " + bdur/1000L + " seconds"); - - // remove unused methods, again? - bstart = System.currentTimeMillis(); - new UnusedMethods().run(group); - bdur = System.currentTimeMillis() - bstart; - System.out.println("unused methods took " + bdur/1000L + " seconds"); - - - new MethodInliner().run(group); +// // remove except RuntimeException +// bstart = System.currentTimeMillis(); +// new RuntimeExceptions().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("runtime exception took " + bdur/1000L + " seconds"); +// +// // remove unused methods +// bstart = System.currentTimeMillis(); +// new UnusedMethods().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused methods took " + bdur/1000L + " seconds"); +// +// new UnreachedCode().run(group); +// +// // remove illegal state exceptions, frees up some parameters +// bstart = System.currentTimeMillis(); +// new IllegalStateExceptions().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("illegal state exception took " + bdur/1000L + " seconds"); +// +// // remove constant logically dead parameters +// bstart = System.currentTimeMillis(); +// new ConstantParameter().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("constant param took " + bdur/1000L + " seconds"); +// +// // remove unhit blocks +// bstart = System.currentTimeMillis(); +// new UnreachedCode().run(group); +// //new UnusedBlocks().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused blocks took " + bdur/1000L + " seconds"); +// +// // remove unused parameters +// bstart = System.currentTimeMillis(); +// new UnusedParameters().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused params took " + bdur/1000L + " seconds"); +// +// // remove jump obfuscation +// //new Jumps().run(group); +// +// // remove unused fields +// bstart = System.currentTimeMillis(); +// new UnusedFields().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused fields took " + bdur/1000L + " seconds"); +// +// // remove unused methods, again? +// bstart = System.currentTimeMillis(); +// new UnusedMethods().run(group); +// bdur = System.currentTimeMillis() - bstart; +// System.out.println("unused methods took " + bdur/1000L + " seconds"); +// +// +// new MethodInliner().run(group); // new ModularArithmeticDeobfuscation().run(group); - new MethodMover().run(group); + //new MethodMover().run(group); + + new FieldMover().run(group); saveJar(group, args[1]); diff --git a/src/main/java/info/sigterm/deob/Field.java b/src/main/java/info/sigterm/deob/Field.java index eedfac36b3..32e81e0719 100644 --- a/src/main/java/info/sigterm/deob/Field.java +++ b/src/main/java/info/sigterm/deob/Field.java @@ -57,6 +57,11 @@ public class Field { return fields; } + + public void setFields(Fields fields) + { + this.fields = fields; + } public short getAccessFlags() { diff --git a/src/main/java/info/sigterm/deob/attributes/code/Instruction.java b/src/main/java/info/sigterm/deob/attributes/code/Instruction.java index b503c4cd07..cf0bd0f7bf 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/Instruction.java +++ b/src/main/java/info/sigterm/deob/attributes/code/Instruction.java @@ -222,7 +222,7 @@ public abstract class Instruction { } - public void renameField(Field f, String name) + public void renameField(Field f, info.sigterm.deob.pool.Field name) { } diff --git a/src/main/java/info/sigterm/deob/attributes/code/Instructions.java b/src/main/java/info/sigterm/deob/attributes/code/Instructions.java index 1eb0d27216..a591dd9a27 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/Instructions.java +++ b/src/main/java/info/sigterm/deob/attributes/code/Instructions.java @@ -232,10 +232,10 @@ public class Instructions i.renameClass(cf, name); } - public void renameField(Field f, String name) + public void renameField(Field f, info.sigterm.deob.pool.Field newField) { for (Instruction i : instructions) - i.renameField(f, name); + i.renameField(f, newField); } public void renameMethod(Method oldMethod, info.sigterm.deob.pool.Method newMethod) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/FieldInstruction.java b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/FieldInstruction.java index f3ed7bfa3f..d0d99fb163 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/FieldInstruction.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/FieldInstruction.java @@ -5,4 +5,6 @@ import info.sigterm.deob.pool.Field; public interface FieldInstruction { public Field getField(); + + public info.sigterm.deob.Field getMyField(); } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/GetField.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/GetField.java index 759d284370..f21a65cc8a 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/GetField.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/GetField.java @@ -61,6 +61,20 @@ public class GetField extends Instruction implements GetFieldInstruction return field; } + @Override + public info.sigterm.deob.Field getMyField() + { + Class clazz = field.getClassEntry(); + NameAndType nat = field.getNameAndType(); + + ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + if (cf == null) + return null; + + info.sigterm.deob.Field f2 = cf.findFieldDeep(nat); + return f2; + } + @Override public void renameClass(ClassFile cf, String name) { @@ -72,7 +86,7 @@ public class GetField extends Instruction implements GetFieldInstruction } @Override - public void renameField(info.sigterm.deob.Field f, String name) + public void renameField(info.sigterm.deob.Field f, Field newField) { Class clazz = field.getClassEntry(); NameAndType nat = field.getNameAndType(); @@ -85,9 +99,6 @@ public class GetField extends Instruction implements GetFieldInstruction assert f2 != null; if (f2 == f) - { - NameAndType newNat = new NameAndType(name, nat.getDescriptorType()); - field = new Field(clazz, newNat); - } + field = newField; } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/GetStatic.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/GetStatic.java index 3e25792a34..5db702abc2 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/GetStatic.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/GetStatic.java @@ -73,6 +73,20 @@ public class GetStatic extends Instruction implements GetFieldInstruction { return field; } + + @Override + public info.sigterm.deob.Field getMyField() + { + Class clazz = field.getClassEntry(); + NameAndType nat = field.getNameAndType(); + + ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + if (cf == null) + return null; + + info.sigterm.deob.Field f2 = cf.findFieldDeep(nat); + return f2; + } @Override public void renameClass(ClassFile cf, String name) @@ -85,7 +99,7 @@ public class GetStatic extends Instruction implements GetFieldInstruction } @Override - public void renameField(info.sigterm.deob.Field f, String name) + public void renameField(info.sigterm.deob.Field f, Field newField) { Class clazz = field.getClassEntry(); NameAndType nat = field.getNameAndType(); @@ -99,8 +113,7 @@ public class GetStatic extends Instruction implements GetFieldInstruction if (f2 == f) { - NameAndType newNat = new NameAndType(name, nat.getDescriptorType()); - field = new Field(clazz, newNat); + field = newField; } } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/PutField.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/PutField.java index 9099ebc38c..6a2316c76b 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/PutField.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/PutField.java @@ -55,6 +55,20 @@ public class PutField extends Instruction implements SetFieldInstruction { return field; } + + @Override + public info.sigterm.deob.Field getMyField() + { + Class clazz = field.getClassEntry(); + NameAndType nat = field.getNameAndType(); + + ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + if (cf == null) + return null; + + info.sigterm.deob.Field f2 = cf.findFieldDeep(nat); + return f2; + } @Override public void renameClass(ClassFile cf, String name) @@ -67,7 +81,7 @@ public class PutField extends Instruction implements SetFieldInstruction } @Override - public void renameField(info.sigterm.deob.Field f, String name) + public void renameField(info.sigterm.deob.Field f, Field newField) { Class clazz = field.getClassEntry(); NameAndType nat = field.getNameAndType(); @@ -80,8 +94,7 @@ public class PutField extends Instruction implements SetFieldInstruction if (f2 == f) { - NameAndType newNat = new NameAndType(name, nat.getDescriptorType()); - field = new Field(clazz, newNat); + field = newField; } } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/PutStatic.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/PutStatic.java index 42b073ec75..09212d4dd6 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/PutStatic.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/PutStatic.java @@ -55,6 +55,20 @@ public class PutStatic extends Instruction implements SetFieldInstruction return field; } + @Override + public info.sigterm.deob.Field getMyField() + { + Class clazz = field.getClassEntry(); + NameAndType nat = field.getNameAndType(); + + ClassFile cf = this.getInstructions().getCode().getAttributes().getClassFile().getGroup().findClass(clazz.getName()); + if (cf == null) + return null; + + info.sigterm.deob.Field f2 = cf.findFieldDeep(nat); + return f2; + } + @Override public void renameClass(ClassFile cf, String name) { @@ -66,7 +80,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction } @Override - public void renameField(info.sigterm.deob.Field f, String name) + public void renameField(info.sigterm.deob.Field f, Field newField) { Class clazz = field.getClassEntry(); NameAndType nat = field.getNameAndType(); @@ -79,8 +93,7 @@ public class PutStatic extends Instruction implements SetFieldInstruction if (f2 == f) { - NameAndType newNat = new NameAndType(name, nat.getDescriptorType()); - field = new Field(clazz, newNat); + field = newField; } } } diff --git a/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java b/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java new file mode 100644 index 0000000000..7617eb256a --- /dev/null +++ b/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java @@ -0,0 +1,124 @@ +package info.sigterm.deob.deobfuscators; + +import info.sigterm.deob.ClassFile; +import info.sigterm.deob.ClassGroup; +import info.sigterm.deob.Deobfuscator; +import info.sigterm.deob.Field; +import info.sigterm.deob.Method; +import info.sigterm.deob.attributes.Code; +import info.sigterm.deob.attributes.code.Instruction; +import info.sigterm.deob.attributes.code.instruction.types.FieldInstruction; +import info.sigterm.deob.pool.NameAndType; +import java.util.Collection; +import org.apache.commons.collections4.map.MultiValueMap; + +public class FieldMover implements Deobfuscator +{ + private ClassGroup group; + private MultiValueMap fields = new MultiValueMap<>(); + + private void findUses() + { + fields.clear(); + + for (ClassFile cf : group.getClasses()) + { + for (Method m : cf.getMethods().getMethods()) + { + Code code = m.getCode(); + + if (code == null) + continue; + + for (Instruction i : code.getInstructions().getInstructions()) + { + if (!(i instanceof FieldInstruction)) + continue; + + FieldInstruction fi = (FieldInstruction) i; + Field field = fi.getMyField(); + + if (field == null) + continue; + + if (!field.isStatic()) + continue; + + if (fields.containsKey(field)) + { + Collection col = fields.getCollection(field); + if (!col.contains(cf)) + fields.put(field, cf); + } + else + fields.put(field, cf); + } + } + } + } + + private int moveFields() + { + int count = 0; + + for (Field field : fields.keySet()) + { + Collection cfs = fields.getCollection(field); + + if (cfs.size() != 1) + { + // XXX clinit + continue; + } + + ClassFile cf = cfs.iterator().next(); + + if (field.getFields().getClassFile() == cf) + continue; + + moveField(field, cf); + ++count; + } + + return count; + } + + private void moveField(Field field, ClassFile to) + { + assert field.getFields().getClassFile() != to; + + info.sigterm.deob.pool.Field newField = new info.sigterm.deob.pool.Field( + new info.sigterm.deob.pool.Class(to.getName()), + new NameAndType(field.getName(), field.getType()) + ); + + // move on instructions + for (ClassFile cf : group.getClasses()) + { + for (Method m : cf.getMethods().getMethods()) + { + Code code = m.getCode(); + + if (code == null) + continue; + + code.getInstructions().renameField(field, newField); + } + } + + // move the field + field.getFields().getFields().remove(field); + to.getFields().getFields().add(field); + field.setFields(to.getFields()); + } + + @Override + public void run(ClassGroup group) + { + group.buildClassGraph(); + this.group = group; + findUses(); + moveFields(); + } + +} diff --git a/src/main/java/info/sigterm/deob/deobfuscators/RenameUnique.java b/src/main/java/info/sigterm/deob/deobfuscators/RenameUnique.java index 13f0d0e40d..4cb75489b7 100644 --- a/src/main/java/info/sigterm/deob/deobfuscators/RenameUnique.java +++ b/src/main/java/info/sigterm/deob/deobfuscators/RenameUnique.java @@ -95,7 +95,11 @@ public class RenameUnique implements Deobfuscator if (method.getCode() != null) { Instructions instructions = method.getCode().getInstructions(); - instructions.renameField(field, name); + info.sigterm.deob.pool.Field newField = new info.sigterm.deob.pool.Field( + new info.sigterm.deob.pool.Class(c.getName()), + new NameAndType(name, field.getType()) + ); + instructions.renameField(field, newField); } } }