From a163bc4c46e2730716823e4b1b337e7ed93ba3f5 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 30 Mar 2016 19:43:47 -0400 Subject: [PATCH] Add class mapper and use it in annotation mapper, which seems to work more reliably --- .../deobfuscators/arithmetic/ModArith.java | 1 + .../rename/AnnotationMapper.java | 11 ++- .../rename/ClassGroupMapper.java | 44 ++++++++++++ .../deobfuscators/rename/ClassMapper.java | 68 +++++++++++++++++++ .../deob/deobfuscators/rename/Mapper.java | 2 + .../rename/MappingExecutorUtil.java | 18 +++-- .../rename/ParallelExecutorMapping.java | 28 +++++++- .../rename/ClassGroupMapperTest.java | 37 ++++++++++ .../deobfuscators/rename/ClassMapperTest.java | 28 ++++++++ 9 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 src/main/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapper.java create mode 100644 src/main/java/net/runelite/deob/deobfuscators/rename/ClassMapper.java create mode 100644 src/test/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapperTest.java create mode 100644 src/test/java/net/runelite/deob/deobfuscators/rename/ClassMapperTest.java diff --git a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java index a4448fde35..071a4e6131 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java +++ b/src/main/java/net/runelite/deob/deobfuscators/arithmetic/ModArith.java @@ -211,6 +211,7 @@ public class ModArith implements Deobfuscator { Number value; boolean other; + boolean constant; } private MultiValueMap constants = new MultiValueMap(); diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/AnnotationMapper.java b/src/main/java/net/runelite/deob/deobfuscators/rename/AnnotationMapper.java index cb4b26e7b7..ab0e5debd3 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/AnnotationMapper.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/AnnotationMapper.java @@ -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) { diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapper.java b/src/main/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapper.java new file mode 100644 index 0000000000..0a4170ad17 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapper.java @@ -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 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 getMap() + { + return map; + } + + public ClassFile get(ClassFile c) + { + return map.get(c); + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/ClassMapper.java b/src/main/java/net/runelite/deob/deobfuscators/rename/ClassMapper.java new file mode 100644 index 0000000000..bb42d35368 --- /dev/null +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/ClassMapper.java @@ -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 fieldCardinalities(ClassFile cf) + { + List t = cf.getFields().getFields().stream() + .filter(f -> !f.isStatic()) + .map(f -> f.getType()) + .collect(Collectors.toList()); + + Map m = CollectionUtils.getCardinalityMap(t); + + List occurances = new ArrayList<>(m.values()); + Collections.sort(occurances); + return occurances; + } + + private List methodCardinalities(ClassFile cf) + { + List t = cf.getMethods().getMethods().stream() + .filter(m -> !m.isStatic()) + .filter(m -> !m.getName().startsWith("<")) + .map(m -> m.getDescriptor()) + .collect(Collectors.toList()); + + Map m = CollectionUtils.getCardinalityMap(t); + + List occurances = new ArrayList<>(m.values()); + Collections.sort(occurances); + return occurances; + } + + public boolean same() + { + List 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; + } +} diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/Mapper.java b/src/main/java/net/runelite/deob/deobfuscators/rename/Mapper.java index f9f0665a44..dc9ba7f0c6 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/Mapper.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/Mapper.java @@ -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; } diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/MappingExecutorUtil.java b/src/main/java/net/runelite/deob/deobfuscators/rename/MappingExecutorUtil.java index 0f1b2f2ea7..f872640a5f 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/MappingExecutorUtil.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/MappingExecutorUtil.java @@ -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; } } diff --git a/src/main/java/net/runelite/deob/deobfuscators/rename/ParallelExecutorMapping.java b/src/main/java/net/runelite/deob/deobfuscators/rename/ParallelExecutorMapping.java index 920761ea81..e8dee04ede 100644 --- a/src/main/java/net/runelite/deob/deobfuscators/rename/ParallelExecutorMapping.java +++ b/src/main/java/net/runelite/deob/deobfuscators/rename/ParallelExecutorMapping.java @@ -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 map = getMap(); + for (Object key : map.keySet()) + { + Object value = map.get(key); + + mapClass(key, value); + } + } + public Object get(Object o) { return highest(o); diff --git a/src/test/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapperTest.java b/src/test/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapperTest.java new file mode 100644 index 0000000000..a06dd055d2 --- /dev/null +++ b/src/test/java/net/runelite/deob/deobfuscators/rename/ClassGroupMapperTest.java @@ -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); + } + } +} diff --git a/src/test/java/net/runelite/deob/deobfuscators/rename/ClassMapperTest.java b/src/test/java/net/runelite/deob/deobfuscators/rename/ClassMapperTest.java new file mode 100644 index 0000000000..35c1e22e0b --- /dev/null +++ b/src/test/java/net/runelite/deob/deobfuscators/rename/ClassMapperTest.java @@ -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()); + } +}