Add class mapper and use it in annotation mapper, which seems to work more reliably
This commit is contained in:
@@ -211,6 +211,7 @@ public class ModArith implements Deobfuscator
|
||||
{
|
||||
Number value;
|
||||
boolean other;
|
||||
boolean constant;
|
||||
}
|
||||
private MultiValueMap<Field, AssociatedConstant> constants = new MultiValueMap();
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user