Built-in Script Editor
Still a work in progress
This commit is contained in:
parent
d052d0e6d3
commit
f3d5f25743
21 changed files with 498 additions and 111 deletions
|
@ -84,12 +84,14 @@ import static the.bytecode.club.bytecodeviewer.util.MiscUtils.guessLanguage;
|
|||
* + Krakatau Assembly compile - Needs to be fixed
|
||||
*
|
||||
* TODO IN-PROGRESS:
|
||||
* + While loading an external plugin it should check if its java or JS, if so it should ask if you'd like to run or edit the plugin using the PluginWriter
|
||||
* + Resource Importer needs to be rewriten to handle resources better
|
||||
* + Finish dragging code
|
||||
* + Finish right-click tab menu detection
|
||||
* + Fix hook inject for EZ-Injection
|
||||
*
|
||||
* TODO FEATURES:
|
||||
* + CLI Headless needs to be supported
|
||||
* + Add stackmapframes to bytecode decompiler
|
||||
* + Add JEB decompiler optionally, requires them to add jeb library jar
|
||||
* + Add https://github.com/ptnkjke/Java-Bytecode-Editor visualize as a plugin
|
||||
|
@ -164,7 +166,8 @@ public class BytecodeViewer
|
|||
*
|
||||
* @param args files you want to open or CLI
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
public static void main(String[] args)
|
||||
{
|
||||
BytecodeViewer.args = args;
|
||||
System.out.println("https://the.bytecode.club - Created by @Konloch - Bytecode Viewer " + VERSION + ", " + "Fat-Jar: " + FAT_JAR);
|
||||
System.setSecurityManager(sm);
|
||||
|
@ -179,13 +182,22 @@ public class BytecodeViewer
|
|||
showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is "
|
||||
+ "actually out if you use this." + nl +
|
||||
"Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + VERSION + "'s release");
|
||||
|
||||
|
||||
//set swing specific system properties
|
||||
System.setProperty("swing.aatext", "true");
|
||||
|
||||
//setup swing components
|
||||
viewer = new MainViewerGUI();
|
||||
SwingUtilities.updateComponentTreeUI(viewer);
|
||||
|
||||
//load settings and set swing components state
|
||||
SettingsSerializer.loadSettings();
|
||||
|
||||
//set translation language
|
||||
if(!Settings.hasSetLanguageAsSystemLanguage)
|
||||
MiscUtils.setLanguage(guessLanguage());
|
||||
|
||||
//handle CLI
|
||||
int CLI = CommandLineInput.parseCommandLine(args);
|
||||
|
||||
if (CLI == CommandLineInput.STOP)
|
||||
|
@ -634,7 +646,7 @@ public class BytecodeViewer
|
|||
|
||||
if ((e.getKeyCode() == KeyEvent.VK_O) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
|
||||
Configuration.lastHotKeyExecuted = System.currentTimeMillis();
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select File or Folder to open in BCV",
|
||||
"APKs, DEX, Class Files or Zip/Jar/War Archives",
|
||||
Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
@ -678,7 +690,7 @@ public class BytecodeViewer
|
|||
if (viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Zip Export",
|
||||
"Zip Archives",
|
||||
"zip");
|
||||
|
@ -688,20 +700,12 @@ public class BytecodeViewer
|
|||
{
|
||||
Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath();
|
||||
File file = fc.getSelectedFile();
|
||||
|
||||
if (!file.getAbsolutePath().endsWith(".zip"))
|
||||
file = new File(file.getAbsolutePath() + ".zip");
|
||||
|
||||
if (file.exists()) {
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DialogueUtils.canOverwriteFile(file))
|
||||
return;
|
||||
|
||||
final File file2 = file;
|
||||
|
||||
|
|
|
@ -44,4 +44,13 @@ public class Configuration
|
|||
|
||||
public static LAFTheme lafTheme = LAFTheme.SYSTEM; //lightmode by default since it uses the system theme
|
||||
public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
|
||||
|
||||
public static File getLastDirectory()
|
||||
{
|
||||
File lastDir = new File(lastDirectory);
|
||||
if(lastDir.exists())
|
||||
return lastDir;
|
||||
|
||||
return new File(".");
|
||||
}
|
||||
}
|
|
@ -3,12 +3,15 @@ package the.bytecode.club.bytecodeviewer;
|
|||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.imgscalr.Scalr;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.libsDirectory;
|
||||
|
@ -102,6 +105,11 @@ public class Resources {
|
|||
size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
public static String loadResourceAsString(String resourcePath) throws IOException
|
||||
{
|
||||
return IOUtils.toString(Resources.class.getResourceAsStream(resourcePath), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static BufferedImage resize(BufferedImage image, int width, int height) {
|
||||
return Scalr.resize(image, Scalr.Method.ULTRA_QUALITY, width, height);
|
||||
|
|
|
@ -14,9 +14,12 @@ import the.bytecode.club.bytecodeviewer.compilers.InternalCompiler;
|
|||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -220,6 +223,28 @@ public class BytecodeViewer {
|
|||
the.bytecode.club.bytecodeviewer.BytecodeViewer.showMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks if the user would like to overwrite the file
|
||||
*/
|
||||
public static boolean canOverwriteFile(File file) {
|
||||
return DialogueUtils.canOverwriteFile(file);
|
||||
}
|
||||
|
||||
public static void hideFrame(JFrame frame, long milliseconds)
|
||||
{
|
||||
new Thread(()->{
|
||||
long started = System.currentTimeMillis();
|
||||
while(System.currentTimeMillis()-started <= milliseconds)
|
||||
{
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
|
||||
frame.setVisible(false);
|
||||
}, "Timed Swing Hide").start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped Krakatau Decompiler instance.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,7 @@ import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses;
|
|||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
|
||||
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.PluginTemplate;
|
||||
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.*;
|
||||
import the.bytecode.club.bytecodeviewer.resources.exporting.Export;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBoxMenuItem;
|
||||
|
@ -104,6 +105,8 @@ public class MainViewerGUI extends JFrame
|
|||
public final JMenu pluginsMainMenu = new TranslatedJMenu("Plugins", Translation.PLUGINS);
|
||||
public final JMenuItem openExternalPlugin = new TranslatedJMenuItem("Open Plugin...", Translation.OPEN_PLUGIN);
|
||||
public final JMenu recentPluginsSecondaryMenu = new TranslatedJMenu("Recent Plugins", Translation.RECENT_PLUGINS);
|
||||
public final JMenuItem newJavaPlugin = new TranslatedJMenuItem("New Java Plugin...", Translation.NEW_JAVA_PLUGIN);
|
||||
public final JMenuItem newJavascriptPlugin = new TranslatedJMenuItem("New Javascript Plugin...", Translation.NEW_JAVASCRIPT_PLUGIN);
|
||||
public final JMenuItem codeSequenceDiagram = new TranslatedJMenuItem("Code Sequence Diagram", Translation.CODE_SEQUENCE_DIAGRAM);
|
||||
public final JMenuItem maliciousCodeScanner = new TranslatedJMenuItem("Malicious Code Scanner", Translation.MALICIOUS_CODE_SCANNER);
|
||||
public final JMenuItem showAllStrings = new TranslatedJMenuItem("Show All Strings", Translation.SHOW_ALL_STRINGS);
|
||||
|
@ -591,6 +594,9 @@ public class MainViewerGUI extends JFrame
|
|||
pluginsMainMenu.add(new JSeparator());
|
||||
pluginsMainMenu.add(recentPluginsSecondaryMenu);
|
||||
pluginsMainMenu.add(new JSeparator());
|
||||
pluginsMainMenu.add(newJavaPlugin);
|
||||
pluginsMainMenu.add(newJavascriptPlugin);
|
||||
pluginsMainMenu.add(new JSeparator());
|
||||
pluginsMainMenu.add(codeSequenceDiagram);
|
||||
pluginsMainMenu.add(maliciousCodeScanner);
|
||||
pluginsMainMenu.add(showMainMethods);
|
||||
|
@ -604,6 +610,8 @@ public class MainViewerGUI extends JFrame
|
|||
pluginsMainMenu.add(zStringArrayDecrypter);
|
||||
|
||||
openExternalPlugin.addActionListener(arg0 -> openExternalPlugin());
|
||||
newJavaPlugin.addActionListener(arg0 -> PluginTemplate.JAVA.openEditorExceptionHandled());
|
||||
newJavascriptPlugin.addActionListener(arg0 -> PluginTemplate.JAVASCRIPT.openEditorExceptionHandled());
|
||||
codeSequenceDiagram.addActionListener(arg0 -> CodeSequenceDiagram.open());
|
||||
maliciousCodeScanner.addActionListener(e -> MaliciousCodeScannerOptions.open());
|
||||
showMainMethods.addActionListener(e -> PluginManager.runPlugin(new ShowMainMethods()));
|
||||
|
@ -839,7 +847,7 @@ public class MainViewerGUI extends JFrame
|
|||
|
||||
public void selectFile()
|
||||
{
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select File or Folder to open in BCV",
|
||||
"APKs, DEX, Class Files or Zip/Jar/War Archives",
|
||||
Constants.SUPPORTED_FILE_EXTENSIONS);
|
||||
|
@ -859,7 +867,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectPythonC() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Python 2.7 Executable",
|
||||
"Python (Or PyPy for speed) 2.7 Executable",
|
||||
"everything");
|
||||
|
@ -876,7 +884,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectJavac() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Javac Executable",
|
||||
"Javac Executable (Requires JDK 'C:/programfiles/Java/JDK_xx/bin/javac.exe)",
|
||||
"everything");
|
||||
|
@ -893,7 +901,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectJava() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Java Executable",
|
||||
"Java Executable (Inside Of JRE/JDK 'C:/programfiles/Java/JDK_xx/bin/java.exe')",
|
||||
"everything");
|
||||
|
@ -910,7 +918,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectPythonC3() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Python 3.x Executable",
|
||||
"Python (Or PyPy for speed) 3.x Executable",
|
||||
"everything");
|
||||
|
@ -927,7 +935,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectOpenalLibraryFolder() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Library Folder",
|
||||
"Optional Library Folder",
|
||||
"everything");
|
||||
|
@ -948,7 +956,7 @@ public class MainViewerGUI extends JFrame
|
|||
}
|
||||
|
||||
public void selectJRERTLibrary() {
|
||||
final JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
final JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select JRE RT Jar",
|
||||
"JRE RT Library",
|
||||
"everything");
|
||||
|
@ -966,7 +974,7 @@ public class MainViewerGUI extends JFrame
|
|||
|
||||
public void openExternalPlugin()
|
||||
{
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select External Plugin",
|
||||
"External Plugin",
|
||||
"everything");
|
||||
|
|
|
@ -50,6 +50,7 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
private final JLabel titleHeader = new JLabel("");
|
||||
private final Color scrollBackground = new Color(0x3c3f41);
|
||||
private final Color scrollForeground = new Color(0x575859);
|
||||
private Runnable onCtrlS;
|
||||
|
||||
public SearchableRSyntaxTextArea()
|
||||
{
|
||||
|
@ -91,6 +92,12 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiers() & KeyEvent.CTRL_MASK) != 0))
|
||||
searchInput.requestFocus();
|
||||
|
||||
if (onCtrlS != null && (keyEvent.getKeyCode() == KeyEvent.VK_S) && ((keyEvent.getModifiers() & KeyEvent.CTRL_MASK) != 0))
|
||||
{
|
||||
onCtrlS.run();
|
||||
return;
|
||||
}
|
||||
|
||||
BytecodeViewer.checkHotKey(keyEvent);
|
||||
}));
|
||||
}
|
||||
|
@ -116,6 +123,11 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
return "";
|
||||
}
|
||||
|
||||
public void setOnCtrlS(Runnable onCtrlS)
|
||||
{
|
||||
this.onCtrlS = onCtrlS;
|
||||
}
|
||||
|
||||
public RTextScrollPane getScrollPane()
|
||||
{
|
||||
return scrollPane;
|
||||
|
@ -140,4 +152,9 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
{
|
||||
return titleHeader;
|
||||
}
|
||||
|
||||
public Runnable getOnCtrlS()
|
||||
{
|
||||
return onCtrlS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,12 @@ public final class PluginManager {
|
|||
public static Set<String> pluginExtensions() {
|
||||
return launchStrategies.keySet();
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, PluginLaunchStrategy> getLaunchStrategies()
|
||||
{
|
||||
return launchStrategies;
|
||||
}
|
||||
|
||||
public static FileFilter fileFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package the.bytecode.club.bytecodeviewer.plugin;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import the.bytecode.club.bytecodeviewer.Resources;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/1/2021
|
||||
*/
|
||||
public enum PluginTemplate
|
||||
{
|
||||
JAVA("/templates/Template.java"),
|
||||
JAVASCRIPT("/templates/Template.js"),
|
||||
;
|
||||
|
||||
private final String resourcePath;
|
||||
private final String extension;
|
||||
private String contents;
|
||||
|
||||
PluginTemplate(String resourcePath)
|
||||
{
|
||||
this.resourcePath = resourcePath;
|
||||
this.extension = FilenameUtils.getExtension(resourcePath);
|
||||
}
|
||||
|
||||
public String getContents() throws IOException
|
||||
{
|
||||
if(contents == null)
|
||||
contents = Resources.loadResourceAsString(resourcePath);
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
public String getExtension()
|
||||
{
|
||||
return extension;
|
||||
}
|
||||
|
||||
public PluginWriter openEditorExceptionHandled()
|
||||
{
|
||||
try
|
||||
{
|
||||
return openEditor();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
new ExceptionUI(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public PluginWriter openEditor() throws IOException
|
||||
{
|
||||
PluginWriter writer = new PluginWriter(this);
|
||||
writer.setVisible(true);
|
||||
return writer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package the.bytecode.club.bytecodeviewer.plugin;
|
||||
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.apache.commons.compress.utils.FileNameUtils;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.Resources;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
|
||||
import the.bytecode.club.bytecodeviewer.translation.Translation;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJMenu;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJMenuItem;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.Settings.addRecentPlugin;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/1/2021
|
||||
*/
|
||||
public class PluginWriter extends JFrame
|
||||
{
|
||||
private SearchableRSyntaxTextArea area;
|
||||
private JMenuItem menuSaveAs;
|
||||
private JMenuItem menuSave;
|
||||
private String content;
|
||||
private String pluginName;
|
||||
private File savePath;
|
||||
|
||||
public PluginWriter(PluginTemplate template) throws IOException
|
||||
{
|
||||
this.content = template.getContents();
|
||||
this.pluginName = "Template." + template.getExtension();
|
||||
buildGUI();
|
||||
}
|
||||
|
||||
public PluginWriter(String content, String pluginName)
|
||||
{
|
||||
this.content = content;
|
||||
this.pluginName = pluginName;
|
||||
buildGUI();
|
||||
}
|
||||
|
||||
public void buildGUI()
|
||||
{
|
||||
setTitle("Editing BCV Plugin: " + pluginName);
|
||||
setIconImages(Resources.iconList);
|
||||
setSize(new Dimension(542, 316));
|
||||
|
||||
area = (SearchableRSyntaxTextArea) Configuration.rstaTheme.apply(new SearchableRSyntaxTextArea());
|
||||
area.setOnCtrlS(this::save);
|
||||
area.setText(content);
|
||||
area.setCaretPosition(0);
|
||||
area.setSyntaxEditingStyle(SyntaxLanguage.detectLanguage(pluginName, content).getSyntaxConstant());
|
||||
content = null;
|
||||
|
||||
JButton run = new JButton("Run");
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu menu = new TranslatedJMenu("File", Translation.FILE);
|
||||
JMenuItem menuRun = new TranslatedJMenuItem("Run", Translation.RUN);
|
||||
menuSaveAs = new TranslatedJMenuItem("Save As...", Translation.SAVE_AS);
|
||||
menuSave = new TranslatedJMenuItem("Save...", Translation.SAVE);
|
||||
menuSave.setVisible(false);
|
||||
|
||||
menuBar.add(menu);
|
||||
menu.add(menuRun);
|
||||
menu.add(menuSaveAs);
|
||||
menu.add(menuSave);
|
||||
|
||||
setJMenuBar(menuBar);
|
||||
add(area.getScrollPane());
|
||||
add(run, BorderLayout.SOUTH);
|
||||
|
||||
run.addActionListener((l)->runPlugin());
|
||||
menuRun.addActionListener((l)->runPlugin());
|
||||
menuSaveAs.addActionListener((l)-> save());
|
||||
menuSave.addActionListener((l)-> save());
|
||||
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
public void runPlugin()
|
||||
{
|
||||
File tempFile = new File(tempDirectory + fs + "temp" + MiscUtils.randomString(32) + fs + pluginName);
|
||||
tempFile.getParentFile().mkdirs();
|
||||
|
||||
try
|
||||
{
|
||||
//write to temporary file location
|
||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), area.getText(), false);
|
||||
//run plugin from that location
|
||||
PluginManager.runPlugin(tempFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
new ExceptionUI(e);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
tempFile.getParentFile().delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPluginName(String name)
|
||||
{
|
||||
this.pluginName = name;
|
||||
setTitle("Editing BCV Plugin: " + name);
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
Thread exportThread = new Thread(() ->
|
||||
{
|
||||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
if(savePath == null)
|
||||
{
|
||||
final String ext = FileNameUtils.getExtension(pluginName);
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Save Plugin",
|
||||
"BCV Plugin",
|
||||
ext);
|
||||
|
||||
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
Configuration.lastDirectory = fc.getSelectedFile().getAbsolutePath();
|
||||
File file = fc.getSelectedFile();
|
||||
String path = file.getAbsolutePath();
|
||||
|
||||
//auto append extension
|
||||
if (!path.endsWith("." + ext))
|
||||
path = path + "." + ext;
|
||||
|
||||
if (!DialogueUtils.canOverwriteFile(path))
|
||||
return;
|
||||
|
||||
//swap from save-as to having a defined path each save
|
||||
setSourceFile(new File(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DiskWriter.replaceFile(savePath.getAbsolutePath(), area.getText(), false);
|
||||
addRecentPlugin(savePath);
|
||||
}, "Plugin Editor Save");
|
||||
exportThread.start();
|
||||
}
|
||||
|
||||
public void setSourceFile(File file)
|
||||
{
|
||||
menuSaveAs.setVisible(false);
|
||||
menuSave.setVisible(true);
|
||||
savePath = file;
|
||||
setPluginName(file.getAbsolutePath());
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
|||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
|
@ -39,7 +40,7 @@ public class ResourceDecompiling
|
|||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Zip Export",
|
||||
"Zip Archives",
|
||||
"zip");
|
||||
|
@ -54,18 +55,8 @@ public class ResourceDecompiling
|
|||
if (!file.getAbsolutePath().endsWith(".zip"))
|
||||
file = new File(file.getAbsolutePath() + ".zip");
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(file))
|
||||
return;
|
||||
|
||||
final File javaSucks = file;
|
||||
final String path = MiscUtils.append(file, ".zip"); // cheap hax cause string is final
|
||||
|
@ -207,7 +198,7 @@ public class ResourceDecompiling
|
|||
return;
|
||||
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Java Files",
|
||||
"Java Source Files",
|
||||
"java");
|
||||
|
@ -221,18 +212,8 @@ public class ResourceDecompiling
|
|||
BytecodeViewer.viewer.updateBusyStatus(true);
|
||||
final String path = MiscUtils.append(file, ".java"); // cheap hax because string is final
|
||||
|
||||
if (new File(path).exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(path))
|
||||
return;
|
||||
|
||||
JOptionPane pane = new JOptionPane(
|
||||
"What decompiler will you use?");
|
||||
|
|
|
@ -5,10 +5,7 @@ import the.bytecode.club.bytecodeviewer.Configuration;
|
|||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter;
|
||||
import the.bytecode.club.bytecodeviewer.util.APKTool;
|
||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
|
@ -73,7 +70,7 @@ public class APKExport implements Exporter
|
|||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select APK Export",
|
||||
"Android APK",
|
||||
"apk");
|
||||
|
@ -90,18 +87,8 @@ public class APKExport implements Exporter
|
|||
output = output + ".apk";
|
||||
|
||||
final File file2 = new File(output);
|
||||
if (file2.exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(file2))
|
||||
return;
|
||||
|
||||
Thread saveThread = new Thread(() ->
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
|||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter;
|
||||
import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
|
@ -36,7 +37,7 @@ public class DexExport implements Exporter
|
|||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select DEX Export",
|
||||
"Android DEX Files",
|
||||
"dex");
|
||||
|
@ -53,18 +54,8 @@ public class DexExport implements Exporter
|
|||
output = output + ".dex";
|
||||
|
||||
File outputPath = new File(output);
|
||||
if (outputPath.exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(outputPath))
|
||||
return;
|
||||
|
||||
Thread saveAsJar = new Thread(() ->
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ import the.bytecode.club.bytecodeviewer.gui.components.ExportJar;
|
|||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
|
@ -30,7 +31,7 @@ public class RunnableJarExporter implements Exporter
|
|||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Jar Export",
|
||||
"Jar Archives",
|
||||
"jar");
|
||||
|
@ -46,18 +47,8 @@ public class RunnableJarExporter implements Exporter
|
|||
if (!path.endsWith(".jar"))
|
||||
path = path + ".jar";
|
||||
|
||||
if (new File(path).exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(path))
|
||||
return;
|
||||
|
||||
new ExportJar(path).setVisible(true);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import the.bytecode.club.bytecodeviewer.Configuration;
|
|||
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
import the.bytecode.club.bytecodeviewer.resources.exporting.Exporter;
|
||||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -30,7 +31,7 @@ public class ZipExport implements Exporter
|
|||
if (BytecodeViewer.viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
|
||||
return;
|
||||
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Zip Export",
|
||||
"Zip Archives",
|
||||
"zip");
|
||||
|
@ -45,18 +46,8 @@ public class ZipExport implements Exporter
|
|||
if (!file.getAbsolutePath().endsWith(".zip"))
|
||||
file = new File(file.getAbsolutePath() + ".zip");
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!DialogueUtils.canOverwriteFile(file))
|
||||
return;
|
||||
|
||||
final File file2 = file;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public enum Language
|
|||
printMissingLanguageKeys();
|
||||
|
||||
HashMap<String, String> translationMap = BytecodeViewer.gson.fromJson(
|
||||
IOUtils.toString(Resources.class.getResourceAsStream(resourcePath), StandardCharsets.UTF_8),
|
||||
Resources.loadResourceAsString(resourcePath),
|
||||
new TypeToken<HashMap<String, String>>(){}.getType());
|
||||
|
||||
for(Translation translation : Translation.values())
|
||||
|
@ -100,7 +100,7 @@ public enum Language
|
|||
return;
|
||||
|
||||
LinkedMap<String, String> translationMap = BytecodeViewer.gson.fromJson(
|
||||
IOUtils.toString(Resources.class.getResourceAsStream(resourcePath), StandardCharsets.UTF_8),
|
||||
Resources.loadResourceAsString(resourcePath),
|
||||
new TypeToken<LinkedMap<String, String>>(){}.getType());
|
||||
|
||||
HashSet<String> existingKeys = new HashSet<>();
|
||||
|
|
|
@ -14,6 +14,8 @@ public enum Translation
|
|||
RELOAD_RESOURCES,
|
||||
RUN,
|
||||
COMPILE,
|
||||
SAVE,
|
||||
SAVE_AS,
|
||||
SAVE_AS_RUNNABLE_JAR,
|
||||
SAVE_AS_ZIP,
|
||||
SAVE_AS_DEX,
|
||||
|
@ -79,6 +81,8 @@ public enum Translation
|
|||
PLUGINS,
|
||||
OPEN_PLUGIN,
|
||||
RECENT_PLUGINS,
|
||||
NEW_JAVA_PLUGIN,
|
||||
NEW_JAVASCRIPT_PLUGIN,
|
||||
CODE_SEQUENCE_DIAGRAM,
|
||||
MALICIOUS_CODE_SCANNER,
|
||||
SHOW_MAIN_METHODS,
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package the.bytecode.club.bytecodeviewer.util;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialogue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
* @since 7/1/2021
|
||||
*/
|
||||
public class DialogueUtils
|
||||
{
|
||||
/**
|
||||
* Asks if the user would like to overwrite the file
|
||||
*/
|
||||
public static boolean canOverwriteFile(String filePath)
|
||||
{
|
||||
return canOverwriteFile(new File(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks if the user would like to overwrite the file
|
||||
*/
|
||||
public static boolean canOverwriteFile(File file) {
|
||||
if (file.exists())
|
||||
{
|
||||
MultipleChoiceDialogue dialogue = new MultipleChoiceDialogue("Bytecode Viewer - Overwrite File",
|
||||
"Are you sure you wish to overwrite this existing file?",
|
||||
new String[]{"Yes", "No"});
|
||||
|
||||
if (dialogue.promptChoice() == 0) {
|
||||
file.delete();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package the.bytecode.club.bytecodeviewer.util;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
@ -12,7 +13,16 @@ import java.awt.event.KeyEvent;
|
|||
public class KeyEventDispatch implements KeyEventDispatcher
|
||||
{
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent e) {
|
||||
public boolean dispatchKeyEvent(KeyEvent e)
|
||||
{
|
||||
//hardcoded check for searchable syntax panes, this allows specific panels to ctrl + s save externally
|
||||
if(e.getSource() instanceof SearchableRSyntaxTextArea)
|
||||
{
|
||||
SearchableRSyntaxTextArea rSyntaxTextArea = (SearchableRSyntaxTextArea) e.getSource();
|
||||
if(rSyntaxTextArea.getOnCtrlS() != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
BytecodeViewer.checkHotKey(e);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public class VersionChecker implements Runnable
|
|||
}
|
||||
else if (result == 1)
|
||||
{
|
||||
JFileChooser fc = new FileChooser(new File(Configuration.lastDirectory),
|
||||
JFileChooser fc = new FileChooser(Configuration.getLastDirectory(),
|
||||
"Select Save File",
|
||||
"Zip Archives",
|
||||
"zip");
|
||||
|
|
41
src/main/resources/templates/Template.java
Normal file
41
src/main/resources/templates/Template.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
import the.bytecode.club.bytecodeviewer.api.*;
|
||||
import java.util.ArrayList;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
public class Template extends Plugin
|
||||
{
|
||||
PluginConsole gui = new PluginConsole("Java Template");
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
@Override
|
||||
public void execute(ArrayList<ClassNode> classNodeList)
|
||||
{
|
||||
gui.setVisible(true); //show the console
|
||||
out("Class Nodes: " + classNodeList.size());
|
||||
|
||||
//iterate through each class node
|
||||
for(ClassNode cn : classNodeList)
|
||||
process(cn);
|
||||
|
||||
BytecodeViewer.hideFrame(gui, 10000); //hides the console after 10 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Process each class node
|
||||
*/
|
||||
public void process(ClassNode cn)
|
||||
{
|
||||
out("Node: " + cn.name + ".class");
|
||||
//TODO developer plugin code goes here
|
||||
}
|
||||
|
||||
/**
|
||||
* Print to console
|
||||
*/
|
||||
public void out(String text)
|
||||
{
|
||||
gui.appendText(text);
|
||||
}
|
||||
}
|
35
src/main/resources/templates/Template.js
Normal file
35
src/main/resources/templates/Template.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
var BCV = Java.type("the.bytecode.club.bytecodeviewer.api.BytecodeViewer");
|
||||
var PluginConsole = Java.type("the.bytecode.club.bytecodeviewer.api.PluginConsole");
|
||||
var gui = new PluginConsole("Javascript Template");
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
function execute(classNodeList)
|
||||
{
|
||||
gui.setVisible(true); //show the console
|
||||
out("Class Nodes: " + classNodeList.size());
|
||||
|
||||
//iterate through each class node
|
||||
for (index = 0; index < classNodeList.length; index++)
|
||||
process(classNodeList[index]);
|
||||
|
||||
BCV.hideFrame(gui, 10000); //hides the console after 10 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Process each class node
|
||||
*/
|
||||
function process(cn)
|
||||
{
|
||||
out("Node: " + cn.name + ".class");
|
||||
//TODO developer plugin code goes here
|
||||
}
|
||||
|
||||
/**
|
||||
* Print to console
|
||||
*/
|
||||
function out(text)
|
||||
{
|
||||
gui.appendText(text);
|
||||
}
|
Loading…
Reference in a new issue