diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index 73d4cb80bb..79dada7ecb 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -1,6 +1,8 @@ package info.sigterm.deob; +import info.sigterm.deob.deobfuscators.FieldInliner; import info.sigterm.deob.deobfuscators.FieldMover; +import info.sigterm.deob.deobfuscators.MethodMover; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -94,9 +96,11 @@ public class Deob // new ModularArithmeticDeobfuscation().run(group); - //new MethodMover().run(group); +// new MethodMover().run(group); +// +// new FieldMover().run(group); - new FieldMover().run(group); + new FieldInliner().run(group); saveJar(group, args[1]); diff --git a/src/main/java/info/sigterm/deob/attributes/Attribute.java b/src/main/java/info/sigterm/deob/attributes/Attribute.java index 34f80d29c1..a01b5779c0 100644 --- a/src/main/java/info/sigterm/deob/attributes/Attribute.java +++ b/src/main/java/info/sigterm/deob/attributes/Attribute.java @@ -20,6 +20,13 @@ public abstract class Attribute this.length = is.readInt(); } + Attribute(Attributes attr, AttributeType type, int length) + { + this.attributes = attr; + this.type = type; + this.length = length; + } + public final void write(DataOutputStream out) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); @@ -28,6 +35,8 @@ public abstract class Attribute byte[] b = bout.toByteArray(); out.writeInt(b.length); out.write(b); + + length = b.length; } public abstract void writeAttr(DataOutputStream out) throws IOException; diff --git a/src/main/java/info/sigterm/deob/attributes/Attributes.java b/src/main/java/info/sigterm/deob/attributes/Attributes.java index 00de68452a..e73bb053ec 100644 --- a/src/main/java/info/sigterm/deob/attributes/Attributes.java +++ b/src/main/java/info/sigterm/deob/attributes/Attributes.java @@ -117,4 +117,10 @@ public class Attributes a.write(out); } } + + public void addAttribute(Attribute a) + { + assert a.getAttributes() == this; + attributes.add(a); + } } diff --git a/src/main/java/info/sigterm/deob/attributes/ConstantValue.java b/src/main/java/info/sigterm/deob/attributes/ConstantValue.java index 99f023cc08..d18ba41f4a 100644 --- a/src/main/java/info/sigterm/deob/attributes/ConstantValue.java +++ b/src/main/java/info/sigterm/deob/attributes/ConstantValue.java @@ -17,6 +17,13 @@ public class ConstantValue extends Attribute DataInputStream is = attributes.getStream(); value = this.getAttributes().getClassFile().getPool().getEntry(is.readUnsignedShort()); } + + public ConstantValue(Attributes attributes, PoolEntry value) + { + super(attributes, AttributeType.CONSTANT_VALUE, -1); + + this.value = value; + } public PoolEntry getValue() { diff --git a/src/main/java/info/sigterm/deob/deobfuscators/FieldInliner.java b/src/main/java/info/sigterm/deob/deobfuscators/FieldInliner.java new file mode 100644 index 0000000000..1882981794 --- /dev/null +++ b/src/main/java/info/sigterm/deob/deobfuscators/FieldInliner.java @@ -0,0 +1,187 @@ +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.AttributeType; +import info.sigterm.deob.attributes.Attributes; +import info.sigterm.deob.attributes.Code; +import info.sigterm.deob.attributes.ConstantValue; +import info.sigterm.deob.attributes.code.Instruction; +import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.FieldInstruction; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; +import info.sigterm.deob.attributes.code.instruction.types.SetFieldInstruction; +import info.sigterm.deob.attributes.code.instructions.LDC_W; +import info.sigterm.deob.attributes.code.instructions.NOP; +import java.util.ArrayList; +import java.util.List; + +public class FieldInliner implements Deobfuscator +{ + private ClassGroup group; + private List fields = new ArrayList<>(); + + private List findFieldIns(Field field, boolean set) + { + List ins = new ArrayList<>(); + + 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 sf = (FieldInstruction) i; + + if (sf.getMyField() != field) + continue; + + if (sf instanceof SetFieldInstruction != set) + continue; + + ins.add(sf); + } + } + } + + return ins; + } + + private void makeConstantValues() + { + for (ClassFile cf : group.getClasses()) + { + for (Field f : cf.getFields().getFields()) + { + if (!f.isStatic() || !f.getType().getFullType().equals("Ljava/lang/String;")) + continue; + + Attributes attributes = f.getAttributes(); + ConstantValue constantValue = (ConstantValue) attributes.findType(AttributeType.CONSTANT_VALUE); + if (constantValue != null) + continue; + + List sfis = findFieldIns(f, true); + if (sfis.size() != 1) + continue; + + SetFieldInstruction sfi = (SetFieldInstruction) sfis.get(0); + Instruction ins = (Instruction) sfi; + + Method mOfSet = ins.getInstructions().getCode().getAttributes().getMethod(); + if (!mOfSet.getName().equals("")) + continue; + + // get prev instruction and change to a constant value + Instructions instructions = mOfSet.getCode().getInstructions(); + int idx = instructions.getInstructions().indexOf(ins); + assert idx != -1; + + Instruction prev = instructions.getInstructions().get(idx - 1); + if (!(prev instanceof PushConstantInstruction)) + continue; + + PushConstantInstruction pci = (PushConstantInstruction) prev; + + constantValue = new ConstantValue(attributes, pci.getConstant()); + attributes.addAttribute(constantValue); + + fields.add(f); + + // nop + NOP nop1 = new NOP(instructions), nop2 = new NOP(instructions); + + for (Instruction i : prev.from) + { + i.jump.remove(prev); + i.jump.add(nop1); + i.replace(prev, nop1); + } + prev.from.clear(); + + for (Instruction i : ins.from) + { + i.jump.remove(ins); + i.jump.add(nop1); + i.replace(ins, nop1); + } + ins.from.clear(); + + boolean b = instructions.getInstructions().remove(prev); + assert b; + b = instructions.getInstructions().remove(ins); + assert b; + + instructions.getInstructions().add(idx - 1, nop1); + instructions.getInstructions().add(idx, nop2); + } + } + } + + public int inlineUse() + { + int count = 0; + + for (Field f : fields) + { + // replace getfield with constant push + List fins = findFieldIns(f, false); + ConstantValue value = (ConstantValue) f.getAttributes().findType(AttributeType.CONSTANT_VALUE); + + for (FieldInstruction fin : fins) + { + // remove fin, add push constant + Instruction i = (Instruction) fin; + + i.getInstructions().buildJumpGraph(); + + Instruction pushIns = new LDC_W(i.getInstructions(), value.getValue()); + + List instructions = i.getInstructions().getInstructions(); + + int idx = instructions.indexOf(i); + assert idx != -1; + + // move jumps to i to pushIns + for (Instruction i2 : i.from) + { + i2.jump.remove(i); + i2.jump.add(pushIns); + i2.replace(i, pushIns); + } + i.from.clear(); + + i.getInstructions().remove(i); + instructions.add(idx, pushIns); + + ++count; + } + + f.getFields().getFields().remove(f); + } + + return count; + } + + @Override + public void run(ClassGroup group) + { + this.group = group; + makeConstantValues(); + int count = inlineUse(); + + System.out.println("Inlined " + count + " fields"); + } + +} diff --git a/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java b/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java index 7617eb256a..6e96c78be0 100644 --- a/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java +++ b/src/main/java/info/sigterm/deob/deobfuscators/FieldMover.java @@ -118,7 +118,9 @@ public class FieldMover implements Deobfuscator group.buildClassGraph(); this.group = group; findUses(); - moveFields(); + int count = moveFields(); + + System.out.println("Moved " + count + " fields"); } }