public void scanMethodNode(ClassNode classNode, MethodNode methodNode) throws Exception {
    InsnList iList = methodNode.instructions;

    log("Scanning method " + methodNode.name + " of " + classNode.name);

    LdcInsnNode laststringldconstack = null;
    for (AbstractInsnNode i : iList.toArray()) {
      if (i instanceof LdcInsnNode) {
        LdcInsnNode ldci = (LdcInsnNode) i;
        if (ldci.cst instanceof String) {
          laststringldconstack = ldci;
        }
        continue;
      } else if (i instanceof MethodInsnNode) {
        MethodInsnNode methodi = (MethodInsnNode) i;

        if (laststringldconstack != null
            && methodi.opcode()
                == 0xb8) { // Decryption is always a static call - 0xb8 - invokestatic
          String decrypterclassname = methodi.owner;
          String decryptermethodname = methodi.name;

          if (decrypterclassname.contains(
              "$")) { // Decrypter is always a static method of other class's inner class
            byte[] decrypterFileContents =
                BytecodeViewer.getFileContents(decrypterclassname + ".class");

            // We have to create new node for editing
            // Also, one decrypter method could be used for multiple methods in code, what gives us
            // only part of string decrypted
            ClassNode decrypterclassnode = JarUtils.getNode(decrypterFileContents);

            if (decrypterclassnode != null) {
              MethodNode decryptermethodnode = null;
              for (Object uncasted : decrypterclassnode.methods) {
                if (((MethodNode) uncasted).name.equals(decryptermethodname)) {
                  decryptermethodnode = (MethodNode) uncasted;
                }
              }
              if (decryptermethodnode != null) {

                String keyString =
                    (getConstantPoolSize(classNode.name)
                        + classNode.name
                        + methodNode.name
                        + getConstantPoolSize(classNode.name));

                int newHashCode = keyString.hashCode();

                scanDecrypter(decryptermethodnode, newHashCode);

                try {
                  System.out.println("loading " + decrypterclassname);

                  List<Class<?>> decrypterclasslist =
                      the.bytecode.club.bytecodeviewer.api.BytecodeViewer
                          .loadClassesIntoClassLoader(
                              new ArrayList<ClassNode>(
                                  Arrays.asList(new ClassNode[] {decrypterclassnode})));

                  String decrypted =
                      invokeDecrypter(
                          decrypterclasslist.get(0),
                          decryptermethodname,
                          (String) laststringldconstack.cst);

                  if (decrypted != null) {
                    log("Succesfully invoked decrypter method: " + decrypted);
                    laststringldconstack.cst = decrypted;
                    iList.remove(methodi);
                  }
                } catch (IndexOutOfBoundsException | ClassNotFoundException | IOException e) {
                  e.printStackTrace();
                  log("Could not load decrypter class: " + decrypterclassname);
                }

              } else {
                log(
                    "Could not find decrypter method ("
                        + decryptermethodname
                        + ") of class "
                        + decrypterclassname);
              }
            } else {
              log("Could not find decrypter ClassNode of class " + decrypterclassname);
            }
          }
        }

      } else if (i instanceof InvokeDynamicInsnNode) {
        InvokeDynamicInsnNode methodi = (InvokeDynamicInsnNode) i;
        if (methodi.opcode() == 0xba) {
          // TODO: Safe-reflection deobfuscator here
          // Allatori replaces invokeinterface and invokestatic with invokedynamic

          // log(methodi.bsm.getOwner()+" dot "+methodi.bsm.getName());
          // iList.set(methodi, new MethodInsnNode(0xb8, methodi.bsm.getOwner(),
          // methodi.bsm.getName(), methodi.bsm.getDesc(), false));

        }
      }
      laststringldconstack = null;
    }
  }
  protected String printLdcInsnNode(LdcInsnNode ldc, ListIterator<?> it) {
    if (ldc.cst instanceof String)
      return nameOpcode(ldc.opcode())
          + " \""
          + StringEscapeUtils.escapeJava(ldc.cst.toString())
          + "\" ("
          + ldc.cst.getClass().getCanonicalName()
          + ")";

    return nameOpcode(ldc.opcode())
        + " "
        + StringEscapeUtils.escapeJava(ldc.cst.toString())
        + " ("
        + ldc.cst.getClass().getCanonicalName()
        + ")";
  }
예제 #3
0
 @SuppressWarnings("unchecked")
 private static void processReflection(Remapper remapper, ClassNode node) {
   for (MethodNode mn : (List<MethodNode>) node.methods) {
     InsnList insns = mn.instructions;
     ListIterator<AbstractInsnNode> iterator = insns.iterator();
     while (iterator.hasNext()) {
       AbstractInsnNode insn = iterator.next();
       if (insn.getOpcode() == Opcodes.INVOKESTATIC) {
         MethodInsnNode min = (MethodInsnNode) insn;
         if (min.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
           AbstractInsnNode push = insn.getPrevious();
           if (push.getOpcode() == Opcodes.LDC) {
             LdcInsnNode lin = (LdcInsnNode) push;
             lin.cst = remapper.map(((String) lin.cst).replace('.', '/')).replace('/', '.');
           }
         }
       }
     }
   }
 }