This commit is contained in:
Adam
2015-11-19 16:32:19 -05:00
parent bda6242dcb
commit 804b34d075
15 changed files with 1069 additions and 586 deletions

View File

@@ -24,21 +24,21 @@
<artifactId>commons-compress</artifactId> <artifactId>commons-compress</artifactId>
<version>1.10</version> <version>1.10</version>
</dependency> </dependency>
<dependency> <!-- <dependency>
<groupId>edu.ucla.sspace</groupId> <groupId>edu.ucla.sspace</groupId>
<artifactId>sspace</artifactId> <artifactId>sspace</artifactId>
<version>2.0.4</version> <version>2.0.4</version>
</dependency> </dependency>-->
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.4</version> <version>2.4</version>
</dependency> </dependency>
<dependency> <!-- <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.1</version> <version>3.1</version>
</dependency> </dependency>-->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>

View File

@@ -3,12 +3,14 @@ package net.runelite.deob;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import net.runelite.deob.deobfuscators.MethodInliner; import net.runelite.deob.deobfuscators.MethodInliner;
import net.runelite.deob.deobfuscators.rename.Rename;
import net.runelite.deob.deobfuscators.UnusedMethods; import net.runelite.deob.deobfuscators.UnusedMethods;
import net.runelite.deob.deobfuscators.rename.Rename2;
import net.runelite.deob.execution.Execution; import net.runelite.deob.execution.Execution;
import net.runelite.deob.util.JarUtil; import net.runelite.deob.util.JarUtil;
// XXX something to detect final fields and evaluate them // XXX something to detect final fields and evaluate them
// the problem is static functions which dup,
// graph of method/field (not include static) relationships
public class Deob public class Deob
{ {
@@ -103,7 +105,7 @@ public class Deob
ClassGroup group1 = JarUtil.loadJar(new File("d:/rs/07/adamin1.jar")), ClassGroup group1 = JarUtil.loadJar(new File("d:/rs/07/adamin1.jar")),
group2 = JarUtil.loadJar(new File("d:/rs/07/adamin2.jar")); group2 = JarUtil.loadJar(new File("d:/rs/07/adamin2.jar"));
Rename rename = new Rename(); Rename2 rename = new Rename2();
rename.run(group1, group2); rename.run(group1, group2);
} }

View File

@@ -17,8 +17,13 @@ import java.util.List;
public class Method public class Method
{ {
public static final int ACC_PUBLIC = 0x1;
public static final int ACC_PRIVATE = 0x2;
public static final int ACC_PROTECTED = 0x4;
public static final int ACC_STATIC = 0x8; public static final int ACC_STATIC = 0x8;
public static final int ACC_FINAL = 0x10;
public static final int ACC_SYNCHRONIZED = 0x20; public static final int ACC_SYNCHRONIZED = 0x20;
public static final int ACC_ABSTRACT = 0x400;
private Methods methods; private Methods methods;
@@ -80,6 +85,11 @@ public class Method
this.attributes = a; this.attributes = a;
} }
public short getAccessFlags()
{
return accessFlags;
}
public String getName() public String getName()
{ {
return name; return name;

View File

@@ -1,246 +1,246 @@
package net.runelite.deob.deobfuscators.rename; //package net.runelite.deob.deobfuscators.rename;
//
import edu.ucla.sspace.graph.Edge; //import edu.ucla.sspace.graph.Edge;
import edu.ucla.sspace.graph.Graph; //import edu.ucla.sspace.graph.Graph;
import edu.ucla.sspace.graph.isomorphism.IsomorphismTester; //import edu.ucla.sspace.graph.isomorphism.IsomorphismTester;
import edu.ucla.sspace.graph.isomorphism.VF2IsomorphismTester; //import edu.ucla.sspace.graph.isomorphism.VF2IsomorphismTester;
import java.util.HashMap; //import java.util.HashMap;
import java.util.HashSet; //import java.util.HashSet;
import java.util.List; //import java.util.List;
import java.util.Map; //import java.util.Map;
import java.util.Map.Entry; //import java.util.Map.Entry;
import java.util.Optional; //import java.util.Optional;
import java.util.Set; //import java.util.Set;
import java.util.stream.Collectors; //import java.util.stream.Collectors;
import net.runelite.deob.ClassGroup; //import net.runelite.deob.ClassGroup;
import net.runelite.deob.Method; //import net.runelite.deob.Method;
import net.runelite.deob.execution.Execution; //import net.runelite.deob.execution.Execution;
import net.runelite.deob.execution.Frame; //import net.runelite.deob.execution.Frame;
import net.runelite.deob.execution.MethodContext; //import net.runelite.deob.execution.MethodContext;
//
public class Rename //public class Rename
{ //{
private ClassGroup groupOne, groupTwo; // private ClassGroup groupOne, groupTwo;
//
// respective executions // // respective executions
//private Execution eone, etwo; // //private Execution eone, etwo;
//
// old -> new object mapping // // old -> new object mapping
private Map<Object, Object> objMap = new HashMap<>(); // private Map<Object, Object> objMap = new HashMap<>();
//
// methods which have been processed in the original // // methods which have been processed in the original
private Set<Method> processed = new HashSet<>(); // private Set<Method> processed = new HashSet<>();
//
private static String cname(Method m) { return m.getMethods().getClassFile().getName(); } // private static String cname(Method m) { return m.getMethods().getClassFile().getName(); }
private static String mname(Method m) { return cname(m) + "." + m.getName(); } // private static String mname(Method m) { return cname(m) + "." + m.getName(); }
//
private void compare(MethodContext m1, Graph g1, MethodContext m2, Graph g2) // private void compare(MethodContext m1, Graph g1, MethodContext m2, Graph g2)
{ // {
Set<Edge> edges = new HashSet<>(g1.edges()); // edges in g1 not in g2 // Set<Edge> edges = new HashSet<>(g1.edges()); // edges in g1 not in g2
for (Edge e : (Set<Edge>) g2.edges()) // for (Edge e : (Set<Edge>) g2.edges())
{ // {
edges.remove(e); // edges.remove(e);
} // }
//
for (Edge e : edges) // for (Edge e : edges)
{ // {
Method me1 = m1.getIdMap().get(e.from()).get(0); // Method me1 = m1.getIdMap().get(e.from()).get(0);
Method me2 = m1.getIdMap().get(e.to()).get(0); // Method me2 = m1.getIdMap().get(e.to()).get(0);
//
System.out.println("EDGE IN 1 NOT IN 2: " + mname(me1) + " -> " + mname(me2)); // System.out.println("EDGE IN 1 NOT IN 2: " + mname(me1) + " -> " + mname(me2));
//
Method om1 = m2.getIdMap().get(e.from()).get(0); // Method om1 = m2.getIdMap().get(e.from()).get(0);
Method om2 = m2.getIdMap().get(e.to()).get(0); // Method om2 = m2.getIdMap().get(e.to()).get(0);
//
System.out.println(" OTHER SIDE: " + mname(om1) + " -> " + mname(om2)); // System.out.println(" OTHER SIDE: " + mname(om1) + " -> " + mname(om2));
} // }
//System.out.println(edges); // //System.out.println(edges);
//
if (g2.order() == g1.order()) // if (g2.order() == g1.order())
{ // {
int[] v1 = g1.vertices().toPrimitiveArray(), // int[] v1 = g1.vertices().toPrimitiveArray(),
v2 = g2.vertices().toPrimitiveArray(); // v2 = g2.vertices().toPrimitiveArray();
for (int i = 0; i < g1.order(); ++i) // for (int i = 0; i < g1.order(); ++i)
{
Method me1 = m1.getIdMap().get(v1[i]).get(0);
Method me2 = m2.getIdMap().get(v2[i]).get(0);
System.out.println("VMATCH " + mname(me1) + " -> " + mname(me2));
}
}
}
private boolean compare(Frame f1, Frame f2)
{
Graph g1 = f1.getMethodCtx().getGraph(), g2 = f2.getMethodCtx().getGraph();
IsomorphismTester isoTest = new /*Typed*/VF2IsomorphismTester();
if (g1.size() != g2.size() || g1.order() != g2.order() || !isoTest.areIsomorphic(g1, g2))
{
System.out.println("IN " + mname(f1.getMethod()) + " -> " + mname(f2.getMethod()));
compare(f1.getMethodCtx(), g1, f2.getMethodCtx(), g2);
System.out.println("Not isomorphic " + g1.size() + " " + g2.size());
return false;
}
Map<Integer, Integer> mapping = isoTest.findIsomorphism(g1, g2);
Map<Integer, List<Method>> map1 = f1.getMethodCtx().getIdMap(), map2 = f2.getMethodCtx().getIdMap();
for (Entry<Integer, Integer> e : mapping.entrySet())
{
// if (e.getKey() == null || e.getValue() == null)
// { // {
// assert e.getKey() == e.getValue(); // Method me1 = m1.getIdMap().get(v1[i]).get(0);
// continue; // Method me2 = m2.getIdMap().get(v2[i]).get(0);
//
// System.out.println("VMATCH " + mname(me1) + " -> " + mname(me2));
// } // }
// }
List<Method> i1 = map1.get(e.getKey()); // }
List<Method> i2 = map2.get(e.getValue()); //
// private boolean compare(Frame f1, Frame f2)
//assert i1.getClass() == i2.getClass(); // {
// Graph g1 = f1.getMethodCtx().getGraph(), g2 = f2.getMethodCtx().getGraph();
//InvokeInstruction ii1 = (InvokeInstruction) i1, ii2 = (InvokeInstruction) i2; //
// IsomorphismTester isoTest = new /*Typed*/VF2IsomorphismTester();
//assert ii1.getMethods().size() == ii2.getMethods().size(); // if (g1.size() != g2.size() || g1.order() != g2.order() || !isoTest.areIsomorphic(g1, g2))
// {
assert i1.size() == i2.size(); // System.out.println("IN " + mname(f1.getMethod()) + " -> " + mname(f2.getMethod()));
// compare(f1.getMethodCtx(), g1, f2.getMethodCtx(), g2);
for (int i = 0; i < i1.size(); ++i) // System.out.println("Not isomorphic " + g1.size() + " " + g2.size());
{ // return false;
Method m1 = i1.get(i), m2 = i2.get(i); // }
//
// assert objMap.containsKey(m1) == false || objMap.get(m1) == m2; // Map<Integer, Integer> mapping = isoTest.findIsomorphism(g1, g2);
objMap.put(m1, m2); // Map<Integer, List<Method>> map1 = f1.getMethodCtx().getIdMap(), map2 = f2.getMethodCtx().getIdMap();
} //
// for (Entry<Integer, Integer> e : mapping.entrySet())
System.out.println("MATCH " + i1.get(0).getName() + " -> " + i2.get(0).getName()); // {
} //// if (e.getKey() == null || e.getValue() == null)
//// {
return true; //// assert e.getKey() == e.getValue();
} //// continue;
//// }
private void process(Method one, Method two) //
{ // List<Method> i1 = map1.get(e.getKey());
Execution eone = new Execution(groupOne); // List<Method> i2 = map2.get(e.getValue());
eone.setBuildGraph(true); //
eone.setFollowInvokes(false); // //assert i1.getClass() == i2.getClass();
eone.addMethod(one); //
eone.run(); // //InvokeInstruction ii1 = (InvokeInstruction) i1, ii2 = (InvokeInstruction) i2;
//
Execution etwo = new Execution(groupTwo); // //assert ii1.getMethods().size() == ii2.getMethods().size();
etwo.setBuildGraph(true); //
etwo.setFollowInvokes(false); // assert i1.size() == i2.size();
etwo.addMethod(two); //
etwo.run(); // for (int i = 0; i < i1.size(); ++i)
// {
// get frames for respective methods // Method m1 = i1.get(i), m2 = i2.get(i);
List<Frame> f1 = eone.processedFrames, f2 = etwo.processedFrames; //
//// assert objMap.containsKey(m1) == false || objMap.get(m1) == m2;
f1 = f1.stream().filter(f -> f.getMethod() == one).collect(Collectors.toList()); // objMap.put(m1, m2);
f2 = f2.stream().filter(f -> f.getMethod() == two).collect(Collectors.toList()); // }
//
//List<Frame> f1 = eone.processedFrames.stream().filter(f -> f.getMethod() == one).collect(Collectors.toList()); // System.out.println("MATCH " + i1.get(0).getName() + " -> " + i2.get(0).getName());
//List<Frame> f2 = etwo.processedFrames.stream().filter(f -> f.getMethod() == two).collect(Collectors.toList()); // }
//
Frame p1 = null, p2 = null; // return true;
outer: // }
for (Frame fr1 : f1) //
for (Frame fr2 : f2) // private void process(Method one, Method two)
{ // {
if (p1 == null) p1 = fr1; // Execution eone = new Execution(groupOne);
if (p2 == null) p2 = fr2;
assert fr1.getMethod() == one;
assert fr2.getMethod() == two;
assert fr1.getMethodCtx() == p1.getMethodCtx();
assert fr2.getMethodCtx() == p2.getMethodCtx();
}
assert p1.getMethod() == one;
assert p2.getMethod() == two;
outer2:
for (Frame fr1 : f1)
for (Frame fr2 : f2)
{
boolean b = compare(fr1, fr2);
if (!b)
{
System.out.println("Mismatch " + p1.getMethod().getMethods().getClassFile().getName() + "." + p1.getMethod().getName() + " <-> " + p2.getMethod().getMethods().getClassFile().getName() + "." + p2.getMethod().getName());
System.out.println(one.getMethods().getClassFile().getName() + "." + one.getName() + " and " + two.getMethods().getClassFile().getName() + "." + two.getName());
int i =7;
}
break outer2;
}
System.out.println("end");
}
public void run(ClassGroup one, ClassGroup two)
{
groupOne = one;
groupTwo = two;
// Execution eone = new Execution(one);
// eone.setBuildGraph(true); // eone.setBuildGraph(true);
// eone.setFollowInvokes(false); // eone.setFollowInvokes(false);
// eone.populateInitialMethods(); // eone.addMethod(one);
// List<Method> initial1 = eone.getInitialMethods().stream().sorted((m1, m2) -> m1.getName().compareTo(m2.getName())).collect(Collectors.toList());
// eone.run(); // eone.run();
// //
// Execution etwo = new Execution(two); // Execution etwo = new Execution(groupTwo);
// etwo.setBuildGraph(true); // etwo.setBuildGraph(true);
// etwo.setFollowInvokes(false); // etwo.setFollowInvokes(false);
// etwo.populateInitialMethods(); // etwo.addMethod(two);
// List<Method> initial2 = etwo.getInitialMethods().stream().sorted((m1, m2) -> m1.getName().compareTo(m2.getName())).collect(Collectors.toList());
// etwo.run(); // etwo.run();
// //
// assert initial1.size() == initial2.size(); // // get frames for respective methods
// List<Frame> f1 = eone.processedFrames, f2 = etwo.processedFrames;
// //
// for (int i = 0; i < initial1.size(); ++i) // f1 = f1.stream().filter(f -> f.getMethod() == one).collect(Collectors.toList());
// f2 = f2.stream().filter(f -> f.getMethod() == two).collect(Collectors.toList());
//
// //List<Frame> f1 = eone.processedFrames.stream().filter(f -> f.getMethod() == one).collect(Collectors.toList());
// //List<Frame> f2 = etwo.processedFrames.stream().filter(f -> f.getMethod() == two).collect(Collectors.toList());
//
// Frame p1 = null, p2 = null;
// outer:
// for (Frame fr1 : f1)
// for (Frame fr2 : f2)
// {
// if (p1 == null) p1 = fr1;
// if (p2 == null) p2 = fr2;
//
// assert fr1.getMethod() == one;
// assert fr2.getMethod() == two;
//
// assert fr1.getMethodCtx() == p1.getMethodCtx();
// assert fr2.getMethodCtx() == p2.getMethodCtx();
// }
//
// assert p1.getMethod() == one;
// assert p2.getMethod() == two;
//
// outer2:
// for (Frame fr1 : f1)
// for (Frame fr2 : f2)
// {
// boolean b = compare(fr1, fr2);
// if (!b)
// {
// System.out.println("Mismatch " + p1.getMethod().getMethods().getClassFile().getName() + "." + p1.getMethod().getName() + " <-> " + p2.getMethod().getMethods().getClassFile().getName() + "." + p2.getMethod().getName());
// System.out.println(one.getMethods().getClassFile().getName() + "." + one.getName() + " and " + two.getMethods().getClassFile().getName() + "." + two.getName());
// int i =7;
// }
// break outer2;
// }
//
// System.out.println("end");
// }
// public void run(ClassGroup one, ClassGroup two)
// {
// groupOne = one;
// groupTwo = two;
//
//// Execution eone = new Execution(one);
//// eone.setBuildGraph(true);
//// eone.setFollowInvokes(false);
//// eone.populateInitialMethods();
//// List<Method> initial1 = eone.getInitialMethods().stream().sorted((m1, m2) -> m1.getName().compareTo(m2.getName())).collect(Collectors.toList());
//// eone.run();
////
//// Execution etwo = new Execution(two);
//// etwo.setBuildGraph(true);
//// etwo.setFollowInvokes(false);
//// etwo.populateInitialMethods();
//// List<Method> initial2 = etwo.getInitialMethods().stream().sorted((m1, m2) -> m1.getName().compareTo(m2.getName())).collect(Collectors.toList());
//// etwo.run();
////
//// assert initial1.size() == initial2.size();
////
//// for (int i = 0; i < initial1.size(); ++i)
//// {
//// Method m1 = initial1.get(i), m2 = initial2.get(i);
////
//// assert m1.getName().equals(m2.getName());
////
//// objMap.put(m1, m2);
//// }
//
// process(
// one.findClass("client").findMethod("vmethod2999"),
// two.findClass("client").findMethod("vmethod2978")
// );
//
// for (;;)
// { // {
// Method m1 = initial1.get(i), m2 = initial2.get(i); // Optional next = objMap.keySet().stream()
// .filter(m -> !processed.contains(m))
// .findAny();
// if (!next.isPresent())
// break;
// //
// assert m1.getName().equals(m2.getName()); // Method m = (Method) next.get();
// Method m2 = (Method) objMap.get(m);
// //
// objMap.put(m1, m2); // if (m.getCode() == null || m2.getCode() == null)
// {
// processed.add(m);
// continue;
// }
//
// System.out.println("Scanning " + m.getMethods().getClassFile().getName() + "." + m.getName() + " -> " + m2.getMethods().getClassFile().getName() + "." + m2.getName());
// process(m, m2);
// processed.add(m);
// } // }
//
process( // for (Entry<Object, Object> e : objMap.entrySet())
one.findClass("client").findMethod("vmethod2999"), // {
two.findClass("client").findMethod("vmethod2978") // Method m1 = (Method) e.getKey();
); // Method m2 = (Method) e.getValue();
//
for (;;) // System.out.println("FINAL " + m1.getMethods().getClassFile().getName() + "." + m1.getName() + " -> " + m2.getMethods().getClassFile().getName() + "." + m2.getName());
{ // }
Optional next = objMap.keySet().stream() //
.filter(m -> !processed.contains(m)) // System.out.println("done count " + objMap.size());
.findAny(); // }
if (!next.isPresent()) //}
break;
Method m = (Method) next.get();
Method m2 = (Method) objMap.get(m);
if (m.getCode() == null || m2.getCode() == null)
{
processed.add(m);
continue;
}
System.out.println("Scanning " + m.getMethods().getClassFile().getName() + "." + m.getName() + " -> " + m2.getMethods().getClassFile().getName() + "." + m2.getName());
process(m, m2);
processed.add(m);
}
for (Entry<Object, Object> e : objMap.entrySet())
{
Method m1 = (Method) e.getKey();
Method m2 = (Method) e.getValue();
System.out.println("FINAL " + m1.getMethods().getClassFile().getName() + "." + m1.getName() + " -> " + m2.getMethods().getClassFile().getName() + "." + m2.getName());
}
System.out.println("done count " + objMap.size());
}
}

View File

@@ -0,0 +1,162 @@
package net.runelite.deob.deobfuscators.rename;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.runelite.deob.ClassFile;
import net.runelite.deob.ClassGroup;
import net.runelite.deob.Field;
import net.runelite.deob.Method;
import net.runelite.deob.deobfuscators.rename.graph.Graph;
import net.runelite.deob.deobfuscators.rename.graph.Vertex;
import net.runelite.deob.deobfuscators.rename.graph.VertexType;
import net.runelite.deob.execution.Execution;
import net.runelite.deob.signature.Signature;
public class Rename2
{
private Graph g1, g2;
private static String cname(Method m) { return m.getMethods().getClassFile().getName(); }
private static String mname(Method m) { return cname(m) + "." + m.getName(); }
private static String fname(Field f) { return f.getFields().getClassFile().getName() + "." + f.getName(); }
public static void collide(Object o0, Object o1, Object o2)
{
assert o0.getClass() == o1.getClass();
assert o1.getClass() == o2.getClass();
if (o1 instanceof Method)
{
Method m1 = (Method) o1;
Method m2 = (Method) o2;
System.out.println("COLLISION " + mname(m1) + " -> " + mname(m2));
}
else if (o1 instanceof Field)
{
Field f0 = (Field) o0;
Field f1 = (Field) o1;
Field f2 = (Field) o2;
System.out.println("COLLISION " + fname(f0) + ": " + fname(f1) + " -> " + fname(f2));
}
else
assert false;
}
private Map<Signature, Method> find(ClassFile cf)
{
Map<Signature, Method> set = new HashMap();
Set collided = new HashSet();
for (Method m : cf.getMethods().getMethods())
{
if (m.isStatic())
continue;
Signature sig = m.getDescriptor();
if (set.containsKey(sig) || collided.contains(sig))
{
collided.add(sig);
set.remove(sig);
continue;
}
set.put(sig, m);
}
return set;
}
void mapClassMethods(Map<Signature, Method> one, Map<Signature, Method> two)
{
if (!one.keySet().equals(two.keySet()))
return;
for (Signature sig : one.keySet())
{
Method m1 = one.get(sig);
Method m2 = two.get(sig);
Vertex v1 = g1.getVertexFor(m1);
Vertex v2 = g2.getVertexFor(m2);
v1.is(v2);
v2.is(v1);
System.out.println(mname(m1) + " is " + mname(m2));
}
}
private void solve()
{
List<Vertex> solved = g1.getVerticies().stream().filter(v -> v.getOther() != null).collect(Collectors.toList());
for (Vertex s : solved)
{
Vertex other = s.getOther();
s.getEdges().stream()
.map(e -> e.getTo()) // e.from is always s
.filter(v -> v.getOther() == null) // only get vertexes that aren't solved yet
.forEach(v ->
v.merge(
other.getEdges().stream()
.map(e -> e.getTo())
.filter(v2 -> v2.getOther() == null)
.filter(v2 -> v.couldBeEqual(v2))
.collect(Collectors.toList())
)
);
}
}
public void run(ClassGroup one, ClassGroup two)
{
Execution eone = new Execution(one);
eone.setBuildGraph(true);
//eone.setFollowInvokes(false);
eone.populateInitialMethods();
eone.run();
Execution etwo = new Execution(two);
etwo.setBuildGraph(true);
//etwo.setFollowInvokes(false);
etwo.populateInitialMethods();
etwo.run();
g1 = eone.getGraph();
g2 = etwo.getGraph();
System.out.println(eone.getGraph());
System.out.println(etwo.getGraph());
for (int i = 0; i < Math.min(one.getClasses().size(), two.getClasses().size()); ++i)
{
Map m1 = this.find(one.getClasses().get(i));
Map m2 = this.find(two.getClasses().get(i));
mapClassMethods(m1, m2);
}
for (;;)
{
int before = g1.solved(null);
System.out.println("Before " + before);
solve();
g1.getVerticies().forEach(v -> v.finish());
int after = g1.solved(null);
System.out.println("After " + after);
if (before == after)
break;
}
g1.check();g2.check();
System.out.println("methods " +g1.solved(VertexType.METHOD));
System.out.println("f " +g1.solved(VertexType.FIELD));
}
}

View File

@@ -0,0 +1,64 @@
package net.runelite.deob.deobfuscators.rename.graph;
import java.util.Objects;
public class Edge
{
private final Vertex from, to;
public Edge(Vertex from, Vertex to)
{
this.from = from;
this.to = to;
assert from.getGraph() == to.getGraph();
}
public Vertex getFrom()
{
return from;
}
public Vertex getTo()
{
return to;
}
@Override
public int hashCode()
{
int hash = 7;
hash = 11 * hash + Objects.hashCode(this.from);
hash = 11 * hash + Objects.hashCode(this.to);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Edge other = (Edge) obj;
if (!Objects.equals(this.from, other.from))
{
return false;
}
if (!Objects.equals(this.to, other.to))
{
return false;
}
return true;
}
}

View File

@@ -0,0 +1,79 @@
package net.runelite.deob.deobfuscators.rename.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Graph
{
private List<Vertex> verticies = new ArrayList<>();
private Map<Object, Vertex> o2v = new HashMap<>();
private int edgeCount;
public Vertex getVertexFor(Object o)
{
Vertex v = o2v.get(o);
if (v != null)
return v;
v = new Vertex(this, o);
o2v.put(o, v);
verticies.add(v);
return v;
}
public void addEdge(Object from, Object to)
{
assert from != null;
assert to != null;
Vertex v1 = getVertexFor(from), v2 = getVertexFor(to);
Edge e = new Edge(v1, v2);
if (v1.addEdge(e))
++edgeCount;
}
public List<Vertex> getVerticies()
{
return verticies;
}
public int vertexCount()
{
return verticies.size();
}
public int edgeCount()
{
return edgeCount;
}
@Override
public String toString()
{
return "Graph{" + "verticies=" + verticies.size() + ", edgeCount=" + edgeCount + '}';
}
public void check()
{
for (Vertex v : verticies)
{
if (v.getOther() != null)
{
assert v.getOther().getOther() == v;
}
}
}
public int solved(VertexType type)
{
int solved = 0;
for (Vertex v : verticies)
if (v.getOther() != null && (type == null || v.getType() == type))
++solved;
return solved;
}
}

View File

@@ -0,0 +1,174 @@
package net.runelite.deob.deobfuscators.rename.graph;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import net.runelite.deob.ClassFile;
import net.runelite.deob.Field;
import net.runelite.deob.Method;
import net.runelite.deob.deobfuscators.rename.Rename2;
import org.apache.commons.collections4.CollectionUtils;
public class Vertex
{
private Graph graph;
private Object object;
private VertexType type;
private Set<Edge> edges = new HashSet<>();
private Collection<Vertex> mightBe;
private Vertex is;
public Vertex(Graph graph, Object object)
{
this.graph = graph;
this.object = object;
if (object instanceof Method)
type = VertexType.METHOD;
else if (object instanceof Field)
type = VertexType.FIELD;
else
assert false;
}
public Graph getGraph()
{
return graph;
}
public Object getObject()
{
return object;
}
public VertexType getType()
{
return type;
}
public void setType(VertexType type)
{
this.type = type;
}
public boolean addEdge(Edge edge)
{
return edges.add(edge);
}
public Set<Edge> getEdges()
{
return edges;
}
public void merge(Collection<Vertex> maybe)
{
// mightBe and maybe
if (mightBe == null)
mightBe = maybe;
else
mightBe = CollectionUtils.intersection(mightBe, maybe);
}
public void finish()
{
if (mightBe != null && mightBe.size() == 1)
{
is(mightBe.stream().findAny().get());
is.is(this);
mightBe = null;
}
}
public void is(Vertex other)
{
if (is != null)
{
assert graph != other.graph;
assert is.graph == other.graph;
Rename2.collide(object, is.object, other.object);
}
assert is == null;
assert other.graph != graph;
this.is = other;
}
public Vertex getOther()
{
return is;
}
private boolean couldBeEqual(ClassFile cf1, ClassFile cf2)
{
if (!cf1.getName().equals(cf2.getName()))
return false;
if (!cf1.getInterfaces().getInterfaces().equals(cf2.getInterfaces().getInterfaces()))
return false;
if (!cf1.getParentClass().equals(cf2.getParentClass()))
return false;
return true;
}
public boolean couldBeEqual(Vertex other)
{
assert this != other;
assert graph != other.graph;
assert is == null;
assert other.is == null;
if (this.getType() != other.getType())
return false;
if (this.getType() == VertexType.METHOD)
{
Method m1 = (Method) object;
Method m2 = (Method) other.object;
assert !m1.isStatic();
assert !m2.isStatic();
if (m1.getName().equals("<init>") != m2.getName().equals("<init>"))
return false;
if (!m1.getDescriptor().equals(m2.getDescriptor()))
return false;
if (m1.getAccessFlags() != m2.getAccessFlags())
return false;
ClassFile cf1 = m1.getMethods().getClassFile(), cf2 = m2.getMethods().getClassFile();
if (!couldBeEqual(cf1, cf2))
return false;
}
else if (type == VertexType.FIELD)
{
Field f1 = (Field) object;
Field f2 = (Field) other.object;
if (!f1.getType().equals(f2.getType()))
return false;
if (f1.isStatic() != f2.isStatic() || f1.getAccessFlags() != f2.getAccessFlags())
return false;
if (!f1.isStatic())
{
ClassFile cf1 = f1.getFields().getClassFile(), cf2 = f2.getFields().getClassFile();
if (!couldBeEqual(cf1, cf2))
return false;
}
}
else
assert false;
return true;
}
}

View File

@@ -0,0 +1,8 @@
package net.runelite.deob.deobfuscators.rename.graph;
public enum VertexType
{
METHOD,
FIELD;
}

View File

@@ -7,6 +7,7 @@ import net.runelite.deob.Method;
import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.Instruction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -14,7 +15,11 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.runelite.deob.attributes.code.instruction.types.FieldInstruction;
import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction;
import net.runelite.deob.attributes.code.instructions.InvokeStatic;
import net.runelite.deob.deobfuscators.arithmetic.Encryption; import net.runelite.deob.deobfuscators.arithmetic.Encryption;
import net.runelite.deob.deobfuscators.rename.graph.Graph;
import org.apache.commons.collections4.map.MultiValueMap; import org.apache.commons.collections4.map.MultiValueMap;
public class Execution public class Execution
@@ -24,12 +29,12 @@ public class Execution
processedFrames = new LinkedList<>(); processedFrames = new LinkedList<>();
public Set<Method> methods = new HashSet<>(); // all methods public Set<Method> methods = new HashSet<>(); // all methods
public Set<Instruction> executed = new HashSet<>(); // executed instructions public Set<Instruction> executed = new HashSet<>(); // executed instructions
private MultiValueMap<MIKey, 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 MultiValueMap<Instruction, InstructionContext> contexts = new MultiValueMap<>();
private Map<Method, MethodContext> methodContexts = new HashMap<>(); private Map<Method, MethodContext> methodContexts = new HashMap<>();
private boolean buildGraph; // if true the frame graph is built and execution hasJumped also compares previous instructions private boolean buildGraph; // if true the frame graph is built and execution hasJumped also compares previous instructions
private boolean followInvokes = true; private Graph graph = new Graph();
public Execution(ClassGroup group) public Execution(ClassGroup group)
{ {
@@ -46,16 +51,6 @@ public class Execution
this.encryption = encryption; this.encryption = encryption;
} }
public boolean isFollowInvokes()
{
return followInvokes;
}
public void setFollowInvokes(boolean followInvokes)
{
this.followInvokes = followInvokes;
}
public List<Method> getInitialMethods() public List<Method> getInitialMethods()
{ {
List<Method> methods = new ArrayList<>(); List<Method> methods = new ArrayList<>();
@@ -101,27 +96,26 @@ public class Execution
private boolean hasInvoked(InstructionContext from, Method to) private boolean hasInvoked(InstructionContext from, Method to)
{ {
Frame frame = from.getFrame(); Collection<Method> methods = invokes.getCollection(from);
MIKey key = new MIKey(frame.prevVertex.intValue(), from);
Collection<Method> methods = invokes.getCollection(key);
if (methods != null && methods.contains(to)) if (methods != null && methods.contains(to))
return true; return true;
invokes.put(key, to); invokes.put(from, to);
return false; return false;
} }
private void addFrame(Frame frame) private void addFrame(Frame frame)
{ {
frames.add(0, frame); frames.add(frame);
//frames.add(0, frame);
} }
public void invoke(InstructionContext from, Method to) public void invoke(InstructionContext from, Method to)
{ {
Frame frame = from.getFrame(); Frame frame = from.getFrame();
if (!this.isFollowInvokes() && !to.isStatic()) // if (!this.isFollowInvokes() && !to.isStatic())
return; // return;
if (hasInvoked(from, to)) if (hasInvoked(from, to))
return; return;
@@ -161,16 +155,16 @@ public class Execution
assert frame.isExecuting(); assert frame.isExecuting();
frame.execute(); frame.execute();
if (!frame.isExecuting()) // if (!frame.isExecuting())
{ // {
//assert frames.get(0) == frame; assert frames.get(0) == frame;
frames.remove(frame); frames.remove(frame);
processedFrames.add(frame); processedFrames.add(frame);
} // }
else // else
{ // {
// another frame takes priority // // another frame takes priority
} // }
} }
System.out.println("Processed " + fcount + " frames"); System.out.println("Processed " + fcount + " frames");
@@ -201,4 +195,39 @@ public class Execution
{ {
this.buildGraph = buildGraph; this.buildGraph = buildGraph;
} }
protected void buildGraph(Frame frame, Instruction i)
{
if (!isBuildGraph())
return;
if (i instanceof InvokeInstruction)
{
if (i instanceof InvokeStatic)
return;
InvokeInstruction ii = (InvokeInstruction) i;
List<Method> methods = ii.getMethods();
if (methods.isEmpty())
return;
for (Method m : methods)
graph.addEdge(frame.nonStatic, m);
}
else if (i instanceof FieldInstruction)
{
FieldInstruction fi = (FieldInstruction) i;
if (fi.getMyField() == null)
return;
graph.addEdge(frame.nonStatic, fi.getMyField());
}
}
public Graph getGraph()
{
return graph;
}
} }

View File

@@ -11,7 +11,6 @@ import net.runelite.deob.attributes.code.Instructions;
import net.runelite.deob.pool.NameAndType; import net.runelite.deob.pool.NameAndType;
import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction; import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction;
import net.runelite.deob.attributes.code.instruction.types.ReturnInstruction; import net.runelite.deob.attributes.code.instruction.types.ReturnInstruction;
import org.apache.commons.lang3.mutable.MutableInt;
public class Frame public class Frame
{ {
@@ -23,10 +22,7 @@ public class Frame
private Variables variables; private Variables variables;
private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame
private MethodContext ctx; private MethodContext ctx;
protected MutableInt prevVertex = new MutableInt(-1); protected Method nonStatic; // next non static method up the stack
//protected int prevVertex = -1;
//private List<Method> prevInvokes;
private Frame from;
public Frame(Execution execution, Method method) public Frame(Execution execution, Method method)
{ {
@@ -38,6 +34,7 @@ public class Frame
stack = new Stack(code.getMaxStack()); stack = new Stack(code.getMaxStack());
variables = new Variables(code.getMaxLocals()); variables = new Variables(code.getMaxLocals());
ctx = execution.getMethodContext(method); ctx = execution.getMethodContext(method);
nonStatic = method;
} }
public void initialize() public void initialize()
@@ -63,12 +60,15 @@ public class Frame
// initialize frame from invoking context // initialize frame from invoking context
assert ctx.getInstruction() instanceof InvokeInstruction; assert ctx.getInstruction() instanceof InvokeInstruction;
if (!this.getExecution().isFollowInvokes() && this.getMethod().isStatic()) //if (!this.getExecution().isFollowInvokes() && this.getMethod().isStatic())
if (this.getMethod().isStatic())
{ {
assert from == null; //assert this.nonStatic == null;
from = ctx.getFrame(); this.nonStatic = ctx.getFrame().nonStatic;
this.ctx = ctx.getFrame().ctx; // share ctx if this method is static //assert from == null;
this.prevVertex = ctx.getFrame().prevVertex; //from = ctx.getFrame();
//this.ctx = ctx.getFrame().ctx; // share ctx if this method is static
//this.prevVertex = ctx.getFrame().prevVertex;
} }
// initialize LVT. the last argument is popped first, and is at arguments[0] // initialize LVT. the last argument is popped first, and is at arguments[0]
@@ -104,9 +104,10 @@ public class Frame
this.stack = new Stack(other.stack); this.stack = new Stack(other.stack);
this.variables = new Variables(other.variables); this.variables = new Variables(other.variables);
this.ctx = other.ctx; this.ctx = other.ctx;
this.prevVertex = new MutableInt(other.prevVertex); //this.prevVertex = new MutableInt(other.prevVertex);
//this.prevInvokes = other.prevInvokes; //this.prevInvokes = other.prevInvokes;
from = other.from; nonStatic = other.nonStatic;
// from = other.from;
} }
public Frame dup() public Frame dup()
@@ -175,10 +176,6 @@ public class Frame
{ {
Instruction oldCur = cur; Instruction oldCur = cur;
if (cur instanceof ReturnInstruction)
if (processReturn())
break;
try try
{ {
cur.execute(this); cur.execute(this);
@@ -211,7 +208,7 @@ public class Frame
if (!executing) if (!executing)
break; break;
ctx.buildGraph(this, oldCur); execution.buildGraph(this, oldCur);
if (oldCur == cur) if (oldCur == cur)
{ {
@@ -224,12 +221,12 @@ public class Frame
/* jump */ /* jump */
} }
if (!execution.frames.isEmpty() && execution.frames.get(0) != this) // if (!execution.frames.isEmpty() && execution.frames.get(0) != this)
{ // {
stop(); // the prev frame must be an invokestatic? // stop(); // the prev frame must be an invokestatic?
assert execution.frames.get(0).getMethod().isStatic(); // assert execution.frames.get(0).getMethod().isStatic();
break; // break;
} // }
} }
} }
@@ -267,7 +264,7 @@ public class Frame
assert to.getInstructions() == method.getCode().getInstructions(); assert to.getInstructions() == method.getCode().getInstructions();
assert method.getCode().getInstructions().getInstructions().contains(to); assert method.getCode().getInstructions().getInstructions().contains(to);
if (ctx.hasJumped(prevVertex, from, to)) if (ctx.hasJumped(from, to))
{ {
executing = false; executing = false;
return; return;
@@ -276,24 +273,24 @@ public class Frame
cur = to; cur = to;
} }
private boolean processReturn() // private boolean processReturn()
{ // {
if (this.getExecution().isFollowInvokes() || !this.getMethod().isStatic()) // if (this.getExecution().isFollowInvokes() || !this.getMethod().isStatic())
return false; // return false;
//
if (from == null) // if (from == null)
return false; // return false;
//
assert !from.isExecuting(); // assert !from.isExecuting();
//
// update method, cur, stack, variables, from outermost method // // update method, cur, stack, variables, from outermost method
this.method = from.method; // this.method = from.method;
//this.executing = from.executing; // //this.executing = from.executing;
this.cur = from.cur; // this.cur = from.cur;
this.stack = new Stack(from.stack); // this.stack = new Stack(from.stack);
this.variables = new Variables(from.variables); // this.variables = new Variables(from.variables);
//
//stop(); // now that weve switched this should still be running // //stop(); // now that weve switched this should still be running
return true; // this stops frame execution // return true; // this stops frame execution
} // }
} }

View File

@@ -1,51 +0,0 @@
package net.runelite.deob.execution;
import java.util.Objects;
class MIKey
{
private int prevVertex;
private InstructionContext ictx;
public MIKey(int prevVertex, InstructionContext ictx)
{
this.prevVertex = prevVertex;
this.ictx = ictx;
}
@Override
public int hashCode()
{
int hash = 7;
hash = 97 * hash + this.prevVertex;
hash = 97 * hash + Objects.hashCode(this.ictx);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final MIKey other = (MIKey) obj;
if (this.prevVertex != other.prevVertex)
{
return false;
}
if (!Objects.equals(this.ictx, other.ictx))
{
return false;
}
return true;
}
}

View File

@@ -1,130 +1,130 @@
package net.runelite.deob.execution; package net.runelite.deob.execution;
import edu.ucla.sspace.graph.DirectedEdge; import java.util.Arrays;
import edu.ucla.sspace.graph.Graph;
import edu.ucla.sspace.graph.SimpleDirectedEdge;
import edu.ucla.sspace.graph.SparseDirectedGraph;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import net.runelite.deob.Method; import net.runelite.deob.Method;
import net.runelite.deob.attributes.code.Instruction; import net.runelite.deob.attributes.code.Instruction;
import net.runelite.deob.attributes.code.instruction.types.FieldInstruction;
import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction; import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction;
import net.runelite.deob.attributes.code.instructions.InvokeStatic; import net.runelite.deob.attributes.code.instructions.InvokeStatic;
import net.runelite.deob.util.IdGen; import net.runelite.deob.deobfuscators.rename.graph.Graph;
import org.apache.commons.collections4.map.MultiValueMap; import org.apache.commons.collections4.map.MultiValueMap;
import org.apache.commons.lang3.mutable.MutableInt;
public class MethodContext public class MethodContext
{ {
private Execution execution; private Execution execution;
private MultiValueMap<MIKey, Instruction> visited = new MultiValueMap<>(); private MultiValueMap<InstructionContext, Instruction> visited = new MultiValueMap<>();
private IdGen ids = new IdGen(); //private IdGen ids = new IdGen();
private Map<Integer, List<Method>> idMap = new HashMap<>(); //private Map<Integer, List<Method>> idMap = new HashMap<>();
private Map<List<Method>, Integer> insMap = new HashMap<>(); //private Map<List<Method>, Integer> insMap = new HashMap<>();
private Graph graph = new SparseDirectedGraph(); // private Graph graph = new Graph();
public MethodContext(Execution execution) public MethodContext(Execution execution)
{ {
this.execution = execution; this.execution = execution;
} }
public Map<Integer, List<Method>> getIdMap() // public Map<Integer, List<Method>> getIdMap()
{ // {
return idMap; // return idMap;
} // }
public Graph getGraph()
{
return graph;
}
protected boolean hasJumped(MutableInt prevVertex, InstructionContext from, Instruction to)
protected boolean hasJumped(InstructionContext from, Instruction to)
{ {
// with this true, there are so many frames I can't run a full execution without oom. Collection<Instruction> i = visited.getCollection(from);
MIKey key = execution.isBuildGraph() ? new MIKey(prevVertex.intValue(), from) : new MIKey(-1, from);
Collection<Instruction> i = visited.getCollection(key);
if (i != null && i.contains(to)) if (i != null && i.contains(to))
return true; return true;
visited.put(key, to); visited.put(from, to);
return false; return false;
} }
private int getIdFor(List<Method> i) // private int getIdFor(List<Method> i)
{ // {
if (insMap.containsKey(i)) // if (insMap.containsKey(i))
return insMap.get(i); // return insMap.get(i);
//
// assert idMap.values().contains(i) == false;
//
// int id = ids.get();
//
// //graph.add(id);
//
// this.idMap.put(id, i);
// this.insMap.put(i, id);
//
// return id;
// }
assert idMap.values().contains(i) == false; // protected void buildGraph(Frame frame, Instruction i)
// {
int id = ids.get(); // if (!execution.isBuildGraph())
// return;
//graph.add(id); //
// List<Object> to;
this.idMap.put(id, i); // //List<Method> methods;
this.insMap.put(i, id); // if (i instanceof InvokeInstruction)
// {
return id; // if (i instanceof InvokeStatic)
} // return;
//
protected void buildGraph(Frame frame, Instruction i) // InvokeInstruction ii = (InvokeInstruction) i;
{ //
if (!execution.isBuildGraph()) // List<Method> methods = ii.getMethods();
return; // if (methods.isEmpty())
// return;
List<Method> methods; //
if (i instanceof InvokeInstruction) // to = (List) methods;
{ // }
if (i instanceof InvokeStatic)
return;
InvokeInstruction ii = (InvokeInstruction) i;
methods = ii.getMethods();
if (methods.isEmpty())
return;
}
// else if (i instanceof FieldInstruction) // else if (i instanceof FieldInstruction)
// { // {
// FieldInstruction fi = (FieldInstruction) i; // FieldInstruction fi = (FieldInstruction) i;
// //
// if (fi.getMyField() == null) // if (fi.getMyField() == null)
// return; // return;
//
// to = Arrays.asList(fi.getMyField());
// } // }
else // else
{ // {
return; // return;
} // }
//
if (frame.prevVertex.intValue() == -1) // to.stream().forEach(o -> graph.addEdge(frame.getMethod(), o));
{ //
int id = getIdFor(methods); //// if (frame.prevVertex.intValue() == -1)
//int id = ids.get(); //// {
//graph.add(id); //// int id = getIdFor(methods);
frame.prevVertex.setValue(id); //// //int id = ids.get();
//this.idMap.put(id, i); //// //graph.add(id);
return; //// frame.prevVertex.setValue(id);
} //// //this.idMap.put(id, i);
//// return;
int id = getIdFor(methods); //// }
//int id = ids.get(); ////
//graph.add(id); //// int id = getIdFor(methods);
//idMap.put(id, i); //// //int id = ids.get();
//// //graph.add(id);
if (frame.prevVertex.intValue() == id) //// //idMap.put(id, i);
return; ////
//// if (frame.prevVertex.intValue() == id)
List<Method> from = this.idMap.get(frame.prevVertex.intValue()), to = this.idMap.get(id); //// return;
System.out.println("Added edge " + from.get(0).getMethods().getClassFile().getName() + "." + from.get(0).getName() + ////
" to " + to.get(0).getMethods().getClassFile().getName() + "." + to.get(0).getName() + //// DirectedEdge edge = new SimpleDirectedEdge(frame.prevVertex.intValue(), id);
" (" + frame.prevVertex.intValue() + " -> " + id + ")"); ////
//// if (graph.contains(edge) == false)
DirectedEdge edge = new SimpleDirectedEdge(frame.prevVertex.intValue(), id); //// {
graph.add(edge); //// List<Method> from = this.idMap.get(frame.prevVertex.intValue()), to = this.idMap.get(id);
//// System.out.println("Added edge " + from.get(0).getMethods().getClassFile().getName() + "." + from.get(0).getName() +
frame.prevVertex.setValue(id); //// " to " + to.get(0).getMethods().getClassFile().getName() + "." + to.get(0).getName() +
} //// " (" + frame.prevVertex.intValue() + " -> " + id + ")");
////
//// graph.add(edge);
//// }
////
//// frame.prevVertex.setValue(id);
// }
} }

View File

@@ -2,6 +2,7 @@ package net.runelite.deob.signature;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -48,6 +49,15 @@ public class Signature
return arguments.equals(a.arguments) && rv.equals(a.rv); return arguments.equals(a.arguments) && rv.equals(a.rv);
} }
@Override
public int hashCode()
{
int hash = 5;
hash = 97 * hash + Objects.hashCode(this.arguments);
hash = 97 * hash + Objects.hashCode(this.rv);
return hash;
}
@Override @Override
public String toString() public String toString()
{ {

View File

@@ -1,134 +1,133 @@
package net.runelite.deob.execution; //package net.runelite.deob.execution;
//
import edu.ucla.sspace.graph.Graph; //import net.runelite.deob.ClassGroup;
import net.runelite.deob.ClassGroup; //import net.runelite.deob.ClassGroupFactory;
import net.runelite.deob.ClassGroupFactory; //import net.runelite.deob.Method;
import net.runelite.deob.Method; //import net.runelite.deob.attributes.Code;
import net.runelite.deob.attributes.Code; //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.instructions.Goto;
import net.runelite.deob.attributes.code.instructions.Goto; //import net.runelite.deob.attributes.code.instructions.IConst_0;
import net.runelite.deob.attributes.code.instructions.IConst_0; //import net.runelite.deob.attributes.code.instructions.If0;
import net.runelite.deob.attributes.code.instructions.If0; //import net.runelite.deob.attributes.code.instructions.InvokeStatic;
import net.runelite.deob.attributes.code.instructions.InvokeStatic; //import net.runelite.deob.attributes.code.instructions.NOP;
import net.runelite.deob.attributes.code.instructions.NOP; //import net.runelite.deob.attributes.code.instructions.VReturn;
import net.runelite.deob.attributes.code.instructions.VReturn; //import net.runelite.deob.deobfuscators.rename.graph.Graph;
import net.runelite.deob.signature.Signature; //import org.junit.Assert;
import org.junit.Assert; //import org.junit.Test;
import org.junit.Test; //
//public class FrameTest
public class FrameTest //{
{ // // invoke instruction,
// invoke instruction, // // conditional jump out,
// conditional jump out, // // both jump in,
// both jump in, // // jump,
// jump, // // invoke
// invoke // // check that num edges = 4
// check that num edges = 4 // @Test
@Test // public void testGraph()
public void testGraph() // {
{ // ClassGroup group = ClassGroupFactory.generateGroup();
ClassGroup group = ClassGroupFactory.generateGroup(); // Code code = group.findClass("test").findMethod("func").getCode();
Code code = group.findClass("test").findMethod("func").getCode(); // Instructions ins = code.getInstructions();
Instructions ins = code.getInstructions(); //
// code.setMaxStack(1);
code.setMaxStack(1); //
// Method void1 = group.findClass("test").findMethod("void1"),
Method void1 = group.findClass("test").findMethod("void1"), // void2 = group.findClass("test").findMethod("void2"),
void2 = group.findClass("test").findMethod("void2"), // void3 = group.findClass("test").findMethod("void3"),
void3 = group.findClass("test").findMethod("void3"), // void4 = group.findClass("test").findMethod("void4");
void4 = group.findClass("test").findMethod("void4"); //
// NOP label1 = new NOP(ins),
NOP label1 = new NOP(ins), // label2 = new NOP(ins),
label2 = new NOP(ins), // label3 = new NOP(ins);
label3 = new NOP(ins); //
// Instruction body[] = {
Instruction body[] = { // new InvokeStatic(ins, void1.getPoolMethod()),
new InvokeStatic(ins, void1.getPoolMethod()), //
// new IConst_0(ins),
new IConst_0(ins), // new If0(ins, label1),
new If0(ins, label1), //
// new InvokeStatic(ins, void2.getPoolMethod()),
new InvokeStatic(ins, void2.getPoolMethod()), // new Goto(ins, label2),
new Goto(ins, label2), //
// label1,
label1, // new InvokeStatic(ins, void3.getPoolMethod()),
new InvokeStatic(ins, void3.getPoolMethod()), //
// label2,
label2, // // do something dumb
// do something dumb //
// new Goto(ins, label3),
new Goto(ins, label3), // label3,
label3, //
// new InvokeStatic(ins, void4.getPoolMethod()),
new InvokeStatic(ins, void4.getPoolMethod()), //
// new VReturn(ins)
new VReturn(ins) // };
}; //
// for (Instruction i : body)
for (Instruction i : body) // ins.addInstruction(i);
ins.addInstruction(i); //
// Execution e = new Execution(group);
Execution e = new Execution(group); // e.setBuildGraph(true);
e.setBuildGraph(true); // e.populateInitialMethods();
e.populateInitialMethods(); // e.run();
e.run(); //
// Graph graph = e.processedFrames.get(0).getMethodCtx().getGraph();
Graph graph = e.processedFrames.get(0).getMethodCtx().getGraph(); // Assert.assertEquals(4, graph.size());
Assert.assertEquals(4, graph.size()); // }
} //
// // invoke instruction,
// invoke instruction, // // conditional jump out,
// conditional jump out, // // both jump in,
// both jump in, // // invoke
// invoke // // check that num edges = 4
// check that num edges = 4 // @Test
@Test // public void testGraph2()
public void testGraph2() // {
{ // ClassGroup group = ClassGroupFactory.generateGroup();
ClassGroup group = ClassGroupFactory.generateGroup(); // Code code = group.findClass("test").findMethod("func").getCode();
Code code = group.findClass("test").findMethod("func").getCode(); // Instructions ins = code.getInstructions();
Instructions ins = code.getInstructions(); //
// code.setMaxStack(1);
code.setMaxStack(1); //
// Method void1 = group.findClass("test").findMethod("void1"),
Method void1 = group.findClass("test").findMethod("void1"), // void2 = group.findClass("test").findMethod("void2"),
void2 = group.findClass("test").findMethod("void2"), // void3 = group.findClass("test").findMethod("void3"),
void3 = group.findClass("test").findMethod("void3"), // void4 = group.findClass("test").findMethod("void4");
void4 = group.findClass("test").findMethod("void4"); //
// NOP label1 = new NOP(ins),
NOP label1 = new NOP(ins), // label2 = new NOP(ins);
label2 = new NOP(ins); //
// Instruction body[] = {
Instruction body[] = { // new InvokeStatic(ins, void1.getPoolMethod()),
new InvokeStatic(ins, void1.getPoolMethod()), //
// new IConst_0(ins),
new IConst_0(ins), // new If0(ins, label1),
new If0(ins, label1), //
// new InvokeStatic(ins, void2.getPoolMethod()),
new InvokeStatic(ins, void2.getPoolMethod()), // new Goto(ins, label2),
new Goto(ins, label2), //
// label1,
label1, // new InvokeStatic(ins, void3.getPoolMethod()),
new InvokeStatic(ins, void3.getPoolMethod()), //
// label2,
label2, // // do something dumb
// do something dumb //
// new InvokeStatic(ins, void4.getPoolMethod()),
new InvokeStatic(ins, void4.getPoolMethod()), //
// new VReturn(ins)
new VReturn(ins) // };
}; //
// for (Instruction i : body)
for (Instruction i : body) // ins.addInstruction(i);
ins.addInstruction(i); //
// Execution e = new Execution(group);
Execution e = new Execution(group); // e.setBuildGraph(true);
e.setBuildGraph(true); // e.populateInitialMethods();
e.populateInitialMethods(); // e.run();
e.run(); //
// Graph graph = e.processedFrames.get(0).getMethodCtx().getGraph();
Graph graph = e.processedFrames.get(0).getMethodCtx().getGraph(); // Assert.assertEquals(4, graph.size());
Assert.assertEquals(4, graph.size()); // }
} //}
}