Thinking on modinverse
This commit is contained in:
@@ -2,6 +2,7 @@ package info.sigterm.deob;
|
|||||||
|
|
||||||
import info.sigterm.deob.deobfuscators.IllegalStateExceptions;
|
import info.sigterm.deob.deobfuscators.IllegalStateExceptions;
|
||||||
import info.sigterm.deob.deobfuscators.Jumps;
|
import info.sigterm.deob.deobfuscators.Jumps;
|
||||||
|
import info.sigterm.deob.deobfuscators.ModularArithmeticDeobfuscation;
|
||||||
import info.sigterm.deob.deobfuscators.RuntimeExceptions;
|
import info.sigterm.deob.deobfuscators.RuntimeExceptions;
|
||||||
import info.sigterm.deob.deobfuscators.UnusedBlocks;
|
import info.sigterm.deob.deobfuscators.UnusedBlocks;
|
||||||
import info.sigterm.deob.deobfuscators.UnusedMethods;
|
import info.sigterm.deob.deobfuscators.UnusedMethods;
|
||||||
@@ -57,6 +58,8 @@ public class Deob
|
|||||||
|
|
||||||
// remove jump obfuscation
|
// remove jump obfuscation
|
||||||
new Jumps().run(group);
|
new Jumps().run(group);
|
||||||
|
|
||||||
|
new ModularArithmeticDeobfuscation().run(group);
|
||||||
|
|
||||||
saveJar(group, args[1]);
|
saveJar(group, args[1]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package info.sigterm.deob.attributes.code.instruction.types;
|
||||||
|
|
||||||
|
import info.sigterm.deob.pool.Field;
|
||||||
|
|
||||||
|
public interface GetFieldInstruction
|
||||||
|
{
|
||||||
|
public Field getField();
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package info.sigterm.deob.attributes.code.instruction.types;
|
||||||
|
|
||||||
|
import info.sigterm.deob.pool.PoolEntry;
|
||||||
|
|
||||||
|
public interface PushConstantInstruction
|
||||||
|
{
|
||||||
|
public PoolEntry getConstant();
|
||||||
|
}
|
||||||
@@ -3,17 +3,19 @@ package info.sigterm.deob.attributes.code.instructions;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
import info.sigterm.deob.attributes.code.InstructionType;
|
import info.sigterm.deob.attributes.code.InstructionType;
|
||||||
import info.sigterm.deob.attributes.code.Instructions;
|
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.Frame;
|
||||||
import info.sigterm.deob.execution.InstructionContext;
|
import info.sigterm.deob.execution.InstructionContext;
|
||||||
import info.sigterm.deob.execution.Stack;
|
import info.sigterm.deob.execution.Stack;
|
||||||
import info.sigterm.deob.execution.StackContext;
|
import info.sigterm.deob.execution.StackContext;
|
||||||
import info.sigterm.deob.execution.Type;
|
import info.sigterm.deob.execution.Type;
|
||||||
import info.sigterm.deob.pool.Field;
|
import info.sigterm.deob.pool.Field;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class GetField extends Instruction
|
public class GetField extends Instruction implements GetFieldInstruction
|
||||||
{
|
{
|
||||||
private Field field;
|
private Field field;
|
||||||
|
|
||||||
@@ -47,4 +49,10 @@ public class GetField extends Instruction
|
|||||||
|
|
||||||
frame.addInstructionContext(ins);
|
frame.addInstructionContext(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Field getField()
|
||||||
|
{
|
||||||
|
return field;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import info.sigterm.deob.ClassFile;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
import info.sigterm.deob.attributes.code.InstructionType;
|
import info.sigterm.deob.attributes.code.InstructionType;
|
||||||
import info.sigterm.deob.attributes.code.Instructions;
|
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.Frame;
|
||||||
import info.sigterm.deob.execution.InstructionContext;
|
import info.sigterm.deob.execution.InstructionContext;
|
||||||
import info.sigterm.deob.execution.Stack;
|
import info.sigterm.deob.execution.Stack;
|
||||||
@@ -17,7 +18,7 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class GetStatic extends Instruction
|
public class GetStatic extends Instruction implements GetFieldInstruction
|
||||||
{
|
{
|
||||||
private Field field;
|
private Field field;
|
||||||
|
|
||||||
@@ -65,4 +66,10 @@ public class GetStatic extends Instruction
|
|||||||
f.addReference(this);
|
f.addReference(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Field getField()
|
||||||
|
{
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
import info.sigterm.deob.attributes.code.InstructionType;
|
import info.sigterm.deob.attributes.code.InstructionType;
|
||||||
import info.sigterm.deob.attributes.code.Instructions;
|
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.Frame;
|
||||||
import info.sigterm.deob.execution.InstructionContext;
|
import info.sigterm.deob.execution.InstructionContext;
|
||||||
import info.sigterm.deob.execution.Stack;
|
import info.sigterm.deob.execution.Stack;
|
||||||
@@ -13,7 +14,7 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class LDC extends Instruction
|
public class LDC extends Instruction implements PushConstantInstruction
|
||||||
{
|
{
|
||||||
private PoolEntry value;
|
private PoolEntry value;
|
||||||
|
|
||||||
@@ -56,4 +57,10 @@ public class LDC extends Instruction
|
|||||||
|
|
||||||
frame.addInstructionContext(ins);
|
frame.addInstructionContext(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PoolEntry getConstant()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
import info.sigterm.deob.attributes.code.InstructionType;
|
import info.sigterm.deob.attributes.code.InstructionType;
|
||||||
import info.sigterm.deob.attributes.code.Instructions;
|
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.Frame;
|
||||||
import info.sigterm.deob.execution.InstructionContext;
|
import info.sigterm.deob.execution.InstructionContext;
|
||||||
import info.sigterm.deob.execution.Stack;
|
import info.sigterm.deob.execution.Stack;
|
||||||
@@ -13,7 +14,7 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class LDC2_W extends Instruction
|
public class LDC2_W extends Instruction implements PushConstantInstruction
|
||||||
{
|
{
|
||||||
private PoolEntry value;
|
private PoolEntry value;
|
||||||
|
|
||||||
@@ -44,4 +45,10 @@ public class LDC2_W extends Instruction
|
|||||||
|
|
||||||
frame.addInstructionContext(ins);
|
frame.addInstructionContext(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PoolEntry getConstant()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package info.sigterm.deob.attributes.code.instructions;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
import info.sigterm.deob.attributes.code.InstructionType;
|
import info.sigterm.deob.attributes.code.InstructionType;
|
||||||
import info.sigterm.deob.attributes.code.Instructions;
|
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.Frame;
|
||||||
import info.sigterm.deob.execution.InstructionContext;
|
import info.sigterm.deob.execution.InstructionContext;
|
||||||
import info.sigterm.deob.execution.Stack;
|
import info.sigterm.deob.execution.Stack;
|
||||||
@@ -13,7 +14,7 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class LDC_W extends Instruction
|
public class LDC_W extends Instruction implements PushConstantInstruction
|
||||||
{
|
{
|
||||||
private PoolEntry value;
|
private PoolEntry value;
|
||||||
|
|
||||||
@@ -59,4 +60,10 @@ public class LDC_W extends Instruction
|
|||||||
{
|
{
|
||||||
return "ldc_w " + value;
|
return "ldc_w " + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PoolEntry getConstant()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Field, Integer> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,12 @@ public class Class extends PoolEntry
|
|||||||
Class c = (Class) other;
|
Class c = (Class) other;
|
||||||
return name.equals(c.name);
|
return name.equals(c.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public java.lang.String getName()
|
public java.lang.String getName()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ public class Field extends PoolEntry
|
|||||||
Field f = (Field) other;
|
Field f = (Field) other;
|
||||||
return clazz.equals(f.clazz) && nat.equals(f.nat);
|
return clazz.equals(f.clazz) && nat.equals(f.nat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return clazz.hashCode() ^ nat.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public Class getClassEntry()
|
public Class getClassEntry()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ public class Integer extends PoolEntry
|
|||||||
Integer i = (Integer) other;
|
Integer i = (Integer) other;
|
||||||
return value == i.value;
|
return value == i.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.lang.String toString()
|
||||||
|
{
|
||||||
|
return "" + value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getTypeClass()
|
public Type getTypeClass()
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ public class NameAndType extends PoolEntry
|
|||||||
NameAndType nat = (NameAndType) other;
|
NameAndType nat = (NameAndType) other;
|
||||||
return name.equals(nat.name) && Objects.equals(signature, nat.signature) && Objects.equals(type, nat.type);
|
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()
|
public java.lang.String getName()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user