use of net.runelite.asm.attributes.code.Instructions 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.attributes.code.Instructions 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.attributes.code.Instructions in project runelite by runelite.
the class IllegalStateExceptions method processOne.
private void processOne(InstructionContext ic) {
Instruction ins = ic.getInstruction();
Instructions instructions = ins.getInstructions();
if (instructions == null)
return;
List<Instruction> ilist = instructions.getInstructions();
JumpingInstruction jumpIns = (JumpingInstruction) ins;
assert jumpIns.getJumps().size() == 1;
Instruction to = jumpIns.getJumps().get(0);
// remove stack of if.
if (ins instanceof If) {
ic.removeStack(1);
}
ic.removeStack(0);
int i = ilist.indexOf(ins);
assert i != -1;
// remove up to athrow
while (!(ins instanceof AThrow)) {
instructions.remove(ins);
// don't need to ++i because
ins = ilist.get(i);
}
// remove athrow
instructions.remove(ins);
// insert goto
assert ilist.contains(to);
Goto g = new Goto(instructions, instructions.createLabelFor(to));
ilist.add(i, g);
++count;
}
use of net.runelite.asm.attributes.code.Instructions in project runelite by runelite.
the class PacketHandlerOrder method run.
@Override
public void run(ClassGroup group) {
// This is run on the deobfuscated jar, so there are no symbols yet...
// Find packetType and buffer classes
PacketTypeFinder ptf = new PacketTypeFinder(group);
ptf.find();
BufferFinder bf = new BufferFinder(group);
bf.find();
HandlerFinder hf = new HandlerFinder(group, ptf.getPacketType());
PacketHandlers handlers = hf.findHandlers();
logger.info("Found {} packet handlers", handlers.getHandlers().size());
for (PacketHandler handler : handlers.getHandlers()) {
Execution e = hf.getExecution();
e.reset();
e.staticStep = true;
e.step = false;
e.noInvoke = true;
// exception processing won't do non-local jumps, so
// depending on whether methods are inlined or not
// it may jump completely out of the handler into the
// catch all for all packet handling
// just disable exception execution
e.noExceptions = true;
assert e.frames.isEmpty();
Frame f = handler.jumpFrame.dup();
assert f.isExecuting();
f.getMethodCtx().reset();
e.clearExecutionVisitor();
e.addExecutionVisitor(ictx -> {
if (ictx.getInstruction() instanceof MappableInstruction) {
if (ictx.getInstruction().getType() != InstructionType.INVOKESTATIC) {
if (!handler.mappable.contains(ictx.getInstruction())) {
handler.mappable.add(ictx.getInstruction());
}
}
}
if (ictx.getInstruction().getType() == InstructionType.INVOKEVIRTUAL) {
InvokeInstruction ii = (InvokeInstruction) ictx.getInstruction();
// check if the invoke is on buffer/packetbuffer classes
boolean matches = ii.getMethods().stream().filter(m -> m.getDescriptor().size() == 0).map(method -> method.getClassFile()).anyMatch(cf -> cf == bf.getBuffer() || cf == bf.getPacketBuffer());
if (matches) {
Method method = ii.getMethods().get(0);
Signature signature = method.getDescriptor();
Type returnValue = signature.getReturnValue();
// buffer reference
assert ictx.getPops().size() == 1;
InstructionContext bufferCtx = ictx.getPops().get(0).getPushed();
if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) {
// sometimes buffer is passed to a function and then invoked.
return;
}
PacketRead packetRead = new PacketRead(returnValue, bufferCtx.getInstruction(), ictx);
if (!handler.reads.contains(packetRead)) {
handler.reads.add(packetRead);
}
}
}
if (ictx.getInstruction().getType() == InstructionType.INVOKEVIRTUAL || ictx.getInstruction().getType() == InstructionType.INVOKESPECIAL || ictx.getInstruction().getType() == InstructionType.INVOKEINTERFACE) {
InvokeInstruction ii = (InvokeInstruction) ictx.getInstruction();
// read methods are scrambled so cant count them
if (!handler.hasPacketRead(ictx.getInstruction())) {
handler.methodInvokes.addAll(ii.getMethods());
}
}
if (ictx.getInstruction() instanceof SetFieldInstruction) {
SetFieldInstruction sfi = (SetFieldInstruction) ictx.getInstruction();
Field field = sfi.getMyField();
if (field != null) {
handler.fieldWrite.add(field);
}
}
if (ictx.getInstruction() instanceof GetFieldInstruction) {
GetFieldInstruction gfi = (GetFieldInstruction) ictx.getInstruction();
Field field = gfi.getMyField();
if (field != null) {
handler.fieldRead.add(field);
}
}
if (ictx.getInstruction() instanceof LVTInstruction) {
LVTInstruction lvt = (LVTInstruction) ictx.getInstruction();
if (!lvt.store()) {
// get lvt access order
Frame frame = ictx.getFrame();
int order = frame.getNextOrder();
if (!handler.lvtOrder.containsKey(lvt.getVariableIndex())) {
handler.lvtOrder.put(lvt.getVariableIndex(), order);
}
}
}
if (ictx.getInstruction() instanceof PushConstantInstruction) {
PushConstantInstruction pci = (PushConstantInstruction) ictx.getInstruction();
handler.constants.add(pci.getConstant());
}
});
logger.debug("Beginning execution of opcode {}", handler.getOpcode());
e.run();
logger.info("Executed opcode {}: {} mappable instructions", handler.getOpcode(), handler.mappable.size());
handler.findReorderableReads();
}
List<PacketHandler> unsortedHandlers = new ArrayList<>(handlers.getHandlers());
List<PacketHandler> sortedHandlers = new ArrayList<>(handlers.getHandlers()).stream().sorted((PacketHandler p1, PacketHandler p2) -> {
int c = compareReads(p1.reads, p2.reads);
if (c != 0) {
return c;
}
if (p1.methodInvokes.size() != p2.methodInvokes.size()) {
return Integer.compare(p1.methodInvokes.size(), p2.methodInvokes.size());
}
if (p1.fieldRead.size() != p2.fieldRead.size()) {
return Integer.compare(p1.fieldRead.size(), p2.fieldRead.size());
}
if (p1.fieldWrite.size() != p2.fieldWrite.size()) {
return Integer.compare(p1.fieldWrite.size(), p2.fieldWrite.size());
}
int i = Integer.compare(p1.mappable.size(), p2.mappable.size());
if (i != 0) {
return i;
}
int s1 = hashConstants(p1.constants), s2 = hashConstants(p2.constants);
if (s1 != s2) {
return Integer.compare(s1, s2);
}
logger.warn("Unable to differentiate {} from {}", p1, p2);
return 0;
}).map(s -> s.clone()).collect(Collectors.toList());
assert sortedHandlers.size() == handlers.getHandlers().size();
for (PacketHandler handler : sortedHandlers) {
handler.sortedReads = new ArrayList<>(handler.reads);
Collections.sort(handler.sortedReads, (PacketRead p1, PacketRead p2) -> {
LVTInstruction l1 = (LVTInstruction) p1.getStore();
LVTInstruction l2 = (LVTInstruction) p2.getStore();
if (l1 == null && l2 == null) {
return 0;
}
if (l1 == null) {
return 1;
}
if (l2 == null) {
return -1;
}
if (l1.getVariableIndex() == l2.getVariableIndex()) {
return 0;
}
Integer i1 = handler.lvtOrder.get(l1.getVariableIndex());
Integer i2 = handler.lvtOrder.get(l2.getVariableIndex());
assert i1 != null;
assert i2 != null;
int i = Integer.compare(i1, i2);
if (i == 0) {
logger.warn("Cannot differentiate {} from {}", p1, p2);
}
return i;
});
Collections.reverse(handler.sortedReads);
}
ClassFile runeliteOpcodes = group.findClass(RUNELITE_OPCODES);
assert runeliteOpcodes != null : "Opcodes class must exist";
for (PacketHandler handler : sortedHandlers) {
logger.info("Handler {} mappable {} reads {} invokes {} freads {} fwrites {}", handler.getOpcode(), handler.mappable.size(), handler.reads.size(), handler.methodInvokes.size(), handler.fieldRead.size(), handler.fieldWrite.size());
final String fieldName = "PACKET_SERVER_" + handler.getOpcode();
// Add opcode fields
if (runeliteOpcodes.findField(fieldName) == null) {
Field opField = new Field(runeliteOpcodes, fieldName, Type.INT);
// ACC_FINAL causes javac to inline the fields, which prevents
// the mapper from doing field mapping
opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC);
// setting a non-final static field value
// doesn't work with fernflower
opField.setValue(handler.getOpcode());
runeliteOpcodes.addField(opField);
// add initialization
Method clinit = runeliteOpcodes.findMethod("<clinit>");
assert clinit != null;
Instructions instructions = clinit.getCode().getInstructions();
instructions.addInstruction(0, new LDC(instructions, handler.getOpcode()));
instructions.addInstruction(1, new PutStatic(instructions, opField));
}
}
// Find unique methods
List<Method> methods = unsortedHandlers.stream().map(ph -> ph.getMethod()).distinct().collect(Collectors.toList());
for (Method m : methods) {
List<PacketHandler> unsortedMethodHandlers = unsortedHandlers.stream().filter(ph -> ph.getMethod() == m).collect(Collectors.toList());
List<PacketHandler> sortedMethodHandlers = sortedHandlers.stream().filter(ph -> ph.getMethod() == m).collect(Collectors.toList());
assert unsortedMethodHandlers.size() == sortedMethodHandlers.size();
for (int i = 0; i < sortedMethodHandlers.size(); ++i) {
PacketHandler unsorted = unsortedMethodHandlers.get(i);
PacketHandler sortedh = sortedMethodHandlers.get(i);
// Set opcode/jump from sorted -> unsorted
If jump = (If) unsorted.getJump();
PushConstantInstruction pci = (PushConstantInstruction) unsorted.getPush();
assert unsorted.getOpcode() == ((Number) pci.getConstant()).intValue();
Instructions instructions = unsorted.getMethod().getCode().getInstructions();
final String fieldName = "PACKET_SERVER_" + sortedh.getOpcode();
net.runelite.asm.pool.Field field = new net.runelite.asm.pool.Field(new net.runelite.asm.pool.Class(RUNELITE_OPCODES), fieldName, Type.INT);
instructions.replace(unsorted.getPush(), new GetStatic(instructions, field));
assert jump.getType() == InstructionType.IF_ICMPEQ || jump.getType() == InstructionType.IF_ICMPNE;
Label startLabel = instructions.createLabelFor(sortedh.getStart());
if (jump.getType() == InstructionType.IF_ICMPEQ) {
instructions.replace(jump, new IfICmpEq(instructions, startLabel));
} else if (jump.getType() == InstructionType.IF_ICMPNE) {
// insert a jump after to go to sortedh start
int idx = instructions.getInstructions().indexOf(jump);
assert idx != -1;
instructions.addInstruction(idx + 1, new Goto(instructions, startLabel));
} else {
throw new IllegalStateException();
}
}
}
insertSortedReads(group, sortedHandlers);
insertPacketLength(group, ptf);
}
use of net.runelite.asm.attributes.code.Instructions in project runelite by runelite.
the class CodeVisitor method visitTryCatchBlock.
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
Exceptions exceptions = code.getExceptions();
net.runelite.asm.attributes.code.Exception e = new net.runelite.asm.attributes.code.Exception(exceptions);
Instructions ins = code.getInstructions();
net.runelite.asm.attributes.code.Label startL = ins.findOrCreateLabel(start);
net.runelite.asm.attributes.code.Label endL = ins.findOrCreateLabel(end);
net.runelite.asm.attributes.code.Label handlerL = ins.findOrCreateLabel(handler);
assert startL != null;
assert endL != null;
assert handlerL != null;
e.setStart(startL);
e.setEnd(endL);
e.setHandler(handlerL);
if (type != null) {
e.setCatchType(new net.runelite.asm.pool.Class(type));
}
exceptions.add(e);
}
Aggregations