From ed70355a86f357b644bb7ecd7b90de5a5a6f6f76 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Sun, 11 Jun 2023 15:32:07 +0200 Subject: [PATCH] chore: moved obfuscation stuff to mapping library --- build.gradle | 3 +- .../exceptions/MappingNotFoundException.java | 27 --- .../ftbsc/lll/processor/tools/ASTUtils.java | 6 +- .../lll/processor/tools/ProcessorOptions.java | 14 +- .../tools/containers/FieldContainer.java | 3 +- .../tools/containers/MethodContainer.java | 3 +- .../tools/obfuscation/ObfuscationMapper.java | 225 ------------------ 7 files changed, 16 insertions(+), 265 deletions(-) delete mode 100644 src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java delete mode 100644 src/main/java/ftbsc/lll/processor/tools/obfuscation/ObfuscationMapper.java diff --git a/build.gradle b/build.gradle index 3f51438..5109f86 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,8 @@ repositories { dependencies { implementation 'com.squareup:javapoet:1.13.0' implementation 'org.ow2.asm:asm-commons:9.5' - implementation 'ftbsc:lll:0.4.1' + implementation 'ftbsc:lll:0.4.2' + implementation 'ftbsc.lll:mapper:0.0.2' } jar { diff --git a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java b/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java deleted file mode 100644 index e943c01..0000000 --- a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java +++ /dev/null @@ -1,27 +0,0 @@ -package ftbsc.lll.exceptions; - -import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper; - -/** - * Thrown upon failure to find the requested mapping within a loaded {@link ObfuscationMapper}. - */ -public class MappingNotFoundException extends RuntimeException { - - /** - * Constructs a new mapping not found exception for the specified mapping. - * @param mapping the relevant mapping - */ - public MappingNotFoundException(String mapping) { - super(String.format("Could not find mapping for %s!", mapping)); - } - - /** - * Constructs a new mapping not found exception for the specified mapping - * with the specified reason. - * @param mapping the relevant mapping - * @param reason the reason message - */ - public MappingNotFoundException(String mapping, String reason) { - this(mapping + ": " + reason); - } -} diff --git a/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java b/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java index 0037886..b33a906 100644 --- a/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java +++ b/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java @@ -6,7 +6,7 @@ import ftbsc.lll.exceptions.NotAProxyException; import ftbsc.lll.exceptions.TargetNotFoundException; import ftbsc.lll.processor.annotations.Target; import ftbsc.lll.processor.tools.containers.ClassContainer; -import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper; +import ftbsc.lll.mapper.IMapper; import ftbsc.lll.proxies.ProxyType; import javax.annotation.processing.ProcessingEnvironment; @@ -229,11 +229,11 @@ public class ASTUtils { * @param parentFQN the unobfuscated FQN of the parent class * @param memberName the name of the member * @param methodDescriptor the descriptor of the method, may be null - * @param mapper the {@link ObfuscationMapper} to use, may be null + * @param mapper the {@link IMapper} to use, may be null * @return the internal class name * @since 0.3.0 */ - public static String findMemberName(String parentFQN, String memberName, String methodDescriptor, ObfuscationMapper mapper) { + public static String findMemberName(String parentFQN, String memberName, String methodDescriptor, IMapper mapper) { try { return mapper == null ? memberName : mapper.obfuscateMember(parentFQN, memberName, methodDescriptor); } catch(MappingNotFoundException e) { diff --git a/src/main/java/ftbsc/lll/processor/tools/ProcessorOptions.java b/src/main/java/ftbsc/lll/processor/tools/ProcessorOptions.java index 0ef8a18..de751bc 100644 --- a/src/main/java/ftbsc/lll/processor/tools/ProcessorOptions.java +++ b/src/main/java/ftbsc/lll/processor/tools/ProcessorOptions.java @@ -2,7 +2,7 @@ package ftbsc.lll.processor.tools; import ftbsc.lll.IInjector; import ftbsc.lll.exceptions.InvalidResourceException; -import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper; +import ftbsc.lll.mapper.IMapper; import javax.annotation.processing.ProcessingEnvironment; import java.io.*; @@ -12,6 +12,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; /** * Class in charge of containing, parsing and processing all processor options, @@ -33,10 +34,10 @@ public class ProcessorOptions { public final ProcessingEnvironment env; /** - * The {@link ObfuscationMapper} used to convert classes and variables + * The {@link IMapper} used to convert classes and variables * to their obfuscated equivalent. Will be null when no mapper is in use. */ - public final ObfuscationMapper mapper; + public final IMapper mapper; /** * Whether the processor should issue warnings when compiling code anonymous @@ -80,10 +81,9 @@ public class ProcessorOptions { throw new InvalidResourceException(location); } } - //assuming its tsrg file - //todo: replace crappy homebaked parser with actual library - this.mapper = new ObfuscationMapper(new BufferedReader(new InputStreamReader(targetStream, - StandardCharsets.UTF_8)).lines()); + this.mapper = IMapper.getMappers(new BufferedReader( + new InputStreamReader(targetStream, StandardCharsets.UTF_8)).lines().collect(Collectors.toList()) + ).iterator().next(); //TODO: add logic for choosing a specific one } this.anonymousClassWarning = parseBooleanArg(env.getOptions().get("anonymousClassWarning"), true); this.obfuscateInjectorMetadata = parseBooleanArg(env.getOptions().get("obfuscateInjectorMetadata"), true); diff --git a/src/main/java/ftbsc/lll/processor/tools/containers/FieldContainer.java b/src/main/java/ftbsc/lll/processor/tools/containers/FieldContainer.java index 2dd2ecb..0074ebe 100644 --- a/src/main/java/ftbsc/lll/processor/tools/containers/FieldContainer.java +++ b/src/main/java/ftbsc/lll/processor/tools/containers/FieldContainer.java @@ -1,6 +1,7 @@ package ftbsc.lll.processor.tools.containers; import ftbsc.lll.exceptions.AmbiguousDefinitionException; +import ftbsc.lll.mapper.tools.MappingUtils; import ftbsc.lll.processor.annotations.Find; import ftbsc.lll.processor.annotations.Patch; import ftbsc.lll.processor.tools.ProcessorOptions; @@ -73,7 +74,7 @@ public class FieldContainer { this.name = this.elem.getSimpleName().toString(); this.descriptor = descriptorFromType(this.elem.asType(), options.env); } - this.descriptorObf = options.mapper == null ? this.descriptor : options.mapper.obfuscateType(Type.getType(this.descriptor)).getDescriptor(); + this.descriptorObf = options.mapper == null ? this.descriptor : MappingUtils.obfuscateType(Type.getType(this.descriptor), options.mapper).getDescriptor(); this.nameObf = findMemberName(parent.fqn, this.name, null, options.mapper); } diff --git a/src/main/java/ftbsc/lll/processor/tools/containers/MethodContainer.java b/src/main/java/ftbsc/lll/processor/tools/containers/MethodContainer.java index 714ee54..f646a1c 100644 --- a/src/main/java/ftbsc/lll/processor/tools/containers/MethodContainer.java +++ b/src/main/java/ftbsc/lll/processor/tools/containers/MethodContainer.java @@ -2,6 +2,7 @@ package ftbsc.lll.processor.tools.containers; import ftbsc.lll.exceptions.AmbiguousDefinitionException; import ftbsc.lll.exceptions.TargetNotFoundException; +import ftbsc.lll.mapper.tools.MappingUtils; import ftbsc.lll.processor.annotations.Find; import ftbsc.lll.processor.annotations.Patch; import ftbsc.lll.processor.annotations.Target; @@ -78,7 +79,7 @@ public class MethodContainer { this.name = this.elem.getSimpleName().toString(); this.descriptor = descriptorFromExecutableElement(this.elem, options.env); } - this.descriptorObf = options.mapper == null ? this.descriptor : options.mapper.obfuscateMethodDescriptor(this.descriptor); + this.descriptorObf = options.mapper == null ? this.descriptor : MappingUtils.obfuscateMethodDescriptor(this.descriptor, options.mapper); this.nameObf = findMemberName(parent.fqn, this.name, this.descriptor, options.mapper); } diff --git a/src/main/java/ftbsc/lll/processor/tools/obfuscation/ObfuscationMapper.java b/src/main/java/ftbsc/lll/processor/tools/obfuscation/ObfuscationMapper.java deleted file mode 100644 index 5938de3..0000000 --- a/src/main/java/ftbsc/lll/processor/tools/obfuscation/ObfuscationMapper.java +++ /dev/null @@ -1,225 +0,0 @@ -package ftbsc.lll.processor.tools.obfuscation; - -import ftbsc.lll.exceptions.AmbiguousDefinitionException; -import ftbsc.lll.exceptions.MappingNotFoundException; -import ftbsc.lll.tools.DescriptorBuilder; -import org.objectweb.asm.Type; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Parses a .tsrg file into a mapper capable of converting from - * deobfuscated names to obfuscated ones. - * Obviously, it may only be used at runtime if the .tsrg file is - * included in the resources. However, in that case, I'd recommend - * using the built-in Forge one and refrain from including an extra - * resource for no good reason. - * TODO: CSV format - * @since 0.2.0 - */ -public class ObfuscationMapper { - - /** - * A Map using the deobfuscated names as keys, - * holding information for that class as value. - */ - private final Map mapper = new HashMap<>(); - - /** - * The public constructor. - * Should be passed a {@link Stream} of Strings, one representing each line. - * Whether they contain line endings or not is irrelevant. - * @param str a {@link Stream} of strings - */ - public ObfuscationMapper(Stream str) { - AtomicReference currentClass = new AtomicReference<>(""); - str.forEach(l -> { - if(l == null) return; - if(l.startsWith("\t")) - mapper.get(currentClass.get()).addMember(l); - else { - String[] sp = l.split(" "); - ObfuscationData s = new ObfuscationData(sp[0], sp[1]); - currentClass.set(s.unobf); - mapper.put(s.unobf, s); - } - }); - } - - /** - * Gets the obfuscated name of the class. - * @param name the unobfuscated internal name of the desired class - * @return the obfuscated name of the class - * @throws MappingNotFoundException if no mapping is found - */ - public String obfuscateClass(String name) { - ObfuscationData data = mapper.get(name.replace('.', '/')); - if(data == null) - throw new MappingNotFoundException(name); - else return data.obf; - } - - /** - * Gets the obfuscated name of a class member (field or method). - * The method signature must be in this format: "methodName methodDescriptor", - * with a space, because that's how it is in .tsrg files. - * @param parentName the unobfuscated internal name of the parent class - * @param memberName the field name or method signature - * @param methodDescriptor the optional descriptor of the member, may be null or partial - * @return the obfuscated name of the given member - * @throws MappingNotFoundException if no mapping is found - */ - public String obfuscateMember(String parentName, String memberName, String methodDescriptor) { - ObfuscationData data = mapper.get(parentName.replace('.', '/')); - if(data == null) - throw new MappingNotFoundException(parentName + "::" + memberName); - return data.get(memberName, methodDescriptor); - } - - /** - * Obfuscates a method descriptor, replacing its class references - * with their obfuscated counterparts. - * @param descriptor a {@link String} containing the descriptor - * @return the obfuscated descriptor - * @since 0.5.1 - */ - public String obfuscateMethodDescriptor(String descriptor) { - Type method = Type.getMethodType(descriptor); - Type[] arguments = method.getArgumentTypes(); - Type returnType = method.getReturnType(); - - Type[] obfArguments = new Type[arguments.length]; - for(int i = 0; i < obfArguments.length; i++) - obfArguments[i] = this.obfuscateType(arguments[i]); - - return Type.getMethodDescriptor(this.obfuscateType(returnType), obfArguments); - } - - /** - * Given a {@link Type} it returns its obfuscated counterpart. - * @param type the type in question - * @return the obfuscated type - * @since 0.5.1 - */ - public Type obfuscateType(Type type) { - //unwrap arrays - Type unwrapped = type; - int arrayLevel = 0; - while(unwrapped.getSort() == org.objectweb.asm.Type.ARRAY) { - unwrapped = unwrapped.getElementType(); - arrayLevel++; - } - - //if it's a primitive no operation is needed - if(type.getSort() < org.objectweb.asm.Type.ARRAY) - return type; - - String internalName = type.getInternalName(); - - String internalNameObf; - try { - internalNameObf = this.obfuscateClass(internalName); - return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameObf, arrayLevel)); - } catch(MappingNotFoundException e) { - return type; - } - } - - /** - * Private class used internally for storing information about each - * class. It's private because there is no good reason anyone would - * want to access this outside of this class. - */ - private static class ObfuscationData { - /** - * The unobfuscated name (FQN with '/' instad of '.') of the class. - */ - private final String unobf; - - /** - * The obfuscated internal name (FQN with '/' instad of '.') of the class. - */ - private final String obf; - - /** - * A {@link Map} tying each member's name or signature to its - * obfuscated counterpart. - */ - private final Map members; - - /** - * The constructor. It takes in the names (obfuscated and non-obfuscated) - * of a class. - * @param unobf the unobfuscated name - * @param obf the obfuscated name - */ - private ObfuscationData(String unobf, String obf) { - this.unobf = unobf; - this.obf = obf; - this.members = new HashMap<>(); - } - - /** - * Adds a member to the target class. - * For fields only the names are required; for methods, - * this takes in the full signature ({@code name + " " + space}). - * @param s the String representing the declaration line - */ - public void addMember(String s) { - String[] split = s.trim().split(" "); - if(split.length == 2) //field - members.put(split[0], split[1]); - else if (split.length == 3) //method - members.put(split[0] + " " + split[1], split[2]); - } - - /** - * Gets an obfuscated member given the method name and a method descriptor, - * which may be partial (i.e. not include return type) or null if the member - * is not a method. - * @param memberName member name - * @param methodDescriptor the method descriptor, or null if it's not a method - * @return the requested obfuscated name, or null if nothing was found - * @throws AmbiguousDefinitionException if not enough data was given to uniquely identify a mapping - */ - public String get(String memberName, String methodDescriptor) { - - //find all keys that start with the name - List candidates = members.keySet().stream().filter( - m -> m.split(" ")[0].equals(memberName) - ).collect(Collectors.toList()); - - if(methodDescriptor != null) { - String signature = String.format("%s %s", memberName, methodDescriptor); - candidates = candidates.stream().filter( - m -> m.equals(signature) - ).collect(Collectors.toList()); - } - - switch(candidates.size()) { - case 0: - throw new MappingNotFoundException(String.format( - "%s.%s%s", - this.unobf, - memberName, - methodDescriptor == null ? "" : "()" - )); - case 1: - return members.get(candidates.get(0)); - default: - throw new AmbiguousDefinitionException(String.format( - "Mapper could not uniquely identify member %s.%s%s, found %d!", - this.unobf, - memberName, - methodDescriptor == null ? "" : "()", - candidates.size() - )); - } - } - } -}