summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/bytecode
diff options
context:
space:
mode:
authorGravatar jeff2015-03-16 19:22:22 -0400
committerGravatar jeff2015-03-16 19:22:22 -0400
commit5e3743a0aca3529eacf9be400c8b8d7547f66e7f (patch)
treeea601747547f78e1b83ab828650932126440e221 /src/cuchaz/enigma/bytecode
parentupdate to new javassist version to (hopefully) get bug fixes (diff)
downloadenigma-fork-5e3743a0aca3529eacf9be400c8b8d7547f66e7f.tar.gz
enigma-fork-5e3743a0aca3529eacf9be400c8b8d7547f66e7f.tar.xz
enigma-fork-5e3743a0aca3529eacf9be400c8b8d7547f66e7f.zip
started adding minimal support for generics
fixed mark-as-deobfuscated issue
Diffstat (limited to 'src/cuchaz/enigma/bytecode')
-rw-r--r--src/cuchaz/enigma/bytecode/ClassRenamer.java164
-rw-r--r--src/cuchaz/enigma/bytecode/ClassTranslator.java42
2 files changed, 124 insertions, 82 deletions
diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java
index e9cdea3..8bc084d 100644
--- a/src/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -23,60 +23,100 @@ import com.google.common.collect.Maps;
23import com.google.common.collect.Sets; 23import com.google.common.collect.Sets;
24 24
25import cuchaz.enigma.mapping.ClassEntry; 25import cuchaz.enigma.mapping.ClassEntry;
26import cuchaz.enigma.mapping.ClassNameReplacer;
27import cuchaz.enigma.mapping.ParameterizedType;
28import cuchaz.enigma.mapping.Translator;
29import cuchaz.enigma.mapping.Type;
26 30
27public class ClassRenamer { 31public class ClassRenamer {
28 32
29 public static void renameClasses(CtClass c, Map<ClassEntry,ClassEntry> map) { 33 public static void renameClasses(CtClass c, final Translator translator) {
30 34 renameClasses(c, new ClassNameReplacer() {
31 // build the map used by javassist 35 @Override
32 ClassMap nameMap = new ClassMap(); 36 public String replace(String className) {
33 for (Map.Entry<ClassEntry,ClassEntry> entry : map.entrySet()) { 37 ClassEntry entry = translator.translateEntry(new ClassEntry(className));
34 nameMap.put(entry.getKey().getName(), entry.getValue().getName()); 38 if (entry != null) {
35 } 39 return entry.getName();
36
37 c.replaceClassName(nameMap);
38
39 // replace simple names in the InnerClasses attribute too
40 ConstPool constants = c.getClassFile().getConstPool();
41 InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag);
42 if (attr != null) {
43 for (int i = 0; i < attr.tableLength(); i++) {
44 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i)));
45 if (attr.innerNameIndex(i) != 0) {
46 attr.setInnerNameIndex(i, constants.addUtf8Info(classEntry.getInnermostClassName()));
47 } 40 }
48 41 return null;
49 /* DEBUG
50 System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i)));
51 */
52 } 42 }
53 } 43 });
54 } 44 }
55 45
56 public static Set<ClassEntry> getAllClassEntries(final CtClass c) { 46 public static void moveAllClassesOutOfDefaultPackage(CtClass c, final String newPackageName) {
47 renameClasses(c, new ClassNameReplacer() {
48 @Override
49 public String replace(String className) {
50 ClassEntry entry = new ClassEntry(className);
51 if (entry.isInDefaultPackage()) {
52 return newPackageName + "/" + entry.getName();
53 }
54 return null;
55 }
56 });
57 }
58
59 public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) {
60 renameClasses(c, new ClassNameReplacer() {
61 @Override
62 public String replace(String className) {
63 ClassEntry entry = new ClassEntry(className);
64 if (entry.getPackageName().equals(oldPackageName)) {
65 return entry.getSimpleName();
66 }
67 return null;
68 }
69 });
70 }
71
72 public static void renameClasses(CtClass c, ClassNameReplacer replacer) {
73 Map<ParameterizedType,ParameterizedType> map = Maps.newHashMap();
74 for (ParameterizedType type : ClassRenamer.getAllClassTypes(c)) {
75 ParameterizedType renamedType = new ParameterizedType(type, replacer);
76 if (!type.equals(renamedType)) {
77 map.put(type, renamedType);
78 }
79 }
80 renameTypes(c, map);
81 }
82
83 public static Set<ParameterizedType> getAllClassTypes(final CtClass c) {
57 84
58 // get the classes that javassist knows about 85 // TODO: might have to scan SignatureAttributes directly because javassist is buggy
59 final Set<ClassEntry> entries = Sets.newHashSet(); 86
87 // get the class types that javassist knows about
88 final Set<ParameterizedType> types = Sets.newHashSet();
60 ClassMap map = new ClassMap() { 89 ClassMap map = new ClassMap() {
61 @Override 90 @Override
62 public Object get(Object obj) { 91 public Object get(Object obj) {
63 if (obj instanceof String) { 92 if (obj instanceof String) {
64 String str = (String)obj; 93 String str = (String)obj;
65 94
66 // javassist throws a lot of weird things at this map 95 // sometimes javasist gives us dot-separated classes... whadda hell?
67 // I either have to implement my on class scanner, or just try to filter out the weirdness 96 str = str.replace('.', '/');
68 // I'm opting to filter out the weirdness for now
69 97
70 // skip anything with generic arguments 98 // skip weird types
71 if (str.indexOf('<') >= 0 || str.indexOf('>') >= 0 || str.indexOf(';') >= 0) { 99 boolean hasNestedParams = str.indexOf('<') >= 0 && str.indexOf('<', str.indexOf('<')+1) >= 0;
100 boolean hasWeirdChars = str.indexOf('*') >= 0 || str.indexOf('-') >= 0 || str.indexOf('+') >= 0;
101 if (hasNestedParams || hasWeirdChars) {
102 // TEMP
103 System.out.println("Skipped translating: " + str);
72 return null; 104 return null;
73 } 105 }
74 106
75 // convert path/to/class.inner to path/to/class$inner 107 ParameterizedType type = new ParameterizedType(new Type("L" + str + ";"));
76 str = str.replace('.', '$'); 108 assert(type.isClass());
109 // TEMP
110 try {
111 type.getClassEntry();
112 } catch (Throwable t) {
113 // bad type
114 // TEMP
115 System.out.println("Skipped translating: " + str);
116 return null;
117 }
77 118
78 // remember everything else 119 types.add(type);
79 entries.add(new ClassEntry(str));
80 } 120 }
81 return null; 121 return null;
82 } 122 }
@@ -85,26 +125,46 @@ public class ClassRenamer {
85 }; 125 };
86 c.replaceClassName(map); 126 c.replaceClassName(map);
87 127
88 return entries; 128 return types;
89 } 129 }
90 130
91 public static void moveAllClassesOutOfDefaultPackage(CtClass c, String newPackageName) { 131 public static void renameTypes(CtClass c, Map<ParameterizedType,ParameterizedType> map) {
92 Map<ClassEntry,ClassEntry> map = Maps.newHashMap(); 132
93 for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { 133 // convert the type map to a javassist class map
94 if (classEntry.isInDefaultPackage()) { 134 ClassMap nameMap = new ClassMap();
95 map.put(classEntry, new ClassEntry(newPackageName + "/" + classEntry.getName())); 135 for (Map.Entry<ParameterizedType,ParameterizedType> entry : map.entrySet()) {
96 } 136 String source = entry.getKey().toString();
137 String dest = entry.getValue().toString();
138
139 // don't forget to chop off the L ... ;
140 // javassist doesn't want it there
141 source = source.substring(1, source.length() - 1);
142 dest = dest.substring(1, dest.length() - 1);
143
144 nameMap.put(source, dest);
97 } 145 }
98 ClassRenamer.renameClasses(c, map); 146
99 } 147 // replace!!
100 148 c.replaceClassName(nameMap);
101 public static void moveAllClassesIntoDefaultPackage(CtClass c, String oldPackageName) { 149
102 Map<ClassEntry,ClassEntry> map = Maps.newHashMap(); 150 // replace simple names in the InnerClasses attribute too
103 for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { 151 ConstPool constants = c.getClassFile().getConstPool();
104 if (classEntry.getPackageName().equals(oldPackageName)) { 152 InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag);
105 map.put(classEntry, new ClassEntry(classEntry.getSimpleName())); 153 if (attr != null) {
154 for (int i = 0; i < attr.tableLength(); i++) {
155
156 // get the inner class full name (which has already been translated)
157 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i)));
158
159 if (attr.innerNameIndex(i) != 0) {
160 // update the inner name
161 attr.setInnerNameIndex(i, constants.addUtf8Info(classEntry.getInnermostClassName()));
162 }
163
164 /* DEBUG
165 System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i)));
166 */
106 } 167 }
107 } 168 }
108 ClassRenamer.renameClasses(c, map);
109 } 169 }
110} 170}
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java
index 94ab2c4..7952577 100644
--- a/src/cuchaz/enigma/bytecode/ClassTranslator.java
+++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java
@@ -10,8 +10,6 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.bytecode; 11package cuchaz.enigma.bytecode;
12 12
13import java.util.Map;
14
15import javassist.CtBehavior; 13import javassist.CtBehavior;
16import javassist.CtClass; 14import javassist.CtClass;
17import javassist.CtField; 15import javassist.CtField;
@@ -19,9 +17,6 @@ import javassist.CtMethod;
19import javassist.bytecode.ConstPool; 17import javassist.bytecode.ConstPool;
20import javassist.bytecode.Descriptor; 18import javassist.bytecode.Descriptor;
21import javassist.bytecode.SourceFileAttribute; 19import javassist.bytecode.SourceFileAttribute;
22
23import com.google.common.collect.Maps;
24
25import cuchaz.enigma.mapping.BehaviorEntry; 20import cuchaz.enigma.mapping.BehaviorEntry;
26import cuchaz.enigma.mapping.ClassEntry; 21import cuchaz.enigma.mapping.ClassEntry;
27import cuchaz.enigma.mapping.EntryFactory; 22import cuchaz.enigma.mapping.EntryFactory;
@@ -50,20 +45,15 @@ public class ClassTranslator {
50 45
51 case ConstPool.CONST_Fieldref: { 46 case ConstPool.CONST_Fieldref: {
52 47
53 // translate the name 48 // translate the name and type
54 FieldEntry entry = new FieldEntry( 49 FieldEntry entry = EntryFactory.getFieldEntry(
55 new ClassEntry(Descriptor.toJvmName(constants.getFieldrefClassName(i))), 50 Descriptor.toJvmName(constants.getFieldrefClassName(i)),
56 constants.getFieldrefName(i), 51 constants.getFieldrefName(i),
57 new Type(constants.getFieldrefType(i)) 52 constants.getFieldrefType(i)
58 ); 53 );
59 FieldEntry translatedEntry = m_translator.translateEntry(entry); 54 FieldEntry translatedEntry = m_translator.translateEntry(entry);
60 55 if (!entry.equals(translatedEntry)) {
61 // translate the type 56 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedEntry.getType().toString());
62 Type type = new Type(constants.getFieldrefType(i));
63 Type translatedType = m_translator.translateType(type);
64
65 if (!entry.equals(translatedEntry) || !type.equals(translatedType)) {
66 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedType.toString());
67 } 57 }
68 } 58 }
69 break; 59 break;
@@ -71,15 +61,14 @@ public class ClassTranslator {
71 case ConstPool.CONST_Methodref: 61 case ConstPool.CONST_Methodref:
72 case ConstPool.CONST_InterfaceMethodref: { 62 case ConstPool.CONST_InterfaceMethodref: {
73 63
74 // translate the name and type 64 // translate the name and type (ie signature)
75 BehaviorEntry entry = EntryFactory.getBehaviorEntry( 65 BehaviorEntry entry = EntryFactory.getBehaviorEntry(
76 Descriptor.toJvmName(editor.getMemberrefClassname(i)), 66 Descriptor.toJvmName(editor.getMemberrefClassname(i)),
77 editor.getMemberrefName(i), 67 editor.getMemberrefName(i),
78 editor.getMemberrefType(i) 68 editor.getMemberrefType(i)
79 ); 69 );
80 BehaviorEntry translatedEntry = m_translator.translateEntry(entry); 70 BehaviorEntry translatedEntry = m_translator.translateEntry(entry);
81 71 if (!entry.equals(translatedEntry)) {
82 if (!entry.getName().equals(translatedEntry.getName()) || !entry.getSignature().equals(translatedEntry.getSignature())) {
83 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedEntry.getSignature().toString()); 72 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedEntry.getSignature().toString());
84 } 73 }
85 } 74 }
@@ -120,25 +109,18 @@ public class ClassTranslator {
120 } 109 }
121 110
122 if (entry.getSignature() != null) { 111 if (entry.getSignature() != null) {
123 // translate the type 112 // translate the signature
124 Signature translatedSignature = m_translator.translateSignature(entry.getSignature()); 113 Signature translatedSignature = m_translator.translateSignature(entry.getSignature());
125 behavior.getMethodInfo().setDescriptor(translatedSignature.toString()); 114 behavior.getMethodInfo().setDescriptor(translatedSignature.toString());
126 } 115 }
127 } 116 }
128 117
129 // translate all the class names referenced in the code 118 // translate all the class names referenced in the code
130 // the above code only changed method/field/reference names and types, but not the class names themselves 119 // the above code only changed method/field/reference names and types, but not the rest of the class references
131 Map<ClassEntry,ClassEntry> map = Maps.newHashMap(); 120 ClassRenamer.renameClasses(c, m_translator);
132 for (ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries(c)) {
133 ClassEntry deobfClassEntry = m_translator.translateEntry(obfClassEntry);
134 if (!obfClassEntry.equals(deobfClassEntry)) {
135 map.put(obfClassEntry, deobfClassEntry);
136 }
137 }
138 ClassRenamer.renameClasses(c, map);
139 121
140 // translate the source file attribute too 122 // translate the source file attribute too
141 ClassEntry deobfClassEntry = map.get(classEntry); 123 ClassEntry deobfClassEntry = m_translator.translateEntry(classEntry);
142 if (deobfClassEntry != null) { 124 if (deobfClassEntry != null) {
143 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassName()) + ".java"; 125 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassName()) + ".java";
144 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); 126 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile));