Built-in Script Editor

Still a work in progress
This commit is contained in:
Konloch 2021-07-01 14:54:10 -07:00
parent d052d0e6d3
commit f3d5f25743
21 changed files with 498 additions and 111 deletions

View file

@ -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;

View 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(".");
}
}

View 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);

View file

@ -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.
*

View file

@ -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");

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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?");

View file

@ -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(() ->
{

View file

@ -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(() ->
{

View file

@ -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);
}

View file

@ -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;

View 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<>();

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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");

View 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);
}
}

View 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);
}