From b81577c6f0404657d69cc2da9e92b50c1bbafc04 Mon Sep 17 00:00:00 2001 From: Konloch Date: Mon, 12 Jul 2021 06:59:26 -0700 Subject: [PATCH] Autodetect Python CLI Still a WIP --- .../club/bytecodeviewer/BytecodeViewer.java | 2 - .../bytecodeviewer/SettingsSerializer.java | 4 + .../compilers/impl/KrakatauAssembler.java | 14 +- .../decompilers/impl/KrakatauDecompiler.java | 41 ++-- .../impl/KrakatauDisassembler.java | 27 ++- .../gui/components/HTMLPane.java | 4 +- .../resources/ExternalResources.java | 179 ++++++++++-------- .../club/bytecodeviewer/util/Enjarify.java | 9 +- 8 files changed, 161 insertions(+), 119 deletions(-) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index f423e749..d6534705 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -633,8 +633,6 @@ public class BytecodeViewer /** * because Smali and Baksmali System.exit if it failed - * - * @param i */ public static void exit(int i) { } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/SettingsSerializer.java b/src/main/java/the/bytecode/club/bytecodeviewer/SettingsSerializer.java index 8147c65b..b314b9ba 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/SettingsSerializer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/SettingsSerializer.java @@ -193,6 +193,8 @@ public class SettingsSerializer save(BytecodeViewer.viewer.viewPane3.isPaneEditable()); save(Configuration.javaTools); + save(Configuration.python2Extra); + save(Configuration.python3Extra); } catch (Exception e) { BytecodeViewer.handleException(e); } @@ -352,6 +354,8 @@ public class SettingsSerializer BytecodeViewer.viewer.viewPane3.setPaneEditable(asBoolean(133)); Configuration.javaTools = asString(134); + Configuration.python2Extra = asString(135); + Configuration.python3Extra = asString(136); } catch (Exception e) { //ignore because errors are expected, first start up and outdated settings. e.printStackTrace(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/impl/KrakatauAssembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/impl/KrakatauAssembler.java index d92979fd..1ba9f36b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/impl/KrakatauAssembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/impl/KrakatauAssembler.java @@ -8,6 +8,7 @@ import java.util.Objects; import me.konloch.kontainer.io.DiskWriter; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.ArrayUtils; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Constants; @@ -46,7 +47,7 @@ public class KrakatauAssembler extends InternalCompiler @Override public byte[] compile(String contents, String name) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return null; String origName = MiscUtils.randomString(20); @@ -68,14 +69,19 @@ public class KrakatauAssembler extends InternalCompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "assemble.py", "-out", tempDirectory.getAbsolutePath(), tempJ.getAbsolutePath() - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDecompiler.java index cff9c937..3edb396d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDecompiler.java @@ -9,8 +9,8 @@ import java.io.StringWriter; import java.util.Arrays; import java.util.stream.Collectors; import me.konloch.kontainer.io.DiskReader; +import org.apache.commons.lang3.ArrayUtils; import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bootloader.resource.ExternalResource; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Constants; @@ -69,7 +69,7 @@ public class KrakatauDecompiler extends InternalDecompiler public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return "You need to set your Python 2.7 path!"; ExternalResources.getSingleton().rtCheck(); @@ -93,8 +93,13 @@ public class KrakatauDecompiler extends InternalDecompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3 @@ -104,7 +109,7 @@ public class KrakatauDecompiler extends InternalDecompiler "-out", krakatauTempDir.getAbsolutePath(), cn.name + ".class" - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); @@ -149,7 +154,7 @@ public class KrakatauDecompiler extends InternalDecompiler @Override public String decompileClassNode(ClassNode cn, byte[] b) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return "You need to set your Python 2.7 path!"; if (Configuration.rt.isEmpty()) { @@ -173,8 +178,13 @@ public class KrakatauDecompiler extends InternalDecompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3 @@ -184,7 +194,7 @@ public class KrakatauDecompiler extends InternalDecompiler "-out", tempDirectory.getAbsolutePath(), cn.name + ".class" - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); @@ -232,7 +242,7 @@ public class KrakatauDecompiler extends InternalDecompiler @Override public void decompileToZip(String sourceJar, String zipName) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return; ExternalResources.getSingleton().rtCheck(); @@ -250,8 +260,13 @@ public class KrakatauDecompiler extends InternalDecompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "decompile.py", "-skip", //love you storyyeller <3 @@ -261,7 +276,7 @@ public class KrakatauDecompiler extends InternalDecompiler "-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath() - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDisassembler.java index 15ee2cb3..4475b409 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/KrakatauDisassembler.java @@ -7,6 +7,7 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import me.konloch.kontainer.io.DiskReader; +import org.apache.commons.lang3.ArrayUtils; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Configuration; @@ -48,7 +49,7 @@ public class KrakatauDisassembler extends InternalDecompiler { @Override public String decompileClassNode(ClassNode cn, byte[] b) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return "You need to set your Python 2.7 path!"; String s = ExceptionUI.SEND_STACKTRACE_TO_NL; @@ -60,8 +61,13 @@ public class KrakatauDisassembler extends InternalDecompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "disassemble.py", "-path", @@ -69,7 +75,7 @@ public class KrakatauDisassembler extends InternalDecompiler "-out", tempDirectory.getAbsolutePath(), cn.name + ".class" - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); @@ -113,7 +119,7 @@ public class KrakatauDisassembler extends InternalDecompiler @Override public void decompileToZip(String sourceJar, String zipName) { - if(!ExternalResources.getSingleton().hasSetPythonCommand()) + if(!ExternalResources.getSingleton().hasSetPython2Command()) return; String ran = MiscUtils.randomString(32); @@ -124,8 +130,13 @@ public class KrakatauDisassembler extends InternalDecompiler try { BytecodeViewer.sm.pauseBlocking(); - ProcessBuilder pb = new ProcessBuilder( - Configuration.python2, + + String[] pythonCommands = new String[]{Configuration.python2}; + if(!Configuration.python2Extra.isEmpty()) + pythonCommands = ArrayUtils.addAll(pythonCommands, Configuration.python2Extra); + + ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( + pythonCommands, "-O", //love you storyyeller <3 krakatauWorkingDirectory + fs + "disassemble.py", "-path", @@ -133,7 +144,7 @@ public class KrakatauDisassembler extends InternalDecompiler "-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath() - ); + )); Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java index abb070c5..f7b47e8d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/HTMLPane.java @@ -34,8 +34,8 @@ public class HTMLPane extends JEditorPane text = text.replace("{java}", Configuration.java); text = text.replace("{javac}", Configuration.javac); text = text.replace("{bcvDir}", BCVDir.getAbsolutePath()); - text = text.replace("{python}", Configuration.python2); - text = text.replace("{python3}", Configuration.python3); + text = text.replace("{python}", Configuration.python2+" " + Configuration.python2Extra); + text = text.replace("{python3}", Configuration.python3 + " " + Configuration.python3Extra); text = text.replace("{rt}", Configuration.rt); text = text.replace("{lib}", Configuration.library); text = text.replace("{krakatauVersion}", krakatauVersion); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ExternalResources.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/ExternalResources.java index da8d8827..dc8b2462 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/ExternalResources.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/ExternalResources.java @@ -49,36 +49,21 @@ public class ExternalResources } /** - * Auto-detect the Java command + * Auto-detect Java via command-line */ public String getJavaCommand(boolean blockTillSelected) { - boolean empty = Configuration.java.isEmpty(); - - if(!empty) + if(!Configuration.java.isEmpty()) return Configuration.java; - try - { - BytecodeViewer.sm.pauseBlocking(); - //read the version output to verify it exists - ProcessBuilder pb = new ProcessBuilder("java", "-version"); - Process p = pb.start(); - p.waitFor(); - - if(readProcess(p).toLowerCase().contains("java version")) - { - Configuration.java = "java"; //java is set - return Configuration.java; - } - } - catch (Exception e) { } //ignore - finally - { - BytecodeViewer.sm.resumeBlocking(); - } + //check CLI for java + testCommand(new String[]{"java", "-version"}, "java version", ()->{ + Configuration.java = "java"; + }); + if(!Configuration.java.isEmpty()) + return Configuration.java; - //TODO auto-detect the Java path + //TODO auto-detect the JRE path boolean block = true; while (Configuration.java.isEmpty() && block) { @@ -92,7 +77,7 @@ public class ExternalResources } /** - * Check if the python command has been set + * Check if java tools has been set */ public boolean hasJavaToolsSet() { @@ -100,7 +85,7 @@ public class ExternalResources } /** - * Auto-detect the Java command + * Auto-detect Java tools.jar */ public String getJavaTools(boolean blockTillSelected) { @@ -109,7 +94,7 @@ public class ExternalResources if(!empty) return Configuration.javaTools; - //TODO auto-detect the Java path + //TODO auto-detect the JDK path boolean block = true; while (Configuration.javaTools.isEmpty() && block) { @@ -123,75 +108,44 @@ public class ExternalResources } /** - * Check if the python command has been set + * Check if the python 2 command has been set */ - public boolean hasSetPythonCommand() + public boolean hasSetPython2Command() { - return !getPythonCommand(false).isEmpty(); + return !getPython2Command(false).isEmpty(); } /** - * Auto-detect the Java command + * Auto-detect python 2 via command-line */ - public String getPythonCommand(boolean blockTillSelected) + public String getPython2Command(boolean blockTillSelected) { - boolean empty = Configuration.java.isEmpty(); + if(!Configuration.python2.isEmpty()) + return Configuration.python2; - if(!empty) - return Configuration.java; //check using python CLI flag - try - { - BytecodeViewer.sm.pauseBlocking(); - - //read the version output to verify python 2 - ProcessBuilder pb = new ProcessBuilder("python", "-2", "--version"); - Process p = pb.start(); - p.waitFor(); - - //set python path - if(readProcess(p).toLowerCase().contains("python 2")) - { - Configuration.python2 = "python"; - Configuration.python2Extra = "-2"; - return Configuration.python2; - } - } - catch (Exception e) { } //ignore - finally - { - BytecodeViewer.sm.resumeBlocking(); - } + testCommand(new String[]{"python", "-2", "--version"}, "python 2", ()->{ + Configuration.python2 = "python"; + Configuration.python2Extra = "-2"; + }); + if(!Configuration.python2.isEmpty()) + return Configuration.python2; + //check if 'python' command is bound as python 2.X - try - { - BytecodeViewer.sm.pauseBlocking(); - - //read the version output to verify python 2 - ProcessBuilder pb = new ProcessBuilder("python", "--version"); - Process p = pb.start(); - p.waitFor(); - - //set python path - if(readProcess(p).toLowerCase().contains("python 2")) - { - Configuration.python2 = "python"; - return Configuration.python2; - } - } - catch (Exception e) { } //ignore - finally - { - BytecodeViewer.sm.resumeBlocking(); - } + testCommand(new String[]{"python", "--version"}, "python 2", ()->{ + Configuration.python2 = "python"; + }); + if(!Configuration.python2.isEmpty()) + return Configuration.python2; - //TODO auto-detect the Python path + + //TODO auto-detect the Python path (C:/Program Files/Python) boolean block = true; while (Configuration.python2.isEmpty() && block) { - BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path."); + BytecodeViewer.showMessage("You need to set your Python 2.7 (or PyPy 2.7 for speed) executable path."); selectPython2(); block = !blockTillSelected; //signal block flag off } @@ -199,6 +153,39 @@ public class ExternalResources return Configuration.python2; } + /** + * Check if the python 3 command has been set + */ + public boolean hasSetPython3Command() + { + return !getPython3Command(false).isEmpty(); + } + + /** + * Auto-detect python 3 via command-line + */ + public String getPython3Command(boolean blockTillSelected) + { + //check if 'python' command is bound as python 2.X + testCommand(new String[]{"python", "--version"}, "python 3", ()->{ + Configuration.python3 = "python"; + }); + if(!Configuration.python3.isEmpty()) + return Configuration.python3; + + + //TODO auto-detect the Python path (C:/Program Files/Python) + boolean block = true; + while (Configuration.python3.isEmpty() && block) + { + BytecodeViewer.showMessage("You need to set your Python 3.x (or PyPy 3.x for speed) executable path."); + selectPython3(); + block = !blockTillSelected; //signal block flag off + } + + return Configuration.python3; + } + //rt.jar check public synchronized void rtCheck() { @@ -220,7 +207,7 @@ public class ExternalResources public void selectPython2() { final File file = DialogueUtils.fileChooser("Select Python 2.7 Executable", - "Python (Or PyPy for speed) 2.7 Executable", + "Python 2.7 (Or PyPy 2.7 for speed) Executable", "everything"); if(file == null) @@ -233,7 +220,7 @@ public class ExternalResources public void selectPython3() { final File file = DialogueUtils.fileChooser("Select Python 3.x Executable", - "Python (Or PyPy for speed) 3.x Executable", + "Python 3.x (Or PyPy 3.x for speed) Executable", "everything"); if(file == null) @@ -344,6 +331,33 @@ public class ExternalResources return null; } + /** + * Used to test the command-line for compatibility + */ + public void testCommand(String[] command, String matchingText, Runnable onMatch) + { + try + { + BytecodeViewer.sm.pauseBlocking(); + + //read the version output + ProcessBuilder pb = new ProcessBuilder(command); + Process p = pb.start(); + p.waitFor(); + + //check for matching text + if(readProcess(p).toLowerCase().contains(matchingText)) + { + onMatch.run(); + } + } + catch (Exception e) { } //ignore + finally + { + BytecodeViewer.sm.resumeBlocking(); + } + } + /** * @author https://stackoverflow.com/a/16714180 */ @@ -352,6 +366,7 @@ public class ExternalResources BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder builder = new StringBuilder(); String line; + while ((line = reader.readLine()) != null) { builder.append(line); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java index 05d9e5aa..9440537c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java @@ -40,15 +40,8 @@ public class Enjarify { * @param output the output .jar file */ public static synchronized void apk2Jar(File input, File output) { - if (Configuration.python3.isEmpty()) { - BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 3.x executable path."); - ExternalResources.getSingleton().selectPython3(); - } - - if (Configuration.python3.isEmpty()) { - BytecodeViewer.showMessage("You need to set Python!"); + if(!ExternalResources.getSingleton().hasSetPython3Command()) return; - } try { BytecodeViewer.sm.pauseBlocking();