Rewrite multi deob, this looks rather nice
This commit is contained in:
@@ -84,11 +84,11 @@ public class Deob
|
|||||||
|
|
||||||
//new ModArith().run(group);
|
//new ModArith().run(group);
|
||||||
|
|
||||||
//new MultiplicationDeobfuscator().run(group); // this causes spinning?
|
new MultiplicationDeobfuscator().run(group); // this causes spinning?
|
||||||
|
|
||||||
new MultiplyOneDeobfuscator().run(group);
|
// new MultiplyOneDeobfuscator().run(group);
|
||||||
|
//
|
||||||
new MultiplyZeroDeobfuscator().run(group);
|
// new MultiplyZeroDeobfuscator().run(group);
|
||||||
|
|
||||||
saveJar(group, args[1]);
|
saveJar(group, args[1]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
package net.runelite.deob.deobfuscators.arithmetic;
|
package net.runelite.deob.deobfuscators.arithmetic;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import net.runelite.deob.ClassGroup;
|
import net.runelite.deob.ClassGroup;
|
||||||
import net.runelite.deob.Deobfuscator;
|
import net.runelite.deob.Deobfuscator;
|
||||||
import net.runelite.deob.attributes.code.Instruction;
|
import net.runelite.deob.attributes.code.Instruction;
|
||||||
import net.runelite.deob.attributes.code.Instructions;
|
import net.runelite.deob.attributes.code.Instructions;
|
||||||
|
import net.runelite.deob.attributes.code.instruction.types.GetFieldInstruction;
|
||||||
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
|
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
|
||||||
|
import net.runelite.deob.attributes.code.instructions.BiPush;
|
||||||
|
import net.runelite.deob.attributes.code.instructions.IAdd;
|
||||||
import net.runelite.deob.attributes.code.instructions.IMul;
|
import net.runelite.deob.attributes.code.instructions.IMul;
|
||||||
|
import net.runelite.deob.attributes.code.instructions.ISub;
|
||||||
import net.runelite.deob.attributes.code.instructions.SiPush;
|
import net.runelite.deob.attributes.code.instructions.SiPush;
|
||||||
import net.runelite.deob.execution.Execution;
|
import net.runelite.deob.execution.Execution;
|
||||||
import net.runelite.deob.execution.Frame;
|
import net.runelite.deob.execution.Frame;
|
||||||
@@ -28,42 +31,141 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
|||||||
this.group = group;
|
this.group = group;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
int count = 0;
|
||||||
while ((i = runOnce()) > 0)
|
while ((i = runOnce()) > 0)
|
||||||
|
{
|
||||||
System.out.println("Replaced " + i + " constants");
|
System.out.println("Replaced " + i + " constants");
|
||||||
|
count += i;
|
||||||
|
}
|
||||||
|
System.out.println("Total changed " + count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InstructionContext> getConstants(InstructionContext ctx)
|
private MultiplicationExpression parseExpression(InstructionContext ctx)
|
||||||
|
//private List<InstructionContext> getConstants(InstructionContext ctx)
|
||||||
{
|
{
|
||||||
List<InstructionContext> l = new ArrayList<>();
|
MultiplicationExpression me = new MultiplicationExpression();
|
||||||
|
|
||||||
assert ctx.getInstruction() instanceof IMul;
|
//assert ctx.getInstruction() instanceof IMul;
|
||||||
|
|
||||||
|
//
|
||||||
|
if (ctx.getInstruction() instanceof PushConstantInstruction)
|
||||||
|
{
|
||||||
|
if (ctx.getInstruction() instanceof BiPush || ctx.getInstruction() instanceof SiPush)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushConstantInstruction pci = (PushConstantInstruction) ctx.getInstruction();
|
||||||
|
// int value = (int) pci.getConstant().getObject();
|
||||||
|
//
|
||||||
|
// if (value == 1)
|
||||||
|
// return null
|
||||||
|
|
||||||
|
me.instructions.add(ctx);
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
for (StackContext sctx : ctx.getPops())
|
for (StackContext sctx : ctx.getPops())
|
||||||
{
|
{
|
||||||
InstructionContext i = sctx.getPushed();
|
InstructionContext i = sctx.getPushed();
|
||||||
|
|
||||||
if (i.getInstruction() instanceof IMul)
|
// if this instruction is imul, look at pops
|
||||||
|
if (ctx.getInstruction() instanceof IMul)
|
||||||
{
|
{
|
||||||
l.addAll(getConstants(i));
|
if (i.getInstruction() instanceof PushConstantInstruction)
|
||||||
|
{
|
||||||
|
if (i.getInstruction() instanceof BiPush || i.getInstruction() instanceof SiPush)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
// a constant of imul
|
||||||
|
me.instructions.add(i);
|
||||||
|
}
|
||||||
|
else if (i.getInstruction() instanceof IMul)
|
||||||
|
{
|
||||||
|
// chained imul, append to me
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MultiplicationExpression other = parseExpression(i);
|
||||||
|
|
||||||
|
me.instructions.addAll(other.instructions);
|
||||||
|
me.subexpressions.addAll(other.subexpressions);
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex)
|
||||||
|
{
|
||||||
|
// this is ok? just don't include it?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub)
|
||||||
|
{
|
||||||
|
// imul using result of iadd or isub. evaluate expression
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MultiplicationExpression other = parseExpression(i);
|
||||||
|
|
||||||
|
// subexpr
|
||||||
|
//if (other != null)
|
||||||
|
me.subexpressions.add(other);
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex)
|
||||||
|
{
|
||||||
|
assert me.subexpressions.isEmpty();
|
||||||
|
// subexpression is too complex. we can still simplify the top level though
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i.getInstruction() instanceof GetFieldInstruction)
|
||||||
|
{
|
||||||
|
// non constant, ignore
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//throw new IllegalStateException();
|
||||||
|
//System.out.println("imul pops something I don't know " + i.getInstruction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (i.getInstruction() instanceof PushConstantInstruction)
|
// this is an iadd/sub
|
||||||
|
else if (ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub)
|
||||||
{
|
{
|
||||||
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
MultiplicationExpression other = parseExpression(i); // parse this side of the add/sub
|
||||||
int value = (int) pci.getConstant().getObject();
|
|
||||||
if (value != 1) // already been touched, otherwise we keep multiplying the same ins over and over
|
//if (other != null)
|
||||||
l.add(i);
|
me.subexpressions.add(other);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//throw new IllegalStateException();
|
||||||
|
//System.out.println(ctx.getInstruction() + " pops something I dont know " + i.getInstruction());
|
||||||
|
}
|
||||||
|
// else if (i.getInstruction() instanceof PushConstantInstruction)
|
||||||
|
// {
|
||||||
|
// me.instructions.add(i);
|
||||||
|
// //PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||||
|
// //int value = (int) pci.getConstant().getObject();
|
||||||
|
// //if (value != 1) // already been touched, otherwise we keep multiplying the same ins over and over
|
||||||
|
// // l.add(i);
|
||||||
|
// }
|
||||||
|
// else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub)
|
||||||
|
// {
|
||||||
|
// MultiplicationExpression other = parseExpression(i);
|
||||||
|
//
|
||||||
|
// me.subexpressions.add(other);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return l;
|
if (me.instructions.isEmpty() && me.subexpressions.isEmpty())
|
||||||
|
throw new IllegalStateException();
|
||||||
|
//return null;
|
||||||
|
|
||||||
|
return me;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOnlyPath(Execution execution, Frame frame, InstructionContext ctx)
|
private boolean isOnlyPath(Execution execution, InstructionContext ctx)
|
||||||
{
|
{
|
||||||
for (Frame f : execution.processedFrames)
|
Collection<InstructionContext> ins = execution.getInstructonContexts(ctx.getInstruction());
|
||||||
if (f.getMethod() == frame.getMethod())
|
for (InstructionContext i : ins)
|
||||||
for (InstructionContext i : f.getInstructions())
|
//for (Frame f : execution.processedFrames)
|
||||||
if (i.getInstruction() == ctx.getInstruction())
|
// if (f.getMethod() == frame.getMethod())
|
||||||
|
// for (InstructionContext i : f.getInstructions())
|
||||||
|
//if (i.getInstruction() == ctx.getInstruction())
|
||||||
{
|
{
|
||||||
if (!i.equals(ctx))
|
if (!i.equals(ctx))
|
||||||
{
|
{
|
||||||
@@ -73,6 +175,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<Instruction> done = new HashSet<>();
|
||||||
private int runOnce()
|
private int runOnce()
|
||||||
{
|
{
|
||||||
group.buildClassGraph();
|
group.buildClassGraph();
|
||||||
@@ -81,7 +184,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
|||||||
e.populateInitialMethods();
|
e.populateInitialMethods();
|
||||||
e.run();
|
e.run();
|
||||||
|
|
||||||
Set<Instruction> done = new HashSet<>();
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (Frame frame : e.processedFrames)
|
for (Frame frame : e.processedFrames)
|
||||||
@@ -91,52 +194,87 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
|||||||
Instruction instruction = ictx.getInstruction();
|
Instruction instruction = ictx.getInstruction();
|
||||||
Instructions instructions = instruction.getInstructions();
|
Instructions instructions = instruction.getInstructions();
|
||||||
|
|
||||||
|
// if (!frame.getMethod().getMethods().getClassFile().getName().equals("class114"))
|
||||||
|
// continue;
|
||||||
|
|
||||||
if (!(instruction instanceof IMul))
|
if (!(instruction instanceof IMul))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
List<InstructionContext> ins = getConstants(ictx);
|
MultiplicationExpression expression;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
expression = parseExpression(ictx);
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ins.size() == 1)
|
if (expression == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (InstructionContext i : ins)
|
//if (expression.subexpressions.isEmpty())
|
||||||
{
|
// continue;
|
||||||
if (done.contains(i.getInstruction()))
|
|
||||||
{
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// there can only be one path to here, or else combinging would change code logic
|
// there can only be one path to here, or else combinging would change code logic
|
||||||
if (!isOnlyPath(e, frame, ictx))
|
if (!isOnlyPath(e, ictx))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int result = 1;
|
|
||||||
|
if (done.contains(instruction))
|
||||||
|
continue;
|
||||||
|
done.add(instruction);
|
||||||
|
|
||||||
// calculate result
|
count += expression.simplify(1);
|
||||||
for (InstructionContext i : ins)
|
if (MultiplicationExpression.replace)
|
||||||
{
|
{
|
||||||
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
MultiplicationExpression.replace = false;
|
||||||
int value = (int) pci.getConstant().getObject();
|
return count;
|
||||||
|
|
||||||
result *= value;
|
|
||||||
}
|
}
|
||||||
|
//break;
|
||||||
// set result on ins
|
// List<InstructionContext> ins = getConstants(ictx);
|
||||||
for (InstructionContext i : ins)
|
//
|
||||||
{
|
// if (ins.size() == 1)
|
||||||
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
// continue;
|
||||||
Instruction newIns = pci.setConstant(new net.runelite.deob.pool.Integer(result));
|
//
|
||||||
++count;
|
// for (InstructionContext i : ins)
|
||||||
if (newIns != pci)
|
// {
|
||||||
{
|
// if (done.contains(i.getInstruction()))
|
||||||
instructions.replace((Instruction) pci, newIns);
|
// {
|
||||||
}
|
// continue outer;
|
||||||
result = 1; // rest of the results go to 1
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for (InstructionContext i : ins)
|
// // there can only be one path to here, or else combinging would change code logic
|
||||||
done.add(i.getInstruction());
|
// if (!isOnlyPath(e, frame, ictx))
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// int result = 1;
|
||||||
|
//
|
||||||
|
// // calculate result
|
||||||
|
// for (InstructionContext i : ins)
|
||||||
|
// {
|
||||||
|
// PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||||
|
// int value = (int) pci.getConstant().getObject();
|
||||||
|
//
|
||||||
|
// result *= value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // set result on ins
|
||||||
|
// for (InstructionContext i : ins)
|
||||||
|
// {
|
||||||
|
// PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||||
|
// Instruction newIns = pci.setConstant(new net.runelite.deob.pool.Integer(result));
|
||||||
|
// ++count;
|
||||||
|
// if (newIns != pci)
|
||||||
|
// {
|
||||||
|
// instructions.replace((Instruction) pci, newIns);
|
||||||
|
// }
|
||||||
|
// result = 1; // rest of the results go to 1
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (InstructionContext i : ins)
|
||||||
|
// done.add(i.getInstruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package net.runelite.deob.deobfuscators.arithmetic;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import net.runelite.deob.attributes.code.Instruction;
|
||||||
|
import net.runelite.deob.attributes.code.instruction.types.PushConstantInstruction;
|
||||||
|
import net.runelite.deob.execution.InstructionContext;
|
||||||
|
|
||||||
|
public class MultiplicationExpression
|
||||||
|
{
|
||||||
|
List<InstructionContext> instructions = new ArrayList<>(); // push constant instructions that are being multiplied
|
||||||
|
List<MultiplicationExpression> subexpressions = new ArrayList<>(); // for distributing, each subexpr is * by this
|
||||||
|
static boolean replace;
|
||||||
|
|
||||||
|
int simplify(int start)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int result = start;
|
||||||
|
|
||||||
|
// calculate result
|
||||||
|
for (InstructionContext i : instructions)
|
||||||
|
{
|
||||||
|
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||||
|
int value = (int) pci.getConstant().getObject();
|
||||||
|
|
||||||
|
result *= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiply subexpressions by result
|
||||||
|
if (!subexpressions.isEmpty())
|
||||||
|
{
|
||||||
|
for (MultiplicationExpression me : subexpressions)
|
||||||
|
{
|
||||||
|
count += me.simplify(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 1; // constant has been distributed, outer numbers all go to 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// set result on ins
|
||||||
|
for (InstructionContext i : instructions)
|
||||||
|
{
|
||||||
|
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||||
|
Instruction newIns = pci.setConstant(new net.runelite.deob.pool.Integer(result));
|
||||||
|
++count;
|
||||||
|
if (newIns != pci)
|
||||||
|
{
|
||||||
|
newIns.getInstructions().replace((Instruction) pci, newIns);
|
||||||
|
replace = true;
|
||||||
|
}
|
||||||
|
result = 1; // rest of the results go to 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ public class Execution
|
|||||||
public Set<Instruction> executed = new HashSet<>(); // executed instructions
|
public Set<Instruction> executed = new HashSet<>(); // executed instructions
|
||||||
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
|
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
|
||||||
private Encryption encryption;
|
private Encryption encryption;
|
||||||
|
public MultiValueMap<Instruction, InstructionContext> contexts = new MultiValueMap<>();
|
||||||
|
|
||||||
public Execution(ClassGroup group)
|
public Execution(ClassGroup group)
|
||||||
{
|
{
|
||||||
@@ -102,4 +103,9 @@ public class Execution
|
|||||||
|
|
||||||
System.out.println("Processed " + fcount + " frames");
|
System.out.println("Processed " + fcount + " frames");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<InstructionContext> getInstructonContexts(Instruction i)
|
||||||
|
{
|
||||||
|
return contexts.getCollection(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ public class Frame
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstructionContext ictx = this.instructions.get(this.instructions.size() - 1);
|
||||||
|
assert ictx.getInstruction() == oldCur;
|
||||||
|
execution.contexts.put(oldCur, ictx);
|
||||||
|
|
||||||
execution.executed.add(oldCur);
|
execution.executed.add(oldCur);
|
||||||
|
|
||||||
processExceptions(oldCur);
|
processExceptions(oldCur);
|
||||||
|
|||||||
Reference in New Issue
Block a user