Begin inject
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/target/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
/nbproject/
|
||||
23
.project
23
.project
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>deob</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,12 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
@@ -1,4 +0,0 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
2
pom.xml
2
pom.xml
@@ -51,8 +51,6 @@
|
||||
<groupId>net.runelite.rs</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -185,6 +185,11 @@ public class ClassFile
|
||||
return fields.findField(name);
|
||||
}
|
||||
|
||||
public Field findField(NameAndType nat)
|
||||
{
|
||||
return fields.findField(nat);
|
||||
}
|
||||
|
||||
public Class getPoolClass()
|
||||
{
|
||||
return name;
|
||||
|
||||
@@ -30,6 +30,12 @@ public class Interfaces
|
||||
classFile = c;
|
||||
}
|
||||
|
||||
public void addInterface(Class clazz)
|
||||
{
|
||||
if (!interfaces.contains(clazz))
|
||||
interfaces.add(clazz);
|
||||
}
|
||||
|
||||
public List<Class> getInterfaces()
|
||||
{
|
||||
return interfaces;
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.runelite.deob.attributes.annotation.Annotation;
|
||||
import net.runelite.deob.signature.Type;
|
||||
|
||||
public class Annotations extends Attribute
|
||||
{
|
||||
@@ -26,6 +27,14 @@ public class Annotations extends Attribute
|
||||
annotations.add(annotation);
|
||||
}
|
||||
|
||||
public Annotation find(Type type)
|
||||
{
|
||||
for (Annotation a : annotations)
|
||||
if (a.getType().equals(type))
|
||||
return a;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAttribute(DataInputStream is) throws IOException
|
||||
{
|
||||
|
||||
@@ -40,6 +40,11 @@ public class Annotation
|
||||
return elements;
|
||||
}
|
||||
|
||||
public Element getElement()
|
||||
{
|
||||
return elements.get(0);
|
||||
}
|
||||
|
||||
public void addElement(Element element)
|
||||
{
|
||||
elements.add(element);
|
||||
|
||||
@@ -43,6 +43,11 @@ public class Element
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getString()
|
||||
{
|
||||
return (String) value.getObject();
|
||||
}
|
||||
|
||||
public void load(DataInputStream is) throws IOException
|
||||
{
|
||||
ConstantPool pool = annotation.getAnnotations().getAttributes().getClassFile().getPool();
|
||||
|
||||
@@ -30,6 +30,13 @@ public class GetField extends Instruction implements GetFieldInstruction
|
||||
super(instructions, type, pc);
|
||||
}
|
||||
|
||||
public GetField(Instructions instructions, Field field)
|
||||
{
|
||||
super(instructions, InstructionType.GETFIELD, -1);
|
||||
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
||||
@@ -9,14 +9,18 @@ import net.runelite.deob.execution.InstructionContext;
|
||||
import net.runelite.deob.execution.Stack;
|
||||
import net.runelite.deob.execution.StackContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Return extends Instruction implements ReturnInstruction
|
||||
{
|
||||
public Return(Instructions instructions, InstructionType type, int pc) throws IOException
|
||||
public Return(Instructions instructions, InstructionType type, int pc)
|
||||
{
|
||||
super(instructions, type, pc);
|
||||
}
|
||||
|
||||
public Return(Instructions instructions)
|
||||
{
|
||||
super(instructions, InstructionType.RETURN, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Frame frame)
|
||||
|
||||
240
src/main/java/net/runelite/deob/injection/Inject.java
Normal file
240
src/main/java/net/runelite/deob/injection/Inject.java
Normal file
@@ -0,0 +1,240 @@
|
||||
package net.runelite.deob.injection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import net.runelite.deob.ClassFile;
|
||||
import net.runelite.deob.ClassGroup;
|
||||
import net.runelite.deob.Field;
|
||||
import net.runelite.deob.Interfaces;
|
||||
import net.runelite.deob.Method;
|
||||
import net.runelite.deob.attributes.Annotations;
|
||||
import net.runelite.deob.attributes.Attributes;
|
||||
import net.runelite.deob.attributes.Code;
|
||||
import net.runelite.deob.attributes.annotation.Annotation;
|
||||
import net.runelite.deob.attributes.code.Instruction;
|
||||
import net.runelite.deob.attributes.code.Instructions;
|
||||
import net.runelite.deob.attributes.code.instructions.ALoad;
|
||||
import net.runelite.deob.attributes.code.instructions.GetField;
|
||||
import net.runelite.deob.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.deob.attributes.code.instructions.IMul;
|
||||
import net.runelite.deob.attributes.code.instructions.LDC2_W;
|
||||
import net.runelite.deob.attributes.code.instructions.LDC_W;
|
||||
import net.runelite.deob.attributes.code.instructions.LMul;
|
||||
import net.runelite.deob.attributes.code.instructions.Return;
|
||||
import net.runelite.deob.signature.Type;
|
||||
import net.runelite.deob.pool.Class;
|
||||
import net.runelite.deob.pool.NameAndType;
|
||||
import net.runelite.deob.signature.Signature;
|
||||
import net.runelite.mapping.Import;
|
||||
|
||||
public class Inject
|
||||
{
|
||||
private static final Type OBFUSCATED_NAME = new Type("Lnet/runelite/mapping/ObfuscatedName;");
|
||||
private static final Type EXPORT = new Type("Lnet/runelite/mapping/Export;");
|
||||
private static final Type IMPLEMENTS = new Type("Lnet/runelite/mapping/Implements;");
|
||||
private static final Type OBFUSCATED_GETTER = new Type("Lnet/runelite/mapping/ObfuscatedGetter;");
|
||||
|
||||
private static java.lang.Class<?> clientClass;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
clientClass = java.lang.Class.forName("net.runelite.rs.api.Client");
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// deobfuscated contains exports etc to apply to vanilla
|
||||
private final ClassGroup deobfuscated, vanilla;
|
||||
|
||||
public Inject(ClassGroup deobfuscated, ClassGroup vanilla)
|
||||
{
|
||||
this.deobfuscated = deobfuscated;
|
||||
this.vanilla = vanilla;
|
||||
}
|
||||
|
||||
private Type toObType(Type t)
|
||||
{
|
||||
String className = t.getType();
|
||||
ClassFile cf = deobfuscated.findClass(className);
|
||||
|
||||
Annotations an = cf.getAttributes().getAnnotations();
|
||||
String obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
|
||||
return new Type(obfuscatedName, t.getArrayDims());
|
||||
}
|
||||
|
||||
private Signature toObSignature(Signature s)
|
||||
{
|
||||
Signature sig = new Signature();
|
||||
sig.setTypeOfReturnValue(toObType(s.getReturnValue()));
|
||||
for (Type t : s.getArguments())
|
||||
sig.addArg(toObType(t));
|
||||
return sig;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
for (ClassFile cf : deobfuscated.getClasses())
|
||||
{
|
||||
Annotations an = cf.getAttributes().getAnnotations();
|
||||
String obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
|
||||
|
||||
ClassFile other = vanilla.findClass(obfuscatedName);
|
||||
assert other != null;
|
||||
|
||||
java.lang.Class implementingClass = injectInterface(cf, other);
|
||||
if (implementingClass == null)
|
||||
continue;
|
||||
|
||||
for (Field f : cf.getFields().getFields())
|
||||
{
|
||||
an = f.getAttributes().getAnnotations();
|
||||
|
||||
if (an.find(EXPORT) == null)
|
||||
continue; // not an exported field
|
||||
|
||||
String exportedName = an.find(EXPORT).getElement().toString();
|
||||
obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
|
||||
|
||||
Annotation getterAnnotation = an.find(OBFUSCATED_GETTER);
|
||||
Number getter = null;
|
||||
if (getterAnnotation != null)
|
||||
getter = (Number) getterAnnotation.getElement().getValue().getObject();
|
||||
|
||||
// the ob jar is the same as the vanilla so this field must exist in this class.
|
||||
|
||||
Field otherf = other.findField(new NameAndType(obfuscatedName, toObType(f.getType())));
|
||||
assert otherf != null;
|
||||
|
||||
assert f.isStatic() == otherf.isStatic();
|
||||
|
||||
//
|
||||
|
||||
ClassFile targetClass = f.isStatic() ? vanilla.findClass("client") : other; // target class for getter
|
||||
java.lang.Class targetApiClass = f.isStatic() ? clientClass : implementingClass; // target api class for getter
|
||||
|
||||
java.lang.reflect.Method apiMethod = findImportMethodOnApi(targetApiClass, exportedName);
|
||||
|
||||
injectGetter(targetClass, apiMethod, otherf, getter);
|
||||
}
|
||||
|
||||
for (Method m : cf.getMethods().getMethods())
|
||||
{
|
||||
an = m.getAttributes().getAnnotations();
|
||||
|
||||
if (an.find(EXPORT) == null)
|
||||
continue; // not an exported method
|
||||
|
||||
String exportedName = an.find(EXPORT).getElement().toString();
|
||||
obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
|
||||
|
||||
// XXX static methods don't have to be in the same class, so we should have @ObfuscatedClass or something
|
||||
|
||||
Method otherm = other.findMethod(new NameAndType(obfuscatedName, toObSignature(m.getDescriptor())));
|
||||
assert otherm != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private java.lang.Class injectInterface(ClassFile cf, ClassFile other)
|
||||
{
|
||||
Annotations an = cf.getAttributes().getAnnotations();
|
||||
if (an == null)
|
||||
return null;
|
||||
|
||||
Annotation a = an.find(IMPLEMENTS);
|
||||
if (a == null)
|
||||
return null;
|
||||
|
||||
String ifaceName = a.getElement().toString();
|
||||
Class clazz = new Class(ifaceName);
|
||||
|
||||
Interfaces interfaces = other.getInterfaces();
|
||||
interfaces.addInterface(clazz);
|
||||
|
||||
try
|
||||
{
|
||||
return java.lang.Class.forName(ifaceName);
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
ex.addSuppressed(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private java.lang.reflect.Method findImportMethodOnApi(java.lang.Class<?> clazz, String name)
|
||||
{
|
||||
for (java.lang.reflect.Method method : clazz.getMethods())
|
||||
{
|
||||
Import i = method.getAnnotation(Import.class);
|
||||
|
||||
if (i == null || !name.equals(i.value()))
|
||||
continue;
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void injectGetter(ClassFile clazz, java.lang.reflect.Method method, Field field, Number getter)
|
||||
{
|
||||
// clazz = class file we're injecting the method into.
|
||||
// method = api method (java reflect) that we're overriding
|
||||
// field = field we're getting. might not be in this class if static.
|
||||
// getter = encryption getter
|
||||
|
||||
assert clazz.findMethod(method.getName()) == null;
|
||||
assert field.isStatic() || field.getFields().getClassFile() == clazz;
|
||||
|
||||
Signature sig = new Signature();
|
||||
sig.setTypeOfReturnValue(field.getType());
|
||||
Method getterMethod = new Method(clazz.getMethods(), method.getName(), sig);
|
||||
|
||||
Attributes methodAttributes = getterMethod.getAttributes();
|
||||
|
||||
// create code attribute
|
||||
Code code = new Code(methodAttributes);
|
||||
methodAttributes.addAttribute(code);
|
||||
|
||||
Instructions instructions = code.getInstructions();
|
||||
List<Instruction> ins = new ArrayList<>();
|
||||
|
||||
if (field.isStatic())
|
||||
{
|
||||
ins.add(new GetStatic(instructions, field.getPoolField()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
ins.add(new GetField(instructions, field.getPoolField()));
|
||||
}
|
||||
|
||||
if (getter != null)
|
||||
{
|
||||
assert getter instanceof Integer || getter instanceof Long;
|
||||
|
||||
if (getter instanceof Integer)
|
||||
{
|
||||
ins.add(new LDC_W(instructions, (int) getter));
|
||||
ins.add(new IMul(instructions));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new LDC2_W(instructions, (long) getter));
|
||||
ins.add(new LMul(instructions));
|
||||
}
|
||||
}
|
||||
|
||||
ins.add(new Return(instructions));
|
||||
|
||||
clazz.getMethods().addMethod(getterMethod);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,10 @@ public class Signature
|
||||
private List<Type> arguments = new ArrayList<>();
|
||||
private Type rv;
|
||||
|
||||
public Signature()
|
||||
{
|
||||
}
|
||||
|
||||
public Signature(String str)
|
||||
{
|
||||
Matcher m = paramRetPattern.matcher(str);
|
||||
@@ -90,6 +94,11 @@ public class Signature
|
||||
arguments.set(i, type);
|
||||
}
|
||||
|
||||
public void addArg(Type type)
|
||||
{
|
||||
arguments.add(type);
|
||||
}
|
||||
|
||||
public Type getReturnValue()
|
||||
{
|
||||
return rv;
|
||||
@@ -99,4 +108,9 @@ public class Signature
|
||||
{
|
||||
rv = type;
|
||||
}
|
||||
|
||||
public List<Type> getArguments()
|
||||
{
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user