public static void renameFieldNode(
      String originalParentName,
      String originalFieldName,
      String originalFieldDesc,
      String newFieldParent,
      String newFieldName,
      String newFieldDesc) {
    for (ClassNode c : BytecodeViewer.getLoadedClasses()) {
      for (Object o : c.methods.toArray()) {
        MethodNode m = (MethodNode) o;
        for (AbstractInsnNode i : m.instructions.toArray()) {
          if (i instanceof FieldInsnNode) {
            FieldInsnNode field = (FieldInsnNode) i;

            if (field.owner.equals(originalParentName)
                && field.name.equals(originalFieldName)
                && field.desc.equals(originalFieldDesc)) {
              if (newFieldParent != null) field.owner = newFieldParent;
              if (newFieldName != null) field.name = newFieldName;
              if (newFieldDesc != null) field.desc = newFieldDesc;
            }
          }
        }
      }
    }
  }
 /**
  * Runs a new plugin instance
  *
  * @param newPluginInstance the new plugin instance
  */
 public static void runPlugin(Plugin newPluginInstance) {
   if (pluginInstance == null || pluginInstance.isFinished()) {
     pluginInstance = newPluginInstance;
     pluginInstance.start(); // start the thread
   } else if (!pluginInstance.isFinished()) {
     BytecodeViewer.showMessage(
         "There is currently another plugin running right now, please wait for that to finish executing.");
   }
 }
  @Override
  public void decompileToZip(String zipName) {
    File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp.jar");
    if (tempZip.exists()) tempZip.delete();

    JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath());

    try {
      doSaveJarDecompiled(tempZip, new File(zipName));
    } catch (Exception e) {
      new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
    }
  }
 @Override
 public void setVisible(boolean b) {
   super.setVisible(b);
   txtrBytecodeViewerIs.setText(
       "Bytecode Viewer "
           + BytecodeViewer.version
           + " is an open source program developed and maintained by Konloch ([email protected])\r\n"
           + "100% free and open sourced licensed under GPL v3 CopyLeft\r\n\r\n"
           + "Settings:"
           + BytecodeViewer.nl
           + "BCV Dir: "
           + BytecodeViewer.getBCVDirectory()
           + BytecodeViewer.nl
           + "Python: "
           + BytecodeViewer.python
           + BytecodeViewer.nl
           + "RT.jar:"
           + BytecodeViewer.rt
           + BytecodeViewer.nl
           + "Optional Lib: "
           + BytecodeViewer.library
           + BytecodeViewer.nl
           + "BCV Krakatau: v"
           + BytecodeViewer.krakatauVersion
           + BytecodeViewer.nl
           + "Krakatau Dir: "
           + BytecodeViewer.krakatauWorkingDirectory
           + BytecodeViewer.nl
           + BytecodeViewer.nl
           + "Keybinds:"
           + BytecodeViewer.nl
           + "CTRL + O: Open/add new jar/class/apk"
           + BytecodeViewer.nl
           + "CTLR + N: Reset the workspace"
           + BytecodeViewer.nl
           + "CTRL + W: Closes the currently opened tab"
           + BytecodeViewer.nl
           + "CTRL + T: Compile"
           + BytecodeViewer.nl
           + "CTRL + S: Save classes as zip"
           + BytecodeViewer.nl
           + "CTRL + R: Run (EZ-Inject) - dynamically load the classes and invoke a main class"
           + "\r\n\r\nIt uses code from the following:\r\n    J-RET by WaterWolf\r\n    JHexPane by Sam Koivu\r\n    RSynaxPane by Robert Futrell\r\n    Commons IO by Apache\r\n    ASM by OW2\r\n    FernFlower by Stiver\r\n    Procyon by Mstrobel\r\n    CFR by Lee Benfield\r\n    CFIDE by Bibl\r\n    Smali by JesusFreke\r\n    Dex2Jar by pxb1..?\r\n    Krakatau by Storyyeller\r\n\r\nIf you're interested in Java Reverse Engineering, join The Bytecode Club\r\nhttps://the.bytecode.club");
 }
  public static void renameMethodNode(
      String originalParentName,
      String originalMethodName,
      String originalMethodDesc,
      String newParent,
      String newName,
      String newDesc) {
    for (ClassNode c : BytecodeViewer.getLoadedClasses()) {
      for (Object o : c.methods.toArray()) {
        MethodNode m = (MethodNode) o;
        for (AbstractInsnNode i : m.instructions.toArray()) {
          if (i instanceof MethodInsnNode) {
            MethodInsnNode mi = (MethodInsnNode) i;
            if (mi.owner.equals(originalParentName)
                && mi.name.equals(originalMethodName)
                && mi.desc.equals(originalMethodDesc)) {
              if (newParent != null) mi.owner = newParent;
              if (newName != null) mi.name = newName;
              if (newDesc != null) mi.desc = newDesc;
            }
          } else {
            // System.out.println(i.getOpcode()+":"+c.name+":"+m.name);
          }
        }

        if (m.signature != null) {
          if (newName != null) m.signature = m.signature.replace(originalMethodName, newName);
          if (newParent != null) m.signature = m.signature.replace(originalParentName, newParent);
        }

        if (m.name.equals(originalMethodName)
            && m.desc.equals(originalMethodDesc)
            && c.name.equals(originalParentName)) {
          if (newName != null) m.name = newName;
          if (newDesc != null) m.desc = newDesc;
        }
      }
    }
  }
  public static void renameClassNode(final String oldName, final String newName) {
    for (ClassNode c : BytecodeViewer.getLoadedClasses()) {
      for (Object oo : c.innerClasses) {
        InnerClassNode innerClassNode = (InnerClassNode) oo;
        if (innerClassNode.innerName != null && innerClassNode.innerName.equals(oldName)) {
          innerClassNode.innerName = newName;
        }
        if (innerClassNode.name.equals(oldName)) {
          innerClassNode.name = newName;
        }
        if (innerClassNode.outerName != null && innerClassNode.outerName.equals(oldName)) {
          innerClassNode.outerName = newName;
        }
      }

      if (c.signature != null) c.signature = c.signature.replace(oldName, newName);

      if (c.superName.equals(oldName)) {
        c.superName = newName;
      }
      for (Object o : c.fields.toArray()) {
        FieldNode f = (FieldNode) o;
        f.desc = f.desc.replace(oldName, newName);
      }
      for (Object o : c.interfaces.toArray()) {
        String truxerLipton = (String) o;
        truxerLipton = truxerLipton.replace(oldName, newName);
      }
      for (Object o : c.methods.toArray()) {
        MethodNode m = (MethodNode) o;

        if (m.localVariables != null) {
          for (LocalVariableNode node : (List<LocalVariableNode>) m.localVariables) {
            node.desc = node.desc.replace(oldName, newName);
          }
        }

        if (m.signature != null) m.signature = m.signature.replace(oldName, newName);

        for (int i = 0; i < m.exceptions.size(); i++) {
          if (m.exceptions.get(i).equals(oldName)) m.exceptions.set(i, newName);
        }

        for (AbstractInsnNode i : m.instructions.toArray()) {
          if (i instanceof TypeInsnNode) {
            TypeInsnNode t = (TypeInsnNode) i;
            if (t.desc.equals(oldName)) {
              t.desc = newName;
            }
          }
          if (i instanceof MethodInsnNode) {
            MethodInsnNode mi = (MethodInsnNode) i;
            if (mi.owner.equals(oldName)) mi.owner = newName;
            mi.desc = mi.desc.replace(oldName, newName);
          }
          if (i instanceof FieldInsnNode) {
            FieldInsnNode fi = (FieldInsnNode) i;
            if (fi.owner.equals(oldName)) fi.owner = newName;
            fi.desc = fi.desc.replace(oldName, newName);
          }
        }
      }
    }
  }
  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;
    }
  }
 private int getConstantPoolSize(String className) {
   byte[] fileContents = BytecodeViewer.getFileContents(className + ".class");
   return readUnsignedShort(fileContents, 8);
 }