Rewrite multi deob, this looks rather nice
This commit is contained in:
@@ -84,11 +84,11 @@ public class Deob
|
||||
|
||||
//new ModArith().run(group);
|
||||
|
||||
//new MultiplicationDeobfuscator().run(group); // this causes spinning?
|
||||
new MultiplicationDeobfuscator().run(group); // this causes spinning?
|
||||
|
||||
new MultiplyOneDeobfuscator().run(group);
|
||||
|
||||
new MultiplyZeroDeobfuscator().run(group);
|
||||
// new MultiplyOneDeobfuscator().run(group);
|
||||
//
|
||||
// new MultiplyZeroDeobfuscator().run(group);
|
||||
|
||||
saveJar(group, args[1]);
|
||||
|
||||
|
||||
+190
-52
@@ -1,15 +1,18 @@
|
||||
package net.runelite.deob.deobfuscators.arithmetic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.runelite.deob.ClassGroup;
|
||||
import net.runelite.deob.Deobfuscator;
|
||||
import net.runelite.deob.attributes.code.Instruction;
|
||||
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.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.ISub;
|
||||
import net.runelite.deob.attributes.code.instructions.SiPush;
|
||||
import net.runelite.deob.execution.Execution;
|
||||
import net.runelite.deob.execution.Frame;
|
||||
@@ -28,42 +31,141 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
||||
this.group = group;
|
||||
|
||||
int i;
|
||||
int count = 0;
|
||||
while ((i = runOnce()) > 0)
|
||||
{
|
||||
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())
|
||||
{
|
||||
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();
|
||||
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);
|
||||
MultiplicationExpression other = parseExpression(i); // parse this side of the add/sub
|
||||
|
||||
//if (other != null)
|
||||
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)
|
||||
if (f.getMethod() == frame.getMethod())
|
||||
for (InstructionContext i : f.getInstructions())
|
||||
if (i.getInstruction() == ctx.getInstruction())
|
||||
Collection<InstructionContext> ins = execution.getInstructonContexts(ctx.getInstruction());
|
||||
for (InstructionContext i : ins)
|
||||
//for (Frame f : execution.processedFrames)
|
||||
// if (f.getMethod() == frame.getMethod())
|
||||
// for (InstructionContext i : f.getInstructions())
|
||||
//if (i.getInstruction() == ctx.getInstruction())
|
||||
{
|
||||
if (!i.equals(ctx))
|
||||
{
|
||||
@@ -73,6 +175,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<Instruction> done = new HashSet<>();
|
||||
private int runOnce()
|
||||
{
|
||||
group.buildClassGraph();
|
||||
@@ -81,7 +184,7 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
||||
e.populateInitialMethods();
|
||||
e.run();
|
||||
|
||||
Set<Instruction> done = new HashSet<>();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (Frame frame : e.processedFrames)
|
||||
@@ -91,52 +194,87 @@ public class MultiplicationDeobfuscator implements Deobfuscator
|
||||
Instruction instruction = ictx.getInstruction();
|
||||
Instructions instructions = instruction.getInstructions();
|
||||
|
||||
// if (!frame.getMethod().getMethods().getClassFile().getName().equals("class114"))
|
||||
// continue;
|
||||
|
||||
if (!(instruction instanceof IMul))
|
||||
continue;
|
||||
|
||||
List<InstructionContext> ins = getConstants(ictx);
|
||||
MultiplicationExpression expression;
|
||||
try
|
||||
{
|
||||
expression = parseExpression(ictx);
|
||||
}
|
||||
catch (IllegalStateException ex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ins.size() == 1)
|
||||
if (expression == null)
|
||||
continue;
|
||||
|
||||
for (InstructionContext i : ins)
|
||||
{
|
||||
if (done.contains(i.getInstruction()))
|
||||
{
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
//if (expression.subexpressions.isEmpty())
|
||||
// continue;
|
||||
|
||||
// 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;
|
||||
|
||||
int result = 1;
|
||||
|
||||
if (done.contains(instruction))
|
||||
continue;
|
||||
done.add(instruction);
|
||||
|
||||
// calculate result
|
||||
for (InstructionContext i : ins)
|
||||
count += expression.simplify(1);
|
||||
if (MultiplicationExpression.replace)
|
||||
{
|
||||
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
|
||||
int value = (int) pci.getConstant().getObject();
|
||||
|
||||
result *= value;
|
||||
MultiplicationExpression.replace = false;
|
||||
return count;
|
||||
}
|
||||
|
||||
// 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());
|
||||
//break;
|
||||
// List<InstructionContext> ins = getConstants(ictx);
|
||||
//
|
||||
// if (ins.size() == 1)
|
||||
// continue;
|
||||
//
|
||||
// for (InstructionContext i : ins)
|
||||
// {
|
||||
// if (done.contains(i.getInstruction()))
|
||||
// {
|
||||
// continue outer;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // there can only be one path to here, or else combinging would change code logic
|
||||
// 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;
|
||||
|
||||
+56
@@ -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
|
||||
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
|
||||
private Encryption encryption;
|
||||
public MultiValueMap<Instruction, InstructionContext> contexts = new MultiValueMap<>();
|
||||
|
||||
public Execution(ClassGroup group)
|
||||
{
|
||||
@@ -102,4 +103,9 @@ public class Execution
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
InstructionContext ictx = this.instructions.get(this.instructions.size() - 1);
|
||||
assert ictx.getInstruction() == oldCur;
|
||||
execution.contexts.put(oldCur, ictx);
|
||||
|
||||
execution.executed.add(oldCur);
|
||||
|
||||
processExceptions(oldCur);
|
||||
|
||||
Reference in New Issue
Block a user