This commit is contained in:
Adam
2015-12-05 18:42:16 -05:00
parent b9b2ef70f2
commit 9b2b5fdecf
11 changed files with 278 additions and 122 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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

View File

@@ -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;

View File

@@ -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");
// }

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)