diff options
| author | 2017-03-08 08:17:04 +0100 | |
|---|---|---|
| committer | 2017-03-08 08:17:04 +0100 | |
| commit | 6e464ea251cab63c776ece0b2a356f1498ffa294 (patch) | |
| tree | 5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/Deobfuscator.java | |
| parent | Drop unix case style and implement hashCode when equals is overrided (diff) | |
| download | enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip | |
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/Deobfuscator.java | 1163 |
1 files changed, 580 insertions, 583 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 2602abc..934d02a 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 12 | 13 | ||
| 13 | import com.google.common.base.Charsets; | 14 | import com.google.common.base.Charsets; |
| @@ -40,587 +41,583 @@ import java.util.jar.JarOutputStream; | |||
| 40 | 41 | ||
| 41 | public class Deobfuscator { | 42 | public class Deobfuscator { |
| 42 | 43 | ||
| 43 | public interface ProgressListener { | 44 | private final JarFile jar; |
| 44 | void init(int totalWork, String title); | 45 | private final DecompilerSettings settings; |
| 45 | 46 | private final JarIndex jarIndex; | |
| 46 | void onProgress(int numDone, String message); | 47 | private final MappingsRenamer renamer; |
| 47 | } | 48 | private final Map<TranslationDirection, Translator> translatorCache; |
| 48 | 49 | private Mappings mappings; | |
| 49 | private final JarFile jar; | 50 | public Deobfuscator(JarFile jar) { |
| 50 | private final DecompilerSettings settings; | 51 | this.jar = jar; |
| 51 | private final JarIndex jarIndex; | 52 | |
| 52 | private final MappingsRenamer renamer; | 53 | // build the jar index |
| 53 | private final Map<TranslationDirection, Translator> translatorCache; | 54 | this.jarIndex = new JarIndex(); |
| 54 | private Mappings mappings; | 55 | this.jarIndex.indexJar(this.jar, true); |
| 55 | 56 | ||
| 56 | public Deobfuscator(JarFile jar) { | 57 | // config the decompiler |
| 57 | this.jar = jar; | 58 | this.settings = DecompilerSettings.javaDefaults(); |
| 58 | 59 | this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); | |
| 59 | // build the jar index | 60 | this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); |
| 60 | this.jarIndex = new JarIndex(); | 61 | this.settings.setForceExplicitTypeArguments( |
| 61 | this.jarIndex.indexJar(this.jar, true); | 62 | Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); |
| 62 | 63 | // DEBUG | |
| 63 | // config the decompiler | 64 | this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); |
| 64 | this.settings = DecompilerSettings.javaDefaults(); | 65 | this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); |
| 65 | this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); | 66 | |
| 66 | this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); | 67 | // init defaults |
| 67 | this.settings.setForceExplicitTypeArguments( | 68 | this.translatorCache = Maps.newTreeMap(); |
| 68 | Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); | 69 | this.renamer = new MappingsRenamer(this.jarIndex, null); |
| 69 | // DEBUG | 70 | // init mappings |
| 70 | this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); | 71 | setMappings(new Mappings()); |
| 71 | this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); | 72 | } |
| 72 | 73 | ||
| 73 | // init defaults | 74 | public JarFile getJar() { |
| 74 | this.translatorCache = Maps.newTreeMap(); | 75 | return this.jar; |
| 75 | this.renamer = new MappingsRenamer(this.jarIndex, null); | 76 | } |
| 76 | // init mappings | 77 | |
| 77 | setMappings(new Mappings()); | 78 | public String getJarName() { |
| 78 | } | 79 | return this.jar.getName(); |
| 79 | 80 | } | |
| 80 | public JarFile getJar() { | 81 | |
| 81 | return this.jar; | 82 | public JarIndex getJarIndex() { |
| 82 | } | 83 | return this.jarIndex; |
| 83 | 84 | } | |
| 84 | public String getJarName() { | 85 | |
| 85 | return this.jar.getName(); | 86 | public Mappings getMappings() { |
| 86 | } | 87 | return this.mappings; |
| 87 | 88 | } | |
| 88 | public JarIndex getJarIndex() { | 89 | |
| 89 | return this.jarIndex; | 90 | public void setMappings(Mappings val) { |
| 90 | } | 91 | setMappings(val, true); |
| 91 | 92 | } | |
| 92 | public Mappings getMappings() { | 93 | |
| 93 | return this.mappings; | 94 | public void setMappings(Mappings val, boolean warnAboutDrops) { |
| 94 | } | 95 | if (val == null) { |
| 95 | 96 | val = new Mappings(); | |
| 96 | public void setMappings(Mappings val) { | 97 | } |
| 97 | setMappings(val, true); | 98 | |
| 98 | } | 99 | // drop mappings that don't match the jar |
| 99 | 100 | MappingsChecker checker = new MappingsChecker(this.jarIndex); | |
| 100 | public void setMappings(Mappings val, boolean warnAboutDrops) { | 101 | checker.dropBrokenMappings(val); |
| 101 | if (val == null) { | 102 | if (warnAboutDrops) { |
| 102 | val = new Mappings(); | 103 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedClassMappings().entrySet()) { |
| 103 | } | 104 | System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 104 | 105 | } | |
| 105 | // drop mappings that don't match the jar | 106 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedInnerClassMappings().entrySet()) { |
| 106 | MappingsChecker checker = new MappingsChecker(this.jarIndex); | 107 | System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 107 | checker.dropBrokenMappings(val); | 108 | } |
| 108 | if (warnAboutDrops) { | 109 | for (java.util.Map.Entry<FieldEntry, FieldMapping> mapping : checker.getDroppedFieldMappings().entrySet()) { |
| 109 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedClassMappings().entrySet()) { | 110 | System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 110 | System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 111 | } |
| 111 | } | 112 | for (java.util.Map.Entry<BehaviorEntry, MethodMapping> mapping : checker.getDroppedMethodMappings().entrySet()) { |
| 112 | for (java.util.Map.Entry<ClassEntry, ClassMapping> mapping : checker.getDroppedInnerClassMappings().entrySet()) { | 113 | System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); |
| 113 | System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 114 | } |
| 114 | } | 115 | } |
| 115 | for (java.util.Map.Entry<FieldEntry, FieldMapping> mapping : checker.getDroppedFieldMappings().entrySet()) { | 116 | |
| 116 | System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 117 | this.mappings = val; |
| 117 | } | 118 | this.renamer.setMappings(mappings); |
| 118 | for (java.util.Map.Entry<BehaviorEntry, MethodMapping> mapping : checker.getDroppedMethodMappings().entrySet()) { | 119 | this.translatorCache.clear(); |
| 119 | System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); | 120 | } |
| 120 | } | 121 | |
| 121 | } | 122 | public Translator getTranslator(TranslationDirection direction) { |
| 122 | 123 | return this.translatorCache.computeIfAbsent(direction, | |
| 123 | this.mappings = val; | 124 | k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); |
| 124 | this.renamer.setMappings(mappings); | 125 | } |
| 125 | this.translatorCache.clear(); | 126 | |
| 126 | } | 127 | public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) { |
| 127 | 128 | for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { | |
| 128 | public Translator getTranslator(TranslationDirection direction) { | 129 | // skip inner classes |
| 129 | return this.translatorCache.computeIfAbsent(direction, | 130 | if (obfClassEntry.isInnerClass()) { |
| 130 | k -> this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex())); | 131 | continue; |
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) { | 134 | // separate the classes |
| 134 | for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { | 135 | ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry); |
| 135 | // skip inner classes | 136 | if (!deobfClassEntry.equals(obfClassEntry)) { |
| 136 | if (obfClassEntry.isInnerClass()) { | 137 | // if the class has a mapping, clearly it's deobfuscated |
| 137 | continue; | 138 | deobfClasses.add(deobfClassEntry); |
| 138 | } | 139 | } else if (obfClassEntry.getPackageName() != null) { |
| 139 | 140 | // also call it deobufscated if it's not in the none package | |
| 140 | // separate the classes | 141 | deobfClasses.add(obfClassEntry); |
| 141 | ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry); | 142 | } else { |
| 142 | if (!deobfClassEntry.equals(obfClassEntry)) { | 143 | // otherwise, assume it's still obfuscated |
| 143 | // if the class has a mapping, clearly it's deobfuscated | 144 | obfClasses.add(obfClassEntry); |
| 144 | deobfClasses.add(deobfClassEntry); | 145 | } |
| 145 | } else if (obfClassEntry.getPackageName() != null) { | 146 | } |
| 146 | // also call it deobufscated if it's not in the none package | 147 | } |
| 147 | deobfClasses.add(obfClassEntry); | 148 | |
| 148 | } else { | 149 | public TranslatingTypeLoader createTypeLoader() { |
| 149 | // otherwise, assume it's still obfuscated | 150 | return new TranslatingTypeLoader( |
| 150 | obfClasses.add(obfClassEntry); | 151 | this.jar, |
| 151 | } | 152 | this.jarIndex, |
| 152 | } | 153 | getTranslator(TranslationDirection.Obfuscating), |
| 153 | } | 154 | getTranslator(TranslationDirection.Deobfuscating) |
| 154 | 155 | ); | |
| 155 | public TranslatingTypeLoader createTypeLoader() | 156 | } |
| 156 | { | 157 | |
| 157 | return new TranslatingTypeLoader( | 158 | public CompilationUnit getSourceTree(String className) { |
| 158 | this.jar, | 159 | |
| 159 | this.jarIndex, | 160 | // we don't know if this class name is obfuscated or deobfuscated |
| 160 | getTranslator(TranslationDirection.Obfuscating), | 161 | // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out |
| 161 | getTranslator(TranslationDirection.Deobfuscating) | 162 | // the decompiler only sees classes after deobfuscation, so we need to load it by the deobfuscated name if there is one |
| 162 | ); | 163 | |
| 163 | } | 164 | // first, assume class name is deobf |
| 164 | 165 | String deobfClassName = className; | |
| 165 | public CompilationUnit getSourceTree(String className) { | 166 | |
| 166 | 167 | // if it wasn't actually deobf, then we can find a mapping for it and get the deobf name | |
| 167 | // we don't know if this class name is obfuscated or deobfuscated | 168 | ClassMapping classMapping = this.mappings.getClassByObf(className); |
| 168 | // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out | 169 | if (classMapping != null && classMapping.getDeobfName() != null) { |
| 169 | // the decompiler only sees classes after deobfuscation, so we need to load it by the deobfuscated name if there is one | 170 | deobfClassName = classMapping.getDeobfName(); |
| 170 | 171 | } | |
| 171 | // first, assume class name is deobf | 172 | |
| 172 | String deobfClassName = className; | 173 | // set the type loader |
| 173 | 174 | TranslatingTypeLoader loader = createTypeLoader(); | |
| 174 | // if it wasn't actually deobf, then we can find a mapping for it and get the deobf name | 175 | this.settings.setTypeLoader(loader); |
| 175 | ClassMapping classMapping = this.mappings.getClassByObf(className); | 176 | |
| 176 | if (classMapping != null && classMapping.getDeobfName() != null) { | 177 | // see if procyon can find the type |
| 177 | deobfClassName = classMapping.getDeobfName(); | 178 | TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); |
| 178 | } | 179 | if (type == null) { |
| 179 | 180 | throw new Error(String.format("Unable to find type: %s (deobf: %s)\nTried class names: %s", | |
| 180 | // set the type loader | 181 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) |
| 181 | TranslatingTypeLoader loader = createTypeLoader(); | 182 | )); |
| 182 | this.settings.setTypeLoader(loader); | 183 | } |
| 183 | 184 | TypeDefinition resolvedType = type.resolve(); | |
| 184 | // see if procyon can find the type | 185 | |
| 185 | TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); | 186 | // decompile it! |
| 186 | if (type == null) { | 187 | DecompilerContext context = new DecompilerContext(); |
| 187 | throw new Error(String.format("Unable to find type: %s (deobf: %s)\nTried class names: %s", | 188 | context.setCurrentType(resolvedType); |
| 188 | className, deobfClassName, loader.getClassNamesToTry(deobfClassName) | 189 | context.setSettings(this.settings); |
| 189 | )); | 190 | AstBuilder builder = new AstBuilder(context); |
| 190 | } | 191 | builder.addType(resolvedType); |
| 191 | TypeDefinition resolvedType = type.resolve(); | 192 | builder.runTransformations(null); |
| 192 | 193 | return builder.getCompilationUnit(); | |
| 193 | // decompile it! | 194 | } |
| 194 | DecompilerContext context = new DecompilerContext(); | 195 | |
| 195 | context.setCurrentType(resolvedType); | 196 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) { |
| 196 | context.setSettings(this.settings); | 197 | return getSourceIndex(sourceTree, source, null); |
| 197 | AstBuilder builder = new AstBuilder(context); | 198 | } |
| 198 | builder.addType(resolvedType); | 199 | |
| 199 | builder.runTransformations(null); | 200 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, Boolean ignoreBadTokens) { |
| 200 | return builder.getCompilationUnit(); | 201 | |
| 201 | } | 202 | // build the source index |
| 202 | 203 | SourceIndex index; | |
| 203 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) { | 204 | if (ignoreBadTokens != null) { |
| 204 | return getSourceIndex(sourceTree, source, null); | 205 | index = new SourceIndex(source, ignoreBadTokens); |
| 205 | } | 206 | } else { |
| 206 | 207 | index = new SourceIndex(source); | |
| 207 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, Boolean ignoreBadTokens) { | 208 | } |
| 208 | 209 | sourceTree.acceptVisitor(new SourceIndexVisitor(), index); | |
| 209 | // build the source index | 210 | |
| 210 | SourceIndex index; | 211 | // DEBUG |
| 211 | if (ignoreBadTokens != null) { | 212 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); |
| 212 | index = new SourceIndex(source, ignoreBadTokens); | 213 | |
| 213 | } else { | 214 | // resolve all the classes in the source references |
| 214 | index = new SourceIndex(source); | 215 | for (Token token : index.referenceTokens()) { |
| 215 | } | 216 | EntryReference<Entry, Entry> deobfReference = index.getDeobfReference(token); |
| 216 | sourceTree.acceptVisitor(new SourceIndexVisitor(), index); | 217 | |
| 217 | 218 | // get the obfuscated entry | |
| 218 | // DEBUG | 219 | Entry obfEntry = obfuscateEntry(deobfReference.entry); |
| 219 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); | 220 | |
| 220 | 221 | // try to resolve the class | |
| 221 | // resolve all the classes in the source references | 222 | ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); |
| 222 | for (Token token : index.referenceTokens()) { | 223 | if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { |
| 223 | EntryReference<Entry, Entry> deobfReference = index.getDeobfReference(token); | 224 | // change the class of the entry |
| 224 | 225 | obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); | |
| 225 | // get the obfuscated entry | 226 | |
| 226 | Entry obfEntry = obfuscateEntry(deobfReference.entry); | 227 | // save the new deobfuscated reference |
| 227 | 228 | deobfReference.entry = deobfuscateEntry(obfEntry); | |
| 228 | // try to resolve the class | 229 | index.replaceDeobfReference(token, deobfReference); |
| 229 | ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); | 230 | } |
| 230 | if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { | 231 | |
| 231 | // change the class of the entry | 232 | // DEBUG |
| 232 | obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); | 233 | // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); |
| 233 | 234 | } | |
| 234 | // save the new deobfuscated reference | 235 | |
| 235 | deobfReference.entry = deobfuscateEntry(obfEntry); | 236 | return index; |
| 236 | index.replaceDeobfReference(token, deobfReference); | 237 | } |
| 237 | } | 238 | |
| 238 | 239 | public String getSource(CompilationUnit sourceTree) { | |
| 239 | // DEBUG | 240 | // render the AST into source |
| 240 | // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); | 241 | StringWriter buf = new StringWriter(); |
| 241 | } | 242 | sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); |
| 242 | 243 | sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), this.settings), null); | |
| 243 | return index; | 244 | return buf.toString(); |
| 244 | } | 245 | } |
| 245 | 246 | ||
| 246 | public String getSource(CompilationUnit sourceTree) { | 247 | public void writeSources(File dirOut, ProgressListener progress) { |
| 247 | // render the AST into source | 248 | // get the classes to decompile |
| 248 | StringWriter buf = new StringWriter(); | 249 | Set<ClassEntry> classEntries = Sets.newHashSet(); |
| 249 | sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); | 250 | for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { |
| 250 | sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), this.settings), null); | 251 | // skip inner classes |
| 251 | return buf.toString(); | 252 | if (obfClassEntry.isInnerClass()) { |
| 252 | } | 253 | continue; |
| 253 | 254 | } | |
| 254 | public void writeSources(File dirOut, ProgressListener progress) { | 255 | |
| 255 | // get the classes to decompile | 256 | classEntries.add(obfClassEntry); |
| 256 | Set<ClassEntry> classEntries = Sets.newHashSet(); | 257 | } |
| 257 | for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { | 258 | |
| 258 | // skip inner classes | 259 | if (progress != null) { |
| 259 | if (obfClassEntry.isInnerClass()) { | 260 | progress.init(classEntries.size(), "Decompiling classes..."); |
| 260 | continue; | 261 | } |
| 261 | } | 262 | |
| 262 | 263 | // DEOBFUSCATE ALL THE THINGS!! @_@ | |
| 263 | classEntries.add(obfClassEntry); | 264 | int i = 0; |
| 264 | } | 265 | for (ClassEntry obfClassEntry : classEntries) { |
| 265 | 266 | ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry)); | |
| 266 | if (progress != null) { | 267 | if (progress != null) { |
| 267 | progress.init(classEntries.size(), "Decompiling classes..."); | 268 | progress.onProgress(i++, deobfClassEntry.toString()); |
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | // DEOBFUSCATE ALL THE THINGS!! @_@ | 271 | try { |
| 271 | int i = 0; | 272 | // get the source |
| 272 | for (ClassEntry obfClassEntry : classEntries) { | 273 | String source = getSource(getSourceTree(obfClassEntry.getName())); |
| 273 | ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry)); | 274 | |
| 274 | if (progress != null) { | 275 | // write the file |
| 275 | progress.onProgress(i++, deobfClassEntry.toString()); | 276 | File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); |
| 276 | } | 277 | file.getParentFile().mkdirs(); |
| 277 | 278 | try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { | |
| 278 | try { | 279 | out.write(source); |
| 279 | // get the source | 280 | } |
| 280 | String source = getSource(getSourceTree(obfClassEntry.getName())); | 281 | } catch (Throwable t) { |
| 281 | 282 | // don't crash the whole world here, just log the error and keep going | |
| 282 | // write the file | 283 | // TODO: set up logback via log4j |
| 283 | File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); | 284 | System.err.println("Unable to deobfuscate class " + deobfClassEntry + " (" + obfClassEntry + ")"); |
| 284 | file.getParentFile().mkdirs(); | 285 | t.printStackTrace(System.err); |
| 285 | try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { | 286 | } |
| 286 | out.write(source); | 287 | } |
| 287 | } | 288 | if (progress != null) { |
| 288 | } catch (Throwable t) { | 289 | progress.onProgress(i, "Done!"); |
| 289 | // don't crash the whole world here, just log the error and keep going | 290 | } |
| 290 | // TODO: set up logback via log4j | 291 | } |
| 291 | System.err.println("Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")"); | 292 | |
| 292 | t.printStackTrace(System.err); | 293 | private void addAllPotentialAncestors(Set<ClassEntry> classEntries, ClassEntry classObfEntry) { |
| 293 | } | 294 | for (ClassEntry interfaceEntry : jarIndex.getTranslationIndex().getInterfaces(classObfEntry)) { |
| 294 | } | 295 | if (classEntries.add(interfaceEntry)) { |
| 295 | if (progress != null) { | 296 | addAllPotentialAncestors(classEntries, interfaceEntry); |
| 296 | progress.onProgress(i, "Done!"); | 297 | } |
| 297 | } | 298 | } |
| 298 | } | 299 | |
| 299 | 300 | ClassEntry superClassEntry = jarIndex.getTranslationIndex().getSuperclass(classObfEntry); | |
| 300 | private void addAllPotentialAncestors(Set<ClassEntry> classEntries, ClassEntry classObfEntry) { | 301 | if (superClassEntry != null && classEntries.add(superClassEntry)) { |
| 301 | for (ClassEntry interfaceEntry : jarIndex.getTranslationIndex().getInterfaces(classObfEntry)) { | 302 | addAllPotentialAncestors(classEntries, superClassEntry); |
| 302 | if (classEntries.add(interfaceEntry)) { | 303 | } |
| 303 | addAllPotentialAncestors(classEntries, interfaceEntry); | 304 | } |
| 304 | } | 305 | |
| 305 | } | 306 | private boolean isBehaviorProvider(ClassEntry classObfEntry, BehaviorEntry behaviorEntry) { |
| 306 | 307 | if (behaviorEntry instanceof MethodEntry) { | |
| 307 | ClassEntry superClassEntry = jarIndex.getTranslationIndex().getSuperclass(classObfEntry); | 308 | MethodEntry methodEntry = (MethodEntry) behaviorEntry; |
| 308 | if (superClassEntry != null && classEntries.add(superClassEntry)) { | 309 | |
| 309 | addAllPotentialAncestors(classEntries, superClassEntry); | 310 | Set<ClassEntry> classEntries = new HashSet<>(); |
| 310 | } | 311 | addAllPotentialAncestors(classEntries, classObfEntry); |
| 311 | } | 312 | |
| 312 | 313 | for (ClassEntry parentEntry : classEntries) { | |
| 313 | private boolean isBehaviorProvider(ClassEntry classObfEntry, BehaviorEntry behaviorEntry) { | 314 | MethodEntry ancestorMethodEntry = new MethodEntry(parentEntry, methodEntry.getName(), methodEntry.getSignature()); |
| 314 | if (behaviorEntry instanceof MethodEntry) { | 315 | if (jarIndex.containsObfBehavior(ancestorMethodEntry)) { |
| 315 | MethodEntry methodEntry = (MethodEntry) behaviorEntry; | 316 | return false; |
| 316 | 317 | } | |
| 317 | Set<ClassEntry> classEntries = new HashSet<>(); | 318 | } |
| 318 | addAllPotentialAncestors(classEntries, classObfEntry); | 319 | } |
| 319 | 320 | ||
| 320 | for (ClassEntry parentEntry : classEntries) { | 321 | return true; |
| 321 | MethodEntry ancestorMethodEntry = new MethodEntry(parentEntry, methodEntry.getName(), methodEntry.getSignature()); | 322 | } |
| 322 | if (jarIndex.containsObfBehavior(ancestorMethodEntry)) { | 323 | |
| 323 | return false; | 324 | public void rebuildMethodNames(ProgressListener progress) { |
| 324 | } | 325 | int i = 0; |
| 325 | } | 326 | Map<ClassMapping, Map<Entry, String>> renameClassMap = new HashMap<>(); |
| 326 | } | 327 | |
| 327 | 328 | progress.init(getMappings().classes().size() * 3, "Rebuilding method names"); | |
| 328 | return true; | 329 | |
| 329 | } | 330 | for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { |
| 330 | 331 | Map<Entry, String> renameEntries = new HashMap<>(); | |
| 331 | public void rebuildMethodNames(ProgressListener progress) { | 332 | |
| 332 | int i = 0; | 333 | progress.onProgress(i++, classMapping.getDeobfName()); |
| 333 | Map<ClassMapping, Map<Entry, String>> renameClassMap = new HashMap<>(); | 334 | |
| 334 | 335 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { | |
| 335 | progress.init(getMappings().classes().size() * 3, "Rebuilding method names"); | 336 | ClassEntry classObfEntry = classMapping.getObfEntry(); |
| 336 | 337 | BehaviorEntry obfEntry = methodMapping.getObfEntry(classObfEntry); | |
| 337 | for (ClassMapping classMapping : Lists.newArrayList(getMappings().classes())) { | 338 | |
| 338 | Map<Entry, String> renameEntries = new HashMap<>(); | 339 | if (isBehaviorProvider(classObfEntry, obfEntry)) { |
| 339 | 340 | if (hasDeobfuscatedName(obfEntry) && !(obfEntry instanceof ConstructorEntry) | |
| 340 | progress.onProgress(i++, classMapping.getDeobfName()); | 341 | && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { |
| 341 | 342 | renameEntries.put(obfEntry, methodMapping.getDeobfName()); | |
| 342 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { | 343 | } |
| 343 | ClassEntry classObfEntry = classMapping.getObfEntry(); | 344 | |
| 344 | BehaviorEntry obfEntry = methodMapping.getObfEntry(classObfEntry); | 345 | for (ArgumentMapping argumentMapping : Lists.newArrayList(methodMapping.arguments())) { |
| 345 | 346 | Entry argObfEntry = argumentMapping.getObfEntry(obfEntry); | |
| 346 | if (isBehaviorProvider(classObfEntry, obfEntry)) { | 347 | if (hasDeobfuscatedName(argObfEntry)) { |
| 347 | if (hasDeobfuscatedName(obfEntry) && !(obfEntry instanceof ConstructorEntry) | 348 | renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName()); |
| 348 | && !(methodMapping.getDeobfName().equals(methodMapping.getObfName()))) { | 349 | } |
| 349 | renameEntries.put(obfEntry, methodMapping.getDeobfName()); | 350 | } |
| 350 | } | 351 | } |
| 351 | 352 | } | |
| 352 | for (ArgumentMapping argumentMapping : Lists.newArrayList(methodMapping.arguments())) { | 353 | |
| 353 | Entry argObfEntry = argumentMapping.getObfEntry(obfEntry); | 354 | renameClassMap.put(classMapping, renameEntries); |
| 354 | if (hasDeobfuscatedName(argObfEntry)) { | 355 | } |
| 355 | renameEntries.put(argObfEntry, deobfuscateEntry(argObfEntry).getName()); | 356 | |
| 356 | } | 357 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { |
| 357 | } | 358 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); |
| 358 | } | 359 | |
| 359 | } | 360 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { |
| 360 | 361 | Entry obfEntry = entry.getKey(); | |
| 361 | renameClassMap.put(classMapping, renameEntries); | 362 | |
| 362 | } | 363 | removeMapping(obfEntry); |
| 363 | 364 | } | |
| 364 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { | 365 | } |
| 365 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); | 366 | |
| 366 | 367 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { | |
| 367 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { | 368 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); |
| 368 | Entry obfEntry = entry.getKey(); | 369 | |
| 369 | 370 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { | |
| 370 | removeMapping(obfEntry); | 371 | Entry obfEntry = entry.getKey(); |
| 371 | } | 372 | String name = entry.getValue(); |
| 372 | } | 373 | |
| 373 | 374 | rename(obfEntry, name); | |
| 374 | for (Map.Entry<ClassMapping, Map<Entry, String>> renameClassMapEntry : renameClassMap.entrySet()) { | 375 | } |
| 375 | progress.onProgress(i++, renameClassMapEntry.getKey().getDeobfName()); | 376 | } |
| 376 | 377 | } | |
| 377 | for (Map.Entry<Entry, String> entry : renameClassMapEntry.getValue().entrySet()) { | 378 | |
| 378 | Entry obfEntry = entry.getKey(); | 379 | public void writeJar(File out, ProgressListener progress) { |
| 379 | String name = entry.getValue(); | 380 | transformJar(out, progress, createTypeLoader()::transformClass); |
| 380 | 381 | } | |
| 381 | rename(obfEntry, name); | 382 | |
| 382 | } | 383 | public void protectifyJar(File out, ProgressListener progress) { |
| 383 | } | 384 | transformJar(out, progress, ClassProtectifier::protectify); |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | public void writeJar(File out, ProgressListener progress) { | 387 | public void publifyJar(File out, ProgressListener progress) { |
| 387 | transformJar(out, progress, createTypeLoader()::transformClass); | 388 | transformJar(out, progress, ClassPublifier::publify); |
| 388 | } | 389 | } |
| 389 | 390 | ||
| 390 | public void protectifyJar(File out, ProgressListener progress) { | 391 | public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { |
| 391 | transformJar(out, progress, ClassProtectifier::protectify); | 392 | try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { |
| 392 | } | 393 | if (progress != null) { |
| 393 | 394 | progress.init(JarClassIterator.getClassEntries(this.jar).size(), "Transforming classes..."); | |
| 394 | public void publifyJar(File out, ProgressListener progress) { | 395 | } |
| 395 | transformJar(out, progress, ClassPublifier::publify); | 396 | |
| 396 | } | 397 | int i = 0; |
| 397 | 398 | for (CtClass c : JarClassIterator.classes(this.jar)) { | |
| 398 | public interface ClassTransformer { | 399 | if (progress != null) { |
| 399 | CtClass transform(CtClass c) throws Exception; | 400 | progress.onProgress(i++, c.getName()); |
| 400 | } | 401 | } |
| 401 | 402 | ||
| 402 | public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { | 403 | try { |
| 403 | try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { | 404 | c = transformer.transform(c); |
| 404 | if (progress != null) { | 405 | outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); |
| 405 | progress.init(JarClassIterator.getClassEntries(this.jar).size(), "Transforming classes..."); | 406 | outJar.write(c.toBytecode()); |
| 406 | } | 407 | outJar.closeEntry(); |
| 407 | 408 | } catch (Throwable t) { | |
| 408 | int i = 0; | 409 | throw new Error("Unable to transform class " + c.getName(), t); |
| 409 | for (CtClass c : JarClassIterator.classes(this.jar)) { | 410 | } |
| 410 | if (progress != null) { | 411 | } |
| 411 | progress.onProgress(i++, c.getName()); | 412 | if (progress != null) { |
| 412 | } | 413 | progress.onProgress(i, "Done!"); |
| 413 | 414 | } | |
| 414 | try { | 415 | |
| 415 | c = transformer.transform(c); | 416 | outJar.close(); |
| 416 | outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); | 417 | } catch (IOException ex) { |
| 417 | outJar.write(c.toBytecode()); | 418 | throw new Error("Unable to write to Jar file!"); |
| 418 | outJar.closeEntry(); | 419 | } |
| 419 | } catch (Throwable t) { | 420 | } |
| 420 | throw new Error("Unable to transform class " + c.getName(), t); | 421 | |
| 421 | } | 422 | public <T extends Entry> T obfuscateEntry(T deobfEntry) { |
| 422 | } | 423 | if (deobfEntry == null) { |
| 423 | if (progress != null) { | 424 | return null; |
| 424 | progress.onProgress(i, "Done!"); | 425 | } |
| 425 | } | 426 | return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); |
| 426 | 427 | } | |
| 427 | outJar.close(); | 428 | |
| 428 | } catch (IOException ex) { | 429 | public <T extends Entry> T deobfuscateEntry(T obfEntry) { |
| 429 | throw new Error("Unable to write to Jar file!"); | 430 | if (obfEntry == null) { |
| 430 | } | 431 | return null; |
| 431 | } | 432 | } |
| 432 | 433 | return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); | |
| 433 | public <T extends Entry> T obfuscateEntry(T deobfEntry) { | 434 | } |
| 434 | if (deobfEntry == null) { | 435 | |
| 435 | return null; | 436 | public <E extends Entry, C extends Entry> EntryReference<E, C> obfuscateReference(EntryReference<E, C> deobfReference) { |
| 436 | } | 437 | if (deobfReference == null) { |
| 437 | return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); | 438 | return null; |
| 438 | } | 439 | } |
| 439 | 440 | return new EntryReference<>(obfuscateEntry(deobfReference.entry), obfuscateEntry(deobfReference.context), deobfReference); | |
| 440 | public <T extends Entry> T deobfuscateEntry(T obfEntry) { | 441 | } |
| 441 | if (obfEntry == null) { | 442 | |
| 442 | return null; | 443 | public <E extends Entry, C extends Entry> EntryReference<E, C> deobfuscateReference(EntryReference<E, C> obfReference) { |
| 443 | } | 444 | if (obfReference == null) { |
| 444 | return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); | 445 | return null; |
| 445 | } | 446 | } |
| 446 | 447 | return new EntryReference<>(deobfuscateEntry(obfReference.entry), deobfuscateEntry(obfReference.context), obfReference); | |
| 447 | public <E extends Entry, C extends Entry> EntryReference<E, C> obfuscateReference(EntryReference<E, C> deobfReference) { | 448 | } |
| 448 | if (deobfReference == null) { | 449 | |
| 449 | return null; | 450 | public boolean isObfuscatedIdentifier(Entry obfEntry) { |
| 450 | } | 451 | return isObfuscatedIdentifier(obfEntry, false); |
| 451 | return new EntryReference<>(obfuscateEntry(deobfReference.entry), obfuscateEntry(deobfReference.context), deobfReference); | 452 | } |
| 452 | } | 453 | |
| 453 | 454 | public boolean isObfuscatedIdentifier(Entry obfEntry, boolean hack) { | |
| 454 | public <E extends Entry, C extends Entry> EntryReference<E, C> deobfuscateReference(EntryReference<E, C> obfReference) { | 455 | |
| 455 | if (obfReference == null) { | 456 | if (obfEntry instanceof MethodEntry) { |
| 456 | return null; | 457 | |
| 457 | } | 458 | // HACKHACK: Object methods are not obfuscated identifiers |
| 458 | return new EntryReference<>(deobfuscateEntry(obfReference.entry), deobfuscateEntry(obfReference.context), obfReference); | 459 | MethodEntry obfMethodEntry = (MethodEntry) obfEntry; |
| 459 | } | 460 | String name = obfMethodEntry.getName(); |
| 460 | 461 | String sig = obfMethodEntry.getSignature().toString(); | |
| 461 | public boolean isObfuscatedIdentifier(Entry obfEntry) { | 462 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { |
| 462 | return isObfuscatedIdentifier(obfEntry, false); | 463 | return false; |
| 463 | } | 464 | } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { |
| 464 | 465 | return false; | |
| 465 | public boolean isObfuscatedIdentifier(Entry obfEntry, boolean hack) { | 466 | } else if (name.equals("finalize") && sig.equals("()V")) { |
| 466 | 467 | return false; | |
| 467 | if (obfEntry instanceof MethodEntry) { | 468 | } else if (name.equals("getClass") && sig.equals("()Ljava/lang/Class;")) { |
| 468 | 469 | return false; | |
| 469 | // HACKHACK: Object methods are not obfuscated identifiers | 470 | } else if (name.equals("hashCode") && sig.equals("()I")) { |
| 470 | MethodEntry obfMethodEntry = (MethodEntry) obfEntry; | 471 | return false; |
| 471 | String name = obfMethodEntry.getName(); | 472 | } else if (name.equals("notify") && sig.equals("()V")) { |
| 472 | String sig = obfMethodEntry.getSignature().toString(); | 473 | return false; |
| 473 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { | 474 | } else if (name.equals("notifyAll") && sig.equals("()V")) { |
| 474 | return false; | 475 | return false; |
| 475 | } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { | 476 | } else if (name.equals("toString") && sig.equals("()Ljava/lang/String;")) { |
| 476 | return false; | 477 | return false; |
| 477 | } else if (name.equals("finalize") && sig.equals("()V")) { | 478 | } else if (name.equals("wait") && sig.equals("()V")) { |
| 478 | return false; | 479 | return false; |
| 479 | } else if (name.equals("getClass") && sig.equals("()Ljava/lang/Class;")) { | 480 | } else if (name.equals("wait") && sig.equals("(J)V")) { |
| 480 | return false; | 481 | return false; |
| 481 | } else if (name.equals("hashCode") && sig.equals("()I")) { | 482 | } else if (name.equals("wait") && sig.equals("(JI)V")) { |
| 482 | return false; | 483 | return false; |
| 483 | } else if (name.equals("notify") && sig.equals("()V")) { | 484 | } |
| 484 | return false; | 485 | |
| 485 | } else if (name.equals("notifyAll") && sig.equals("()V")) { | 486 | // FIXME: HACK EVEN MORE HACK! |
| 486 | return false; | 487 | if (hack && this.jarIndex.containsObfEntry(obfEntry.getClassEntry())) |
| 487 | } else if (name.equals("toString") && sig.equals("()Ljava/lang/String;")) { | 488 | return true; |
| 488 | return false; | 489 | } |
| 489 | } else if (name.equals("wait") && sig.equals("()V")) { | 490 | |
| 490 | return false; | 491 | return this.jarIndex.containsObfEntry(obfEntry); |
| 491 | } else if (name.equals("wait") && sig.equals("(J)V")) { | 492 | } |
| 492 | return false; | 493 | |
| 493 | } else if (name.equals("wait") && sig.equals("(JI)V")) { | 494 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference, boolean activeHack) { |
| 494 | return false; | 495 | return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry(), activeHack); |
| 495 | } | 496 | } |
| 496 | 497 | ||
| 497 | // FIXME: HACK EVEN MORE HACK! | 498 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference) { |
| 498 | if (hack && this.jarIndex.containsObfEntry(obfEntry.getClassEntry())) | 499 | return isRenameable(obfReference, false); |
| 499 | return true; | 500 | } |
| 500 | } | 501 | |
| 501 | 502 | public boolean hasDeobfuscatedName(Entry obfEntry) { | |
| 502 | return this.jarIndex.containsObfEntry(obfEntry); | 503 | Translator translator = getTranslator(TranslationDirection.Deobfuscating); |
| 503 | } | 504 | if (obfEntry instanceof ClassEntry) { |
| 504 | 505 | ClassEntry obfClass = (ClassEntry) obfEntry; | |
| 505 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference, boolean activeHack) { | 506 | List<ClassMapping> mappingChain = this.mappings.getClassMappingChain(obfClass); |
| 506 | return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry(), activeHack); | 507 | ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); |
| 507 | } | 508 | return classMapping != null && classMapping.getDeobfName() != null; |
| 508 | 509 | } else if (obfEntry instanceof FieldEntry) { | |
| 509 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference) { | 510 | return translator.translate((FieldEntry) obfEntry) != null; |
| 510 | return isRenameable(obfReference, false); | 511 | } else if (obfEntry instanceof MethodEntry) { |
| 511 | } | 512 | return translator.translate((MethodEntry) obfEntry) != null; |
| 512 | 513 | } else if (obfEntry instanceof ConstructorEntry) { | |
| 513 | // NOTE: these methods are a bit messy... oh well | 514 | // constructors have no names |
| 514 | 515 | return false; | |
| 515 | public boolean hasDeobfuscatedName(Entry obfEntry) { | 516 | } else if (obfEntry instanceof ArgumentEntry) { |
| 516 | Translator translator = getTranslator(TranslationDirection.Deobfuscating); | 517 | return translator.translate((ArgumentEntry) obfEntry) != null; |
| 517 | if (obfEntry instanceof ClassEntry) { | 518 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 518 | ClassEntry obfClass = (ClassEntry) obfEntry; | 519 | // TODO: Implement it |
| 519 | List<ClassMapping> mappingChain = this.mappings.getClassMappingChain(obfClass); | 520 | //return translator.translate((LocalVariableEntry)obfEntry) != null; |
| 520 | ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); | 521 | return false; |
| 521 | return classMapping != null && classMapping.getDeobfName() != null; | 522 | } else { |
| 522 | } else if (obfEntry instanceof FieldEntry) { | 523 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); |
| 523 | return translator.translate((FieldEntry) obfEntry) != null; | 524 | } |
| 524 | } else if (obfEntry instanceof MethodEntry) { | 525 | } |
| 525 | return translator.translate((MethodEntry) obfEntry) != null; | 526 | |
| 526 | } else if (obfEntry instanceof ConstructorEntry) { | 527 | public void rename(Entry obfEntry, String newName) { |
| 527 | // constructors have no names | 528 | rename(obfEntry, newName, true); |
| 528 | return false; | 529 | } |
| 529 | } else if (obfEntry instanceof ArgumentEntry) { | 530 | |
| 530 | return translator.translate((ArgumentEntry) obfEntry) != null; | 531 | // NOTE: these methods are a bit messy... oh well |
| 531 | } else if (obfEntry instanceof LocalVariableEntry) { | 532 | |
| 532 | // TODO: Implement it | 533 | public void rename(Entry obfEntry, String newName, boolean clearCache) { |
| 533 | //return translator.translate((LocalVariableEntry)obfEntry) != null; | 534 | if (obfEntry instanceof ClassEntry) { |
| 534 | return false; | 535 | this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); |
| 535 | } else { | 536 | } else if (obfEntry instanceof FieldEntry) { |
| 536 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 537 | this.renamer.setFieldName((FieldEntry) obfEntry, newName); |
| 537 | } | 538 | } else if (obfEntry instanceof MethodEntry) { |
| 538 | } | 539 | this.renamer.setMethodTreeName((MethodEntry) obfEntry, newName); |
| 539 | 540 | } else if (obfEntry instanceof ConstructorEntry) { | |
| 540 | public void rename(Entry obfEntry, String newName) { | 541 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 541 | rename(obfEntry, newName, true); | 542 | } else if (obfEntry instanceof ArgumentEntry) { |
| 542 | } | 543 | this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); |
| 543 | 544 | } else if (obfEntry instanceof LocalVariableEntry) { | |
| 544 | public void rename(Entry obfEntry, String newName, boolean clearCache) { | 545 | // TODO: Implement it |
| 545 | if (obfEntry instanceof ClassEntry) { | 546 | } else { |
| 546 | this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); | 547 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); |
| 547 | } else if (obfEntry instanceof FieldEntry) { | 548 | } |
| 548 | this.renamer.setFieldName((FieldEntry) obfEntry, newName); | 549 | |
| 549 | } else if (obfEntry instanceof MethodEntry) { | 550 | // clear caches |
| 550 | this.renamer.setMethodTreeName((MethodEntry) obfEntry, newName); | 551 | if (clearCache) |
| 551 | } else if (obfEntry instanceof ConstructorEntry) { | 552 | this.translatorCache.clear(); |
| 552 | throw new IllegalArgumentException("Cannot rename constructors"); | 553 | } |
| 553 | } else if (obfEntry instanceof ArgumentEntry) { | 554 | |
| 554 | this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); | 555 | public void removeMapping(Entry obfEntry) { |
| 555 | } else if (obfEntry instanceof LocalVariableEntry) { | 556 | if (obfEntry instanceof ClassEntry) { |
| 556 | // TODO: Implement it | 557 | this.renamer.removeClassMapping((ClassEntry) obfEntry); |
| 557 | } else { | 558 | } else if (obfEntry instanceof FieldEntry) { |
| 558 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 559 | this.renamer.removeFieldMapping((FieldEntry) obfEntry); |
| 559 | } | 560 | } else if (obfEntry instanceof MethodEntry) { |
| 560 | 561 | this.renamer.removeMethodTreeMapping((MethodEntry) obfEntry); | |
| 561 | // clear caches | 562 | } else if (obfEntry instanceof ConstructorEntry) { |
| 562 | if (clearCache) | 563 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 563 | this.translatorCache.clear(); | 564 | } else if (obfEntry instanceof ArgumentEntry) { |
| 564 | } | 565 | this.renamer.removeArgumentMapping((ArgumentEntry) obfEntry); |
| 565 | 566 | } else { | |
| 566 | public void removeMapping(Entry obfEntry) { | 567 | throw new Error("Unknown entry type: " + obfEntry); |
| 567 | if (obfEntry instanceof ClassEntry) { | 568 | } |
| 568 | this.renamer.removeClassMapping((ClassEntry) obfEntry); | 569 | |
| 569 | } else if (obfEntry instanceof FieldEntry) { | 570 | // clear caches |
| 570 | this.renamer.removeFieldMapping((FieldEntry) obfEntry); | 571 | this.translatorCache.clear(); |
| 571 | } else if (obfEntry instanceof MethodEntry) { | 572 | } |
| 572 | this.renamer.removeMethodTreeMapping((MethodEntry) obfEntry); | 573 | |
| 573 | } else if (obfEntry instanceof ConstructorEntry) { | 574 | public void markAsDeobfuscated(Entry obfEntry) { |
| 574 | throw new IllegalArgumentException("Cannot rename constructors"); | 575 | if (obfEntry instanceof ClassEntry) { |
| 575 | } else if (obfEntry instanceof ArgumentEntry) { | 576 | this.renamer.markClassAsDeobfuscated((ClassEntry) obfEntry); |
| 576 | this.renamer.removeArgumentMapping((ArgumentEntry) obfEntry); | 577 | } else if (obfEntry instanceof FieldEntry) { |
| 577 | } else { | 578 | this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); |
| 578 | throw new Error("Unknown entry type: " + obfEntry); | 579 | } else if (obfEntry instanceof MethodEntry) { |
| 579 | } | 580 | this.renamer.markMethodTreeAsDeobfuscated((MethodEntry) obfEntry); |
| 580 | 581 | } else if (obfEntry instanceof ConstructorEntry) { | |
| 581 | // clear caches | 582 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 582 | this.translatorCache.clear(); | 583 | } else if (obfEntry instanceof ArgumentEntry) { |
| 583 | } | 584 | this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); |
| 584 | 585 | } else if (obfEntry instanceof LocalVariableEntry) { | |
| 585 | public void markAsDeobfuscated(Entry obfEntry) { | 586 | // TODO: Implement it |
| 586 | if (obfEntry instanceof ClassEntry) { | 587 | } else { |
| 587 | this.renamer.markClassAsDeobfuscated((ClassEntry) obfEntry); | 588 | throw new Error("Unknown entry type: " + obfEntry); |
| 588 | } else if (obfEntry instanceof FieldEntry) { | 589 | } |
| 589 | this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); | 590 | |
| 590 | } else if (obfEntry instanceof MethodEntry) { | 591 | // clear caches |
| 591 | this.renamer.markMethodTreeAsDeobfuscated((MethodEntry) obfEntry); | 592 | this.translatorCache.clear(); |
| 592 | } else if (obfEntry instanceof ConstructorEntry) { | 593 | } |
| 593 | throw new IllegalArgumentException("Cannot rename constructors"); | 594 | |
| 594 | } else if (obfEntry instanceof ArgumentEntry) { | 595 | public void changeModifier(Entry entry, Mappings.EntryModifier modifierEntry) { |
| 595 | this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); | 596 | Entry obfEntry = obfuscateEntry(entry); |
| 596 | } else if (obfEntry instanceof LocalVariableEntry) { | 597 | if (obfEntry instanceof ClassEntry) |
| 597 | // TODO: Implement it | 598 | this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); |
| 598 | } else { | 599 | else if (obfEntry instanceof FieldEntry) |
| 599 | throw new Error("Unknown entry type: " + obfEntry); | 600 | this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); |
| 600 | } | 601 | else if (obfEntry instanceof BehaviorEntry) |
| 601 | 602 | this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry); | |
| 602 | // clear caches | 603 | else |
| 603 | this.translatorCache.clear(); | 604 | throw new Error("Unknown entry type: " + obfEntry); |
| 604 | } | 605 | } |
| 605 | 606 | ||
| 606 | public void changeModifier(Entry entry, Mappings.EntryModifier modifierEntry) | 607 | public Mappings.EntryModifier getModifier(Entry obEntry) { |
| 607 | { | 608 | Entry entry = obfuscateEntry(obEntry); |
| 608 | Entry obfEntry = obfuscateEntry(entry); | 609 | if (entry != null) |
| 609 | if (obfEntry instanceof ClassEntry) | 610 | obEntry = entry; |
| 610 | this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); | 611 | return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry); |
| 611 | else if (obfEntry instanceof FieldEntry) | 612 | } |
| 612 | this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); | 613 | |
| 613 | else if (obfEntry instanceof BehaviorEntry) | 614 | public interface ProgressListener { |
| 614 | this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry); | 615 | void init(int totalWork, String title); |
| 615 | else | 616 | |
| 616 | throw new Error("Unknown entry type: " + obfEntry); | 617 | void onProgress(int numDone, String message); |
| 617 | } | 618 | } |
| 618 | 619 | ||
| 619 | public Mappings.EntryModifier getModifier(Entry obEntry) | 620 | public interface ClassTransformer { |
| 620 | { | 621 | CtClass transform(CtClass c) throws Exception; |
| 621 | Entry entry = obfuscateEntry(obEntry); | 622 | } |
| 622 | if (entry != null) | ||
| 623 | obEntry = entry; | ||
| 624 | return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry); | ||
| 625 | } | ||
| 626 | } | 623 | } |