From a88175ffc95792b88a8724f66db6dda2b8cc32ee Mon Sep 17 00:00:00 2001
From: gegy1000
Date: Tue, 17 Jul 2018 19:14:08 +0200
Subject: ASM Based Class Translator (#1)
* Initial port to ASM
* Package updates
* Annotation + inner class translation
* Fix inner class mapping
* More bytecode translation
* Signature refactoring
* Fix highlighting of mapped names
* Fix parameter name offset
* Fix anonymous class generation
* Fix issues with inner class signature transformation
* Fix bridged method detection
* Fix compile issues
* Resolve all failed tests
* Apply deobfuscated name to transformed classes
* Fix class signatures not being translated
* Fix frame array type translation
* Fix frame array type translation
* Fix array translation in method calls
* Fix method reference and bridge detection
* Fix handling of null deobf mappings
* Parameter translation in interfaces
* Fix enum parameter index offset
* Fix parsed local variable indexing
* Fix stackoverflow on rebuilding method names
* Ignore invalid decompiled variable indices
* basic source jar
* Output directly to file on source export
* Make decompile parallel
* fix incorrect super calls
* Use previous save state to delete old mapping files
* Fix old mappings not properly being removed
* Fix old mappings not properly being removed
* make isMethodProvider public
(cherry picked from commit ebad6a9)
* speed up Deobfuscator's getSources by using a single TranslatingTypeloader and caching the ClassLoaderTypeloader
* ignore .idea project folders
* move SynchronizedTypeLoader to a non-inner
* fix signature remap of inners for now
* index & resolve method/field references for usages view
* Allow reader/writer subclasses to provide the underlying file operations
* fix giving obf classes a name not removing them from the panel
* buffer the ParsedJar class entry inputstream, allow use with a jarinputstream
* make CachingClasspathTypeLoader public
* make CachingClasspathTypeLoader public
* support enum switches with obfuscated SwitchMaps
---
.../java/cuchaz/enigma/bytecode/ClassRenamer.java | 539 ---------------------
1 file changed, 539 deletions(-)
delete mode 100644 src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
(limited to 'src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java')
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
deleted file mode 100644
index 62a838d..0000000
--- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.bytecode;
-
-import cuchaz.enigma.mapping.ClassEntry;
-import cuchaz.enigma.mapping.ClassNameReplacer;
-import cuchaz.enigma.mapping.Mappings;
-import cuchaz.enigma.mapping.Translator;
-import javassist.CtBehavior;
-import javassist.CtClass;
-import javassist.CtField;
-import javassist.Modifier;
-import javassist.bytecode.*;
-import javassist.bytecode.SignatureAttribute.*;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class ClassRenamer {
-
- public static void applyModifier(Object obj, Mappings.EntryModifier modifier) {
- int mod = -1;
- if (obj instanceof CtField)
- mod = ((CtField) obj).getModifiers();
- else if (obj instanceof CtBehavior)
- mod = ((CtBehavior) obj).getModifiers();
- else if (obj instanceof CtClass)
- mod = ((CtClass) obj).getModifiers();
-
- if (mod != -1) {
- switch (modifier) {
- case PRIVATE:
- mod = Modifier.setPrivate(mod);
- break;
- case PROTECTED:
- mod = Modifier.setProtected(mod);
- break;
- case PUBLIC:
- mod = Modifier.setPublic(mod);
- break;
- default:
- break;
- }
- if (obj instanceof CtField)
- ((CtField) obj).setModifiers(mod);
- else if (obj instanceof CtBehavior)
- ((CtBehavior) obj).setModifiers(mod);
- else
- ((CtClass) obj).setModifiers(mod);
- }
- }
-
- public static void renameClasses(CtClass c, final Translator translator) {
- renameClasses(c, className -> {
- ClassEntry entry = translator.translateEntry(new ClassEntry(className));
- if (entry != null) {
- return entry.getName();
- }
- return null;
- });
- }
-
- public static void moveAllClassesOutOfDefaultPackage(CtClass c, final String newPackageName) {
- renameClasses(c, className -> {
- ClassEntry entry = new ClassEntry(className);
- if (entry.isInDefaultPackage()) {
- return newPackageName + "/" + entry.getName();
- }
- return null;
- });
- }
-
- public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) {
- renameClasses(c, className -> {
- ClassEntry entry = new ClassEntry(className);
- if (entry.getPackageName().equals(oldPackageName)) {
- return entry.getSimpleName();
- }
- return null;
- });
- }
-
- @SuppressWarnings("unchecked")
- public static void renameClasses(CtClass c, ClassNameReplacer replacer) {
-
- // sadly, we can't use CtClass.renameClass() because SignatureAttribute.renameClass() is extremely buggy =(
-
- ReplacerClassMap map = new ReplacerClassMap(replacer);
- ClassFile classFile = c.getClassFile();
-
- // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo)
- ConstPool constPool = c.getClassFile().getConstPool();
- constPool.renameClass(map);
-
- // rename class attributes
- renameAttributes(classFile.getAttributes(), map, SignatureType.Class);
-
- // rename methods
- for (MethodInfo methodInfo : (List) classFile.getMethods()) {
- methodInfo.setDescriptor(Descriptor.rename(methodInfo.getDescriptor(), map));
- renameAttributes(methodInfo.getAttributes(), map, SignatureType.Method);
- }
-
- // rename fields
- for (FieldInfo fieldInfo : (List) classFile.getFields()) {
- fieldInfo.setDescriptor(Descriptor.rename(fieldInfo.getDescriptor(), map));
- renameAttributes(fieldInfo.getAttributes(), map, SignatureType.Field);
- }
-
- // rename the class name itself last
- // NOTE: don't use the map here, because setName() calls the buggy SignatureAttribute.renameClass()
- // we only want to replace exactly this class name
- String newName = renameClassName(c.getName(), map);
- if (newName != null) {
- c.setName(newName);
- }
-
- // replace simple names in the InnerClasses attribute too
- InnerClassesAttribute attr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag);
- if (attr != null) {
- for (int i = 0; i < attr.tableLength(); i++) {
-
- String innerName = attr.innerClass(i);
- // get the inner class full name (which has already been translated)
- ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName));
-
- if (attr.innerNameIndex(i) != 0) {
- // update the inner name
- attr.setInnerNameIndex(i, constPool.addUtf8Info(classEntry.getInnermostClassName()));
- }
-
- /* DEBUG
- System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i)));
- */
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private static void renameAttributes(List attributes, ReplacerClassMap map, SignatureType type) {
- try {
-
- // make the rename class method accessible
- Method renameClassMethod = AttributeInfo.class.getDeclaredMethod("renameClass", Map.class);
- renameClassMethod.setAccessible(true);
-
- for (AttributeInfo attribute : attributes) {
- if (attribute instanceof SignatureAttribute) {
- // this has to be handled specially because SignatureAttribute.renameClass() is buggy as hell
- SignatureAttribute signatureAttribute = (SignatureAttribute) attribute;
- String newSignature = type.rename(signatureAttribute.getSignature(), map);
- if (newSignature != null) {
- signatureAttribute.setSignature(newSignature);
- }
- } else if (attribute instanceof CodeAttribute) {
- // code attributes have signature attributes too (indirectly)
- CodeAttribute codeAttribute = (CodeAttribute) attribute;
- renameAttributes(codeAttribute.getAttributes(), map, type);
- } else if (attribute instanceof LocalVariableTypeAttribute) {
- // lvt attributes have signature attributes too
- LocalVariableTypeAttribute localVariableAttribute = (LocalVariableTypeAttribute) attribute;
- renameLocalVariableTypeAttribute(localVariableAttribute, map);
- } else {
- renameClassMethod.invoke(attribute, map);
- }
- }
-
- } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
- throw new Error("Unable to call javassist methods by reflection!", ex);
- }
- }
-
- private static void renameLocalVariableTypeAttribute(LocalVariableTypeAttribute attribute, ReplacerClassMap map) {
-
- // adapted from LocalVariableAttribute.renameClass()
- ConstPool cp = attribute.getConstPool();
- int n = attribute.tableLength();
- byte[] info = attribute.get();
- for (int i = 0; i < n; ++i) {
- int pos = i * 10 + 2;
- int index = ByteArray.readU16bit(info, pos + 6);
- if (index != 0) {
- String signature = cp.getUtf8Info(index);
- String newSignature = renameLocalVariableSignature(signature, map);
- if (newSignature != null) {
- ByteArray.write16bit(cp.addUtf8Info(newSignature), info, pos + 6);
- }
- }
- }
- }
-
- private static String renameLocalVariableSignature(String signature, ReplacerClassMap map) {
-
- // for some reason, signatures with . in them don't count as field signatures
- // looks like anonymous classes delimit with . in stead of $
- // convert the . to $, but keep track of how many we replace
- // we need to put them back after we translate
- int start = signature.lastIndexOf('$') + 1;
- int numConverted = 0;
- StringBuilder buf = new StringBuilder(signature);
- for (int i = buf.length() - 1; i >= start; i--) {
- char c = buf.charAt(i);
- if (c == '.') {
- buf.setCharAt(i, '$');
- numConverted++;
- }
- }
- signature = buf.toString();
-
- // translate
- String newSignature = renameFieldSignature(signature, map);
- if (newSignature != null) {
-
- // put the delimiters back
- buf = new StringBuilder(newSignature);
- for (int i = buf.length() - 1; i >= 0 && numConverted > 0; i--) {
- char c = buf.charAt(i);
- if (c == '$') {
- buf.setCharAt(i, '.');
- numConverted--;
- }
- }
- assert (numConverted == 0);
- newSignature = buf.toString();
-
- return newSignature;
- }
-
- return null;
- }
-
- private static String renameClassSignature(String signature, ReplacerClassMap map) {
- try {
- ClassSignature type = renameType(SignatureAttribute.toClassSignature(signature), map);
- return type.encode();
- } catch (BadBytecode ex) {
- throw new Error("Can't parse field signature: " + signature);
- }
- }
-
- private static String renameFieldSignature(String signature, ReplacerClassMap map) {
- try {
- ObjectType type = renameType(SignatureAttribute.toFieldSignature(signature), map);
- if (type != null) {
- return type.encode();
- }
- return null;
- } catch (BadBytecode ex) {
- throw new Error("Can't parse class signature: " + signature);
- }
- }
-
- private static String renameMethodSignature(String signature, ReplacerClassMap map) {
- try {
- MethodSignature type = renameType(SignatureAttribute.toMethodSignature(signature), map);
- return type.encode();
- } catch (BadBytecode ex) {
- throw new Error("Can't parse method signature: " + signature);
- }
- }
-
- private static TypeParameter[] renameTypeParameter(TypeParameter[] typeParamTypes, ReplacerClassMap map) {
- if (typeParamTypes != null) {
- typeParamTypes = Arrays.copyOf(typeParamTypes, typeParamTypes.length);
- for (int i = 0; i < typeParamTypes.length; i++) {
- TypeParameter newParamType = renameType(typeParamTypes[i], map);
- if (newParamType != null) {
- typeParamTypes[i] = newParamType;
- }
- }
- }
- return typeParamTypes;
- }
-
- private static ClassSignature renameType(ClassSignature type, ReplacerClassMap map) {
-
- TypeParameter[] typeParamTypes = renameTypeParameter(type.getParameters(), map);
-
- ClassType superclassType = type.getSuperClass();
- if (superclassType != ClassType.OBJECT) {
- ClassType newSuperclassType = renameType(superclassType, map);
- if (newSuperclassType != null) {
- superclassType = newSuperclassType;
- }
- }
-
- ClassType[] interfaceTypes = type.getInterfaces();
- if (interfaceTypes != null) {
- interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length);
- for (int i = 0; i < interfaceTypes.length; i++) {
- ClassType newInterfaceType = renameType(interfaceTypes[i], map);
- if (newInterfaceType != null) {
- interfaceTypes[i] = newInterfaceType;
- }
- }
- }
-
- return new ClassSignature(typeParamTypes, superclassType, interfaceTypes);
- }
-
- private static MethodSignature renameType(MethodSignature type, ReplacerClassMap map) {
-
- TypeParameter[] typeParamTypes = renameTypeParameter(type.getTypeParameters(), map);
-
- Type[] paramTypes = type.getParameterTypes();
- if (paramTypes != null) {
- paramTypes = Arrays.copyOf(paramTypes, paramTypes.length);
- for (int i = 0; i < paramTypes.length; i++) {
- Type newParamType = renameType(paramTypes[i], map);
- if (newParamType != null) {
- paramTypes[i] = newParamType;
- }
- }
- }
-
- Type returnType = type.getReturnType();
- if (returnType != null) {
- Type newReturnType = renameType(returnType, map);
- if (newReturnType != null) {
- returnType = newReturnType;
- }
- }
-
- ObjectType[] exceptionTypes = type.getExceptionTypes();
- if (exceptionTypes != null) {
- exceptionTypes = Arrays.copyOf(exceptionTypes, exceptionTypes.length);
- for (int i = 0; i < exceptionTypes.length; i++) {
- ObjectType newExceptionType = renameType(exceptionTypes[i], map);
- if (newExceptionType != null) {
- exceptionTypes[i] = newExceptionType;
- }
- }
- }
-
- return new MethodSignature(typeParamTypes, paramTypes, returnType, exceptionTypes);
- }
-
- private static Type renameType(Type type, ReplacerClassMap map) {
- if (type instanceof ObjectType) {
- return renameType((ObjectType) type, map);
- } else if (type instanceof BaseType) {
- return renameType((BaseType) type, map);
- } else {
- throw new Error("Don't know how to rename type " + type.getClass());
- }
- }
-
- private static ObjectType renameType(ObjectType type, ReplacerClassMap map) {
- if (type instanceof ArrayType) {
- return renameType((ArrayType) type, map);
- } else if (type instanceof ClassType) {
- return renameType((ClassType) type, map);
- } else if (type instanceof TypeVariable) {
- return renameType((TypeVariable) type, map);
- } else {
- throw new Error("Don't know how to rename type " + type.getClass());
- }
- }
-
- private static BaseType renameType(BaseType type, ReplacerClassMap map) {
- // don't have to rename primitives
- return null;
- }
-
- private static TypeVariable renameType(TypeVariable type, ReplacerClassMap map) {
- // don't have to rename template args
- return null;
- }
-
- private static ClassType renameType(ClassType type, ReplacerClassMap map) {
-
- // translate type args
- TypeArgument[] args = type.getTypeArguments();
- if (args != null) {
- args = Arrays.copyOf(args, args.length);
- for (int i = 0; i < args.length; i++) {
- TypeArgument newType = renameType(args[i], map);
- if (newType != null) {
- args[i] = newType;
- }
- }
- }
-
- if (type instanceof NestedClassType) {
- NestedClassType nestedType = (NestedClassType) type;
-
- // translate the name
- String name = getClassName(type);
- String newName = map.get(name);
- if (newName != null) {
- name = new ClassEntry(newName).getInnermostClassName();
- }
-
- // translate the parent class too
- ClassType parent = renameType(nestedType.getDeclaringClass(), map);
- if (parent == null) {
- parent = nestedType.getDeclaringClass();
- }
-
- return new NestedClassType(parent, name, args);
- } else {
-
- // translate the name
- String name = type.getName();
- String newName = renameClassName(name, map);
- if (newName != null) {
- name = newName;
- }
-
- return new ClassType(name, args);
- }
- }
-
- private static String getClassName(ClassType type) {
- if (type instanceof NestedClassType) {
- NestedClassType nestedType = (NestedClassType) type;
- return getClassName(nestedType.getDeclaringClass()) + "$" + Descriptor.toJvmName(type.getName().replace('.', '$'));
- } else {
- return Descriptor.toJvmName(type.getName());
- }
- }
-
- private static String renameClassName(String name, ReplacerClassMap map) {
- String newName = map.get(Descriptor.toJvmName(name));
- if (newName != null) {
- return Descriptor.toJavaName(newName);
- }
- return null;
- }
-
- private static TypeArgument renameType(TypeArgument type, ReplacerClassMap map) {
- ObjectType subType = type.getType();
- if (subType != null) {
- ObjectType newSubType = renameType(subType, map);
- if (newSubType != null) {
- switch (type.getKind()) {
- case ' ':
- return new TypeArgument(newSubType);
- case '+':
- return TypeArgument.subclassOf(newSubType);
- case '-':
- return TypeArgument.superOf(newSubType);
- default:
- throw new Error("Unknown type kind: " + type.getKind());
- }
- }
- }
- return null;
- }
-
- private static ArrayType renameType(ArrayType type, ReplacerClassMap map) {
- Type newSubType = renameType(type.getComponentType(), map);
- if (newSubType != null) {
- return new ArrayType(type.getDimension(), newSubType);
- }
- return null;
- }
-
- private static TypeParameter renameType(TypeParameter type, ReplacerClassMap map) {
-
- ObjectType superclassType = type.getClassBound();
- if (superclassType != null) {
- ObjectType newSuperclassType = renameType(superclassType, map);
- if (newSuperclassType != null) {
- superclassType = newSuperclassType;
- }
- }
-
- ObjectType[] interfaceTypes = type.getInterfaceBound();
- if (interfaceTypes != null) {
- interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length);
- for (int i = 0; i < interfaceTypes.length; i++) {
- ObjectType newInterfaceType = renameType(interfaceTypes[i], map);
- if (newInterfaceType != null) {
- interfaceTypes[i] = newInterfaceType;
- }
- }
- }
-
- return new TypeParameter(type.getName(), superclassType, interfaceTypes);
- }
-
- private enum SignatureType {
- Class {
- @Override
- public String rename(String signature, ReplacerClassMap map) {
- return renameClassSignature(signature, map);
- }
- },
- Field {
- @Override
- public String rename(String signature, ReplacerClassMap map) {
- return renameFieldSignature(signature, map);
- }
- },
- Method {
- @Override
- public String rename(String signature, ReplacerClassMap map) {
- return renameMethodSignature(signature, map);
- }
- };
-
- public abstract String rename(String signature, ReplacerClassMap map);
- }
-
- private static class ReplacerClassMap extends HashMap {
-
- private ClassNameReplacer replacer;
-
- public ReplacerClassMap(ClassNameReplacer replacer) {
- this.replacer = replacer;
- }
-
- @Override
- public String get(Object obj) {
- if (obj instanceof String) {
- return get((String) obj);
- }
- return null;
- }
-
- public String get(String className) {
- return replacer.replace(className);
- }
- }
-}
--
cgit v1.2.3