feat: implemented multimapper

This commit is contained in:
zaaarf 2023-08-26 18:47:04 +02:00
parent f03bb3c932
commit 4f5394ce5a
No known key found for this signature in database
GPG key ID: 6445A5CD15E5B40C
3 changed files with 141 additions and 15 deletions

View file

@ -0,0 +1,123 @@
package ftbsc.lll.mapper.impl;
import com.google.auto.service.AutoService;
import ftbsc.lll.exceptions.MalformedMappingsException;
import ftbsc.lll.exceptions.MappingNotFoundException;
import ftbsc.lll.mapper.IMapper;
import ftbsc.lll.mapper.MapperProvider;
import ftbsc.lll.mapper.tools.MappingUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Special mapper type that actually resolves to an ordered
* sequence of mappers applied one after the other.
*/
@AutoService(IMapper.class)
public class MultiMapper implements IMapper {
/**
* The list of mappers.
*/
private final List<IMapper> mapperList = new ArrayList<>();
/**
* Checks whether this mapper can process the given lines.
* @param lines the lines to read
* @return whether this type of mapper can process these lines
*/
@Override
public boolean claim(List<String> lines) {
return lines.get(0).equals("lll multimapper");
}
/**
* Populates the {@link IMapper} given the lines, ignoring errors depending on the
* given ignoreErrors flag.
* @param lines the lines to read
* @param ignoreErrors try to ignore errors and keep going
* @throws MalformedMappingsException if an error is encountered and ignoreErrors is false
*/
@Override
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
for(int i = 1; i < lines.size(); i++) {
List<String> data = MapperProvider.fetchFromLocalOrRemote(lines.get(i));
IMapper mapper = MapperProvider.getMapper(data);
mapper.populate(data, ignoreErrors);
this.mapperList.add(mapper);
}
}
/**
* Completely resets the mapper, clearing it of all existing mappings.
*/
@Override
public void reset() {
this.mapperList.forEach(IMapper::reset);
this.mapperList.clear();
}
/**
* Gets the obfuscated name of the class.
* @param name the plain internal name of the desired class
* @return the obfuscated name of the class
* @throws MappingNotFoundException if no mapping is found
*/
@Override
public String obfuscateClass(String name) throws MappingNotFoundException {
for(IMapper mapper : this.mapperList)
name = mapper.obfuscateClass(name);
return name;
}
/**
* Gets the plain name of the class.
* @param nameObf the obfuscated internal name of the desired class
* @return the plain name of the class
* @throws MappingNotFoundException if no mapping is found
*/
@Override
public String deobfuscateClass(String nameObf) throws MappingNotFoundException {
for(int i = this.mapperList.size() - 1; i >= 0; i--)
nameObf = this.mapperList.get(i).deobfuscateClass(nameObf);
return nameObf;
}
/**
* Gets the obfuscated name of a class member (field or method).
* @param parentName the plain internal name of the parent class
* @param memberName the field name or method signature
* @param methodDescriptor the descriptor of the member (only for methods)
* @return the obfuscated name of the given member
* @throws MappingNotFoundException if no mapping is found
*/
@Override
public String obfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException {
for(IMapper mapper : this.mapperList) {
memberName = mapper.obfuscateMember(parentName, memberName, methodDescriptor);
methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, false);
parentName = mapper.obfuscateClass(parentName);
}
return memberName;
}
/**
* Gets the plain name of a class member (field or method).
* @param parentName the obfuscated internal name of the parent class
* @param memberName the obfuscated field name or method signature
* @param methodDescriptor the obfuscated descriptor of the member (only for methods)
* @return the plain name of the given member
* @throws MappingNotFoundException if no mapping is found
*/
@Override
public String deobfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException {
for(int i = this.mapperList.size() - 1; i >= 0; i--) {
IMapper mapper = this.mapperList.get(i);
memberName = mapper.deobfuscateMember(parentName, memberName, methodDescriptor);
methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, true);
parentName = mapper.deobfuscateClass(parentName);
}
return memberName;
}
}

View file

@ -10,33 +10,34 @@ import org.objectweb.asm.Type;
* mappers. * mappers.
*/ */
public class MappingUtils { public class MappingUtils {
/** /**
* Obfuscates a method descriptor, replacing its class references * Maps a method descriptor, replacing its class references with their mapped counterparts.
* with their obfuscated counterparts.
* @param descriptor a {@link String} containing the descriptor * @param descriptor a {@link String} containing the descriptor
* @param mapper the {@link IMapper} to use for the process * @param mapper the {@link IMapper} to use for the process
* @return the obfuscated descriptor * @param reverse whether it should deobfuscate rather than obfuscate
* @return the mapped descriptor
*/ */
public static String obfuscateMethodDescriptor(String descriptor, IMapper mapper) { public static String mapMethodDescriptor(String descriptor, IMapper mapper, boolean reverse) {
Type method = Type.getMethodType(descriptor); Type method = Type.getMethodType(descriptor);
Type[] arguments = method.getArgumentTypes(); Type[] arguments = method.getArgumentTypes();
Type returnType = method.getReturnType(); Type returnType = method.getReturnType();
Type[] obfArguments = new Type[arguments.length]; Type[] mappedArguents = new Type[arguments.length];
for(int i = 0; i < obfArguments.length; i++) for(int i = 0; i < mappedArguents.length; i++)
obfArguments[i] = obfuscateType(arguments[i], mapper); mappedArguents[i] = mapType(arguments[i], mapper, reverse);
return Type.getMethodDescriptor(obfuscateType(returnType, mapper), obfArguments); return Type.getMethodDescriptor(mapType(returnType, mapper, reverse), mappedArguents);
} }
/** /**
* Given a {@link Type} and a valid {@link IMapper} it returns its obfuscated * Given a {@link Type} and a valid {@link IMapper} it returns its mapped counterpart.
* counterpart.
* @param type the type in question * @param type the type in question
* @param mapper the {@link IMapper} to use for the process * @param mapper the {@link IMapper} to use for the process
* @param reverse whether it should deobfuscate rather than obfuscate
* @return the obfuscated type * @return the obfuscated type
*/ */
public static Type obfuscateType(Type type, IMapper mapper) { public static Type mapType(Type type, IMapper mapper, boolean reverse) {
//unwrap arrays //unwrap arrays
Type unwrapped = type; Type unwrapped = type;
int arrayLevel = 0; int arrayLevel = 0;
@ -51,10 +52,12 @@ public class MappingUtils {
String internalName = type.getInternalName(); String internalName = type.getInternalName();
String internalNameObf; String internalNameMapped;
try { try {
internalNameObf = mapper.obfuscateClass(internalName); internalNameMapped = reverse
return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameObf, arrayLevel)); ? mapper.deobfuscateClass(internalName)
: mapper.obfuscateClass(internalName);
return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel));
} catch(MappingNotFoundException e) { } catch(MappingNotFoundException e) {
return type; return type;
} }

View file

@ -77,7 +77,7 @@ public class ClassData {
public ClassData generateReverseMappings(IMapper mapper) { public ClassData generateReverseMappings(IMapper mapper) {
ClassData reverse = new ClassData(this.nameMapped, this.name); ClassData reverse = new ClassData(this.nameMapped, this.name);
this.methods.forEach((signature, data) -> reverse.addMethod(nameMapped, signature.name, this.methods.forEach((signature, data) -> reverse.addMethod(nameMapped, signature.name,
MappingUtils.obfuscateMethodDescriptor(signature.descriptor, mapper))); MappingUtils.mapMethodDescriptor(signature.descriptor, mapper, false)));
this.fields.forEach((name, data) -> reverse.addField(data.nameMapped, name)); this.fields.forEach((name, data) -> reverse.addField(data.nameMapped, name));
return reverse; return reverse;
} }