Search in sources :

Example 1 with BufferFinder

use of net.runelite.deob.deobfuscators.transformers.buffer.BufferFinder in project runelite by runelite.

the class RuneliteBufferTransformer method injectBufferMethods.

/**
 * inject runelite buffer methods
 *
 * @param group
 */
private void injectBufferMethods(ClassGroup group) {
    BufferFinder bf = new BufferFinder(group);
    bf.find();
    BufferPayloadFinder bpf = new BufferPayloadFinder(bf.getBuffer());
    bpf.find();
    BufferMethodInjector bmi = new BufferMethodInjector(bpf);
    try {
        bmi.inject();
    } catch (IOException ex) {
        logger.warn("unable to inject buffer methods", ex);
    }
}
Also used : BufferFinder(net.runelite.deob.deobfuscators.transformers.buffer.BufferFinder) BufferPayloadFinder(net.runelite.deob.deobfuscators.transformers.buffer.BufferPayloadFinder) BufferMethodInjector(net.runelite.deob.deobfuscators.transformers.buffer.BufferMethodInjector) IOException(java.io.IOException)

Example 2 with BufferFinder

use of net.runelite.deob.deobfuscators.transformers.buffer.BufferFinder 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);
}
Also used : IfICmpEq(net.runelite.asm.attributes.code.instructions.IfICmpEq) LoggerFactory(org.slf4j.LoggerFactory) PacketHandler(net.runelite.deob.s2c.PacketHandler) Goto(net.runelite.asm.attributes.code.instructions.Goto) If(net.runelite.asm.attributes.code.instructions.If) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) InstructionType(net.runelite.asm.attributes.code.InstructionType) SetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction) PacketTypeFinder(net.runelite.deob.deobfuscators.packethandler.PacketTypeFinder) GetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction) Type(net.runelite.asm.Type) Deobfuscator(net.runelite.deob.Deobfuscator) BufferFinder(net.runelite.deob.deobfuscators.transformers.buffer.BufferFinder) Collectors(java.util.stream.Collectors) InstructionContext(net.runelite.asm.execution.InstructionContext) ComparisonInstruction(net.runelite.asm.attributes.code.instruction.types.ComparisonInstruction) List(java.util.List) ACC_PUBLIC(org.objectweb.asm.Opcodes.ACC_PUBLIC) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) PacketRead(net.runelite.deob.deobfuscators.packethandler.PacketRead) Signature(net.runelite.asm.signature.Signature) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) MessageDigest(java.security.MessageDigest) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) ACC_STATIC(org.objectweb.asm.Opcodes.ACC_STATIC) ArrayList(java.util.ArrayList) ClassGroup(net.runelite.asm.ClassGroup) Method(net.runelite.asm.Method) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) JumpingInstruction(net.runelite.asm.attributes.code.instruction.types.JumpingInstruction) GetStatic(net.runelite.asm.attributes.code.instructions.GetStatic) Frame(net.runelite.asm.execution.Frame) Logger(org.slf4j.Logger) RUNELITE_OPCODES(net.runelite.deob.deobfuscators.transformers.OpcodesTransformer.RUNELITE_OPCODES) Field(net.runelite.asm.Field) PacketLengthFinder(net.runelite.deob.deobfuscators.packethandler.PacketLengthFinder) Ints(com.google.common.primitives.Ints) InvokeVirtual(net.runelite.asm.attributes.code.instructions.InvokeVirtual) Execution(net.runelite.asm.execution.Execution) ClassFile(net.runelite.asm.ClassFile) Label(net.runelite.asm.attributes.code.Label) PacketHandlers(net.runelite.deob.s2c.PacketHandlers) HandlerFinder(net.runelite.deob.s2c.HandlerFinder) IfEq(net.runelite.asm.attributes.code.instructions.IfEq) LDC(net.runelite.asm.attributes.code.instructions.LDC) Instructions(net.runelite.asm.attributes.code.Instructions) Instruction(net.runelite.asm.attributes.code.Instruction) MappableInstruction(net.runelite.asm.attributes.code.instruction.types.MappableInstruction) Collections(java.util.Collections) Frame(net.runelite.asm.execution.Frame) BufferFinder(net.runelite.deob.deobfuscators.transformers.buffer.BufferFinder) PacketHandlers(net.runelite.deob.s2c.PacketHandlers) ArrayList(java.util.ArrayList) Label(net.runelite.asm.attributes.code.Label) LDC(net.runelite.asm.attributes.code.instructions.LDC) PacketRead(net.runelite.deob.deobfuscators.packethandler.PacketRead) Field(net.runelite.asm.Field) MappableInstruction(net.runelite.asm.attributes.code.instruction.types.MappableInstruction) Execution(net.runelite.asm.execution.Execution) GetStatic(net.runelite.asm.attributes.code.instructions.GetStatic) IfICmpEq(net.runelite.asm.attributes.code.instructions.IfICmpEq) InstructionContext(net.runelite.asm.execution.InstructionContext) SetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction) Goto(net.runelite.asm.attributes.code.instructions.Goto) ClassFile(net.runelite.asm.ClassFile) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) Instructions(net.runelite.asm.attributes.code.Instructions) Method(net.runelite.asm.Method) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) InstructionType(net.runelite.asm.attributes.code.InstructionType) Type(net.runelite.asm.Type) PacketHandler(net.runelite.deob.s2c.PacketHandler) Signature(net.runelite.asm.signature.Signature) HandlerFinder(net.runelite.deob.s2c.HandlerFinder) PacketTypeFinder(net.runelite.deob.deobfuscators.packethandler.PacketTypeFinder) GetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction) If(net.runelite.asm.attributes.code.instructions.If)

Aggregations

Ints (com.google.common.primitives.Ints)1 IOException (java.io.IOException)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 ArrayList (java.util.ArrayList)1 Collections (java.util.Collections)1 List (java.util.List)1 Collectors (java.util.stream.Collectors)1 ClassFile (net.runelite.asm.ClassFile)1 ClassGroup (net.runelite.asm.ClassGroup)1 Field (net.runelite.asm.Field)1 Method (net.runelite.asm.Method)1 Type (net.runelite.asm.Type)1 Instruction (net.runelite.asm.attributes.code.Instruction)1 InstructionType (net.runelite.asm.attributes.code.InstructionType)1 Instructions (net.runelite.asm.attributes.code.Instructions)1 Label (net.runelite.asm.attributes.code.Label)1 ComparisonInstruction (net.runelite.asm.attributes.code.instruction.types.ComparisonInstruction)1 GetFieldInstruction (net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction)1 InvokeInstruction (net.runelite.asm.attributes.code.instruction.types.InvokeInstruction)1