diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index 95c8e75bbe..1bed050100 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -2,6 +2,7 @@ package info.sigterm.deob; import info.sigterm.deob.deobfuscators.IllegalStateExceptions; import info.sigterm.deob.deobfuscators.Jumps; +import info.sigterm.deob.deobfuscators.ModularArithmeticDeobfuscation; import info.sigterm.deob.deobfuscators.RuntimeExceptions; import info.sigterm.deob.deobfuscators.UnusedBlocks; import info.sigterm.deob.deobfuscators.UnusedMethods; @@ -57,6 +58,8 @@ public class Deob // remove jump obfuscation new Jumps().run(group); + + new ModularArithmeticDeobfuscation().run(group); saveJar(group, args[1]); diff --git a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/GetFieldInstruction.java b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/GetFieldInstruction.java new file mode 100644 index 0000000000..e0bdf7da21 --- /dev/null +++ b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/GetFieldInstruction.java @@ -0,0 +1,8 @@ +package info.sigterm.deob.attributes.code.instruction.types; + +import info.sigterm.deob.pool.Field; + +public interface GetFieldInstruction +{ + public Field getField(); +} diff --git a/src/main/java/info/sigterm/deob/attributes/code/instruction/types/PushConstantInstruction.java b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/PushConstantInstruction.java new file mode 100644 index 0000000000..18420a418b --- /dev/null +++ b/src/main/java/info/sigterm/deob/attributes/code/instruction/types/PushConstantInstruction.java @@ -0,0 +1,8 @@ +package info.sigterm.deob.attributes.code.instruction.types; + +import info.sigterm.deob.pool.PoolEntry; + +public interface PushConstantInstruction +{ + public PoolEntry getConstant(); +} 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 b98ceff926..8129e7d5e4 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 @@ -3,17 +3,19 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.GetFieldInstruction; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.Stack; import info.sigterm.deob.execution.StackContext; import info.sigterm.deob.execution.Type; import info.sigterm.deob.pool.Field; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class GetField extends Instruction +public class GetField extends Instruction implements GetFieldInstruction { private Field field; @@ -47,4 +49,10 @@ public class GetField extends Instruction frame.addInstructionContext(ins); } + + @Override + public Field getField() + { + return field; + } } 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 c67d09d0cc..674257dbee 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 @@ -4,6 +4,7 @@ import info.sigterm.deob.ClassFile; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.GetFieldInstruction; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.Stack; @@ -17,7 +18,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class GetStatic extends Instruction +public class GetStatic extends Instruction implements GetFieldInstruction { private Field field; @@ -65,4 +66,10 @@ public class GetStatic extends Instruction f.addReference(this); } + @Override + public Field getField() + { + return field; + } + } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC.java index f737c83175..01c21a29ef 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC.java @@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.Stack; @@ -13,7 +14,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class LDC extends Instruction +public class LDC extends Instruction implements PushConstantInstruction { private PoolEntry value; @@ -56,4 +57,10 @@ public class LDC extends Instruction frame.addInstructionContext(ins); } + + @Override + public PoolEntry getConstant() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC2_W.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC2_W.java index ae2507eafe..fe3e15c8c9 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC2_W.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC2_W.java @@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.Stack; @@ -13,7 +14,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class LDC2_W extends Instruction +public class LDC2_W extends Instruction implements PushConstantInstruction { private PoolEntry value; @@ -44,4 +45,10 @@ public class LDC2_W extends Instruction frame.addInstructionContext(ins); } + + @Override + public PoolEntry getConstant() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC_W.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC_W.java index 15a03c9d7d..b412ffd118 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC_W.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/LDC_W.java @@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.InstructionType; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.Stack; @@ -13,7 +14,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class LDC_W extends Instruction +public class LDC_W extends Instruction implements PushConstantInstruction { private PoolEntry value; @@ -59,4 +60,10 @@ public class LDC_W extends Instruction { return "ldc_w " + value; } + + @Override + public PoolEntry getConstant() + { + return value; + } } diff --git a/src/main/java/info/sigterm/deob/deobfuscators/ModularArithmeticDeobfuscation.java b/src/main/java/info/sigterm/deob/deobfuscators/ModularArithmeticDeobfuscation.java new file mode 100644 index 0000000000..af596c4e63 --- /dev/null +++ b/src/main/java/info/sigterm/deob/deobfuscators/ModularArithmeticDeobfuscation.java @@ -0,0 +1,135 @@ +package info.sigterm.deob.deobfuscators; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import info.sigterm.deob.ClassFile; +import info.sigterm.deob.ClassGroup; +import info.sigterm.deob.Method; +import info.sigterm.deob.attributes.Code; +import info.sigterm.deob.attributes.code.Instruction; +import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instruction.types.GetFieldInstruction; +import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction; +import info.sigterm.deob.attributes.code.instructions.IMul; +import info.sigterm.deob.execution.Execution; +import info.sigterm.deob.execution.Frame; +import info.sigterm.deob.execution.InstructionContext; +import info.sigterm.deob.execution.StackContext; +import info.sigterm.deob.pool.Field; + +public class ModularArithmeticDeobfuscation +{ + /* try to identify: + * + lvt = field * constant + getfield dy/e I + ldc 1512989863 + imul + istore_1 + + or + + field * constant compare+conditional jump + getstatic client/c I + ldc -2061786953 + imul + bipush 30 + if_icmpeq LABEL0x86 + + or + + (constant * field) - lvt + ldc 1512989863 + getstatic client/cq Ldy; + getfield dy/e I + imul + iload_1 + isub + + field * constant where result is: + stored in lvt + compared with something + any other operation with lvt + */ + private void run(Execution execution, ClassGroup group) + { + Map constants = new HashMap<>(); + for (Frame frame : execution.processedFrames) + { + for (InstructionContext ctx : frame.getInstructions()) + { + // I think it is easier to detect the getters instead of the setters, + // and then calculate the setters. + if (!(ctx.getInstruction() instanceof IMul)) + continue; + + // check for push constant and for get field instruction + Instruction one = ctx.getPops().get(0).getIns().getInstruction(); + Instruction two = ctx.getPops().get(1).getIns().getInstruction(); + + PushConstantInstruction pc = null; + GetFieldInstruction gf = null; + if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) + { + pc = (PushConstantInstruction) one; + gf = (GetFieldInstruction) two; + } + else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) + { + pc = (PushConstantInstruction) two; + gf = (GetFieldInstruction) one; + } + + if (pc == null) + continue; + + try + { + int constant = Integer.parseInt(pc.getConstant().toString()); + modInverse(constant); + } + catch (ArithmeticException ex) + { + continue; + } + + Integer old = constants.get(gf.getField()); + int newi = Integer.parseInt(pc.getConstant().toString()); + + if (old != null && (int) old != newi) + System.out.println("For " + gf.getField().getNameAndType().getName() + " in " + gf.getField().getClassEntry().getName() + " constant " + pc.getConstant().toString() + " mismatch on " + old); + + constants.put(gf.getField(), newi); + + // see what the result is used for? + } + } + } + + private static BigInteger modInverse(BigInteger val, int bits) + { + BigInteger shift = BigInteger.ONE.shiftLeft(bits); + return val.modInverse(shift); + } + + private static int modInverse(int val) + { + return modInverse(BigInteger.valueOf(val), 32).intValue(); + } + + private static long modInverse(long val) + { + return modInverse(BigInteger.valueOf(val), 64).intValue(); + } + + public void run(ClassGroup group) + { + Execution execution = new Execution(group); + execution.run(); + + run(execution, group); + } +} diff --git a/src/main/java/info/sigterm/deob/pool/Class.java b/src/main/java/info/sigterm/deob/pool/Class.java index f9aba1956e..02b4e53009 100644 --- a/src/main/java/info/sigterm/deob/pool/Class.java +++ b/src/main/java/info/sigterm/deob/pool/Class.java @@ -41,6 +41,12 @@ public class Class extends PoolEntry Class c = (Class) other; return name.equals(c.name); } + + @Override + public int hashCode() + { + return name.hashCode(); + } public java.lang.String getName() { diff --git a/src/main/java/info/sigterm/deob/pool/Field.java b/src/main/java/info/sigterm/deob/pool/Field.java index 0ce9e560f3..550ba39425 100644 --- a/src/main/java/info/sigterm/deob/pool/Field.java +++ b/src/main/java/info/sigterm/deob/pool/Field.java @@ -45,6 +45,12 @@ public class Field extends PoolEntry Field f = (Field) other; return clazz.equals(f.clazz) && nat.equals(f.nat); } + + @Override + public int hashCode() + { + return clazz.hashCode() ^ nat.hashCode(); + } public Class getClassEntry() { diff --git a/src/main/java/info/sigterm/deob/pool/Integer.java b/src/main/java/info/sigterm/deob/pool/Integer.java index bdc7c2a9b7..64cef71735 100644 --- a/src/main/java/info/sigterm/deob/pool/Integer.java +++ b/src/main/java/info/sigterm/deob/pool/Integer.java @@ -36,6 +36,12 @@ public class Integer extends PoolEntry Integer i = (Integer) other; return value == i.value; } + + @Override + public java.lang.String toString() + { + return "" + value; + } @Override public Type getTypeClass() diff --git a/src/main/java/info/sigterm/deob/pool/NameAndType.java b/src/main/java/info/sigterm/deob/pool/NameAndType.java index 580969287c..fff0e6dcdb 100644 --- a/src/main/java/info/sigterm/deob/pool/NameAndType.java +++ b/src/main/java/info/sigterm/deob/pool/NameAndType.java @@ -75,6 +75,12 @@ public class NameAndType extends PoolEntry NameAndType nat = (NameAndType) other; return name.equals(nat.name) && Objects.equals(signature, nat.signature) && Objects.equals(type, nat.type); } + + @Override + public int hashCode() + { + return name.hashCode(); + } public java.lang.String getName() {