Add class mapper and use it in annotation mapper, which seems to work more reliably

This commit is contained in:
Adam
2016-03-30 19:43:47 -04:00
parent b3efaec8e6
commit a163bc4c46
9 changed files with 231 additions and 6 deletions

View File

@@ -211,6 +211,7 @@ public class ModArith implements Deobfuscator
{
Number value;
boolean other;
boolean constant;
}
private MultiValueMap<Field, AssociatedConstant> constants = new MultiValueMap();

View File

@@ -29,10 +29,19 @@ public class AnnotationMapper
public void run()
{
int count = 0;
ClassGroupMapper m = new ClassGroupMapper(source, target);
m.map();
for (ClassFile c : source.getClasses())
{
ClassFile other = (ClassFile) mapping.get(c);
ClassFile other = m.get(c);
if (other == null)
{
other = (ClassFile) mapping.get(c);
System.out.println("FALLBACK " + c + " -> " + other);
}
if (other == null)
{

View File

@@ -0,0 +1,44 @@
package net.runelite.deob.deobfuscators.rename;
import java.util.HashMap;
import java.util.Map;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
public class ClassGroupMapper
{
private final ClassGroup one, two;
private final Map<ClassFile, ClassFile> map = new HashMap<>();
public ClassGroupMapper(ClassGroup one, ClassGroup two)
{
this.one = one;
this.two = two;
}
public void map()
{
for (ClassFile cf1 : one.getClasses())
for (ClassFile cf2 : two.getClasses())
{
if (!MappingExecutorUtil.isMaybeEqual(cf1, cf2))
continue;
ClassMapper m = new ClassMapper(cf1, cf2);
if (!m.same())
continue;
map.put(cf1, cf2);
}
}
public Map<ClassFile, ClassFile> getMap()
{
return map;
}
public ClassFile get(ClassFile c)
{
return map.get(c);
}
}

View File

@@ -0,0 +1,68 @@
package net.runelite.deob.deobfuscators.rename;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.runelite.asm.ClassFile;
import net.runelite.asm.signature.Signature;
import net.runelite.asm.signature.Type;
import org.apache.commons.collections4.CollectionUtils;
public class ClassMapper
{
private final ClassFile one, two;
public ClassMapper(ClassFile one, ClassFile two)
{
this.one = one;
this.two = two;
}
private List<Integer> fieldCardinalities(ClassFile cf)
{
List<Type> t = cf.getFields().getFields().stream()
.filter(f -> !f.isStatic())
.map(f -> f.getType())
.collect(Collectors.toList());
Map<Type, Integer> m = CollectionUtils.getCardinalityMap(t);
List<Integer> occurances = new ArrayList<>(m.values());
Collections.sort(occurances);
return occurances;
}
private List<Integer> methodCardinalities(ClassFile cf)
{
List<Signature> t = cf.getMethods().getMethods().stream()
.filter(m -> !m.isStatic())
.filter(m -> !m.getName().startsWith("<"))
.map(m -> m.getDescriptor())
.collect(Collectors.toList());
Map<Signature, Integer> m = CollectionUtils.getCardinalityMap(t);
List<Integer> occurances = new ArrayList<>(m.values());
Collections.sort(occurances);
return occurances;
}
public boolean same()
{
List<Integer> c1 = fieldCardinalities(one), c2 = fieldCardinalities(two);
if (!c1.equals(c2))
return false;
c1 = methodCardinalities(one);
c2 = methodCardinalities(two);
if (!c1.equals(c2))
return false;
return true;
}
}

View File

@@ -38,6 +38,8 @@ public class Mapper
finalm.merge(mapStaticMethods(source, target));
finalm.merge(mapMethods(source, target));
finalm.merge(mapPackets(finalm, source, target));
finalm.buildClasses();
mapping = finalm;
}

View File

@@ -1,11 +1,8 @@
package net.runelite.deob.deobfuscators.rename;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
import net.runelite.asm.Interfaces;
import net.runelite.asm.Method;
import net.runelite.asm.attributes.code.Instruction;
import net.runelite.asm.attributes.code.instruction.types.ArrayLoad;
@@ -330,6 +327,19 @@ public class MappingExecutorUtil
public static boolean isMaybeEqual(ClassFile cf1, ClassFile cf2)
{
if (cf1 == null && cf2 == null)
return true;
if (cf1 == null || cf2 == null)
return false;
if (!isMaybeEqual(cf1.getParent(), cf2.getParent()))
return false;
Interfaces i1 = cf1.getInterfaces(), i2 = cf2.getInterfaces();
if (i1.getInterfaces().size() != i2.getInterfaces().size())
return false;
return true;
}
}

View File

@@ -4,6 +4,7 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -80,7 +81,7 @@ public class ParallelExecutorMapping
public void map(Object one, Object two)
{
mapClass(one, two);
//mapClass(one, two);
Mapping m = getMapping(one, two);
@@ -101,6 +102,11 @@ public class ParallelExecutorMapping
Field f1 = (Field) one;
Field f2 = (Field) two;
assert f1.isStatic() == f2.isStatic();
if (f1.isStatic() || f2.isStatic())
return;
cf1 = f1.getFields().getClassFile();
cf2 = f2.getFields().getClassFile();
@@ -112,6 +118,11 @@ public class ParallelExecutorMapping
Method m1 = (Method) one;
Method m2 = (Method) two;
assert m1.isStatic() == m1.isStatic();
if (m1.isStatic() || m2.isStatic())
return;
cf1 = m1.getMethods().getClassFile();
cf2 = m2.getMethods().getClassFile();
@@ -130,6 +141,21 @@ public class ParallelExecutorMapping
m.inc();
}
public void buildClasses()
{
for (Object o : new HashSet<>(map.keySet()))
if (o instanceof ClassFile)
map.removeAll(o);
Map<Object, Object> map = getMap();
for (Object key : map.keySet())
{
Object value = map.get(key);
mapClass(key, value);
}
}
public Object get(Object o)
{
return highest(o);

View File

@@ -0,0 +1,37 @@
package net.runelite.deob.deobfuscators.rename;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
import net.runelite.deob.util.JarUtil;
import org.junit.Test;
/**
*
* @author Adam
*/
public class ClassGroupMapperTest
{
private static final String JAR1 = "C:\\Users\\Adam\\.m2\\repository\\net\\runelite\\rs\\rs-client\\1.0-SNAPSHOT\\rs-client-1.0-SNAPSHOT.jar",
JAR2 = "c:/rs/gamepack_v19_postmath.jar",
OUT = "c:/rs/adamout.jar";
@Test
public void testRun() throws IOException
{
ClassGroup group1 = JarUtil.loadJar(new File(JAR1));
ClassGroup group2 = JarUtil.loadJar(new File(JAR2));
ClassGroupMapper m = new ClassGroupMapper(group1, group2);
m.map();
for (ClassFile cf : group1.getClasses())
{
ClassFile cf2 = m.get(cf);
System.out.println(cf + " -> " + cf2);
}
}
}

View File

@@ -0,0 +1,28 @@
package net.runelite.deob.deobfuscators.rename;
import java.io.File;
import java.io.IOException;
import net.runelite.asm.ClassGroup;
import net.runelite.deob.util.JarUtil;
import org.junit.Assert;
import org.junit.Test;
/**
*
* @author Adam
*/
public class ClassMapperTest
{
private static final String JAR1 = "C:\\Users\\Adam\\.m2\\repository\\net\\runelite\\rs\\rs-client\\1.0-SNAPSHOT\\rs-client-1.0-SNAPSHOT.jar",
JAR2 = "c:/rs/gamepack_v19_postmath.jar";
@Test
public void testRun() throws IOException
{
ClassGroup group1 = JarUtil.loadJar(new File(JAR1));
ClassGroup group2 = JarUtil.loadJar(new File(JAR2));
ClassMapper m = new ClassMapper(group1.findClass("class118"), group2.findClass("class119"));
Assert.assertTrue(m.same());
}
}