Allow shadowing int/long fields with obfuscated getters
This commit is contained in:
@@ -13,6 +13,7 @@ import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import com.openosrs.injector.rsapi.RSApiClass;
|
||||
import com.openosrs.injector.rsapi.RSApiMethod;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import net.runelite.asm.Annotated;
|
||||
@@ -30,14 +31,18 @@ import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.DLoad;
|
||||
import net.runelite.asm.attributes.code.instructions.FLoad;
|
||||
import net.runelite.asm.attributes.code.instructions.ILoad;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.attributes.code.instructions.LLoad;
|
||||
import net.runelite.asm.attributes.code.instructions.LMul;
|
||||
import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.attributes.code.instructions.VReturn;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import net.runelite.deob.deobfuscators.arithmetic.DMath;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface InjectUtil
|
||||
@@ -208,7 +213,7 @@ public interface InjectUtil
|
||||
field = clazz.findField(name, type);
|
||||
|
||||
if (field != null)
|
||||
return data.toVanilla(field);
|
||||
return field;
|
||||
}
|
||||
|
||||
for (ClassFile clazz : deob)
|
||||
@@ -219,7 +224,7 @@ public interface InjectUtil
|
||||
field = clazz.findField(name, type);
|
||||
|
||||
if (field != null)
|
||||
return data.toVanilla(field);
|
||||
return field;
|
||||
}
|
||||
|
||||
throw new Injexception(String.format("Static field %s doesn't exist", (type != null ? type + " " : "") + name));
|
||||
@@ -450,4 +455,27 @@ public interface InjectUtil
|
||||
String str = ((org.objectweb.asm.Type) v).getInternalName();
|
||||
return data.toVanilla(data.toDeob(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add after the get
|
||||
*/
|
||||
static void injectObfuscatedGetter(Number getter, Instructions instrs, Consumer<Instruction> into)
|
||||
{
|
||||
into.accept(new LDC(instrs, getter));
|
||||
|
||||
if (getter instanceof Integer)
|
||||
into.accept(new IMul(instrs));
|
||||
else if (getter instanceof Long)
|
||||
into.accept(new LMul(instrs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add IN FRONT of the put
|
||||
*
|
||||
* @param getter should be the same value as for the getter (straight from ObfuscatedGetter)
|
||||
*/
|
||||
static void injectObfuscatedSetter(Number getter, Instructions instrs, Consumer<Instruction> into)
|
||||
{
|
||||
injectObfuscatedGetter(DMath.modInverse(getter), instrs, into);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,10 +53,12 @@ import net.runelite.asm.attributes.annotation.ArrayElement;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instruction.types.FieldInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction;
|
||||
import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.ANewArray;
|
||||
import net.runelite.asm.attributes.code.instructions.CheckCast;
|
||||
@@ -68,7 +70,10 @@ import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.Pop;
|
||||
import net.runelite.asm.attributes.code.instructions.PutField;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class MixinInjector extends AbstractInjector
|
||||
{
|
||||
@@ -82,7 +87,7 @@ public class MixinInjector extends AbstractInjector
|
||||
private static final String MIXIN_BASE = "net/runelite/mixins/";
|
||||
|
||||
private final Map<String, Field> injectedFields = new HashMap<>();
|
||||
private final Map<net.runelite.asm.pool.Field, Field> shadowFields = new HashMap<>();
|
||||
private final Map<net.runelite.asm.pool.Field, ShadowField> shadowFields = new HashMap<>();
|
||||
private int copied = 0, replaced = 0, injected = 0;
|
||||
|
||||
public MixinInjector(InjectData inject)
|
||||
@@ -230,11 +235,23 @@ public class MixinInjector extends AbstractInjector
|
||||
String shadowed = shadow.getElement().getString();
|
||||
|
||||
Field targetField = injectedFields.get(shadowed);
|
||||
Number getter = null;
|
||||
|
||||
if (targetField == null)
|
||||
targetField = InjectUtil.findStaticField(inject, shadowed, null, InjectUtil.apiToDeob(inject, field.getType()));
|
||||
{
|
||||
final Field deobTargetField = InjectUtil.findStaticField(inject, shadowed, null, InjectUtil.apiToDeob(inject, field.getType()));
|
||||
targetField = inject.toVanilla(deobTargetField);
|
||||
|
||||
shadowFields.put(field.getPoolField(), targetField);
|
||||
getter = DeobAnnotations.getObfuscatedGetter(deobTargetField);
|
||||
}
|
||||
|
||||
if ((targetField.getAccessFlags() & Opcodes.ACC_PRIVATE) != 0)
|
||||
throw new Injexception("Shadowed fields can't be private");
|
||||
|
||||
shadowFields.put(
|
||||
field.getPoolField(),
|
||||
new ShadowField(targetField, getter)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,9 +586,25 @@ public class MixinInjector extends AbstractInjector
|
||||
{
|
||||
FieldInstruction fi = (FieldInstruction) i;
|
||||
|
||||
Field shadowed = shadowFields.get(fi.getField());
|
||||
if (shadowed != null)
|
||||
ShadowField shadowField = shadowFields.get(fi.getField());
|
||||
|
||||
if (shadowField != null)
|
||||
{
|
||||
Field shadowed = shadowField.targetField;
|
||||
if (shadowField.obfuscatedGetter != null)
|
||||
{
|
||||
if (i instanceof SetFieldInstruction)
|
||||
{
|
||||
iterator.previous();
|
||||
InjectUtil.injectObfuscatedSetter(shadowField.obfuscatedGetter, i.getInstructions(), iterator::add);
|
||||
iterator.next();
|
||||
}
|
||||
else if (i instanceof GetFieldInstruction)
|
||||
{
|
||||
InjectUtil.injectObfuscatedGetter(shadowField.obfuscatedGetter, i.getInstructions(), iterator::add);
|
||||
}
|
||||
}
|
||||
|
||||
fi.setField(shadowed.getPoolField());
|
||||
}
|
||||
else if (fi.getField().getClazz().getName().equals(mixinCf.getName()))
|
||||
@@ -670,4 +703,13 @@ public class MixinInjector extends AbstractInjector
|
||||
private Method obMethod;
|
||||
private boolean hasGarbageValue;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class ShadowField
|
||||
{
|
||||
private Field targetField;
|
||||
|
||||
@Nullable
|
||||
private Number obfuscatedGetter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ import net.runelite.asm.Method;
|
||||
import net.runelite.asm.Type;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import net.runelite.deob.deobfuscators.arithmetic.DMath;
|
||||
|
||||
public class RSApiInjector extends AbstractInjector
|
||||
{
|
||||
@@ -273,7 +272,7 @@ public class RSApiInjector extends AbstractInjector
|
||||
targetClass,
|
||||
apiMethod,
|
||||
targetField,
|
||||
modInverseOrNull(getter)
|
||||
getter
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -289,13 +288,4 @@ public class RSApiInjector extends AbstractInjector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Number modInverseOrNull(Number getter)
|
||||
{
|
||||
if (getter == null)
|
||||
return null;
|
||||
|
||||
// inverse getter to get the setter
|
||||
return DMath.modInverse(getter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,6 @@ import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.GetField;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.attributes.code.instructions.LMul;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class InjectGetter
|
||||
@@ -53,9 +50,7 @@ public class InjectGetter
|
||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter) throws Injexception
|
||||
{
|
||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||
{
|
||||
throw new Injexception("Duplicate getter method " + apiMethod.getMethod().toString());
|
||||
}
|
||||
|
||||
final String name = apiMethod.getName();
|
||||
final Signature sig = apiMethod.getSignature();
|
||||
@@ -79,16 +74,8 @@ public class InjectGetter
|
||||
ins.add(new GetField(instructions, field.getPoolField()));
|
||||
}
|
||||
|
||||
if (getter instanceof Integer)
|
||||
{
|
||||
ins.add(new LDC(instructions, getter));
|
||||
ins.add(new IMul(instructions));
|
||||
}
|
||||
else if (getter instanceof Long)
|
||||
{
|
||||
ins.add(new LDC(instructions, getter));
|
||||
ins.add(new LMul(instructions));
|
||||
}
|
||||
if (getter != null)
|
||||
InjectUtil.injectObfuscatedGetter(getter, instructions, ins::add);
|
||||
|
||||
ins.add(InjectUtil.createReturnForType(instructions, field.getType()));
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.CheckCast;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.attributes.code.instructions.PutField;
|
||||
import net.runelite.asm.attributes.code.instructions.PutStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.VReturn;
|
||||
@@ -52,12 +50,10 @@ import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class InjectSetter
|
||||
{
|
||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number setter) throws Injexception
|
||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter) throws Injexception
|
||||
{
|
||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||
{
|
||||
throw new Injexception("Duplicate setter method " + apiMethod.getMethod().toString());
|
||||
}
|
||||
|
||||
final String name = apiMethod.getName();
|
||||
final Signature sig = apiMethod.getSignature();
|
||||
@@ -73,9 +69,7 @@ public class InjectSetter
|
||||
|
||||
// load this
|
||||
if (!field.isStatic())
|
||||
{
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
}
|
||||
|
||||
// load argument
|
||||
final Type argumentType = sig.getTypeOfArg(0);
|
||||
@@ -90,25 +84,13 @@ public class InjectSetter
|
||||
ins.add(checkCast);
|
||||
}
|
||||
|
||||
if (setter instanceof Integer)
|
||||
{
|
||||
ins.add(new LDC(instructions, setter));
|
||||
ins.add(new IMul(instructions));
|
||||
}
|
||||
else if (setter instanceof Long)
|
||||
{
|
||||
ins.add(new LDC(instructions, setter));
|
||||
ins.add(new IMul(instructions));
|
||||
}
|
||||
if (getter != null)
|
||||
InjectUtil.injectObfuscatedSetter(getter, instructions, ins::add);
|
||||
|
||||
if (field.isStatic())
|
||||
{
|
||||
ins.add(new PutStatic(instructions, field));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new PutField(instructions, field));
|
||||
}
|
||||
|
||||
ins.add(new VReturn(instructions));
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import javax.inject.Provider;
|
||||
import net.runelite.api.mixins.Copy;
|
||||
@@ -42,12 +43,15 @@ import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Method;
|
||||
import static net.runelite.asm.Type.INT;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.asm.visitors.ClassFileVisitor;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import net.runelite.mapping.ObfuscatedGetter;
|
||||
import net.runelite.mapping.ObfuscatedName;
|
||||
import net.runelite.mapping.ObfuscatedSignature;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -61,7 +65,8 @@ import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
class DeobTarget
|
||||
{
|
||||
@ObfuscatedName("ob_foo4")
|
||||
private static int foo4;
|
||||
@ObfuscatedGetter(intValue = 1157381415)
|
||||
static int foo4;
|
||||
|
||||
@ObfuscatedName("ob_foo3")
|
||||
@ObfuscatedSignature(
|
||||
@@ -77,7 +82,7 @@ class DeobTarget
|
||||
|
||||
class VanillaTarget
|
||||
{
|
||||
private static int ob_foo4;
|
||||
static int ob_foo4;
|
||||
|
||||
private void ob_foo3(int garbageValue)
|
||||
{
|
||||
@@ -208,6 +213,8 @@ public class MixinInjectorTest
|
||||
return true;
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
assert getStaticHasGetter(ob_foo3, "ob_foo4");
|
||||
// Check that the "foo3()" call in the new code body was mapped to the copy
|
||||
assertEquals(ob_foo3
|
||||
.getCode()
|
||||
@@ -272,6 +279,20 @@ public class MixinInjectorTest
|
||||
.count(), 1);
|
||||
}
|
||||
|
||||
private boolean getStaticHasGetter(Method ob_foo3, String gottenField)
|
||||
{
|
||||
ListIterator<Instruction> it = ob_foo3.getCode().getInstructions().listIterator();
|
||||
Instruction i;
|
||||
while (it.hasNext() &&
|
||||
!((i = it.next()) instanceof GetStatic &&
|
||||
((GetStatic) i).getField().getName().equals(gottenField)));
|
||||
|
||||
return
|
||||
(i = it.next()) instanceof LDC &&
|
||||
((LDC) i).getConstantAsInt() == 1157381415 &&
|
||||
it.next() instanceof IMul;
|
||||
}
|
||||
|
||||
private static ClassFile loadClass(Class<?> clazz)
|
||||
{
|
||||
try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".class"))
|
||||
|
||||
Reference in New Issue
Block a user