Search in sources :

Example 16 with LDC

use of net.runelite.asm.attributes.code.instructions.LDC in project runelite by runelite.

the class PacketHandlerOrder method insertPacketLength.

private void insertPacketLength(ClassGroup group, PacketTypeFinder ptf) {
    PacketLengthFinder pfl = new PacketLengthFinder(group, ptf);
    pfl.find();
    GetStatic getArray = pfl.getGetArray();
    // instruction to store packet length
    PutStatic ps = pfl.getStore();
    Instructions instructions = ps.getInstructions();
    List<Instruction> ins = instructions.getInstructions();
    Label getArrayLabel = instructions.createLabelFor(getArray);
    Label storeLabel = instructions.createLabelFor(ps);
    int idx = ins.indexOf(getArray);
    assert idx != -1;
    // to go before label, which must exist
    --idx;
    net.runelite.asm.pool.Field field = new net.runelite.asm.pool.Field(new net.runelite.asm.pool.Class(findClient(group).getName()), RUNELITE_PACKET, Type.BOOLEAN);
    instructions.addInstruction(idx++, new GetStatic(instructions, field));
    instructions.addInstruction(idx++, new IfEq(instructions, getArrayLabel));
    // 2 byte length
    instructions.addInstruction(idx++, new LDC(instructions, -2));
    instructions.addInstruction(idx++, new Goto(instructions, storeLabel));
}
Also used : Goto(net.runelite.asm.attributes.code.instructions.Goto) Label(net.runelite.asm.attributes.code.Label) Instructions(net.runelite.asm.attributes.code.Instructions) LDC(net.runelite.asm.attributes.code.instructions.LDC) PacketLengthFinder(net.runelite.deob.deobfuscators.packethandler.PacketLengthFinder) IfEq(net.runelite.asm.attributes.code.instructions.IfEq) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) SetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction) GetFieldInstruction(net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction) ComparisonInstruction(net.runelite.asm.attributes.code.instruction.types.ComparisonInstruction) PushConstantInstruction(net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction) InvokeInstruction(net.runelite.asm.attributes.code.instruction.types.InvokeInstruction) JumpingInstruction(net.runelite.asm.attributes.code.instruction.types.JumpingInstruction) Instruction(net.runelite.asm.attributes.code.Instruction) MappableInstruction(net.runelite.asm.attributes.code.instruction.types.MappableInstruction) Field(net.runelite.asm.Field) GetStatic(net.runelite.asm.attributes.code.instructions.GetStatic)

Example 17 with LDC

use of net.runelite.asm.attributes.code.instructions.LDC in project runelite by runelite.

the class InjectHook method injectCallback.

private void injectCallback(Instructions ins, int idx, HookInfo hookInfo, StackContext index, StackContext objectPusher) throws InjectionException {
    if (hookInfo.staticMethod == false) {
        if (objectPusher == null) {
            throw new InjectionException("Null object pusher");
        }
        idx = recursivelyPush(ins, idx, objectPusher);
        if (index != null) {
            idx = recursivelyPush(ins, idx, index);
        } else {
            ins.getInstructions().add(idx++, new LDC(ins, -1));
        }
        InvokeVirtual invoke = new InvokeVirtual(ins, new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(hookInfo.clazz), hookInfo.method, new Signature(HOOK_METHOD_SIGNATURE)));
        ins.getInstructions().add(idx++, invoke);
    } else {
        if (index != null) {
            idx = recursivelyPush(ins, idx, index);
        } else {
            ins.getInstructions().add(idx++, new LDC(ins, -1));
        }
        InvokeStatic invoke = new InvokeStatic(ins, new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(hookInfo.clazz), hookInfo.method, new Signature(HOOK_METHOD_SIGNATURE)));
        ins.getInstructions().add(idx++, invoke);
    }
}
Also used : InvokeVirtual(net.runelite.asm.attributes.code.instructions.InvokeVirtual) Signature(net.runelite.asm.signature.Signature) LDC(net.runelite.asm.attributes.code.instructions.LDC) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic)

Example 18 with LDC

use of net.runelite.asm.attributes.code.instructions.LDC 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);
}
Also used : SiPush(net.runelite.asm.attributes.code.instructions.SiPush) LLoad(net.runelite.asm.attributes.code.instructions.LLoad) Return(net.runelite.asm.attributes.code.instructions.Return) InstructionType(net.runelite.asm.attributes.code.InstructionType) DLoad(net.runelite.asm.attributes.code.instructions.DLoad) Instructions(net.runelite.asm.attributes.code.Instructions) LDC(net.runelite.asm.attributes.code.instructions.LDC) Method(net.runelite.asm.Method) CheckCast(net.runelite.asm.attributes.code.instructions.CheckCast) Instruction(net.runelite.asm.attributes.code.Instruction) BiPush(net.runelite.asm.attributes.code.instructions.BiPush) Code(net.runelite.asm.attributes.Code) InstructionType(net.runelite.asm.attributes.code.InstructionType) Type(net.runelite.asm.Type) InvokeVirtual(net.runelite.asm.attributes.code.instructions.InvokeVirtual) Signature(net.runelite.asm.signature.Signature) ALoad(net.runelite.asm.attributes.code.instructions.ALoad) InvokeStatic(net.runelite.asm.attributes.code.instructions.InvokeStatic)

Example 19 with LDC

use of net.runelite.asm.attributes.code.instructions.LDC 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)

Example 20 with LDC

use of net.runelite.asm.attributes.code.instructions.LDC in project runelite by runelite.

the class EnumDeobfuscator method makeEnum.

private void makeEnum(ClassFile cf) {
    // make class an enum
    cf.setEnum();
    // enums super class is java/lang/Enum
    assert cf.getParentClass().getName().equals("java/lang/Object");
    cf.setSuperName("java/lang/Enum");
    // all static fields of the type of the class become enum members
    for (Field field : cf.getFields()) {
        if (field.isStatic() && field.getType().equals(new Type("L" + cf.getName() + ";"))) {
            field.setEnum();
        }
    }
    for (Method method : cf.getMethods()) {
        if (!method.getName().equals("<init>")) {
            continue;
        }
        // Add string as first argument, which is the field name,
        // and ordinal as second argument
        Signature signature = new Signature.Builder().setReturnType(method.getDescriptor().getReturnValue()).addArgument(Type.STRING).addArgument(Type.INT).addArguments(method.getDescriptor().getArguments()).build();
        method.setDescriptor(signature);
        // Remove instructions up to invokespecial
        Instructions ins = method.getCode().getInstructions();
        Instruction i;
        do {
            i = ins.getInstructions().get(0);
            ins.remove(i);
        } while (i.getType() != InstructionType.INVOKESPECIAL);
        // load this
        ins.addInstruction(0, new ALoad(ins, 0));
        // load constant name
        ins.addInstruction(1, new ALoad(ins, 1));
        // ordinal
        ins.addInstruction(2, new ILoad(ins, 2));
        // invoke enum constructor
        ins.addInstruction(3, new InvokeSpecial(ins, ENUM_INIT));
        // Shift all indexes after this up +2 because of the new String and int argument
        for (int j = 4; j < ins.getInstructions().size(); ++j) {
            i = ins.getInstructions().get(j);
            if (i instanceof LVTInstruction) {
                LVTInstruction lvt = ((LVTInstruction) i);
                int idx = lvt.getVariableIndex();
                if (idx != 0) {
                    lvt.setVariableIndex(idx + 2);
                }
            }
        }
    }
    // Order of fields being set in clinit, which is the order
    // the enum fields are actually in
    List<Field> order = new ArrayList<>();
    for (Method method : cf.getMethods()) {
        if (!method.getName().equals("<clinit>")) {
            continue;
        }
        Instructions ins = method.getCode().getInstructions();
        int count = 0;
        // sometimes there is new new invokespecial invokespecial putfield
        // for eg enum member field30(1, 2, String.class, new class5());
        boolean seenDup = false;
        for (int j = 0; j < ins.getInstructions().size(); ++j) {
            Instruction i = ins.getInstructions().get(j);
            if (i.getType() == InstructionType.DUP && !seenDup) {
                // XXX this should actually be the field name, but it seems to have no effect on fernflower
                ins.addInstruction(j + 1, new LDC(ins, "runelite"));
                ins.addInstruction(j + 2, new LDC(ins, count++));
                seenDup = true;
            } else if (i.getType() == InstructionType.INVOKESPECIAL) {
                Instruction next = ins.getInstructions().get(j + 1);
                // check if this is the invokespecial on the enum, putstatic comes next
                if (next.getType() == InstructionType.PUTSTATIC) {
                    InvokeSpecial is = (InvokeSpecial) i;
                    PutStatic ps = (PutStatic) next;
                    net.runelite.asm.pool.Method pmethod = new net.runelite.asm.pool.Method(is.getMethod().getClazz(), is.getMethod().getName(), new Signature.Builder().setReturnType(is.getMethod().getType().getReturnValue()).addArgument(Type.STRING).addArgument(Type.INT).addArguments(is.getMethod().getType().getArguments()).build());
                    is.setMethod(pmethod);
                    Field field = ps.getMyField();
                    assert field != null;
                    order.add(field);
                    seenDup = false;
                }
            }
        }
    }
    // Enum fields must be first. Also they are in order in clinit.
    // Sort fields
    Collections.sort(cf.getFields(), (f1, f2) -> {
        int idx1 = order.indexOf(f1);
        int idx2 = order.indexOf(f2);
        if (idx1 == -1) {
            idx1 = Integer.MAX_VALUE;
        }
        if (idx2 == -1) {
            idx2 = Integer.MAX_VALUE;
        }
        return Integer.compare(idx1, idx2);
    });
}
Also used : InvokeSpecial(net.runelite.asm.attributes.code.instructions.InvokeSpecial) ILoad(net.runelite.asm.attributes.code.instructions.ILoad) ArrayList(java.util.ArrayList) Instructions(net.runelite.asm.attributes.code.Instructions) LDC(net.runelite.asm.attributes.code.instructions.LDC) Method(net.runelite.asm.Method) Instruction(net.runelite.asm.attributes.code.Instruction) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) LVTInstruction(net.runelite.asm.attributes.code.instruction.types.LVTInstruction) PutStatic(net.runelite.asm.attributes.code.instructions.PutStatic) Field(net.runelite.asm.Field) InstructionType(net.runelite.asm.attributes.code.InstructionType) Type(net.runelite.asm.Type) Signature(net.runelite.asm.signature.Signature) ALoad(net.runelite.asm.attributes.code.instructions.ALoad)

Aggregations

LDC (net.runelite.asm.attributes.code.instructions.LDC)46 Instruction (net.runelite.asm.attributes.code.Instruction)39 Instructions (net.runelite.asm.attributes.code.Instructions)38 Code (net.runelite.asm.attributes.Code)32 ClassGroup (net.runelite.asm.ClassGroup)29 Test (org.junit.Test)27 VReturn (net.runelite.asm.attributes.code.instructions.VReturn)26 IMul (net.runelite.asm.attributes.code.instructions.IMul)23 IStore (net.runelite.asm.attributes.code.instructions.IStore)23 ILoad (net.runelite.asm.attributes.code.instructions.ILoad)22 Deobfuscator (net.runelite.deob.Deobfuscator)20 Execution (net.runelite.asm.execution.Execution)19 IAdd (net.runelite.asm.attributes.code.instructions.IAdd)14 Pop (net.runelite.asm.attributes.code.instructions.Pop)13 Method (net.runelite.asm.Method)11 Type (net.runelite.asm.Type)10 Label (net.runelite.asm.attributes.code.Label)10 Field (net.runelite.asm.Field)9 PushConstantInstruction (net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction)9 Signature (net.runelite.asm.signature.Signature)8