hn
This commit is contained in:
@@ -31,67 +31,67 @@ public class Deob
|
||||
|
||||
ClassGroup group = JarUtil.loadJar(new File(args[0]));
|
||||
|
||||
run(group, new RenameUnique());
|
||||
|
||||
// remove except RuntimeException
|
||||
run(group, new RuntimeExceptions());
|
||||
|
||||
// remove unused methods
|
||||
run(group, new UnreachedCode());
|
||||
run(group, new UnusedMethods());
|
||||
|
||||
// remove illegal state exceptions, frees up some parameters
|
||||
run(group, new IllegalStateExceptions());
|
||||
|
||||
// remove constant logically dead parameters
|
||||
run(group, new ConstantParameter());
|
||||
|
||||
// remove unhit blocks
|
||||
run(group, new UnreachedCode());
|
||||
run(group, new UnusedMethods());
|
||||
|
||||
// remove unused parameters
|
||||
run(group, new UnusedParameters());
|
||||
|
||||
// run(group, new RenameUnique());
|
||||
//
|
||||
// // remove except RuntimeException
|
||||
// run(group, new RuntimeExceptions());
|
||||
//
|
||||
// // remove unused methods
|
||||
// run(group, new UnreachedCode());
|
||||
// run(group, new UnusedMethods());
|
||||
//
|
||||
// // remove illegal state exceptions, frees up some parameters
|
||||
// run(group, new IllegalStateExceptions());
|
||||
//
|
||||
// // remove constant logically dead parameters
|
||||
// run(group, new ConstantParameter());
|
||||
//
|
||||
// // remove unhit blocks
|
||||
// run(group, new UnreachedCode());
|
||||
// run(group, new UnusedMethods());
|
||||
//
|
||||
// // remove unused parameters
|
||||
// run(group, new UnusedParameters());
|
||||
//
|
||||
// remove unused fields
|
||||
run(group, new UnusedFields());
|
||||
|
||||
// remove unused methods, again?
|
||||
run(group, new UnusedMethods());
|
||||
|
||||
// run(group, new MethodInliner());
|
||||
// run(group, new UnusedMethods()); // inliner might leave unused methods
|
||||
|
||||
// // broken because rename was removed
|
||||
// //run(group, new MethodMover());
|
||||
|
||||
run(group, new FieldInliner());
|
||||
|
||||
// // XXX this is broken because when moving clinit around, some fields can depend on other fields
|
||||
// // (like multianewarray)
|
||||
// //new FieldMover().run(group);
|
||||
|
||||
run(group, new UnusedClass());
|
||||
|
||||
ModArith mod = new ModArith();
|
||||
mod.run(group);
|
||||
|
||||
int last = -1, cur;
|
||||
while ((cur = mod.runOnce()) > 0)
|
||||
{
|
||||
new MultiplicationDeobfuscator().run(group);
|
||||
|
||||
new MultiplyOneDeobfuscator().run(group);
|
||||
|
||||
new MultiplyZeroDeobfuscator().run(group);
|
||||
|
||||
if (last == cur)
|
||||
break;
|
||||
|
||||
last = cur;
|
||||
}
|
||||
|
||||
mod.annotateEncryption();
|
||||
//
|
||||
// // remove unused methods, again?
|
||||
// run(group, new UnusedMethods());
|
||||
//
|
||||
//// run(group, new MethodInliner());
|
||||
//// run(group, new UnusedMethods()); // inliner might leave unused methods
|
||||
//
|
||||
//// // broken because rename was removed
|
||||
//// //run(group, new MethodMover());
|
||||
//
|
||||
// run(group, new FieldInliner());
|
||||
//
|
||||
//// // XXX this is broken because when moving clinit around, some fields can depend on other fields
|
||||
//// // (like multianewarray)
|
||||
//// //new FieldMover().run(group);
|
||||
//
|
||||
// run(group, new UnusedClass());
|
||||
//
|
||||
// ModArith mod = new ModArith();
|
||||
// mod.run(group);
|
||||
//
|
||||
// int last = -1, cur;
|
||||
// while ((cur = mod.runOnce()) > 0)
|
||||
// {
|
||||
// new MultiplicationDeobfuscator().run(group);
|
||||
//
|
||||
// new MultiplyOneDeobfuscator().run(group);
|
||||
//
|
||||
// new MultiplyZeroDeobfuscator().run(group);
|
||||
//
|
||||
// if (last == cur)
|
||||
// break;
|
||||
//
|
||||
// last = cur;
|
||||
// }
|
||||
//
|
||||
// mod.annotateEncryption();
|
||||
|
||||
// eval constant fields (only set once to a constant in ctor) maybe just inline them
|
||||
|
||||
|
||||
@@ -26,9 +26,7 @@ public class AAStore extends Instruction implements ArrayStore
|
||||
StackContext index = stack.pop();
|
||||
StackContext array = stack.pop();
|
||||
|
||||
ins.pop(value);
|
||||
ins.pop(index);
|
||||
ins.pop(array);
|
||||
ins.pop(value, index, array);
|
||||
|
||||
frame.addInstructionContext(ins);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "invokestatic " + method + " in " + this.getInstructions().getCode().getAttributes().getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataInputStream is) throws IOException
|
||||
{
|
||||
@@ -96,15 +102,6 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
|
||||
// add possible method call to execution
|
||||
Execution execution = frame.getExecution();
|
||||
Frame f = execution.invoke(ins, method);
|
||||
|
||||
if (f != null)
|
||||
{
|
||||
assert f.getMethod() == method;
|
||||
//assert f.lastField == frame.lastField;
|
||||
//assert f.staticReturn == frame;
|
||||
|
||||
//frame.stop();
|
||||
}
|
||||
}
|
||||
|
||||
frame.addInstructionContext(ins);
|
||||
|
||||
@@ -34,6 +34,12 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
|
||||
super(instructions, type, pc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "invokevirtual " + method + " in " + this.getInstructions().getCode().getAttributes().getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataInputStream is) throws IOException
|
||||
{
|
||||
|
||||
@@ -21,6 +21,11 @@ public class NewArray extends Instruction
|
||||
{
|
||||
super(instructions, type, pc);
|
||||
}
|
||||
|
||||
public int getArrayType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataInputStream is) throws IOException
|
||||
|
||||
@@ -30,27 +30,19 @@ public class UnusedFields implements Deobfuscator
|
||||
if (ins instanceof FieldInstruction)
|
||||
{
|
||||
FieldInstruction fi = (FieldInstruction) ins;
|
||||
net.runelite.deob.pool.Field ff = fi.getField();
|
||||
|
||||
// pool to Field
|
||||
ClassFile clazz = group.findClass(ff.getClassEntry().getName());
|
||||
if (clazz == null)
|
||||
if (fi.getMyField() != field)
|
||||
continue;
|
||||
|
||||
Field f = clazz.findFieldDeep(ff.getNameAndType());
|
||||
|
||||
if (field == f)
|
||||
{
|
||||
if (ins instanceof GetFieldInstruction)
|
||||
++get;
|
||||
if (ins instanceof SetFieldInstruction)
|
||||
++set;
|
||||
}
|
||||
|
||||
if (ins instanceof GetFieldInstruction)
|
||||
++get;
|
||||
if (ins instanceof SetFieldInstruction)
|
||||
++set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get == 0 && set == 0)
|
||||
if (get == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -246,27 +246,20 @@ public class Rename2
|
||||
|
||||
assert s.getGraph() != other.getGraph();
|
||||
|
||||
boolean b =false;
|
||||
if (s.toString().equals("Vertex{object=B[] class118.field1980}")
|
||||
&& other.toString().equals("Vertex{object=B[] class118.field1986}"))
|
||||
{
|
||||
b=true;
|
||||
}
|
||||
|
||||
for (Edge e : s.getEdges())
|
||||
{
|
||||
assert e.getFrom() == s;
|
||||
|
||||
boolean b = false;
|
||||
if (e.toString().equals("Edge{from=Vertex{object=client.init()V}, to=Vertex{object=static Ljava/lang/String;[] class14.field209}, type=SETFIELD}"))
|
||||
{
|
||||
b = true;
|
||||
}
|
||||
|
||||
if (e.getTo().getOther() != null)
|
||||
continue; // skip solved edges
|
||||
|
||||
Vertex v = e.getTo(); // end of edge in g1
|
||||
|
||||
boolean b2 = false;
|
||||
if (b && v.toString().equals("Vertex{object=class118.method2566()B}"))
|
||||
{
|
||||
b2 = true;
|
||||
}
|
||||
|
||||
List<Vertex> l = new ArrayList<>();
|
||||
for (Edge e2 : other.getEdges())
|
||||
@@ -289,6 +282,11 @@ public class Rename2
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b)
|
||||
{
|
||||
int i = 5;
|
||||
}
|
||||
|
||||
if (!e.couldBeEqual(e2))
|
||||
{
|
||||
// System.out.println(e + " != " + e2);
|
||||
@@ -397,13 +395,14 @@ public class Rename2
|
||||
System.out.println("methods " +g1.solved(VertexType.METHOD));
|
||||
System.out.println("f " +g1.solved(VertexType.FIELD));
|
||||
|
||||
Vertex stored = null;
|
||||
List<Edge> unsolved = new ArrayList<>();
|
||||
//Vertex stored = null;
|
||||
for (Vertex v : g1.getVerticies())
|
||||
{
|
||||
if (v.getOther() == null)
|
||||
continue;
|
||||
|
||||
if (v.getObject() instanceof Method) continue;
|
||||
//if (v.getObject() instanceof Method) continue;
|
||||
|
||||
//assert stored == null;
|
||||
//stored = v;
|
||||
@@ -412,10 +411,19 @@ public class Rename2
|
||||
{
|
||||
if (e.getTo().getOther() == null)
|
||||
{
|
||||
System.out.println("Edge " + e + " on vertex " + v + " is unsolved");
|
||||
unsolved.add(e);
|
||||
|
||||
if (e.getType() == EdgeType.SETFIELD)
|
||||
System.out.println("Edge " + e + " is unsolved");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (EdgeType t : EdgeType.values())
|
||||
{
|
||||
long count = unsolved.stream().filter(e -> e.getType() == t).count();
|
||||
if (count >0)
|
||||
System.out.println(t + " " + count);
|
||||
}
|
||||
|
||||
// NameMappings col = buildCollisionMap(one, two);
|
||||
// rename(col, two);
|
||||
@@ -430,9 +438,10 @@ public class Rename2
|
||||
|
||||
// for (Vertex v : g1.getVerticies())
|
||||
// {
|
||||
// if (v.getOther() != null)
|
||||
// System.out.println(v.getObject() + " -> " + v.getOther().getOther());
|
||||
// else
|
||||
//// if (v.getOther() != null)
|
||||
//// System.out.println(v.getObject() + " -> " + v.getOther().getOther());
|
||||
//// else
|
||||
// if (v.getObject() instanceof Field)
|
||||
// System.out.println(v.getObject() + " -> unk");
|
||||
// }
|
||||
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
package net.runelite.deob.deobfuscators.rename.graph;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import net.runelite.deob.Field;
|
||||
import net.runelite.deob.Method;
|
||||
import net.runelite.deob.attributes.code.Instruction;
|
||||
import net.runelite.deob.attributes.code.instruction.types.DupInstruction;
|
||||
import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction;
|
||||
import net.runelite.deob.attributes.code.instruction.types.LVTInstruction;
|
||||
import net.runelite.deob.attributes.code.instruction.types.SetFieldInstruction;
|
||||
import net.runelite.deob.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.deob.attributes.code.instructions.NewArray;
|
||||
import net.runelite.deob.execution.InstructionContext;
|
||||
import net.runelite.deob.execution.StackContext;
|
||||
import net.runelite.deob.execution.VariableContext;
|
||||
import net.runelite.deob.execution.Variables;
|
||||
|
||||
public class Edge
|
||||
{
|
||||
@@ -105,9 +116,9 @@ public class Edge
|
||||
if (this.type != other.type)
|
||||
return false;
|
||||
|
||||
if (this.type == EdgeType.SETFIELD)
|
||||
if (this.type == EdgeType.SETFIELD)// || this.type == EdgeType.SETFIELD_FROM)
|
||||
{
|
||||
if (!compareSetField(other.getIns()))
|
||||
if (!compareSetField((Field) this.getTo().getObject(), (Field) other.getTo().getObject(), other.getIns()))
|
||||
return false;
|
||||
}
|
||||
// if (this.weight != other.weight)
|
||||
@@ -115,30 +126,147 @@ public class Edge
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private InstructionContext handleDup(InstructionContext i, StackContext sctx)
|
||||
|
||||
private InstructionContext resolve(
|
||||
InstructionContext ctx,
|
||||
StackContext from // pushed from ctx
|
||||
)
|
||||
{
|
||||
DupInstruction d = (DupInstruction) i.getInstruction();
|
||||
return d.getOriginal(sctx).getPushed();
|
||||
if (ctx.getInstruction() instanceof SetFieldInstruction)
|
||||
{
|
||||
StackContext s = ctx.getPops().get(0);
|
||||
return resolve(s.getPushed(), s);
|
||||
}
|
||||
|
||||
if (ctx.getInstruction() instanceof DupInstruction)
|
||||
{
|
||||
DupInstruction d = (DupInstruction) ctx.getInstruction();
|
||||
StackContext s = d.getOriginal(from);
|
||||
return resolve(s.getPushed(), s);
|
||||
}
|
||||
|
||||
if (ctx.getInstruction() instanceof LVTInstruction)
|
||||
{
|
||||
LVTInstruction lvt = (LVTInstruction) ctx.getInstruction();
|
||||
Variables variables = ctx.getVariables();
|
||||
|
||||
if (lvt.store())
|
||||
{
|
||||
StackContext s = ctx.getPops().get(0); // is this right?
|
||||
return resolve(s.getPushed(), s);
|
||||
}
|
||||
else
|
||||
{
|
||||
VariableContext vctx = variables.get(lvt.getVariableIndex()); // variable being loaded
|
||||
assert vctx != null;
|
||||
|
||||
InstructionContext storedCtx = vctx.getInstructionWhichStored();
|
||||
if (storedCtx == null)
|
||||
return ctx; // parameter?
|
||||
|
||||
return resolve(storedCtx, null);
|
||||
}
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
private boolean compareSetField(InstructionContext other)
|
||||
// private static final String[][] map = {
|
||||
// {"field1989", "field2042"},
|
||||
// {"field164", "field2156"},
|
||||
// {"field2904", "field2881"},
|
||||
// {"field296", "field287"},
|
||||
// {"field297", "field425"},
|
||||
// {"field416", "field420"},
|
||||
// {"field329", "field331"},
|
||||
// {"field2203", "field2216"},
|
||||
// {"field2202", "field2222"},
|
||||
// {"field2100", "field2109"},
|
||||
// };
|
||||
//
|
||||
// private boolean isEqual(SetFieldInstruction sf1, SetFieldInstruction sf2)
|
||||
// {
|
||||
// for (int i = 0; i < map.length; ++i)
|
||||
// {
|
||||
// if (sf1.getMyField() != null && sf1.getMyField().getName().equals(map[i][0]) &&
|
||||
// sf2.getMyField() != null && sf2.getMyField().getName().equals(map[i][1]))
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
private boolean compareSetField(Field field1, Field field2, InstructionContext other)
|
||||
{
|
||||
InstructionContext thisp = ins.getPops().get(0).getPushed(),
|
||||
otherp = other.getPops().get(0).getPushed();
|
||||
|
||||
if (thisp.getInstruction() instanceof DupInstruction)
|
||||
InstructionContext thisp = resolve(ins.getPops().get(0).getPushed(), ins.getPops().get(0)),
|
||||
otherp = resolve(other.getPops().get(0).getPushed(), other.getPops().get(0));
|
||||
|
||||
return couldBeEqual(field1, field2, thisp, otherp);
|
||||
}
|
||||
|
||||
private boolean couldBeEqual(Field field1, Field field2, InstructionContext one, InstructionContext two)
|
||||
{
|
||||
if (field2.getName().equals("field209"))
|
||||
{
|
||||
thisp = handleDup(thisp, ins.getPops().get(0));
|
||||
int i =5;
|
||||
}
|
||||
if (otherp.getInstruction() instanceof DupInstruction)
|
||||
Instruction i1 = one.getInstruction(), i2 = two.getInstruction();
|
||||
|
||||
if (i1 instanceof LVTInstruction && i2 instanceof LVTInstruction)
|
||||
{
|
||||
otherp = handleDup(otherp, other.getPops().get(0));
|
||||
LVTInstruction l1 = (LVTInstruction) i1, l2 = (LVTInstruction) i2;
|
||||
|
||||
assert !l1.store();
|
||||
assert !l2.store();
|
||||
|
||||
VariableContext v1 = one.getVariables().get(l1.getVariableIndex()),
|
||||
v2 = two.getVariables().get(l2.getVariableIndex());
|
||||
|
||||
assert v1.getInstructionWhichStored() == null;
|
||||
assert v2.getInstructionWhichStored() == null;
|
||||
|
||||
return v1.getType().equals(v2.getType());
|
||||
}
|
||||
|
||||
Class[] c1 = thisp.getInstruction().getClass().getInterfaces(),
|
||||
c2 = otherp.getInstruction().getClass().getInterfaces();
|
||||
if (i1 instanceof NewArray && i2 instanceof NewArray)
|
||||
{
|
||||
NewArray a1 = (NewArray) i1, a2 = (NewArray) i2;
|
||||
return a1.getArrayType() == a2.getArrayType();
|
||||
}
|
||||
|
||||
return Arrays.equals(c1, c2);
|
||||
// XXX check for invokestatic vs.
|
||||
if (i1 instanceof InvokeInstruction && i2 instanceof InvokeInstruction)
|
||||
{
|
||||
InvokeInstruction ii1 = (InvokeInstruction) i1, ii2 = (InvokeInstruction) i2;
|
||||
|
||||
List<Method> methods1 = ii1.getMethods(), methods2 = ii2.getMethods();
|
||||
|
||||
if (methods1.size() != methods2.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methods1.isEmpty())
|
||||
{
|
||||
// compare pool Method
|
||||
return ii1.getMethod().equals(ii2.getMethod());
|
||||
}
|
||||
|
||||
Method m1 = methods1.get(0), m2 = methods2.get(0);
|
||||
|
||||
if (!m1.getDescriptor().equals(m2.getDescriptor()))
|
||||
return false;
|
||||
}
|
||||
else if (i1 instanceof InvokeStatic || i2 instanceof InvokeStatic)
|
||||
{
|
||||
return true;
|
||||
//int i = 5;
|
||||
}
|
||||
|
||||
if (!i1.getClass().equals(i2.getClass()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ public class Class extends PoolEntry
|
||||
{
|
||||
index = pool.makeUTF8(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
|
||||
@@ -28,6 +28,12 @@ public class Method extends PoolEntry
|
||||
classIndex = is.readUnsignedShort();
|
||||
natIndex = is.readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String toString()
|
||||
{
|
||||
return clazz + "." + nat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(ConstantPool pool)
|
||||
|
||||
@@ -63,6 +63,15 @@ public class NameAndType extends PoolEntry
|
||||
else
|
||||
descriptorIndex = pool.makeUTF8(type.getFullType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String toString()
|
||||
{
|
||||
if (type != null)
|
||||
return name + " " + type;
|
||||
else
|
||||
return name + signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
|
||||
Reference in New Issue
Block a user