@Test @Ignore public void testRun() throws IOException { PacketHandlerOrder order = new PacketHandlerOrder(); order.run(group); }
@Override public void run(ClassGroup group) { 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; 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(); 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(); assert ictx.getPops().size() == 1; InstructionContext bufferCtx = ictx.getPops().get(0).getPushed(); if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) { 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(); 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()) { 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(); if (runeliteOpcodes.findField(fieldName) == null) { Field opField = new Field(runeliteOpcodes, fieldName, Type.INT); opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC); opField.setValue(handler.getOpcode()); runeliteOpcodes.addField(opField); 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)); } } 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); 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) { 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); }
PacketHandlerOrder implements Deobfuscator { @Override public void run(ClassGroup group) { 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; 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(); 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(); assert ictx.getPops().size() == 1; InstructionContext bufferCtx = ictx.getPops().get(0).getPushed(); if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) { 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(); 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()) { 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(); if (runeliteOpcodes.findField(fieldName) == null) { Field opField = new Field(runeliteOpcodes, fieldName, Type.INT); opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC); opField.setValue(handler.getOpcode()); runeliteOpcodes.addField(opField); 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)); } } 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); 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) { 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); } }
PacketHandlerOrder implements Deobfuscator { @Override public void run(ClassGroup group) { 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; 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(); 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(); assert ictx.getPops().size() == 1; InstructionContext bufferCtx = ictx.getPops().get(0).getPushed(); if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) { 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(); 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()) { 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(); if (runeliteOpcodes.findField(fieldName) == null) { Field opField = new Field(runeliteOpcodes, fieldName, Type.INT); opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC); opField.setValue(handler.getOpcode()); runeliteOpcodes.addField(opField); 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)); } } 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); 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) { 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); }  }
PacketHandlerOrder implements Deobfuscator { @Override public void run(ClassGroup group) { 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; 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(); 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(); assert ictx.getPops().size() == 1; InstructionContext bufferCtx = ictx.getPops().get(0).getPushed(); if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) { 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(); 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()) { 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(); if (runeliteOpcodes.findField(fieldName) == null) { Field opField = new Field(runeliteOpcodes, fieldName, Type.INT); opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC); opField.setValue(handler.getOpcode()); runeliteOpcodes.addField(opField); 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)); } } 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); 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) { 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); }  @Override void run(ClassGroup group); static int hashConstants(List<Object> constants); }
PacketHandlerOrder implements Deobfuscator { @Override public void run(ClassGroup group) { 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; 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(); 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(); assert ictx.getPops().size() == 1; InstructionContext bufferCtx = ictx.getPops().get(0).getPushed(); if (bufferCtx.getInstruction().getType() != InstructionType.GETSTATIC) { 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(); 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()) { 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(); if (runeliteOpcodes.findField(fieldName) == null) { Field opField = new Field(runeliteOpcodes, fieldName, Type.INT); opField.setAccessFlags(ACC_PUBLIC | ACC_STATIC); opField.setValue(handler.getOpcode()); runeliteOpcodes.addField(opField); 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)); } } 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); 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) { 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); }  @Override void run(ClassGroup group); static int hashConstants(List<Object> constants);  }