Search in sources :

Example 16 with Execution

use of net.runelite.asm.execution.Execution in project runelite by runelite.

the class ConstantParameter method run.

@Override
public void run(ClassGroup group) {
    Execution execution = new Execution(group);
    execution.addExecutionVisitor(i -> findParameters(i));
    execution.populateInitialMethods();
    execution.run();
    execution = new Execution(group);
    execution.addMethodContextVisitor(mc -> findDeadParameters(mc));
    execution.populateInitialMethods();
    execution.run();
    execution = new Execution(group);
    execution.addMethodContextVisitor(m -> count += removeDeadOperations(m));
    execution.populateInitialMethods();
    execution.run();
    logger.info("Removed {} logically dead conditional jumps", count);
}
Also used : Execution(net.runelite.asm.execution.Execution)

Example 17 with Execution

use of net.runelite.asm.execution.Execution 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();
}
Also used : InstructionContext(net.runelite.asm.execution.InstructionContext) SetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction) Instructions(net.runelite.asm.attributes.code.Instructions) AConstNull(net.runelite.asm.attributes.code.instructions.AConstNull) Method(net.runelite.asm.Method) DupInstruction(net.runelite.asm.attributes.code.instruction.types.DupInstruction) SetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction) Instruction(net.runelite.asm.attributes.code.Instruction) ArrayStore(net.runelite.asm.attributes.code.instructions.ArrayStore) Code(net.runelite.asm.attributes.Code) Field(net.runelite.asm.Field) PutField(net.runelite.asm.attributes.code.instructions.PutField) Execution(net.runelite.asm.execution.Execution) StackContext(net.runelite.asm.execution.StackContext) HashSet(java.util.HashSet) PutField(net.runelite.asm.attributes.code.instructions.PutField)

Example 18 with Execution

use of net.runelite.asm.execution.Execution in project runelite by runelite.

the class IllegalStateExceptions method run.

@Override
public void run(ClassGroup group) {
    findInteresting(group);
    Execution execution = new Execution(group);
    execution.addExecutionVisitor(i -> visit(i));
    execution.addMethodContextVisitor(i -> visit(i));
    execution.populateInitialMethods();
    execution.run();
    logger.info("Removed " + count + " illegal state exceptions");
}
Also used : Execution(net.runelite.asm.execution.Execution)

Example 19 with Execution

use of net.runelite.asm.execution.Execution 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);
}
Also used : Field(net.runelite.asm.Field) Execution(net.runelite.asm.execution.Execution) ClassFile(net.runelite.asm.ClassFile) Method(net.runelite.asm.Method)

Example 20 with Execution

use of net.runelite.asm.execution.Execution 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

Execution (net.runelite.asm.execution.Execution)44 Instruction (net.runelite.asm.attributes.code.Instruction)25 ClassGroup (net.runelite.asm.ClassGroup)23 Instructions (net.runelite.asm.attributes.code.Instructions)23 Code (net.runelite.asm.attributes.Code)21 Deobfuscator (net.runelite.deob.Deobfuscator)21 LDC (net.runelite.asm.attributes.code.instructions.LDC)19 VReturn (net.runelite.asm.attributes.code.instructions.VReturn)19 IMul (net.runelite.asm.attributes.code.instructions.IMul)18 Test (org.junit.Test)18 IStore (net.runelite.asm.attributes.code.instructions.IStore)17 ILoad (net.runelite.asm.attributes.code.instructions.ILoad)16 InstructionContext (net.runelite.asm.execution.InstructionContext)12 Label (net.runelite.asm.attributes.code.Label)10 Method (net.runelite.asm.Method)8 ClassFile (net.runelite.asm.ClassFile)7 Pop (net.runelite.asm.attributes.code.instructions.Pop)7 StackContext (net.runelite.asm.execution.StackContext)7 Field (net.runelite.asm.Field)5 Dup_X1 (net.runelite.asm.attributes.code.instructions.Dup_X1)5