Allow shadowing int/long fields with obfuscated getters

This commit is contained in:
Lucwousin
2019-11-07 02:16:07 +01:00
parent 4f2c72fb75
commit 28dad8a65c
7 changed files with 107 additions and 57 deletions

View File

@@ -14,7 +14,7 @@ plugins {
}
group = "com.openosrs"
version = "1.0.2"
version = "1.0.2.1"
repositories {
mavenCentral()

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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()));

View File

@@ -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));

View File

@@ -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"))