mirror of
https://github.com/zaaarf/lillero-processor.git
synced 2024-11-24 17:44:48 +01:00
chore: moved obfuscation stuff to mapping library
This commit is contained in:
parent
d528d472a1
commit
ed70355a86
7 changed files with 16 additions and 265 deletions
|
@ -21,7 +21,8 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.squareup:javapoet:1.13.0'
|
implementation 'com.squareup:javapoet:1.13.0'
|
||||||
implementation 'org.ow2.asm:asm-commons:9.5'
|
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 {
|
jar {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import ftbsc.lll.exceptions.NotAProxyException;
|
||||||
import ftbsc.lll.exceptions.TargetNotFoundException;
|
import ftbsc.lll.exceptions.TargetNotFoundException;
|
||||||
import ftbsc.lll.processor.annotations.Target;
|
import ftbsc.lll.processor.annotations.Target;
|
||||||
import ftbsc.lll.processor.tools.containers.ClassContainer;
|
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 ftbsc.lll.proxies.ProxyType;
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
@ -229,11 +229,11 @@ public class ASTUtils {
|
||||||
* @param parentFQN the unobfuscated FQN of the parent class
|
* @param parentFQN the unobfuscated FQN of the parent class
|
||||||
* @param memberName the name of the member
|
* @param memberName the name of the member
|
||||||
* @param methodDescriptor the descriptor of the method, may be null
|
* @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
|
* @return the internal class name
|
||||||
* @since 0.3.0
|
* @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 {
|
try {
|
||||||
return mapper == null ? memberName : mapper.obfuscateMember(parentFQN, memberName, methodDescriptor);
|
return mapper == null ? memberName : mapper.obfuscateMember(parentFQN, memberName, methodDescriptor);
|
||||||
} catch(MappingNotFoundException e) {
|
} catch(MappingNotFoundException e) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ftbsc.lll.processor.tools;
|
||||||
|
|
||||||
import ftbsc.lll.IInjector;
|
import ftbsc.lll.IInjector;
|
||||||
import ftbsc.lll.exceptions.InvalidResourceException;
|
import ftbsc.lll.exceptions.InvalidResourceException;
|
||||||
import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper;
|
import ftbsc.lll.mapper.IMapper;
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -12,6 +12,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class in charge of containing, parsing and processing all processor options,
|
* Class in charge of containing, parsing and processing all processor options,
|
||||||
|
@ -33,10 +34,10 @@ public class ProcessorOptions {
|
||||||
public final ProcessingEnvironment env;
|
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.
|
* 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
|
* Whether the processor should issue warnings when compiling code anonymous
|
||||||
|
@ -80,10 +81,9 @@ public class ProcessorOptions {
|
||||||
throw new InvalidResourceException(location);
|
throw new InvalidResourceException(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//assuming its tsrg file
|
this.mapper = IMapper.getMappers(new BufferedReader(
|
||||||
//todo: replace crappy homebaked parser with actual library
|
new InputStreamReader(targetStream, StandardCharsets.UTF_8)).lines().collect(Collectors.toList())
|
||||||
this.mapper = new ObfuscationMapper(new BufferedReader(new InputStreamReader(targetStream,
|
).iterator().next(); //TODO: add logic for choosing a specific one
|
||||||
StandardCharsets.UTF_8)).lines());
|
|
||||||
}
|
}
|
||||||
this.anonymousClassWarning = parseBooleanArg(env.getOptions().get("anonymousClassWarning"), true);
|
this.anonymousClassWarning = parseBooleanArg(env.getOptions().get("anonymousClassWarning"), true);
|
||||||
this.obfuscateInjectorMetadata = parseBooleanArg(env.getOptions().get("obfuscateInjectorMetadata"), true);
|
this.obfuscateInjectorMetadata = parseBooleanArg(env.getOptions().get("obfuscateInjectorMetadata"), true);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ftbsc.lll.processor.tools.containers;
|
package ftbsc.lll.processor.tools.containers;
|
||||||
|
|
||||||
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
||||||
|
import ftbsc.lll.mapper.tools.MappingUtils;
|
||||||
import ftbsc.lll.processor.annotations.Find;
|
import ftbsc.lll.processor.annotations.Find;
|
||||||
import ftbsc.lll.processor.annotations.Patch;
|
import ftbsc.lll.processor.annotations.Patch;
|
||||||
import ftbsc.lll.processor.tools.ProcessorOptions;
|
import ftbsc.lll.processor.tools.ProcessorOptions;
|
||||||
|
@ -73,7 +74,7 @@ public class FieldContainer {
|
||||||
this.name = this.elem.getSimpleName().toString();
|
this.name = this.elem.getSimpleName().toString();
|
||||||
this.descriptor = descriptorFromType(this.elem.asType(), options.env);
|
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);
|
this.nameObf = findMemberName(parent.fqn, this.name, null, options.mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ftbsc.lll.processor.tools.containers;
|
||||||
|
|
||||||
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
||||||
import ftbsc.lll.exceptions.TargetNotFoundException;
|
import ftbsc.lll.exceptions.TargetNotFoundException;
|
||||||
|
import ftbsc.lll.mapper.tools.MappingUtils;
|
||||||
import ftbsc.lll.processor.annotations.Find;
|
import ftbsc.lll.processor.annotations.Find;
|
||||||
import ftbsc.lll.processor.annotations.Patch;
|
import ftbsc.lll.processor.annotations.Patch;
|
||||||
import ftbsc.lll.processor.annotations.Target;
|
import ftbsc.lll.processor.annotations.Target;
|
||||||
|
@ -78,7 +79,7 @@ public class MethodContainer {
|
||||||
this.name = this.elem.getSimpleName().toString();
|
this.name = this.elem.getSimpleName().toString();
|
||||||
this.descriptor = descriptorFromExecutableElement(this.elem, options.env);
|
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);
|
this.nameObf = findMemberName(parent.fqn, this.name, this.descriptor, options.mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<String, ObfuscationData> 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<String> str) {
|
|
||||||
AtomicReference<String> 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<String, String> 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<String> 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()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue