Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package io.deki.updater.asm.deob;
- import io.deki.updater.asm.FieldMult;
- import io.deki.updater.hook.FieldHook;
- import org.objectweb.asm.Opcodes;
- import org.objectweb.asm.tree.*;
- import java.util.*;
- /**
- * Created by Deki on 09.07.2019
- */
- public class MultFinder {
- private static List<FieldMult> potentialMults, mults;
- /**
- * main function
- * @param nodes List of classnodes from gamepack
- */
- public static void mapMults(Collection<ClassNode> nodes) {
- potentialMults = new ArrayList<>();
- mults = new ArrayList<>();
- for (ClassNode node : nodes) {
- process(node);
- }
- }
- /**
- * Finds a specified hooks' mult in the mappings and sets it.
- * FUN FACT: streams are better for big datasets than iterators,
- * not sure if this counts as a big dataset though :)
- * @param hook Field hook object used to store owner/name/mult
- */
- public static void setMult(FieldHook hook) {
- FieldMult mult = mults.stream().filter(m -> m.getOwner().equals(hook.getClazz())
- && m.getName().equals(hook.getField())).findFirst().orElse(null);
- if (mult != null) hook.setMultiplier(mult.getMult());
- }
- /**
- * Internal method to process each class node.
- * We're looking for this pattern:
- * GETFIELD/GETSTATIC/PUTFIELD
- * LDC
- * IMUL/LMUL
- * (ldc and getter/setter can be swapped)
- * @param node Class node to be processed
- */
- private static void process(ClassNode node) {
- //we want to loop through all methods
- node.methods.forEach(methodNode -> methodNode.instructions.iterator().forEachRemaining(insn -> {
- //we're looking for IMUL/LMULs, no need for the other ones
- if (insn.opcode() != Opcodes.IMUL && insn.opcode() != Opcodes.LMUL) return;
- //get the instruction from before the multiplication instruction
- AbstractInsnNode first = insn.previous();
- long constant = decodeLdc(first);
- FieldInsnNode field = decodeField(first);
- //here we split the path into two for optimal results (thanks spencer!):
- //first option is if the pattern is GET/LDC/MUL
- //second is LDC/GET/MUL
- if (constant == -1) {
- AbstractInsnNode second = first.previous();
- constant = decodeLdc(second);
- } else {
- AbstractInsnNode second = first.previous();
- field = decodeField(second);
- }
- //check if anything is null or if the mult is an even number (thanks spencer!)
- if (field == null || constant == -1 || (constant & 1) == 0) return;
- boolean decoder = field.opcode() == Opcodes.GETFIELD || field.opcode() == Opcodes.GETSTATIC;
- //create a FieldMult object, just used for storing values
- FieldMult mult = new FieldMult(field.owner, field.name, constant, decoder);
- //check if we already mapped the mult in question
- if (mults.contains(mult)) return;
- //check if we already encountered this specific mult.
- //jagex's obfuscator sprinkles in dummy constants, but these never occur more than once.
- //if it's present more than once we're confident that it's the real deal.
- if (potentialMults.contains(mult)) {
- mults.add(mult);
- return;
- }
- //add the field to encountered mults.
- potentialMults.add(mult);
- }));
- }
- private static long decodeLdc(AbstractInsnNode node) {
- //if this isn't an ldc instruction it doesn't match our pattern and we don't need it
- if (node == null || node.opcode() != Opcodes.LDC) return -1;
- //at this point we know it's an ldc and we can store its value for later use.
- //we're parsing the value as a string as the jvm gets angry if we just cast
- return Long.parseLong("" + ((LdcInsnNode) node).cst);
- }
- private static FieldInsnNode decodeField(AbstractInsnNode node) {
- //check if its a getfield/getstatic/putfield, if not we don't want it
- if (node == null || (node.opcode() != Opcodes.GETFIELD && node.opcode() != Opcodes.GETSTATIC
- && node.opcode() != Opcodes.PUTFIELD && node.opcode() != Opcodes.PUTSTATIC)) return null;
- //store this as a FieldInsnNode as I cba to cast it all the time
- return (FieldInsnNode) node;
- }
- public static List<FieldMult> getMults() {
- return mults;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement