use of net.runelite.asm.Method in project runelite by runelite.
the class InjectConstruct method injectConstruct.
public void injectConstruct(ClassFile targetClass, java.lang.reflect.Method apiMethod) throws InjectionException {
logger.info("Injecting construct for {}", apiMethod);
assert targetClass.findMethod(apiMethod.getName()) == null;
Class<?> typeToConstruct = apiMethod.getReturnType();
ClassFile vanillaClass = inject.findVanillaForInterface(typeToConstruct);
if (vanillaClass == null) {
throw new InjectionException("Unable to find vanilla class which implements interface " + typeToConstruct);
}
Signature sig = inject.javaMethodToSignature(apiMethod);
Signature constructorSig = new Signature.Builder().addArguments(Stream.of(apiMethod.getParameterTypes()).map(arg -> {
ClassFile vanilla = inject.findVanillaForInterface(arg);
if (vanilla != null) {
return new Type("L" + vanilla.getName() + ";");
}
return Inject.classToType(arg);
}).collect(Collectors.toList())).setReturnType(Type.VOID).build();
Method vanillaConstructor = vanillaClass.findMethod("<init>", constructorSig);
if (vanillaConstructor == null) {
throw new InjectionException("Unable to find constructor for " + vanillaClass.getName() + ".<init>" + constructorSig);
}
Method setterMethod = new Method(targetClass, apiMethod.getName(), sig);
setterMethod.setAccessFlags(ACC_PUBLIC);
targetClass.addMethod(setterMethod);
Code code = new Code(setterMethod);
setterMethod.setCode(code);
Instructions instructions = code.getInstructions();
List<Instruction> ins = instructions.getInstructions();
ins.add(new New(instructions, vanillaClass.getPoolClass()));
ins.add(new Dup(instructions));
int idx = 1;
int parameter = 0;
for (Type type : vanillaConstructor.getDescriptor().getArguments()) {
Instruction load = inject.createLoadForTypeIndex(instructions, type, idx);
idx += type.getSize();
ins.add(load);
Type paramType = sig.getTypeOfArg(parameter);
if (!type.equals(paramType)) {
CheckCast checkCast = new CheckCast(instructions);
checkCast.setType(type);
ins.add(checkCast);
}
++parameter;
}
ins.add(new InvokeSpecial(instructions, vanillaConstructor.getPoolMethod()));
ins.add(new Return(instructions));
}
use of net.runelite.asm.Method in project runelite by runelite.
the class InjectHook method run.
public void run() {
Execution e = new Execution(inject.getVanilla());
e.populateInitialMethods();
Set<Instruction> done = new HashSet<>();
Set<Instruction> doneIh = new HashSet<>();
e.addExecutionVisitor((InstructionContext ic) -> {
Instruction i = ic.getInstruction();
Instructions ins = i.getInstructions();
Code code = ins.getCode();
Method method = code.getMethod();
if (method.getName().equals(CLINIT)) {
return;
}
if (!(i instanceof SetFieldInstruction)) {
return;
}
if (!done.add(i)) {
return;
}
SetFieldInstruction sfi = (SetFieldInstruction) i;
Field fieldBeingSet = sfi.getMyField();
if (fieldBeingSet == null) {
return;
}
HookInfo hookInfo = hooked.get(fieldBeingSet);
if (hookInfo == null) {
return;
}
String hookName = hookInfo.fieldName;
assert hookName != null;
logger.trace("Found injection location for hook {} at instruction {}", hookName, sfi);
++injectedHooks;
Instruction objectInstruction = new AConstNull(ins);
StackContext objectStackContext = null;
if (sfi instanceof PutField) {
// Object being set on
StackContext objectStack = ic.getPops().get(1);
objectStackContext = objectStack;
}
int idx = ins.getInstructions().indexOf(sfi);
assert idx != -1;
try {
// idx + 1 to insert after the set
injectCallback(ins, idx + 1, hookInfo, null, objectStackContext);
} catch (InjectionException ex) {
throw new RuntimeException(ex);
}
});
// these look like:
// getfield
// iload_0
// iconst_0
// iastore
e.addExecutionVisitor((InstructionContext ic) -> {
Instruction i = ic.getInstruction();
Instructions ins = i.getInstructions();
Code code = ins.getCode();
Method method = code.getMethod();
if (method.getName().equals(CLINIT)) {
return;
}
if (!(i instanceof ArrayStore)) {
return;
}
if (!doneIh.add(i)) {
return;
}
ArrayStore as = (ArrayStore) i;
Field fieldBeingSet = as.getMyField(ic);
if (fieldBeingSet == null) {
return;
}
HookInfo hookInfo = hooked.get(fieldBeingSet);
if (hookInfo == null) {
return;
}
String hookName = hookInfo.fieldName;
// assume this is always at index 1
StackContext index = ic.getPops().get(1);
StackContext arrayReference = ic.getPops().get(2);
InstructionContext arrayReferencePushed = arrayReference.getPushed();
StackContext objectStackContext = null;
if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD) {
StackContext objectReference = arrayReferencePushed.getPops().get(0);
objectStackContext = objectReference;
}
// inject hook after 'i'
logger.info("Found array injection location for hook {} at instruction {}", hookName, i);
++injectedHooks;
int idx = ins.getInstructions().indexOf(i);
assert idx != -1;
try {
injectCallback(ins, idx + 1, hookInfo, index, objectStackContext);
} catch (InjectionException ex) {
throw new RuntimeException(ex);
}
});
e.run();
}
use of net.runelite.asm.Method in project runelite by runelite.
the class InjectInvoker method injectInvoker.
private void injectInvoker(ClassFile clazz, java.lang.reflect.Method method, Method deobfuscatedMethod, Method invokeMethod, String garbage) {
if (clazz.findMethod(method.getName(), deobfuscatedMethod.getDescriptor()) != null) {
logger.warn("Not injecting method {} because it already exists!", method);
// this can happen from exporting a field and method with the same name
return;
}
assert invokeMethod.isStatic() == deobfuscatedMethod.isStatic();
assert invokeMethod.isStatic() || invokeMethod.getClassFile() == clazz;
Type lastGarbageArgumentType = null;
if (deobfuscatedMethod.getDescriptor().getArguments().size() != invokeMethod.getDescriptor().getArguments().size()) {
// allow for obfuscated method to have a single bogus signature at the end
assert deobfuscatedMethod.getDescriptor().size() + 1 == invokeMethod.getDescriptor().size();
List<Type> arguments = invokeMethod.getDescriptor().getArguments();
lastGarbageArgumentType = arguments.get(arguments.size() - 1);
}
// Injected method signature is always the same as the API
Signature apiSignature = inject.javaMethodToSignature(method);
Method invokerMethodSignature = new Method(clazz, method.getName(), apiSignature);
invokerMethodSignature.setAccessFlags(ACC_PUBLIC);
// create code attribute
Code code = new Code(invokerMethodSignature);
invokerMethodSignature.setCode(code);
Instructions instructions = code.getInstructions();
List<Instruction> ins = instructions.getInstructions();
// this + arguments
code.setMaxStack(1 + invokeMethod.getDescriptor().size());
// load function arguments onto the stack.
int index = 0;
if (!invokeMethod.isStatic()) {
// this
ins.add(new ALoad(instructions, index++));
} else {
// this method is always non static
++index;
}
for (int i = 0; i < deobfuscatedMethod.getDescriptor().size(); ++i) {
Type type = deobfuscatedMethod.getDescriptor().getTypeOfArg(i);
Instruction loadInstruction = inject.createLoadForTypeIndex(instructions, type, index);
ins.add(loadInstruction);
Signature invokeDesc = invokeMethod.getDescriptor();
Type obType = invokeDesc.getTypeOfArg(i);
if (!type.equals(obType)) {
CheckCast checkCast = new CheckCast(instructions);
checkCast.setType(obType);
ins.add(checkCast);
}
if (loadInstruction instanceof DLoad || loadInstruction instanceof LLoad) {
index += 2;
} else {
index += 1;
}
}
if (lastGarbageArgumentType != null) {
// if garbage is null here it might just be an unused parameter, not part of the obfuscation
if (garbage == null) {
garbage = "0";
}
switch(lastGarbageArgumentType.toString()) {
case "Z":
case "B":
case "C":
ins.add(new BiPush(instructions, Byte.parseByte(garbage)));
break;
case "S":
ins.add(new SiPush(instructions, Short.parseShort(garbage)));
break;
case "I":
ins.add(new LDC(instructions, Integer.parseInt(garbage)));
break;
case "D":
ins.add(new LDC(instructions, Double.parseDouble(garbage)));
break;
case "F":
ins.add(new LDC(instructions, Float.parseFloat(garbage)));
break;
case "J":
ins.add(new LDC(instructions, Long.parseLong(garbage)));
break;
default:
throw new RuntimeException("Unknown type");
}
}
if (invokeMethod.isStatic()) {
ins.add(new InvokeStatic(instructions, invokeMethod.getPoolMethod()));
} else {
ins.add(new InvokeVirtual(instructions, invokeMethod.getPoolMethod()));
}
Type returnValue = invokeMethod.getDescriptor().getReturnValue();
InstructionType returnType;
if (returnValue.isPrimitive() && returnValue.getDimensions() == 0) {
switch(returnValue.toString()) {
case "Z":
case "I":
returnType = InstructionType.IRETURN;
break;
case "J":
returnType = InstructionType.LRETURN;
break;
case "F":
returnType = InstructionType.FRETURN;
break;
case "D":
returnType = InstructionType.DRETURN;
break;
case "V":
returnType = InstructionType.RETURN;
break;
default:
assert false;
return;
}
} else {
returnType = InstructionType.ARETURN;
}
ins.add(new Return(instructions, returnType));
clazz.addMethod(invokerMethodSignature);
}
use of net.runelite.asm.Method in project runelite by runelite.
the class FieldInliner method makeConstantValues.
private void makeConstantValues() {
for (ClassFile cf : group.getClasses()) {
for (Field f : cf.getFields()) {
if (!f.isStatic() || !f.getType().equals(Type.STRING))
continue;
Object constantValue = f.getValue();
if (constantValue != null)
continue;
List<FieldInstruction> sfis = fieldInstructions.get(f).stream().filter(f2 -> f2 instanceof SetFieldInstruction).collect(Collectors.toList());
if (sfis.size() != 1)
continue;
SetFieldInstruction sfi = (SetFieldInstruction) sfis.get(0);
Instruction ins = (Instruction) sfi;
Method mOfSet = ins.getInstructions().getCode().getMethod();
if (!mOfSet.getName().equals("<clinit>"))
continue;
// get prev instruction and change to a constant value
Instructions instructions = mOfSet.getCode().getInstructions();
int idx = instructions.getInstructions().indexOf(ins);
assert idx != -1;
Instruction prev = instructions.getInstructions().get(idx - 1);
if (!(prev instanceof PushConstantInstruction))
continue;
PushConstantInstruction pci = (PushConstantInstruction) prev;
constantValue = pci.getConstant();
f.setValue(constantValue);
fields.add(f);
boolean b = instructions.getInstructions().remove(prev);
assert b;
b = instructions.getInstructions().remove(ins);
assert b;
}
}
}
use of net.runelite.asm.Method in project runelite by runelite.
the class Order method run.
@Override
public void run(ClassGroup group) {
execution = new Execution(group);
execution.staticStep = true;
execution.populateInitialMethods();
execution.run();
for (int i = 0; i < group.getClasses().size(); i++) {
ClassFile cf = group.getClasses().get(i);
String className = DeobAnnotations.getObfuscatedName(cf.getAnnotations());
nameIndices.put(className, i);
}
int sortedMethods = 0, sortedFields = 0;
for (ClassFile cf : group.getClasses()) {
List<Method> m = cf.getMethods();
Collections.sort(m, this::compareMethod);
sortedMethods += m.size();
// field order of enums is mostly handled in EnumDeobfuscator
if (!cf.isEnum()) {
List<Field> f = cf.getFields();
Collections.sort(f, this::compareFields);
sortedFields += f.size();
}
}
logger.info("Sorted {} methods and {} fields", sortedMethods, sortedFields);
}
Aggregations