Merge branch 'Konloch:master' into go-to-enhancement
This commit is contained in:
commit
9860c9d63c
|
@ -1,68 +1,82 @@
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
|
import the.bytecode.club.bytecodeviewer.*;
|
||||||
import the.bytecode.club.bytecodeviewer.api.*;
|
import the.bytecode.club.bytecodeviewer.api.*;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
|
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** This is an example of a String Decrypter Java Plugin for BCV.
|
* * This is an example of a String Decrypter Java Plugin for BCV.
|
||||||
**
|
* *
|
||||||
** @author [Your-Name-Goes-Here]
|
* * @author [Your-Name-Goes-Here]
|
||||||
**/
|
**/
|
||||||
|
|
||||||
public class ExampleStringDecrypter extends Plugin {
|
public class ExampleStringDecrypter extends Plugin
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(List<ClassNode> classNodesList) {
|
public void execute(List<ClassNode> classNodesList)
|
||||||
|
{
|
||||||
PluginConsole gui = new PluginConsole("Example String Decrypter Java Edition");
|
PluginConsole gui = new PluginConsole("Example String Decrypter Java Edition");
|
||||||
|
|
||||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING",
|
MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING", "WARNING: This will load the classes into the JVM and execute the initialize function" + NL +
|
||||||
"WARNING: This will load the classes into the JVM and execute the initialize function"
|
"for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.", new String[]{"Continue", "Cancel"});
|
||||||
+ nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.",
|
|
||||||
new String[]{"Continue", "Cancel"});
|
|
||||||
|
|
||||||
if (dialog.promptChoice() == 0) {
|
if (dialog.promptChoice() == 0)
|
||||||
|
{
|
||||||
boolean needsWarning = false;
|
boolean needsWarning = false;
|
||||||
|
|
||||||
for (ClassNode cn : classNodesList) {
|
for (ClassNode cn : classNodesList)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
//load the class node into the classloader
|
//load the class node into the classloader
|
||||||
BCV.getClassNodeLoader().addClass(cn);
|
BCV.getClassNodeLoader().addClass(cn);
|
||||||
|
|
||||||
for (Object o : cn.fields.toArray()) {
|
for (Object o : cn.fields.toArray())
|
||||||
|
{
|
||||||
FieldNode f = (FieldNode) o;
|
FieldNode f = (FieldNode) o;
|
||||||
|
|
||||||
//if the class contains the field z, get the class object from the class node
|
//if the class contains the field z, get the class object from the class node
|
||||||
//then print out the value of the fields inside the class
|
//then print out the value of the fields inside the class
|
||||||
//if the strings get decrypted on init, this allows you to dump the current values
|
//if the strings get decrypted on init, this allows you to dump the current values
|
||||||
|
if (f.name.equals("z"))
|
||||||
if (f.name.equals("z")) {
|
{
|
||||||
try {
|
try
|
||||||
for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields()) {
|
{
|
||||||
|
for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields())
|
||||||
|
{
|
||||||
String s = (String) f2.get(null);
|
String s = (String) f2.get(null);
|
||||||
if (s != null && !s.isEmpty())
|
if (s != null && !s.isEmpty())
|
||||||
gui.appendText(cn + ":" + s);
|
gui.appendText(cn + ":" + s);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
gui.appendText("Failed loading class " + cn.name);
|
gui.appendText("Failed loading class " + cn.name);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
needsWarning = true;
|
needsWarning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsWarning) {
|
if (needsWarning)
|
||||||
BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them\n"
|
{
|
||||||
+ "makes sure you include ALL the libraries it requires.");
|
BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them" + NL +
|
||||||
|
"makes sure you include ALL the libraries it requires.");
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.setVisible(true);
|
gui.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,15 @@ import the.bytecode.club.bytecodeviewer.api.*;
|
||||||
** @author [Your Name Goes Here]
|
** @author [Your Name Goes Here]
|
||||||
**/
|
**/
|
||||||
|
|
||||||
public class Skeleton extends Plugin {
|
public class Skeleton extends Plugin
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(List<ClassNode> classNodesList) {
|
public void execute(List<ClassNode> classNodesList)
|
||||||
|
{
|
||||||
PluginConsole gui = new PluginConsole("Skeleton Title");
|
PluginConsole gui = new PluginConsole("Skeleton Title");
|
||||||
gui.setVisible(true);
|
gui.setVisible(true);
|
||||||
gui.appendText("executed skeleton example");
|
gui.appendText("executed skeleton example");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
|
@ -46,11 +46,17 @@ public class XposedGenerator extends Plugin
|
||||||
String className = viewer.getName();
|
String className = viewer.getName();
|
||||||
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
|
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
|
||||||
|
|
||||||
|
if (classnode == null)
|
||||||
|
{
|
||||||
|
BytecodeViewer.showMessage("Open A Classfile First");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Call XposedGenerator class
|
//Call XposedGenerator class
|
||||||
ParseChosenFileContent(className, classnode);
|
parseChosenFileContent(className, classnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ParseChosenFileContent(String classname, ClassNode classNode)
|
public static void parseChosenFileContent(String classname, ClassNode classNode)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -64,7 +70,9 @@ public class XposedGenerator extends Plugin
|
||||||
//Decompile using Fern
|
//Decompile using Fern
|
||||||
String decomp = decompilefern.decompileClassNode(classNode, cont);
|
String decomp = decompilefern.decompileClassNode(classNode, cont);
|
||||||
String[] xposedTemplateTypes = {"Empty", "Parameters", "Helper"};
|
String[] xposedTemplateTypes = {"Empty", "Parameters", "Helper"};
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"}) JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes);
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes);
|
||||||
|
|
||||||
//Set results of parsed methods into a list
|
//Set results of parsed methods into a list
|
||||||
List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
|
List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
|
||||||
String packgExtracted = ProcessContentExtractedPackage(decomp);
|
String packgExtracted = ProcessContentExtractedPackage(decomp);
|
||||||
|
@ -86,6 +94,7 @@ public class XposedGenerator extends Plugin
|
||||||
|
|
||||||
//output methods to pane box
|
//output methods to pane box
|
||||||
int result = JOptionPane.showConfirmDialog(null, myPanel, "Choose Template and Method for Xposed Module", JOptionPane.OK_CANCEL_OPTION);
|
int result = JOptionPane.showConfirmDialog(null, myPanel, "Choose Template and Method for Xposed Module", JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
myPanel.remove();
|
||||||
|
|
||||||
if (result == JOptionPane.OK_OPTION)
|
if (result == JOptionPane.OK_OPTION)
|
||||||
{
|
{
|
||||||
|
@ -129,13 +138,6 @@ public class XposedGenerator extends Plugin
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//TODO: Prompt save dialog
|
|
||||||
File file = new File("./XposedClassTest.java");
|
|
||||||
|
|
||||||
// if file doesn't exist, then create it
|
|
||||||
if (!file.exists())
|
|
||||||
file.createNewFile();
|
|
||||||
|
|
||||||
//Extract the package name only
|
//Extract the package name only
|
||||||
String packageNameOnly = packageName.substring(8, packageName.length() - 2).trim();
|
String packageNameOnly = packageName.substring(8, packageName.length() - 2).trim();
|
||||||
String classToHookNameOnly = classToHook;
|
String classToHookNameOnly = classToHook;
|
||||||
|
@ -151,18 +153,35 @@ public class XposedGenerator extends Plugin
|
||||||
String onlyFunction = CleanUpFunction(functionSplitValues);
|
String onlyFunction = CleanUpFunction(functionSplitValues);
|
||||||
|
|
||||||
//Write Xposed Class
|
//Write Xposed Class
|
||||||
String XposedClassText = "package androidpentesting.com.xposedmodule;" + "\r\n" + "import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" + "\r\n" + "import de.robv.android.xposed.XC_MethodHook;" + "\r\n" + "import de.robv.android.xposed.XposedBridge;" + "\r\n" + "import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;" + "\r\n" + "import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;" + "\r\n" + "\r\n" + "public class XposedClassTest implements IXposedHookLoadPackage {" + "\r\n" + "\r\n" + " public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" + "\r\n" + " String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\";" + "\r\n" + " String functionToHook = " + "\"" + onlyFunction + "\";" + "\r\n" + " if (lpparam.packageName.equals(" + "\"" + packageNameOnly + "\"" + ")){" + "\r" + "\n" + " XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);" + "\r\n" + "\r\n" + " findAndHookMethod(" + "\"" + onlyClass + "\"" + ", lpparam.classLoader, " + " \"" + onlyFunction + "\"" + ", int.class," + "\r\n" + " new XC_MethodHook() {" + "\r\n" + " @Override" + "\r\n" + " protected void beforeHookedMethod(MethodHookParam param) throws " + "Throwable {" + "\r\n" + " //TO BE FILLED BY ANALYST" + "\r\n" + " }" + "\r\n" + " });" + "\r\n" + " }" + "\r\n" + " }" + "\r\n" + "}" + "\r\n";
|
String XposedClassText = "package androidpentesting.com.xposedmodule;" + "\r\n"
|
||||||
FileWriter fw = new FileWriter(file.getAbsoluteFile());
|
+ "import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" + "\r\n"
|
||||||
BufferedWriter bw = new BufferedWriter(fw);
|
+ "import de.robv.android.xposed.XC_MethodHook;" + "\r\n"
|
||||||
bw.write(XposedClassText);
|
+ "import de.robv.android.xposed.XposedBridge;" + "\r\n"
|
||||||
bw.write("\r\n");
|
+ "import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;" + "\r\n"
|
||||||
bw.close();
|
+ "import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;" + "\r\n" + "\r\n"
|
||||||
|
+ "public class XposedClassTest implements IXposedHookLoadPackage {" + "\r\n" + "\r\n"
|
||||||
|
+ " public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" + "\r\n"
|
||||||
|
+ " String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\";" + "\r\n"
|
||||||
|
+ " String functionToHook = " + "\"" + onlyFunction + "\";" + "\r\n" + "\r\n"
|
||||||
|
+ " if (lpparam.packageName.equals(" + "\"" + packageNameOnly + "\"" + ")){" + "\r\n"
|
||||||
|
+ " XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);" + "\r\n" + "\r\n"
|
||||||
|
+ " findAndHookMethod(" + "\"" + onlyClass + "\"" + ", lpparam.classLoader, " + " \"" + onlyFunction + "\"" + ", int.class," + "\r\n"
|
||||||
|
+ " new XC_MethodHook() {" + "\r\n"
|
||||||
|
+ " @Override" + "\r\n"
|
||||||
|
+ " protected void beforeHookedMethod(MethodHookParam param) throws Throwable {" + "\r\n"
|
||||||
|
+ " //TO BE FILLED BY ANALYST" + "\r\n"
|
||||||
|
+ " }" + "\r\n"
|
||||||
|
+ " });" + "\r\n"
|
||||||
|
+ " }" + "\r\n"
|
||||||
|
+ " }" + "\r\n"
|
||||||
|
+ "}" + "\r\n";
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(null, "Xposed Module Generated");
|
PluginConsole gui = new PluginConsole("Xposed Code Generation");
|
||||||
|
gui.appendText(XposedClassText);
|
||||||
|
gui.setVisible(true);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
JOptionPane.showMessageDialog(null, "Error" + e);
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,4 +327,5 @@ public class XposedGenerator extends Plugin
|
||||||
String QUOTE = "'";
|
String QUOTE = "'";
|
||||||
return QUOTE + aText + QUOTE;
|
return QUOTE + aText + QUOTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
6
pom.xml
6
pom.xml
|
@ -54,6 +54,7 @@
|
||||||
<java-parser.version>3.26.2</java-parser.version>
|
<java-parser.version>3.26.2</java-parser.version>
|
||||||
<taskmanager.version>1.0.1</taskmanager.version>
|
<taskmanager.version>1.0.1</taskmanager.version>
|
||||||
<google-java-format.version>1.7</google-java-format.version> <!-- Newer versions require Java 11+ -->
|
<google-java-format.version>1.7</google-java-format.version> <!-- Newer versions require Java 11+ -->
|
||||||
|
<disk-lib.version>1.2.0</disk-lib.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
@ -395,6 +396,11 @@
|
||||||
<artifactId>google-java-format</artifactId>
|
<artifactId>google-java-format</artifactId>
|
||||||
<version>${google-java-format.version}</version>
|
<version>${google-java-format.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.konloch</groupId>
|
||||||
|
<artifactId>DiskLib</artifactId>
|
||||||
|
<version>${disk-lib.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- TODO Re-add for Graal.JS support -->
|
<!-- TODO Re-add for Graal.JS support -->
|
||||||
<!--<dependency>
|
<!--<dependency>
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
package me.konloch.kontainer.io;
|
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to load from the disk, optional caching
|
|
||||||
*
|
|
||||||
* @author Konloch
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DiskReader
|
|
||||||
{
|
|
||||||
|
|
||||||
public static Random random = new Random();
|
|
||||||
public static Map<String, List<String>> map = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to load from file, allows caching
|
|
||||||
*/
|
|
||||||
public synchronized static List<String> loadArrayList(String fileName, boolean cache)
|
|
||||||
{
|
|
||||||
List<String> array = new ArrayList<>();
|
|
||||||
if (!map.containsKey(fileName))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File file = new File(fileName);
|
|
||||||
if (!file.exists()) // doesn't exist, return empty
|
|
||||||
return array;
|
|
||||||
|
|
||||||
try (FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr))
|
|
||||||
{
|
|
||||||
String add;
|
|
||||||
|
|
||||||
while ((add = reader.readLine()) != null)
|
|
||||||
array.add(add);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cache)
|
|
||||||
map.put(fileName, array);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
array = map.get(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to load from file
|
|
||||||
*/
|
|
||||||
public synchronized static String loadAsString(String fileName) throws Exception
|
|
||||||
{
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
|
|
||||||
try (FileReader fr = new FileReader(fileName); BufferedReader reader = new BufferedReader(fr))
|
|
||||||
{
|
|
||||||
for (String add = reader.readLine(); add != null; add = reader.readLine())
|
|
||||||
{
|
|
||||||
s.append(EncodeUtils.unicodeToString(add)).append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to load a string via line number lineNumber = -1 means random.
|
|
||||||
*/
|
|
||||||
public static String loadString(String fileName, int lineNumber, boolean cache) throws Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
List<String> array;
|
|
||||||
if (!map.containsKey(fileName))
|
|
||||||
{
|
|
||||||
array = new ArrayList<>();
|
|
||||||
File file = new File(fileName);
|
|
||||||
|
|
||||||
try (FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr))
|
|
||||||
{
|
|
||||||
String add;
|
|
||||||
|
|
||||||
while ((add = reader.readLine()) != null)
|
|
||||||
array.add(add);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cache)
|
|
||||||
map.put(fileName, array);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
array = map.get(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineNumber == -1)
|
|
||||||
{
|
|
||||||
int size = array.size();
|
|
||||||
return array.get(random.nextInt(size));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return array.get(lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,214 +0,0 @@
|
||||||
package me.konloch.kontainer.io;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will save to disk
|
|
||||||
*
|
|
||||||
* @author Konloch
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DiskWriter
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to insert a difference string with preserving the file extension
|
|
||||||
*
|
|
||||||
* @param fileName The file name
|
|
||||||
* @param difference Normally an integer
|
|
||||||
* @return The filename with the difference inserted and the file extension
|
|
||||||
* preserved
|
|
||||||
*/
|
|
||||||
public static String insertFileName(String fileName, String difference)
|
|
||||||
{
|
|
||||||
String[] babe = fileName.split("\\.");
|
|
||||||
int count = 0;
|
|
||||||
int math = babe.length;
|
|
||||||
StringBuilder m = new StringBuilder();
|
|
||||||
|
|
||||||
for (String s2 : babe)
|
|
||||||
{
|
|
||||||
m.append(s2);
|
|
||||||
if (math - 2 == count)
|
|
||||||
m.append(difference).append(".");
|
|
||||||
else if (math - 1 != count)
|
|
||||||
m.append(".");
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a new line to the file, if it doesn't exist it will automatically
|
|
||||||
* create it.
|
|
||||||
*
|
|
||||||
* @param filename
|
|
||||||
* @param fileContents
|
|
||||||
* @param debug
|
|
||||||
*/
|
|
||||||
public static synchronized void writeNewLine(String filename, byte[] fileContents, boolean debug)
|
|
||||||
{
|
|
||||||
new File(filename).getParentFile().mkdirs();
|
|
||||||
String original = filename;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
boolean saved = false;
|
|
||||||
int failSafe = 0;
|
|
||||||
while (!saved && failSafe++ <= 42069)
|
|
||||||
{
|
|
||||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
|
||||||
{
|
|
||||||
writer.println(Arrays.toString(fileContents));
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Saved " + filename + " to disk");
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Failed saving, trying to save as " + filename);
|
|
||||||
if (original.contains("."))
|
|
||||||
{
|
|
||||||
filename = insertFileName(original, "" + counter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
filename = original + counter;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a string to the file
|
|
||||||
*/
|
|
||||||
public static void writeNewLine(String filename, String lineToWrite)
|
|
||||||
{
|
|
||||||
writeNewLine(filename, lineToWrite, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a string to the file
|
|
||||||
*/
|
|
||||||
public static synchronized void writeNewLine(String filename, String lineToWrite, boolean debug)
|
|
||||||
{
|
|
||||||
new File(filename).getParentFile().mkdirs();
|
|
||||||
String original = filename;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
boolean saved = false;
|
|
||||||
int failSafe = 0;
|
|
||||||
while (!saved && failSafe++ <= 42069)
|
|
||||||
{
|
|
||||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
|
||||||
{
|
|
||||||
writer.println(lineToWrite);
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Saved " + filename + ">" + lineToWrite + " to disk");
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Failed saving, trying to save as " + filename);
|
|
||||||
if (original.contains("."))
|
|
||||||
{
|
|
||||||
filename = insertFileName(original, "" + counter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
filename = original + counter;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the original file if it exists, then writes the fileContents[] to
|
|
||||||
* the file.
|
|
||||||
*
|
|
||||||
* @param filename
|
|
||||||
* @param fileContents
|
|
||||||
* @param debug
|
|
||||||
*/
|
|
||||||
public static synchronized void replaceFileBytes(String filename, byte[] fileContents, boolean debug)
|
|
||||||
{
|
|
||||||
new File(filename).getParentFile().mkdirs();
|
|
||||||
File f = new File(filename);
|
|
||||||
if (f.exists())
|
|
||||||
f.delete();
|
|
||||||
|
|
||||||
String original = filename;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
boolean saved = false;
|
|
||||||
int failSafe = 0;
|
|
||||||
while (!saved && failSafe++ <= 42069)
|
|
||||||
{
|
|
||||||
try (FileOutputStream stream = new FileOutputStream(filename))
|
|
||||||
{
|
|
||||||
stream.write(fileContents);
|
|
||||||
stream.flush();
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Saved " + filename + " to disk");
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Failed saving, trying to save as " + filename);
|
|
||||||
if (original.contains("."))
|
|
||||||
{
|
|
||||||
filename = insertFileName(original, "" + counter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
filename = original + counter;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the original file if it exists, then writes the lineToWrite to
|
|
||||||
* the file.
|
|
||||||
*
|
|
||||||
* @param filename
|
|
||||||
* @param lineToWrite
|
|
||||||
* @param debug
|
|
||||||
*/
|
|
||||||
public static synchronized void replaceFile(String filename, String lineToWrite, boolean debug)
|
|
||||||
{
|
|
||||||
new File(filename).getParentFile().mkdirs();
|
|
||||||
File f = new File(filename);
|
|
||||||
if (f.exists())
|
|
||||||
f.delete();
|
|
||||||
String original = filename;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
boolean saved = false;
|
|
||||||
int failSafe = 0;
|
|
||||||
while (!saved && failSafe++ <= 42069)
|
|
||||||
{
|
|
||||||
try (FileWriter fr = new FileWriter(filename, true); BufferedWriter bw = new BufferedWriter(fr); PrintWriter writer = new PrintWriter(bw))
|
|
||||||
{
|
|
||||||
writer.println(lineToWrite);
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Saved " + filename + ">" + lineToWrite + " to disk");
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
System.out.println("Failed saving, trying to save as " + filename + "_");
|
|
||||||
if (original.contains("."))
|
|
||||||
{
|
|
||||||
filename = insertFileName(original, "" + counter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
filename = original + counter;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,8 +20,8 @@ package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.konloch.disklib.DiskReader;
|
||||||
import com.konloch.taskmanager.TaskManager;
|
import com.konloch.taskmanager.TaskManager;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.api.BCV;
|
import the.bytecode.club.bytecodeviewer.api.BCV;
|
||||||
|
@ -588,7 +588,7 @@ public class BytecodeViewer
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PluginWriter writer = new PluginWriter(DiskReader.loadAsString(file.getAbsolutePath()), file.getName());
|
PluginWriter writer = new PluginWriter(DiskReader.readString(file.getAbsolutePath()), file.getName());
|
||||||
writer.setSourceFile(file);
|
writer.setSourceFile(file);
|
||||||
writer.setVisible(true);
|
writer.setVisible(true);
|
||||||
}
|
}
|
||||||
|
@ -693,7 +693,10 @@ public class BytecodeViewer
|
||||||
*/
|
*/
|
||||||
public static void handleException(Throwable t, String author)
|
public static void handleException(Throwable t, String author)
|
||||||
{
|
{
|
||||||
new ExceptionUI(t, author);
|
if(CLI.isCLI())
|
||||||
|
t.printStackTrace();
|
||||||
|
else
|
||||||
|
new ExceptionUI(t, author);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -47,7 +47,8 @@ public class Constants
|
||||||
// + You can control the java arguments (more memory & stack)
|
// + You can control the java arguments (more memory & stack)
|
||||||
//the cons to this are:
|
//the cons to this are:
|
||||||
// + If you could keep it in memory, now you need to write to disk (windows limitations)
|
// + If you could keep it in memory, now you need to write to disk (windows limitations)
|
||||||
public static final boolean LAUNCH_DECOMPILERS_IN_NEW_PROCESS = false; //TODO
|
public static final boolean LAUNCH_DECOMPILERS_IN_NEW_PROCESS = false; //TODO - work in progress
|
||||||
|
// FernFlower is added
|
||||||
|
|
||||||
//could be automatic by checking if it's loaded a class named whatever for a library
|
//could be automatic by checking if it's loaded a class named whatever for a library
|
||||||
//maybe it could be automatic with some maven plugin?
|
//maybe it could be automatic with some maven plugin?
|
||||||
|
@ -88,6 +89,11 @@ public class Constants
|
||||||
public static String krakatauWorkingDirectory = getBCVDirectory() + FS + "krakatau_" + krakatauVersion;
|
public static String krakatauWorkingDirectory = getBCVDirectory() + FS + "krakatau_" + krakatauVersion;
|
||||||
public static String enjarifyWorkingDirectory = getBCVDirectory() + FS + "enjarify_" + enjarifyVersion;
|
public static String enjarifyWorkingDirectory = getBCVDirectory() + FS + "enjarify_" + enjarifyVersion;
|
||||||
|
|
||||||
|
//DEV_FLAG_* are used for enabling tooling / systems reserved for development.
|
||||||
|
//As a precaution, all variables in here MUST ensure we are working in DEV_MODE only.
|
||||||
|
//Nothing here is meant for user level production, only development level production.
|
||||||
|
public static final boolean DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS = DEV_MODE && false; //enable true / false to disable
|
||||||
|
|
||||||
public static final PrintStream ERR = System.err;
|
public static final PrintStream ERR = System.err;
|
||||||
public static final PrintStream OUT = System.out;
|
public static final PrintStream OUT = System.out;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whenever a key is pressed on the swing UI it should get logged here
|
* Whenever a key is pressed on the swing UI it should get logged here
|
||||||
|
@ -121,8 +122,18 @@ public class GlobalHotKeys
|
||||||
BytecodeViewer.updateBusyStatus(true);
|
BytecodeViewer.updateBusyStatus(true);
|
||||||
Thread jarExport = new Thread(() ->
|
Thread jarExport = new Thread(() ->
|
||||||
{
|
{
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
try
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
{
|
||||||
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
BytecodeViewer.handleException(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
}
|
||||||
}, "Jar Export");
|
}, "Jar Export");
|
||||||
jarExport.start();
|
jarExport.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,15 @@
|
||||||
package the.bytecode.club.bytecodeviewer;
|
package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.BytecodeViewer.gson;
|
import static the.bytecode.club.bytecodeviewer.BytecodeViewer.gson;
|
||||||
|
@ -40,22 +42,29 @@ public class Settings
|
||||||
{
|
{
|
||||||
public static boolean firstBoot = true; //stays true after settings load on first boot
|
public static boolean firstBoot = true; //stays true after settings load on first boot
|
||||||
public static boolean hasSetLanguageAsSystemLanguage = false;
|
public static boolean hasSetLanguageAsSystemLanguage = false;
|
||||||
private static List<String> recentPlugins;
|
private static List<String> recentPlugins = new ArrayList<>();
|
||||||
private static List<String> recentFiles;
|
private static List<String> recentFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
//decompilers will automatically delete their temp files, useful to turn off if you want to quickly debug a decompilers results
|
||||||
|
public static boolean DECOMPILERS_AUTOMATICALLY_CLEANUP = true;
|
||||||
|
public static boolean DECOMPILERS_UNIFORM_SYNTAX_FORMATTING = false; //TODO
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
File filesFile = new File(getBCVDirectory() + FS + "recentfiles.bcv");
|
||||||
|
File pluginsFile = new File(getBCVDirectory() + FS + "recentplugins.bcv");
|
||||||
|
|
||||||
if (new File(FILES_NAME).exists())
|
if (new File(FILES_NAME).exists())
|
||||||
recentFiles = gson.fromJson(DiskReader.loadAsString(FILES_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
recentFiles = gson.fromJson(DiskReader.readString(FILES_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||||
else
|
else if (filesFile.exists())
|
||||||
recentFiles = DiskReader.loadArrayList(getBCVDirectory() + FS + "recentfiles.bcv", false);
|
recentFiles = Arrays.asList(DiskReader.readArray(filesFile));
|
||||||
|
|
||||||
if (new File(PLUGINS_NAME).exists())
|
if (new File(PLUGINS_NAME).exists())
|
||||||
recentPlugins = gson.fromJson(DiskReader.loadAsString(PLUGINS_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
recentPlugins = gson.fromJson(DiskReader.readString(PLUGINS_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||||
else
|
else if (pluginsFile.exists())
|
||||||
recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + FS + "recentplugins.bcv", false);
|
recentPlugins = Arrays.asList(DiskReader.readArray(pluginsFile));
|
||||||
|
|
||||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||||
|
@ -76,7 +85,7 @@ public class Settings
|
||||||
recentFiles.remove(f.getAbsolutePath()); // already added on the list
|
recentFiles.remove(f.getAbsolutePath()); // already added on the list
|
||||||
recentFiles.add(0, f.getAbsolutePath());
|
recentFiles.add(0, f.getAbsolutePath());
|
||||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||||
DiskWriter.replaceFile(FILES_NAME, MiscUtils.listToString(recentFiles), false);
|
saveRecentFiles();
|
||||||
resetRecentFilesMenu();
|
resetRecentFilesMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,11 +93,23 @@ public class Settings
|
||||||
{
|
{
|
||||||
if (recentFiles.remove(f.getAbsolutePath()))
|
if (recentFiles.remove(f.getAbsolutePath()))
|
||||||
{
|
{
|
||||||
DiskWriter.replaceFile(FILES_NAME, MiscUtils.listToString(recentFiles), false);
|
saveRecentFiles();
|
||||||
resetRecentFilesMenu();
|
resetRecentFilesMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void saveRecentFiles()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DiskWriter.write(FILES_NAME, MiscUtils.listToString(recentFiles));
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String getRecentFile()
|
public static String getRecentFile()
|
||||||
{
|
{
|
||||||
if (recentFiles.isEmpty())
|
if (recentFiles.isEmpty())
|
||||||
|
@ -107,7 +128,7 @@ public class Settings
|
||||||
recentPlugins.remove(f.getAbsolutePath()); // already added on the list
|
recentPlugins.remove(f.getAbsolutePath()); // already added on the list
|
||||||
recentPlugins.add(0, f.getAbsolutePath());
|
recentPlugins.add(0, f.getAbsolutePath());
|
||||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||||
DiskWriter.replaceFile(PLUGINS_NAME, MiscUtils.listToString(recentPlugins), false);
|
saveRecentPlugins();
|
||||||
resetRecentFilesMenu();
|
resetRecentFilesMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,11 +136,23 @@ public class Settings
|
||||||
{
|
{
|
||||||
if (recentPlugins.remove(f.getAbsolutePath()))
|
if (recentPlugins.remove(f.getAbsolutePath()))
|
||||||
{
|
{
|
||||||
DiskWriter.replaceFile(PLUGINS_NAME, MiscUtils.listToString(recentPlugins), false);
|
saveRecentPlugins();
|
||||||
resetRecentFilesMenu();
|
resetRecentFilesMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void saveRecentPlugins()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DiskWriter.write(PLUGINS_NAME, MiscUtils.listToString(recentPlugins));
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* resets the recent files menu
|
* resets the recent files menu
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer;
|
package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||||
|
@ -27,6 +27,7 @@ import the.bytecode.club.bytecodeviewer.translation.Language;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.SETTINGS_NAME;
|
import static the.bytecode.club.bytecodeviewer.Constants.SETTINGS_NAME;
|
||||||
|
@ -39,7 +40,9 @@ import static the.bytecode.club.bytecodeviewer.Constants.SETTINGS_NAME;
|
||||||
|
|
||||||
public class SettingsSerializer
|
public class SettingsSerializer
|
||||||
{
|
{
|
||||||
|
private static final String DEPRECATED = "deprecated";
|
||||||
private static boolean settingsFileExists;
|
private static boolean settingsFileExists;
|
||||||
|
private static String[] settings;
|
||||||
|
|
||||||
public static void saveSettingsAsync()
|
public static void saveSettingsAsync()
|
||||||
{
|
{
|
||||||
|
@ -53,7 +56,7 @@ public class SettingsSerializer
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DiskWriter.replaceFile(SETTINGS_NAME, "BCV: " + VERSION, false);
|
DiskWriter.write(SETTINGS_NAME, "BCV: " + VERSION, true);
|
||||||
save(BytecodeViewer.viewer.rbr.isSelected());
|
save(BytecodeViewer.viewer.rbr.isSelected());
|
||||||
save(BytecodeViewer.viewer.rsy.isSelected());
|
save(BytecodeViewer.viewer.rsy.isSelected());
|
||||||
save(BytecodeViewer.viewer.din.isSelected());
|
save(BytecodeViewer.viewer.din.isSelected());
|
||||||
|
@ -132,46 +135,46 @@ public class SettingsSerializer
|
||||||
save(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
save(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
||||||
save(BytecodeViewer.viewer.appendBracketsToLabels.isSelected());
|
save(BytecodeViewer.viewer.appendBracketsToLabels.isSelected());
|
||||||
save(BytecodeViewer.viewer.debugHelpers.isSelected());
|
save(BytecodeViewer.viewer.debugHelpers.isSelected());
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save(BytecodeViewer.viewer.updateCheck.isSelected());
|
save(BytecodeViewer.viewer.updateCheck.isSelected());
|
||||||
save(BytecodeViewer.viewer.viewPane1.getSelectedDecompiler().ordinal());
|
save(BytecodeViewer.viewer.viewPane1.getSelectedDecompiler().ordinal());
|
||||||
save(BytecodeViewer.viewer.viewPane2.getSelectedDecompiler().ordinal());
|
save(BytecodeViewer.viewer.viewPane2.getSelectedDecompiler().ordinal());
|
||||||
save(BytecodeViewer.viewer.viewPane3.getSelectedDecompiler().ordinal());
|
save(BytecodeViewer.viewer.viewPane3.getSelectedDecompiler().ordinal());
|
||||||
save(BytecodeViewer.viewer.refreshOnChange.isSelected());
|
save(BytecodeViewer.viewer.refreshOnChange.isSelected());
|
||||||
save(BytecodeViewer.viewer.isMaximized);
|
save(BytecodeViewer.viewer.isMaximized);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save(Configuration.lastOpenDirectory);
|
save(Configuration.lastOpenDirectory);
|
||||||
save(Configuration.python2);
|
save(Configuration.python2);
|
||||||
save(Configuration.rt);
|
save(Configuration.rt);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save(BytecodeViewer.viewer.decodeAPKResources.isSelected());
|
save(BytecodeViewer.viewer.decodeAPKResources.isSelected());
|
||||||
save(Configuration.library);
|
save(Configuration.library);
|
||||||
save(Configuration.pingback);
|
save(Configuration.pingback);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save(BytecodeViewer.viewer.getFontSize());
|
save(BytecodeViewer.viewer.getFontSize());
|
||||||
save(Configuration.deleteForeignLibraries);
|
save(Configuration.deleteForeignLibraries);
|
||||||
|
|
||||||
if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel()))
|
if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel()))
|
||||||
DiskWriter.writeNewLine(SETTINGS_NAME, "0");
|
DiskWriter.append(SETTINGS_NAME, "0", true);
|
||||||
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
|
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
|
||||||
DiskWriter.writeNewLine(SETTINGS_NAME, "1");
|
DiskWriter.append(SETTINGS_NAME, "1", true);
|
||||||
|
|
||||||
save(Configuration.python3);
|
save(Configuration.python3);
|
||||||
save(Configuration.javac);
|
save(Configuration.javac);
|
||||||
|
@ -184,7 +187,7 @@ public class SettingsSerializer
|
||||||
save(BytecodeViewer.viewer.synchronizedViewing.isSelected());
|
save(BytecodeViewer.viewer.synchronizedViewing.isSelected());
|
||||||
save(BytecodeViewer.viewer.showClassMethods.isSelected());
|
save(BytecodeViewer.viewer.showClassMethods.isSelected());
|
||||||
save(BytecodeViewer.viewer.ren.isSelected());
|
save(BytecodeViewer.viewer.ren.isSelected());
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
|
|
||||||
save(Configuration.lafTheme.name());
|
save(Configuration.lafTheme.name());
|
||||||
save(Configuration.rstaTheme.name());
|
save(Configuration.rstaTheme.name());
|
||||||
|
@ -196,8 +199,8 @@ public class SettingsSerializer
|
||||||
save(BytecodeViewer.viewer.viewPane3.isPaneEditable());
|
save(BytecodeViewer.viewer.viewPane3.isPaneEditable());
|
||||||
|
|
||||||
save(Configuration.javaTools);
|
save(Configuration.javaTools);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save("deprecated");
|
save(DEPRECATED);
|
||||||
save(Configuration.lastSaveDirectory);
|
save(Configuration.lastSaveDirectory);
|
||||||
save(Configuration.lastPluginDirectory);
|
save(Configuration.lastPluginDirectory);
|
||||||
save(Configuration.python2Extra);
|
save(Configuration.python2Extra);
|
||||||
|
@ -224,7 +227,7 @@ public class SettingsSerializer
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//precache the file
|
//precache the file
|
||||||
DiskReader.loadString(SETTINGS_NAME, 0, true);
|
settings = DiskReader.readArray(SETTINGS_NAME);
|
||||||
|
|
||||||
//process the cached file
|
//process the cached file
|
||||||
Configuration.lafTheme = LAFTheme.valueOf(asString(127));
|
Configuration.lafTheme = LAFTheme.valueOf(asString(127));
|
||||||
|
@ -425,21 +428,28 @@ public class SettingsSerializer
|
||||||
|
|
||||||
public static void save(Object o)
|
public static void save(Object o)
|
||||||
{
|
{
|
||||||
DiskWriter.writeNewLine(SETTINGS_NAME, String.valueOf(o), false);
|
try
|
||||||
|
{
|
||||||
|
DiskWriter.append(SETTINGS_NAME, String.valueOf(o), true);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String asString(int lineNumber) throws Exception
|
public static String asString(int lineNumber)
|
||||||
{
|
{
|
||||||
return DiskReader.loadString(SETTINGS_NAME, lineNumber, false);
|
return settings[lineNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean asBoolean(int lineNumber) throws Exception
|
public static boolean asBoolean(int lineNumber)
|
||||||
{
|
{
|
||||||
return Boolean.parseBoolean(DiskReader.loadString(SETTINGS_NAME, lineNumber, false));
|
return Boolean.parseBoolean(settings[lineNumber]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int asInt(int lineNumber) throws Exception
|
public static int asInt(int lineNumber)
|
||||||
{
|
{
|
||||||
return Integer.parseInt(DiskReader.loadString(SETTINGS_NAME, lineNumber, false));
|
return Integer.parseInt(settings[lineNumber]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
public class ExceptionUI extends JFrameConsole
|
public class ExceptionUI extends JFrameConsole
|
||||||
{
|
{
|
||||||
public static final String KONLOCH = "https://github.com/Konloch/bytecode-viewer/issues" +
|
public static final String KONLOCH = "https://github.com/Konloch/bytecode-viewer/issues" +
|
||||||
"or Konloch at https://the.bytecode.club or konloch@gmail.com";
|
" or Konloch at https://the.bytecode.club or konloch@gmail.com";
|
||||||
public static final String SEND_STACKTRACE_TO = buildErrorLogHeader(KONLOCH);
|
public static final String SEND_STACKTRACE_TO = buildErrorLogHeader(KONLOCH);
|
||||||
public static final String SEND_STACKTRACE_TO_NL = SEND_STACKTRACE_TO + NL + NL;
|
public static final String SEND_STACKTRACE_TO_NL = SEND_STACKTRACE_TO + NL + NL;
|
||||||
|
|
||||||
|
|
|
@ -69,18 +69,13 @@ public class BCVCommandLine
|
||||||
{
|
{
|
||||||
CommandLine cmd = PARSER.parse(OPTIONS, args);
|
CommandLine cmd = PARSER.parse(OPTIONS, args);
|
||||||
|
|
||||||
if(cmd.hasOption("language"))
|
|
||||||
System.out.println("OK: " + cmd.getOptionValue("language"));
|
|
||||||
|
|
||||||
//TODO this is a backwards way of searching and will cause collisions
|
//TODO this is a backwards way of searching and will cause collisions
|
||||||
// I'm sure the Apache CLI has a better way of navigating this
|
// I'm sure the Apache CLI has a better way of navigating this
|
||||||
|
|
||||||
for(CLICommand command : COMMANDS)
|
for(CLICommand command : COMMANDS)
|
||||||
{
|
{
|
||||||
System.out.println("OK: " + command.name);
|
|
||||||
if(cmd.hasOption(command.name))
|
if(cmd.hasOption(command.name))
|
||||||
{
|
{
|
||||||
System.out.println("ON: " + command.name);
|
|
||||||
command.runCommand(cmd);
|
command.runCommand(cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -115,9 +110,11 @@ public class BCVCommandLine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//wait 5 seconds to allow time for reading
|
||||||
if (!cmd.hasOption("nowait"))
|
if (!cmd.hasOption("nowait"))
|
||||||
SleepUtil.sleep(5 * 1000);
|
SleepUtil.sleep(5 * 1000);
|
||||||
|
|
||||||
|
//decompiler configuration
|
||||||
File input = new File(cmd.getOptionValue("i"));
|
File input = new File(cmd.getOptionValue("i"));
|
||||||
File output = new File(cmd.getOptionValue("o"));
|
File output = new File(cmd.getOptionValue("o"));
|
||||||
String decompiler = cmd.getOptionValue("decompiler");
|
String decompiler = cmd.getOptionValue("decompiler");
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.cli;
|
package the.bytecode.club.bytecodeviewer.cli;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
import org.apache.commons.cli.DefaultParser;
|
import org.apache.commons.cli.DefaultParser;
|
||||||
|
@ -250,7 +250,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -276,7 +276,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.CFR_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.CFR_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -302,7 +302,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -328,7 +328,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -355,7 +355,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -382,7 +382,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.JD_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.JD_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -409,7 +409,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.SMALI_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.SMALI_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -436,7 +436,7 @@ public class CommandLineInput
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.JADX_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.JADX_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -462,8 +462,8 @@ public class CommandLineInput
|
||||||
{
|
{
|
||||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||||
final ClassWriter cw = accept(cn);
|
final ClassWriter cw = accept(cn);
|
||||||
String contents = Decompiler.ASMIFIER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
String contents = Decompiler.ASMIFIER_CODE_GEN.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,5 +22,7 @@ public class CleanBootCommand extends CLICommand
|
||||||
public void runCommand(CommandLine cmd)
|
public void runCommand(CommandLine cmd)
|
||||||
{
|
{
|
||||||
new File(Constants.getBCVDirectory()).delete();
|
new File(Constants.getBCVDirectory()).delete();
|
||||||
|
|
||||||
|
System.out.println("BCV Directory Deleted - Continuing to GUI...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,5 +24,7 @@ public class CleanCommand extends CLICommand
|
||||||
public void runCommand(CommandLine cmd)
|
public void runCommand(CommandLine cmd)
|
||||||
{
|
{
|
||||||
new File(Constants.getBCVDirectory()).delete();
|
new File(Constants.getBCVDirectory()).delete();
|
||||||
|
|
||||||
|
System.out.println("BCV Directory Deleted - Exiting...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,10 @@ public class HelpCommand extends CLICommand
|
||||||
"-o <output file> Selects the output file",
|
"-o <output file> Selects the output file",
|
||||||
"-t <target classname> Must either be the fully qualified classname or \"all\" to decompile all as zip",
|
"-t <target classname> Must either be the fully qualified classname or \"all\" to decompile all as zip",
|
||||||
"-nowait Doesn't wait for the user to read the CLI messages",
|
"-nowait Doesn't wait for the user to read the CLI messages",
|
||||||
|
"",
|
||||||
"==BCV GUI Commands==",
|
"==BCV GUI Commands==",
|
||||||
"-cleanboot Deletes the BCV directory and continues to boot into the GUI",
|
"-cleanboot Deletes the BCV directory and continues to boot into the GUI",
|
||||||
"-english Forces English language translations"
|
"-language <language> Sets specific language translations"
|
||||||
})
|
})
|
||||||
System.out.println(s);
|
System.out.println(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
||||||
|
@ -69,15 +69,15 @@ public class JavaCompiler extends AbstractCompiler
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write the file we're assembling to disk
|
|
||||||
DiskWriter.replaceFile(javaFile.getAbsolutePath(), contents, false);
|
|
||||||
|
|
||||||
//write the entire temporary classpath to disk
|
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), classPath.getAbsolutePath());
|
|
||||||
|
|
||||||
boolean cont = true;
|
boolean cont = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//write the file we're assembling to disk
|
||||||
|
DiskWriter.write(javaFile.getAbsolutePath(), contents);
|
||||||
|
|
||||||
|
//write the entire temporary classpath to disk
|
||||||
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), classPath.getAbsolutePath());
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
ProcessBuilder pb;
|
ProcessBuilder pb;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
@ -55,21 +55,20 @@ public class KrakatauAssembler extends AbstractCompiler
|
||||||
final File tempDirectory2 = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
final File tempDirectory2 = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
||||||
final File javaFile = new File(tempDirectory1.getAbsolutePath() + FS + fullyQualifiedName + ".j");
|
final File javaFile = new File(tempDirectory1.getAbsolutePath() + FS + fullyQualifiedName + ".j");
|
||||||
final File tempJar = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
final File tempJar = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||||
|
final StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
//create the temp directories
|
//create the temp directories
|
||||||
tempDirectory1.mkdir();
|
tempDirectory1.mkdir();
|
||||||
tempDirectory2.mkdir();
|
tempDirectory2.mkdir();
|
||||||
|
|
||||||
//write the file we're assembling to disk
|
|
||||||
DiskWriter.replaceFile(javaFile.getAbsolutePath(), contents, true);
|
|
||||||
|
|
||||||
//write the entire temporary classpath to disk
|
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//write the file we're assembling to disk
|
||||||
|
DiskWriter.write(javaFile.getAbsolutePath(), contents);
|
||||||
|
|
||||||
|
//write the entire temporary classpath to disk
|
||||||
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
||||||
|
|
||||||
String[] pythonCommands = new String[]{Configuration.python2};
|
String[] pythonCommands = new String[]{Configuration.python2};
|
||||||
if (Configuration.python2Extra)
|
if (Configuration.python2Extra)
|
||||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
package the.bytecode.club.bytecodeviewer.compilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
||||||
|
@ -59,7 +59,7 @@ public class SmaliAssembler extends AbstractCompiler
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//write the file we're assembling to disk
|
//write the file we're assembling to disk
|
||||||
DiskWriter.replaceFile(tempSmali.getAbsolutePath(), contents, false);
|
DiskWriter.write(tempSmali.getAbsolutePath(), contents);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,11 +40,19 @@ public abstract class AbstractDecompiler
|
||||||
|
|
||||||
public abstract void decompileToZip(String sourceJar, String zipName);
|
public abstract void decompileToZip(String sourceJar, String zipName);
|
||||||
|
|
||||||
|
public void decompileToZipFallBack(String sourceJar, String zipName)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
public String getDecompilerName()
|
public String getDecompilerName()
|
||||||
{
|
{
|
||||||
return decompilerName;
|
return decompilerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for the compressed exports (Zip / Jar)
|
||||||
|
*/
|
||||||
public String getDecompilerNameProgrammatic()
|
public String getDecompilerNameProgrammatic()
|
||||||
{
|
{
|
||||||
return decompilerNameProgrammatic;
|
return decompilerNameProgrammatic;
|
||||||
|
|
|
@ -44,8 +44,8 @@ public enum Decompiler
|
||||||
JD_DECOMPILER(new JDGUIDecompiler()), //java decompiler
|
JD_DECOMPILER(new JDGUIDecompiler()), //java decompiler
|
||||||
JADX_DECOMPILER(new JADXDecompiler()), //java decompiler
|
JADX_DECOMPILER(new JADXDecompiler()), //java decompiler
|
||||||
|
|
||||||
ASM_TEXTIFY_DISASSEMBLER(new ASMTextifierDisassembler()), //bytecode disassembler
|
ASM_DISASSEMBLER(new ASMDisassembler()), //bytecode disassembler
|
||||||
ASMIFIER_DECOMPILER(new ASMifierGenerator()), //bytecode disassembler / code gen
|
ASMIFIER_CODE_GEN(new ASMifierGenerator()), //bytecode disassembler / code gen
|
||||||
JAVAP_DISASSEMBLER(new JavapDisassembler()); //bytecode disassembler
|
JAVAP_DISASSEMBLER(new JavapDisassembler()); //bytecode disassembler
|
||||||
|
|
||||||
private final AbstractDecompiler decompiler;
|
private final AbstractDecompiler decompiler;
|
||||||
|
@ -63,7 +63,10 @@ public enum Decompiler
|
||||||
return getDecompiler().getDecompilerName();
|
return getDecompiler().getDecompilerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDecompilerNameProgrammic()
|
/**
|
||||||
|
* Used for the compressed exports (Zip / Jar)
|
||||||
|
*/
|
||||||
|
public String getDecompilerNameProgrammatic()
|
||||||
{
|
{
|
||||||
if(decompiler == null)
|
if(decompiler == null)
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -21,19 +21,27 @@ package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.util.Textifier;
|
import org.objectweb.asm.util.Textifier;
|
||||||
import org.objectweb.asm.util.TraceClassVisitor;
|
import org.objectweb.asm.util.TraceClassVisitor;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DEV_MODE_SIMULATED_ERROR;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Objectweb ASM Textifier output
|
* Objectweb ASM Textifier output
|
||||||
*
|
*
|
||||||
* @author Thiakil
|
* @author Thiakil
|
||||||
*/
|
*/
|
||||||
public class ASMTextifierDisassembler extends AbstractDecompiler
|
public class ASMDisassembler extends AbstractDecompiler
|
||||||
{
|
{
|
||||||
public ASMTextifierDisassembler()
|
public ASMDisassembler()
|
||||||
{
|
{
|
||||||
super("ASM Disassembler", "asm");
|
super("ASM Disassembler", "asm");
|
||||||
}
|
}
|
||||||
|
@ -41,13 +49,35 @@ public class ASMTextifierDisassembler extends AbstractDecompiler
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
StringWriter writer = new StringWriter();
|
String exception;
|
||||||
cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer)));
|
|
||||||
return writer.toString();
|
try
|
||||||
|
{
|
||||||
|
//create writer
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
|
//initialize ASM-Textifier & parse class-file
|
||||||
|
cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer)));
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//return writer contents
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDecompilerName() + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
{
|
{
|
||||||
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,12 +21,20 @@ package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.util.ASMifier;
|
import org.objectweb.asm.util.ASMifier;
|
||||||
import org.objectweb.asm.util.TraceClassVisitor;
|
import org.objectweb.asm.util.TraceClassVisitor;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.util.JavaFormatterUtils;
|
import the.bytecode.club.bytecodeviewer.util.JavaFormatterUtils;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DEV_MODE_SIMULATED_ERROR;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Objectweb ASMifier output
|
* Objectweb ASMifier output
|
||||||
*
|
*
|
||||||
|
@ -42,13 +50,35 @@ public class ASMifierGenerator extends AbstractDecompiler
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
StringWriter writer = new StringWriter();
|
String exception;
|
||||||
cn.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(writer)));
|
|
||||||
return JavaFormatterUtils.formatJavaCode(writer.toString());
|
try
|
||||||
|
{
|
||||||
|
//create writer
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
|
//initialize ASMifier & parse class-file
|
||||||
|
cn.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(writer)));
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//format and return the java writer contents
|
||||||
|
return JavaFormatterUtils.formatJavaCode(writer.toString());
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDecompilerName() + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
{
|
{
|
||||||
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
* Copyright (C) 2014 Konloch - Konloch.com / BytecodeViewer.com *
|
||||||
|
* *
|
||||||
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
|
import com.konloch.disklib.DiskReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an unused class. This is meant to act as a blank decompiler template to aid in developers creating new decompilers / disassemblers.
|
||||||
|
*
|
||||||
|
* @author Konloch
|
||||||
|
* @since 10/02/2024
|
||||||
|
*/
|
||||||
|
public class BlankDecompilerBase extends AbstractDecompiler
|
||||||
|
{
|
||||||
|
public BlankDecompilerBase()
|
||||||
|
{
|
||||||
|
super("[Your] Decompiler", "yourdecompiler");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
|
{
|
||||||
|
TempFile tempFile = null;
|
||||||
|
String exception;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create the temporary files
|
||||||
|
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||||
|
File tempInputClassFile = tempFile.getFile();
|
||||||
|
File tempOutputJavaFile = tempFile.createFileFromExtension(false, true, ".java");
|
||||||
|
|
||||||
|
//write the class-file with bytes
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tempInputClassFile))
|
||||||
|
{
|
||||||
|
fos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//decompile the class-file
|
||||||
|
//TODO this is where you would call your decompiler api
|
||||||
|
// such as YourDecompiler.decompile(tempClassFile, tempOutputJavaFile);
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//if the output file is found, read it
|
||||||
|
if (tempOutputJavaFile.exists())
|
||||||
|
return DiskReader.readString(tempOutputJavaFile.getAbsolutePath());
|
||||||
|
else
|
||||||
|
exception = getDecompilerName() + " " + ERROR + "! " + tempOutputJavaFile.getAbsolutePath() + " does not exist.";
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//cleanup temp files
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDecompilerName() + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
|
{
|
||||||
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,20 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.PrefixedStringBuilder;
|
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.PrefixedStringBuilder;
|
||||||
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DEV_MODE_SIMULATED_ERROR;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @since 7/3/2021
|
* @since 7/3/2021
|
||||||
|
@ -39,11 +47,29 @@ public class BytecodeDisassembler extends AbstractDecompiler
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
return ClassNodeDecompiler.decompile(new PrefixedStringBuilder(), new ArrayList<>(), cn).toString();
|
String exception;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//parse class-file
|
||||||
|
return ClassNodeDecompiler.decompile(new PrefixedStringBuilder(), new ArrayList<>(), cn).toString();
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDecompilerName() + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
{
|
{
|
||||||
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,12 @@ import org.benf.cfr.reader.util.getopt.Options;
|
||||||
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -44,15 +46,14 @@ import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.CFR;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CFR Java Wrapper
|
* CFR Java Wrapper
|
||||||
*
|
*
|
||||||
* @author GraxCode
|
* @author GraxCode (Taken mostly out of Threadtear)
|
||||||
* Taken mostly out of Threadtear.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CFRDecompiler extends AbstractDecompiler
|
public class CFRDecompiler extends AbstractDecompiler
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -71,59 +72,69 @@ public class CFRDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
private String decompile(ClassNode cn, String name, byte[] content)
|
private String decompile(ClassNode cn, String name, byte[] content)
|
||||||
{
|
{
|
||||||
|
String exception;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX);
|
String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX);
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
Consumer<SinkReturns.Decompiled> dumpDecompiled = d -> builder.append(d.getJava());
|
Consumer<SinkReturns.Decompiled> dumpDecompiled = d -> builder.append(d.getJava());
|
||||||
|
|
||||||
|
//initialize CFR
|
||||||
Options options = generateOptions();
|
Options options = generateOptions();
|
||||||
ClassFileSource source = new BCVDataSource(options, cn, classPath, content);
|
ClassFileSource source = new BCVDataSource(options, cn, classPath, content);
|
||||||
CfrDriver driver = new CfrDriver.Builder().withClassFileSource(source).withBuiltOptions(options).withOutputSink(new BCVOutputSinkFactory(dumpDecompiled)).build();
|
CfrDriver driver = new CfrDriver.Builder().withClassFileSource(source).withBuiltOptions(options).withOutputSink(new BCVOutputSinkFactory(dumpDecompiled)).build();
|
||||||
|
|
||||||
|
//decompile the class-file
|
||||||
driver.analyse(Collections.singletonList(name));
|
driver.analyse(Collections.singletonList(name));
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//return the builder contents
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
catch (Throwable t)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
t.printStackTrace();
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
PrintWriter pw = new PrintWriter(sw);
|
|
||||||
t.printStackTrace(pw);
|
|
||||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + sw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String outJar)
|
public void decompileToZip(String sourceJar, String outJar)
|
||||||
{
|
{
|
||||||
try (JarFile jfile = new JarFile(new File(sourceJar));
|
try (JarFile jarFile = new JarFile(new File(sourceJar));
|
||||||
FileOutputStream dest = new FileOutputStream(outJar);
|
FileOutputStream destination = new FileOutputStream(outJar);
|
||||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
BufferedOutputStream buffer = new BufferedOutputStream(destination);
|
||||||
ZipOutputStream out = new ZipOutputStream(buffDest))
|
ZipOutputStream zip = new ZipOutputStream(buffer))
|
||||||
{
|
{
|
||||||
byte[] data = new byte[1024];
|
byte[] data = new byte[1024];
|
||||||
|
Enumeration<JarEntry> ent = jarFile.entries();
|
||||||
Enumeration<JarEntry> ent = jfile.entries();
|
|
||||||
Set<JarEntry> history = new HashSet<>();
|
Set<JarEntry> history = new HashSet<>();
|
||||||
|
|
||||||
while (ent.hasMoreElements())
|
while (ent.hasMoreElements())
|
||||||
{
|
{
|
||||||
JarEntry entry = ent.nextElement();
|
JarEntry entry = ent.nextElement();
|
||||||
|
|
||||||
if (entry.getName().endsWith(CLASS_SUFFIX))
|
if (entry.getName().endsWith(CLASS_SUFFIX))
|
||||||
{
|
{
|
||||||
JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java"));
|
JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java"));
|
||||||
|
|
||||||
if (history.add(etn))
|
if (history.add(etn))
|
||||||
{
|
{
|
||||||
out.putNextEntry(etn);
|
zip.putNextEntry(etn);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IOUtils.write(decompile(null, entry.getName(), IOUtils.toByteArray(jfile.getInputStream(entry))), out, StandardCharsets.UTF_8);
|
IOUtils.write(decompile(null, entry.getName(), IOUtils.toByteArray(jarFile.getInputStream(entry))), zip, StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
out.closeEntry();
|
zip.closeEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,34 +142,36 @@ public class CFRDecompiler extends AbstractDecompiler
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
JarEntry etn = new JarEntry(entry.getName());
|
JarEntry jarEntry = new JarEntry(entry.getName());
|
||||||
if (history.add(etn))
|
|
||||||
|
if (history.add(jarEntry))
|
||||||
continue;
|
continue;
|
||||||
history.add(etn);
|
|
||||||
out.putNextEntry(etn);
|
history.add(jarEntry);
|
||||||
try (InputStream in = jfile.getInputStream(entry))
|
zip.putNextEntry(jarEntry);
|
||||||
|
|
||||||
|
try (InputStream input = jarFile.getInputStream(entry))
|
||||||
{
|
{
|
||||||
if (in != null)
|
if (input != null)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
while ((count = in.read(data, 0, 1024)) != -1)
|
|
||||||
|
while ((count = input.read(data, 0, 1024)) != -1)
|
||||||
{
|
{
|
||||||
out.write(data, 0, count);
|
zip.write(data, 0, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
out.closeEntry();
|
zip.closeEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ZipException ze)
|
catch (ZipException e)
|
||||||
{
|
{
|
||||||
// some jars contain duplicate pom.xml entries: ignore it
|
// some jars contain duplicate pom.xml entries: ignore it
|
||||||
if (!ze.getMessage().contains("duplicate"))
|
if (!e.getMessage().contains("duplicate"))
|
||||||
{
|
throw e;
|
||||||
throw ze;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,7 +239,8 @@ public class CFRDecompiler extends AbstractDecompiler
|
||||||
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content)
|
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content)
|
||||||
{
|
{
|
||||||
super(options);
|
super(options);
|
||||||
this.container = BytecodeViewer.getResourceContainers().stream().filter(rc -> rc.resourceClasses.containsValue(cn)).findFirst().orElse(null);
|
this.container = BytecodeViewer.getResourceContainers()
|
||||||
|
.stream().filter(rc -> rc.resourceClasses.containsValue(cn)).findFirst().orElse(null);
|
||||||
this.classFilePath = classFilePath;
|
this.classFilePath = classFilePath;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +261,6 @@ public class CFRDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
return Pair.make(data, classFilePath);
|
return Pair.make(data, classFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BCVOutputSinkFactory implements OutputSinkFactory
|
private static class BCVOutputSinkFactory implements OutputSinkFactory
|
||||||
|
@ -274,9 +287,7 @@ public class CFRDecompiler extends AbstractDecompiler
|
||||||
return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x);
|
return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ignore ->
|
return ignore -> {};
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,24 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ProcessUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.FERNFLOWER;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A FernFlower wrapper with all the options (except 2)
|
* A FernFlower wrapper with all the options (except 2)
|
||||||
|
@ -47,149 +52,126 @@ public class FernFlowerDecompiler extends AbstractDecompiler
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
File tempZip = new File(sourceJar);
|
TempFile tempFile = null;
|
||||||
|
String exception;
|
||||||
File f = new File(TEMP_DIRECTORY + FS + "temp" + FS);
|
|
||||||
f.mkdir();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), TEMP_DIRECTORY + "./temp/"));
|
//create the temporary files
|
||||||
|
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||||
|
File tempInputClassFile = tempFile.getFile();
|
||||||
|
|
||||||
|
//load java source from temp directory
|
||||||
|
tempFile.setParent(new File(TEMP_DIRECTORY));
|
||||||
|
File tempOutputJavaFile = tempFile.createFileFromExtension(false, true, ".java");
|
||||||
|
|
||||||
|
//write the class-file with bytes
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tempInputClassFile))
|
||||||
|
{
|
||||||
|
fos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//decompile the class-file
|
||||||
|
if (LAUNCH_DECOMPILERS_IN_NEW_PROCESS)
|
||||||
|
{
|
||||||
|
ProcessUtils.runDecompilerExternal(ArrayUtils.addAll(new String[]
|
||||||
|
{
|
||||||
|
ExternalResources.getSingleton().getJavaCommand(true),
|
||||||
|
"-jar", ExternalResources.getSingleton().findLibrary("fernflower")
|
||||||
|
}, generateMainMethod(tempInputClassFile.getAbsolutePath(), tempFile.getParent().getAbsolutePath())
|
||||||
|
), false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempInputClassFile.getAbsolutePath(), new File(TEMP_DIRECTORY).getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//if rename is enabled the file name will be the actual class name
|
||||||
|
if (BytecodeViewer.viewer.ren.isSelected())
|
||||||
|
{
|
||||||
|
int indexOfLastPackage = cn.name.lastIndexOf('/');
|
||||||
|
String classNameNoPackages = indexOfLastPackage < 0 ? cn.name : cn.name.substring(indexOfLastPackage);
|
||||||
|
tempOutputJavaFile = new File(tempFile.getParent(), classNameNoPackages + ".java");
|
||||||
|
tempFile.markAsCreatedFile(tempOutputJavaFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the output file is found, read it
|
||||||
|
if (tempOutputJavaFile.exists() && !Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
return DiskReader.readString(tempOutputJavaFile.getAbsolutePath());
|
||||||
|
else
|
||||||
|
exception = FERNFLOWER + " " + ERROR + "! " + tempOutputJavaFile.getAbsolutePath() + " does not exist.";
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//cleanup temp files
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FERNFLOWER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
|
{
|
||||||
|
final File destination = new File(zipName);
|
||||||
|
File tempInputJarFile = new File(sourceJar);
|
||||||
|
File tempOutputJar = new File(TEMP_DIRECTORY + FS + "temp" + FS + tempInputJarFile.getName());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConsoleDecompiler.main(generateMainMethod(tempInputJarFile.getAbsolutePath(), TEMP_DIRECTORY + "./temp/"));
|
||||||
}
|
}
|
||||||
catch (StackOverflowError | Exception ignored)
|
catch (StackOverflowError | Exception ignored)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
File tempZip2 = new File(TEMP_DIRECTORY + FS + "temp" + FS + tempZip.getName());
|
if (tempOutputJar.exists())
|
||||||
if (tempZip2.exists())
|
tempOutputJar.renameTo(destination);
|
||||||
tempZip2.renameTo(new File(zipName));
|
else //attempt to decompile using fallback
|
||||||
|
decompileToZipFallBack(tempInputJarFile.getAbsolutePath(), destination.getAbsolutePath());
|
||||||
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
|
||||||
{
|
|
||||||
String start = TEMP_DIRECTORY + FS + MiscUtils.getUniqueName("", ".class");
|
|
||||||
|
|
||||||
final File tempClass = new File(start + ".class");
|
|
||||||
|
|
||||||
String exception = "";
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
|
||||||
{
|
|
||||||
fos.write(bytes);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
StringWriter exceptionWriter = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
|
||||||
e.printStackTrace();
|
|
||||||
exception = exceptionWriter.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (LAUNCH_DECOMPILERS_IN_NEW_PROCESS)
|
|
||||||
{
|
|
||||||
/*try
|
|
||||||
{
|
|
||||||
BytecodeViewer.sm.pauseBlocking();
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
|
||||||
new String[]{ExternalResources.getSingleton().getJavaCommand(true), "-jar", ExternalResources.getSingleton().findLibrary("fernflower")},
|
|
||||||
generateMainMethod(tempClass.getAbsolutePath(),
|
|
||||||
new File(tempDirectory).getAbsolutePath())
|
|
||||||
));
|
|
||||||
Process p = pb.start();
|
|
||||||
BytecodeViewer.createdProcesses.add(p);
|
|
||||||
p.waitFor();
|
|
||||||
} catch (Exception e) {
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
} finally {
|
|
||||||
BytecodeViewer.sm.resumeBlocking();
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), new File(TEMP_DIRECTORY).getAbsolutePath()));
|
|
||||||
}
|
|
||||||
catch (Throwable e)
|
|
||||||
{
|
|
||||||
StringWriter exceptionWriter = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
|
||||||
e.printStackTrace();
|
|
||||||
exception = exceptionWriter.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tempClass.delete();
|
|
||||||
|
|
||||||
String javaDir = start;
|
|
||||||
if (BytecodeViewer.viewer.ren.isSelected())
|
|
||||||
{
|
|
||||||
javaDir = TEMP_DIRECTORY + "class_0";
|
|
||||||
}
|
|
||||||
|
|
||||||
final File outputJava = new File(javaDir + ".java");
|
|
||||||
if (outputJava.exists())
|
|
||||||
{
|
|
||||||
String s;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
s = DiskReader.loadAsString(outputJava.getAbsolutePath());
|
|
||||||
|
|
||||||
outputJava.delete();
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
StringWriter exceptionWriter = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
exception += NL + NL + exceptionWriter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FERNFLOWER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] generateMainMethod(String className, String folder)
|
private String[] generateMainMethod(String className, String folder)
|
||||||
{
|
{
|
||||||
return new String[]{"-rbr=" + r(BytecodeViewer.viewer.rbr.isSelected()),
|
return new String[]
|
||||||
"-rsy=" + r(BytecodeViewer.viewer.rsy.isSelected()),
|
{
|
||||||
"-din=" + r(BytecodeViewer.viewer.din.isSelected()),
|
"-rbr=" + ffOnValue(BytecodeViewer.viewer.rbr.isSelected()),
|
||||||
"-dc4=" + r(BytecodeViewer.viewer.dc4.isSelected()),
|
"-rsy=" + ffOnValue(BytecodeViewer.viewer.rsy.isSelected()),
|
||||||
"-das=" + r(BytecodeViewer.viewer.das.isSelected()),
|
"-din=" + ffOnValue(BytecodeViewer.viewer.din.isSelected()),
|
||||||
"-hes=" + r(BytecodeViewer.viewer.hes.isSelected()),
|
"-dc4=" + ffOnValue(BytecodeViewer.viewer.dc4.isSelected()),
|
||||||
"-hdc=" + r(BytecodeViewer.viewer.hdc.isSelected()),
|
"-das=" + ffOnValue(BytecodeViewer.viewer.das.isSelected()),
|
||||||
"-dgs=" + r(BytecodeViewer.viewer.dgs.isSelected()),
|
"-hes=" + ffOnValue(BytecodeViewer.viewer.hes.isSelected()),
|
||||||
"-ner=" + r(BytecodeViewer.viewer.ner.isSelected()),
|
"-hdc=" + ffOnValue(BytecodeViewer.viewer.hdc.isSelected()),
|
||||||
"-den=" + r(BytecodeViewer.viewer.den.isSelected()),
|
"-dgs=" + ffOnValue(BytecodeViewer.viewer.dgs.isSelected()),
|
||||||
"-rgn=" + r(BytecodeViewer.viewer.rgn.isSelected()),
|
"-ner=" + ffOnValue(BytecodeViewer.viewer.ner.isSelected()),
|
||||||
"-bto=" + r(BytecodeViewer.viewer.bto.isSelected()),
|
"-den=" + ffOnValue(BytecodeViewer.viewer.den.isSelected()),
|
||||||
"-nns=" + r(BytecodeViewer.viewer.nns.isSelected()),
|
"-rgn=" + ffOnValue(BytecodeViewer.viewer.rgn.isSelected()),
|
||||||
"-uto=" + r(BytecodeViewer.viewer.uto.isSelected()),
|
"-bto=" + ffOnValue(BytecodeViewer.viewer.bto.isSelected()),
|
||||||
"-udv=" + r(BytecodeViewer.viewer.udv.isSelected()),
|
"-nns=" + ffOnValue(BytecodeViewer.viewer.nns.isSelected()),
|
||||||
"-rer=" + r(BytecodeViewer.viewer.rer.isSelected()),
|
"-uto=" + ffOnValue(BytecodeViewer.viewer.uto.isSelected()),
|
||||||
"-fdi=" + r(BytecodeViewer.viewer.fdi.isSelected()),
|
"-udv=" + ffOnValue(BytecodeViewer.viewer.udv.isSelected()),
|
||||||
"-asc=" + r(BytecodeViewer.viewer.asc.isSelected()),
|
"-rer=" + ffOnValue(BytecodeViewer.viewer.rer.isSelected()),
|
||||||
"-ren=" + r(BytecodeViewer.viewer.ren.isSelected()),
|
"-fdi=" + ffOnValue(BytecodeViewer.viewer.fdi.isSelected()),
|
||||||
className, folder};
|
"-asc=" + ffOnValue(BytecodeViewer.viewer.asc.isSelected()),
|
||||||
|
"-ren=" + ffOnValue(BytecodeViewer.viewer.ren.isSelected()),
|
||||||
|
className, folder
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private String r(boolean b)
|
private String ffOnValue(boolean b)
|
||||||
{
|
{
|
||||||
if (b)
|
if (b)
|
||||||
{
|
|
||||||
return "1";
|
return "1";
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return "0";
|
return "0";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,23 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
|
import com.konloch.disklib.DiskReader;
|
||||||
import jadx.api.JadxArgs;
|
import jadx.api.JadxArgs;
|
||||||
import jadx.api.JadxDecompiler;
|
import jadx.api.JadxDecompiler;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Settings;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.JADX;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JADX Java Wrapper
|
* JADX Java Wrapper
|
||||||
|
@ -49,96 +51,80 @@ public class JADXDecompiler extends AbstractDecompiler
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
String fileStart = TEMP_DIRECTORY + FS;
|
TempFile tempFile = null;
|
||||||
|
String exception;
|
||||||
String exception = "";
|
|
||||||
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
|
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
|
||||||
{
|
|
||||||
fos.write(bytes);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
File freeDirectory = new File(findUnusedFile(fileStart));
|
|
||||||
freeDirectory.mkdirs();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
JadxArgs args = new JadxArgs();
|
//create the temporary files
|
||||||
args.setInputFile(tempClass);
|
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||||
args.setOutDir(freeDirectory);
|
File tempDirectory = tempFile.getParent();
|
||||||
args.setOutDirSrc(freeDirectory);
|
File tempClassFile = tempFile.getFile();
|
||||||
args.setOutDirRes(freeDirectory);
|
|
||||||
|
|
||||||
JadxDecompiler jadx = new JadxDecompiler(args);
|
//write the class-file with bytes
|
||||||
jadx.load();
|
try (FileOutputStream fos = new FileOutputStream(tempClassFile))
|
||||||
jadx.saveSources();
|
|
||||||
}
|
|
||||||
catch (StackOverflowError | Exception e)
|
|
||||||
{
|
|
||||||
StringWriter exceptionWriter = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
|
||||||
e.printStackTrace();
|
|
||||||
exception = exceptionWriter.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
tempClass.delete();
|
|
||||||
|
|
||||||
if (freeDirectory.exists())
|
|
||||||
return findFile(MiscUtils.listFiles(freeDirectory));
|
|
||||||
|
|
||||||
if (exception.isEmpty())
|
|
||||||
exception = "Decompiled source file not found!";
|
|
||||||
|
|
||||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String findUnusedFile(String start)
|
|
||||||
{
|
|
||||||
long index = 0;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
File f = new File(start + index);
|
|
||||||
|
|
||||||
if (!f.exists())
|
|
||||||
return f.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String findFile(File[] fileArray)
|
|
||||||
{
|
|
||||||
for (File f : fileArray)
|
|
||||||
{
|
|
||||||
if (f.isDirectory())
|
|
||||||
return findFile(MiscUtils.listFiles(f));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
String s;
|
fos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
//setup JADX Args
|
||||||
{
|
JadxArgs args = new JadxArgs();
|
||||||
s = DiskReader.loadAsString(f.getAbsolutePath());
|
args.setInputFile(tempClassFile);
|
||||||
}
|
args.setOutDir(tempDirectory);
|
||||||
catch (Exception e)
|
args.setOutDirSrc(tempDirectory);
|
||||||
{
|
args.setOutDirRes(tempDirectory);
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
|
||||||
e.printStackTrace();
|
|
||||||
String exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
|
||||||
|
|
||||||
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
//init jadx decompiler
|
||||||
}
|
JadxDecompiler jadx = new JadxDecompiler(args);
|
||||||
|
|
||||||
return s;
|
//load jadx
|
||||||
|
jadx.load();
|
||||||
|
|
||||||
|
//decompile
|
||||||
|
jadx.saveSources();
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
return searchForJavaFile(MiscUtils.listFiles(tempDirectory));
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//cleanup temp files
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String searchForJavaFile(File[] files) throws Exception
|
||||||
|
{
|
||||||
|
for (File file : files)
|
||||||
|
{
|
||||||
|
if (file.isDirectory())
|
||||||
|
return searchForJavaFile(MiscUtils.listFiles(file));
|
||||||
|
else if(file.getName().toLowerCase().endsWith(".java"))
|
||||||
|
{
|
||||||
|
String contents = DiskReader.readString(file.getAbsolutePath());
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
if(Settings.DECOMPILERS_AUTOMATICALLY_CLEANUP)
|
||||||
|
file.delete();
|
||||||
|
|
||||||
|
return contents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "JADX error!" + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR;
|
return JADX + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL
|
||||||
|
+ "JADX failed to produce any Java files from the provided source.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,10 +18,9 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
|
||||||
import the.bytecode.club.bytecodeviewer.Constants;
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
|
@ -30,14 +29,14 @@ import the.bytecode.club.bytecodeviewer.decompilers.jdgui.DirectoryLoader;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.jdgui.JDGUIClassFileUtil;
|
import the.bytecode.club.bytecodeviewer.decompilers.jdgui.JDGUIClassFileUtil;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.jdgui.PlainTextPrinter;
|
import the.bytecode.club.bytecodeviewer.decompilers.jdgui.PlainTextPrinter;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.JDGUI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JD-Core Decompiler Wrapper
|
* JD-Core Decompiler Wrapper
|
||||||
|
@ -57,38 +56,26 @@ public class JDGUIDecompiler extends AbstractDecompiler
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
|
TempFile tempFile = null;
|
||||||
String exception;
|
String exception;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
//create the temporary files
|
||||||
tempDirectory.mkdir();
|
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||||
|
tempFile.setUniqueName(cn.name);
|
||||||
|
File tempClassFile = tempFile.createFileFromExtension(false, false, ".class");
|
||||||
|
File tempJavaFile = tempFile.createFileFromExtension(false, false, ".java");
|
||||||
|
|
||||||
final File tempClass = new File(tempDirectory.getAbsolutePath() + FS + cn.name + ".class");
|
//make any folders for the packages
|
||||||
final File tempJava = new File(tempDirectory.getAbsolutePath() + FS + cn.name + ".java");
|
makeFolders(tempFile, cn);
|
||||||
|
|
||||||
if (cn.name.contains("/"))
|
try (FileOutputStream fos = new FileOutputStream(tempClassFile))
|
||||||
{
|
|
||||||
String[] raw = cn.name.split("/");
|
|
||||||
String path = tempDirectory.getAbsolutePath() + FS;
|
|
||||||
for (int i = 0; i < raw.length - 1; i++)
|
|
||||||
{
|
|
||||||
path += raw[i] + FS;
|
|
||||||
File f = new File(path);
|
|
||||||
f.mkdir();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
|
||||||
{
|
{
|
||||||
fos.write(bytes);
|
fos.write(bytes);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
String pathToClass = tempClass.getAbsolutePath().replace('/', File.separatorChar).replace('\\', File.separatorChar);
|
String pathToClass = tempClassFile.getAbsolutePath().replace('/', File.separatorChar).replace('\\', File.separatorChar);
|
||||||
String directoryPath = JDGUIClassFileUtil.ExtractDirectoryPath(pathToClass);
|
String directoryPath = JDGUIClassFileUtil.ExtractDirectoryPath(pathToClass);
|
||||||
String internalPath = JDGUIClassFileUtil.ExtractInternalPath(directoryPath, pathToClass);
|
String internalPath = JDGUIClassFileUtil.ExtractInternalPath(directoryPath, pathToClass);
|
||||||
|
|
||||||
|
@ -111,28 +98,52 @@ public class JDGUIDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
org.jd.core.v1.api.Decompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
org.jd.core.v1.api.Decompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
||||||
|
|
||||||
try (PrintStream ps = new PrintStream(tempJava.getAbsolutePath()); PlainTextPrinter printer = new PlainTextPrinter(preferences, ps))
|
try (PrintStream ps = new PrintStream(tempJavaFile.getAbsolutePath());
|
||||||
|
PlainTextPrinter printer = new PlainTextPrinter(preferences, ps))
|
||||||
{
|
{
|
||||||
decompiler.decompile(loader, printer, internalPath, preferences.getPreferences());
|
decompiler.decompile(loader, printer, internalPath, preferences.getPreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
return DiskReader.loadAsString(tempJava.getAbsolutePath());
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//read the java file
|
||||||
|
return DiskReader.readString(tempJavaFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
StringWriter sw = new StringWriter();
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
}
|
||||||
e.printStackTrace();
|
finally
|
||||||
|
{
|
||||||
exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
return JDGUI + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
return JDGUI + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
{
|
{
|
||||||
//TODO
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeFolders(TempFile tempFile, ClassNode cn)
|
||||||
|
{
|
||||||
|
if (cn.name.contains("/"))
|
||||||
|
{
|
||||||
|
String[] raw = cn.name.split("/");
|
||||||
|
String path = tempFile.getParent().getAbsolutePath() + FS;
|
||||||
|
|
||||||
|
for (int i = 0; i < raw.length - 1; i++)
|
||||||
|
{
|
||||||
|
path += raw[i] + FS;
|
||||||
|
File f = new File(path);
|
||||||
|
f.mkdir();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,28 +18,32 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
import the.bytecode.club.bytecodeviewer.Constants;
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsolePrintStream;
|
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsolePrintStream;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
import static the.bytecode.club.bytecodeviewer.api.ExceptionUI.SEND_STACKTRACE_TO;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DEV_MODE_SIMULATED_ERROR;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Javap disassembler
|
* Javap disassembler
|
||||||
* <p>
|
*
|
||||||
* https://github.com/Konloch/bytecode-viewer/issues/93
|
* https://github.com/Konloch/bytecode-viewer/issues/93
|
||||||
*
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
|
@ -59,21 +63,25 @@ public class JavapDisassembler extends AbstractDecompiler
|
||||||
if (!ExternalResources.getSingleton().hasJavaToolsSet())
|
if (!ExternalResources.getSingleton().hasJavaToolsSet())
|
||||||
return "Set Java Tools Path!";
|
return "Set Java Tools Path!";
|
||||||
|
|
||||||
return synchronizedDecompilation(cn, bytes);
|
return disassembleJavaP(cn, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized String synchronizedDecompilation(ClassNode cn, byte[] b)
|
private synchronized String disassembleJavaP(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
TempFile tempFile = null;
|
||||||
final File tempClass = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".class");
|
String exception;
|
||||||
|
|
||||||
tempDirectory.mkdir();
|
JFrameConsolePrintStream sysOutBuffer;
|
||||||
|
|
||||||
DiskWriter.replaceFileBytes(tempClass.getAbsolutePath(), b, false);
|
|
||||||
|
|
||||||
JFrameConsolePrintStream sysOutBuffer = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//create the temporary files
|
||||||
|
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||||
|
File tempClassFile = tempFile.getFile();
|
||||||
|
|
||||||
|
//write the bytes to the class-file
|
||||||
|
DiskWriter.write(tempClassFile.getAbsolutePath(), bytes);
|
||||||
|
|
||||||
//load java tools into a temporary classloader
|
//load java tools into a temporary classloader
|
||||||
URLClassLoader child = new URLClassLoader(new URL[]{new File(Configuration.javaTools).toURI().toURL()}, this.getClass().getClassLoader());
|
URLClassLoader child = new URLClassLoader(new URL[]{new File(Configuration.javaTools).toURI().toURL()}, this.getClass().getClassLoader());
|
||||||
|
|
||||||
|
@ -88,37 +96,54 @@ public class JavapDisassembler extends AbstractDecompiler
|
||||||
BytecodeViewer.sm.silenceExec(true);
|
BytecodeViewer.sm.silenceExec(true);
|
||||||
|
|
||||||
//invoke Javap
|
//invoke Javap
|
||||||
main.invoke(null, (Object) new String[]{"-p", //Shows all classes and members
|
try
|
||||||
"-c", //Prints out disassembled code
|
{
|
||||||
//"-l", //Prints out line and local variable tables
|
main.invoke(null, (Object) new String[]{"-p", //Shows all classes and members
|
||||||
"-constants", //Shows static final constants
|
"-c", //Prints out disassembled code
|
||||||
tempClass.getAbsolutePath()});
|
//"-l", //Prints out line and local variable tables
|
||||||
|
"-constants", //Shows static final constants
|
||||||
|
tempClassFile.getAbsolutePath()});
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e)
|
||||||
|
{
|
||||||
|
//expected warning behaviour on JDK-15
|
||||||
|
}
|
||||||
|
|
||||||
|
//signal finished
|
||||||
|
sysOutBuffer.finished();
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//return output
|
||||||
|
return sysOutBuffer.getTextAreaOutputStreamOut().getBuffer().toString();
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e)
|
catch (IllegalAccessException e)
|
||||||
{
|
{
|
||||||
|
//TODO fallback using CLI (External Process API)
|
||||||
|
|
||||||
return TranslatedStrings.ILLEGAL_ACCESS_ERROR.toString();
|
return TranslatedStrings.ILLEGAL_ACCESS_ERROR.toString();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BytecodeViewer.sm.silenceExec(false);
|
BytecodeViewer.sm.silenceExec(false);
|
||||||
tempClass.delete();
|
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sysOutBuffer != null)
|
return getDecompilerName() + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
{
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
sysOutBuffer.finished();
|
|
||||||
return sysOutBuffer.getTextAreaOutputStreamOut().getBuffer().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SEND_STACKTRACE_TO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
{
|
{
|
||||||
|
decompileToZipFallBack(sourceJar, zipName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
@ -28,15 +28,14 @@ import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
import the.bytecode.club.bytecodeviewer.util.*;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|
||||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Krakatau Java Decompiler Wrapper, requires Python 2.7
|
* Krakatau Java Decompiler Wrapper, requires Python 2.7
|
||||||
|
@ -51,24 +50,6 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
||||||
super("Krakatau Decompiler", "krakatau");
|
super("Krakatau Decompiler", "krakatau");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildCLIArguments()
|
|
||||||
{
|
|
||||||
if (Configuration.library.isEmpty())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
File dir = new File(Configuration.library);
|
|
||||||
if (!dir.exists())
|
|
||||||
return "";
|
|
||||||
if (!dir.isDirectory())
|
|
||||||
return ";" + Configuration.library;
|
|
||||||
|
|
||||||
File[] files = dir.listFiles();
|
|
||||||
if (files == null || files.length == 0)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
return ";" + Arrays.stream(files).filter(File::isFile).map(File::getAbsolutePath).collect(Collectors.joining(";"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
|
@ -79,104 +60,104 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
if (Configuration.rt.isEmpty())
|
if (Configuration.rt.isEmpty())
|
||||||
{
|
{
|
||||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||||
|
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Configuration.rt.isEmpty())
|
if (Configuration.rt.isEmpty())
|
||||||
{
|
{
|
||||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
+ "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||||
|
|
||||||
|
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A
|
||||||
|
+ " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
StringBuilder processOut = new StringBuilder(NL + NL);
|
||||||
final File tempJar = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
StringBuilder processErr = new StringBuilder(NL + NL);
|
||||||
|
int exitCode = Integer.MAX_VALUE;
|
||||||
tempDirectory.mkdir();
|
TempFile tempFile = null;
|
||||||
|
String exception;
|
||||||
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
|
|
||||||
|
|
||||||
return decompileClassNode(tempJar, tempDirectory, cn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String decompileClassNode(File tempJar, File tempDir, ClassNode cn)
|
|
||||||
{
|
|
||||||
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
|
||||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_PYTHON_2_PATH.toString();
|
|
||||||
|
|
||||||
ExternalResources.getSingleton().rtCheck();
|
|
||||||
|
|
||||||
if (Configuration.rt.isEmpty())
|
|
||||||
{
|
|
||||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
|
||||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Configuration.rt.isEmpty())
|
|
||||||
{
|
|
||||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
|
||||||
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
|
||||||
}
|
|
||||||
|
|
||||||
String returnString = ExceptionUI.SEND_STACKTRACE_TO_NL;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//create the temporary files
|
||||||
|
tempFile = TempFile.createTemporaryFile(false, ".jar");
|
||||||
|
tempFile.newTemporaryParent();
|
||||||
|
File tempInputJarFile = tempFile.getFile();
|
||||||
|
File tempDir = tempFile.createFileFromExtension(true, false, ".txt").getParentFile();
|
||||||
|
File tempOutputJavaFile = new File(tempDir.getAbsolutePath() + FS + cn.name + ".java");
|
||||||
|
|
||||||
|
//create out dir
|
||||||
|
tempDir.mkdirs();
|
||||||
|
tempOutputJavaFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
//final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
||||||
|
//javaFile = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||||
|
|
||||||
|
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempInputJarFile.getAbsolutePath());
|
||||||
|
|
||||||
|
if (!ExternalResources.getSingleton().hasSetPython2Command())
|
||||||
|
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_PYTHON_2_PATH.toString();
|
||||||
|
|
||||||
|
ExternalResources.getSingleton().rtCheck();
|
||||||
|
|
||||||
|
if (Configuration.rt.isEmpty())
|
||||||
|
{
|
||||||
|
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||||
|
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Configuration.rt.isEmpty())
|
||||||
|
{
|
||||||
|
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||||
|
return TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + " " + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B;
|
||||||
|
}
|
||||||
|
|
||||||
String[] pythonCommands = new String[]{Configuration.python2};
|
String[] pythonCommands = new String[]{Configuration.python2};
|
||||||
if (Configuration.python2Extra)
|
if (Configuration.python2Extra)
|
||||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||||
krakatauWorkingDirectory + FS + "decompile.py", "-skip", //love you storyyeller <3
|
krakatauWorkingDirectory + FS + "decompile.py",
|
||||||
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath() + buildCLIArguments(),
|
"-skip", //love you storyyeller <3
|
||||||
"-out", tempDir.getAbsolutePath(), cn.name + ".class"));
|
"-nauto",
|
||||||
|
"-path", Configuration.rt + ";" + tempInputJarFile.getAbsolutePath() + buildCLIArguments(),
|
||||||
|
"-out", tempDir.getAbsolutePath(),
|
||||||
|
cn.name + ".class"));
|
||||||
|
|
||||||
Process process = pb.start();
|
Process process = pb.start();
|
||||||
BytecodeViewer.createdProcesses.add(process);
|
BytecodeViewer.createdProcesses.add(process);
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder(TranslatedStrings.PROCESS2 + NL + NL);
|
|
||||||
|
|
||||||
//Read out dir output
|
//Read out dir output
|
||||||
try (InputStream is = process.getInputStream();
|
//ProcessUtils.readProcessToStringBuilderAsync(process, processOut, processErr);
|
||||||
InputStreamReader isr = new InputStreamReader(is);
|
ProcessUtils.readProcessToStringBuilder(process, processOut, processErr);
|
||||||
BufferedReader br = new BufferedReader(isr))
|
|
||||||
{
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null)
|
|
||||||
{
|
|
||||||
log.append(NL).append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.append(NL).append(NL).append(TranslatedStrings.ERROR2).append(NL).append(NL);
|
//wait for process to exit
|
||||||
|
exitCode = process.waitFor();
|
||||||
|
|
||||||
try (InputStream is = process.getErrorStream();
|
//handle simulated errors
|
||||||
InputStreamReader isr = new InputStreamReader(is);
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
BufferedReader br = new BufferedReader(isr))
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
{
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null)
|
|
||||||
{
|
|
||||||
log.append(NL).append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int exitValue = process.waitFor();
|
// read the java file on a successful disassemble
|
||||||
log.append(NL).append(NL).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
return DiskReader.readString(tempOutputJavaFile.getAbsolutePath());
|
||||||
returnString = log.toString();
|
|
||||||
|
|
||||||
// update the string on a successful disassemble
|
|
||||||
returnString = DiskReader.loadAsString(tempDir.getAbsolutePath() + FS + cn.name + ".java");
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
StringWriter sw = new StringWriter();
|
exception = ProcessUtils.mergeLogs(processOut, processErr, exitCode)
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
+ ExceptionUtils.exceptionToString(e);
|
||||||
e.printStackTrace();
|
}
|
||||||
returnString += NL + ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
finally
|
||||||
|
{
|
||||||
|
//delete all temporary files
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnString;
|
return KRAKATAU + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -189,7 +170,8 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
if (Configuration.rt.isEmpty())
|
if (Configuration.rt.isEmpty())
|
||||||
{
|
{
|
||||||
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n" + TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
BytecodeViewer.showMessage(TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_A + "\r\n"
|
||||||
|
+ TranslatedStrings.YOU_NEED_TO_SET_YOUR_JAVA_RT_PATH_B);
|
||||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +189,8 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||||
krakatauWorkingDirectory + FS + "decompile.py", "-skip", //love you storyyeller <3
|
krakatauWorkingDirectory + FS + "decompile.py", "-skip", //love you storyyeller <3
|
||||||
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath(), "-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath()));
|
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath(),
|
||||||
|
"-out", tempDirectory.getAbsolutePath(), tempJar.getAbsolutePath()));
|
||||||
|
|
||||||
Process process = pb.start();
|
Process process = pb.start();
|
||||||
BytecodeViewer.createdProcesses.add(process);
|
BytecodeViewer.createdProcesses.add(process);
|
||||||
|
@ -221,4 +204,25 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
||||||
BytecodeViewer.handleException(e);
|
BytecodeViewer.handleException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String buildCLIArguments()
|
||||||
|
{
|
||||||
|
if (Configuration.library.isEmpty())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
File dir = new File(Configuration.library);
|
||||||
|
|
||||||
|
if (!dir.exists())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (!dir.isDirectory())
|
||||||
|
return ";" + Configuration.library;
|
||||||
|
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null || files.length == 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return ";" + Arrays.stream(files).filter(File::isFile)
|
||||||
|
.map(File::getAbsolutePath).collect(Collectors.joining(";"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
@ -35,6 +35,7 @@ import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.DEV_MODE_SIMULATED_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Krakatau Java Disassembler Wrapper, requires Python 2.7
|
* Krakatau Java Disassembler Wrapper, requires Python 2.7
|
||||||
|
@ -105,8 +106,12 @@ public class KrakatauDisassembler extends AbstractDecompiler
|
||||||
log.append(NL).append(NL).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
log.append(NL).append(NL).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
||||||
returnString = log.toString();
|
returnString = log.toString();
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
// update the string on a successful disassemble
|
// update the string on a successful disassemble
|
||||||
returnString = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + FS + cn.name + ".j");
|
returnString = DiskReader.readString(tempDirectory.getAbsolutePath() + FS + cn.name + ".j");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,11 +27,13 @@ import com.strobel.decompiler.PlainTextOutput;
|
||||||
import com.strobel.decompiler.languages.java.JavaFormattingOptions;
|
import com.strobel.decompiler.languages.java.JavaFormattingOptions;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
import the.bytecode.club.bytecodeviewer.util.EncodeUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.util.TempFile;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -41,8 +43,7 @@ import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PROCYON;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Procyon Java Decompiler Wrapper
|
* Procyon Java Decompiler Wrapper
|
||||||
|
@ -50,12 +51,182 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PRO
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
* @author DeathMarine
|
* @author DeathMarine
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ProcyonDecompiler extends AbstractDecompiler
|
public class ProcyonDecompiler extends AbstractDecompiler
|
||||||
{
|
{
|
||||||
|
|
||||||
public ProcyonDecompiler()
|
public ProcyonDecompiler()
|
||||||
{
|
{
|
||||||
super("Procyon Decompiler", "proycon");
|
super("Procyon Decompiler", "procyon");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
|
{
|
||||||
|
TempFile tempFile = null;
|
||||||
|
String exception;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create the temporary files
|
||||||
|
tempFile = TempFile.createTemporaryFile(false, ".class");
|
||||||
|
File tempInputClassFile = tempFile.getFile();
|
||||||
|
|
||||||
|
//write the ClassNode bytes to the temp file
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tempInputClassFile))
|
||||||
|
{
|
||||||
|
fos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//initialize procyon
|
||||||
|
DecompilerSettings settings = getDecompilerSettings();
|
||||||
|
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
|
||||||
|
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
|
||||||
|
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
|
//lookup the class-file
|
||||||
|
TypeReference type = metadataSystem.lookupType(tempInputClassFile.getCanonicalPath());
|
||||||
|
|
||||||
|
//configure procyon
|
||||||
|
decompilationOptions.setSettings(settings);
|
||||||
|
decompilationOptions.setFullDecompilation(true);
|
||||||
|
|
||||||
|
//parse class-file
|
||||||
|
TypeDefinition resolvedType;
|
||||||
|
|
||||||
|
if (type == null || ((resolvedType = type.resolve()) == null))
|
||||||
|
throw new Exception("Unable to resolve class-filetype.");
|
||||||
|
|
||||||
|
//decompile the class-file
|
||||||
|
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions);
|
||||||
|
|
||||||
|
//handle simulated errors
|
||||||
|
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||||
|
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||||
|
|
||||||
|
//return the writer contents
|
||||||
|
return EncodeUtils.unicodeToString(writer.toString());
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
exception = ExceptionUtils.exceptionToString(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//delete all temporary files
|
||||||
|
if(tempFile != null)
|
||||||
|
tempFile.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PROCYON + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decompileToZip(String sourceJar, String zipName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try (JarFile jarFile = new JarFile(sourceJar);
|
||||||
|
FileOutputStream destination = new FileOutputStream(zipName);
|
||||||
|
BufferedOutputStream buffer = new BufferedOutputStream(destination);
|
||||||
|
ZipOutputStream zip = new ZipOutputStream(buffer))
|
||||||
|
{
|
||||||
|
byte[] data = new byte[1024];
|
||||||
|
|
||||||
|
//initialize procyon
|
||||||
|
DecompilerSettings settings = getDecompilerSettings();
|
||||||
|
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
|
||||||
|
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
|
||||||
|
ITypeLoader jarLoader = new JarTypeLoader(jarFile);
|
||||||
|
|
||||||
|
//lookup the jar-file
|
||||||
|
typeLoader.getTypeLoaders().add(jarLoader);
|
||||||
|
|
||||||
|
//configure procyon
|
||||||
|
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
||||||
|
decompilationOptions.setSettings(settings);
|
||||||
|
decompilationOptions.setFullDecompilation(true);
|
||||||
|
|
||||||
|
//setup jar output
|
||||||
|
Enumeration<JarEntry> ent = jarFile.entries();
|
||||||
|
Set<JarEntry> history = new HashSet<>();
|
||||||
|
|
||||||
|
while (ent.hasMoreElements())
|
||||||
|
{
|
||||||
|
JarEntry entry = ent.nextElement();
|
||||||
|
|
||||||
|
if (entry.getName().endsWith(".class"))
|
||||||
|
{
|
||||||
|
JarEntry etn = new JarEntry(entry.getName().replace(".class", ".java"));
|
||||||
|
|
||||||
|
if (history.add(etn))
|
||||||
|
{
|
||||||
|
zip.putNextEntry(etn);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String internalName = StringUtilities.removeRight(entry.getName(), ".class");
|
||||||
|
TypeReference type = metadataSystem.lookupType(internalName);
|
||||||
|
TypeDefinition resolvedType;
|
||||||
|
|
||||||
|
if ((type == null) || ((resolvedType = type.resolve()) == null))
|
||||||
|
throw new Exception("Unable to resolve type.");
|
||||||
|
|
||||||
|
Writer writer = new OutputStreamWriter(zip);
|
||||||
|
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions);
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JarEntry etn = new JarEntry(entry.getName());
|
||||||
|
|
||||||
|
if (history.add(etn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
history.add(etn);
|
||||||
|
zip.putNextEntry(etn);
|
||||||
|
|
||||||
|
try (InputStream in = jarFile.getInputStream(entry))
|
||||||
|
{
|
||||||
|
if (in != null)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
while ((count = in.read(data, 0, 1024)) != -1)
|
||||||
|
{
|
||||||
|
zip.write(data, 0, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ZipException ze)
|
||||||
|
{
|
||||||
|
// some jars contain duplicate pom.xml entries: ignore it
|
||||||
|
if (!ze.getMessage().contains("duplicate"))
|
||||||
|
throw ze;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (StackOverflowError | Exception e)
|
||||||
|
{
|
||||||
|
BytecodeViewer.handleException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecompilerSettings getDecompilerSettings()
|
public DecompilerSettings getDecompilerSettings()
|
||||||
|
@ -79,165 +250,6 @@ public class ProcyonDecompiler extends AbstractDecompiler
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
|
||||||
{
|
|
||||||
String exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
final String fileStart = TEMP_DIRECTORY + FS + "temp";
|
|
||||||
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
|
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempClass))
|
|
||||||
{
|
|
||||||
fos.write(bytes);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
DecompilerSettings settings = getDecompilerSettings();
|
|
||||||
|
|
||||||
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
|
|
||||||
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
|
|
||||||
TypeReference type = metadataSystem.lookupType(tempClass.getCanonicalPath());
|
|
||||||
|
|
||||||
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
|
||||||
decompilationOptions.setSettings(settings);
|
|
||||||
decompilationOptions.setFullDecompilation(true);
|
|
||||||
|
|
||||||
TypeDefinition resolvedType;
|
|
||||||
|
|
||||||
if (type == null || ((resolvedType = type.resolve()) == null))
|
|
||||||
throw new Exception("Unable to resolve type.");
|
|
||||||
|
|
||||||
StringWriter stringwriter = new StringWriter();
|
|
||||||
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions);
|
|
||||||
|
|
||||||
return EncodeUtils.unicodeToString(stringwriter.toString());
|
|
||||||
}
|
|
||||||
catch (StackOverflowError | Exception e)
|
|
||||||
{
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PROCYON + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void decompileToZip(String sourceJar, String zipName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
doSaveJarDecompiled(new File(sourceJar), new File(zipName));
|
|
||||||
}
|
|
||||||
catch (StackOverflowError | Exception e)
|
|
||||||
{
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author DeathMarine
|
|
||||||
*/
|
|
||||||
private void doSaveJarDecompiled(File inFile, File outFile) throws Exception
|
|
||||||
{
|
|
||||||
try (JarFile jfile = new JarFile(inFile);
|
|
||||||
FileOutputStream dest = new FileOutputStream(outFile);
|
|
||||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
|
||||||
ZipOutputStream out = new ZipOutputStream(buffDest))
|
|
||||||
{
|
|
||||||
byte[] data = new byte[1024];
|
|
||||||
DecompilerSettings settings = getDecompilerSettings();
|
|
||||||
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
|
|
||||||
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
|
|
||||||
ITypeLoader jarLoader = new JarTypeLoader(jfile);
|
|
||||||
typeLoader.getTypeLoaders().add(jarLoader);
|
|
||||||
|
|
||||||
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
|
||||||
decompilationOptions.setSettings(settings);
|
|
||||||
decompilationOptions.setFullDecompilation(true);
|
|
||||||
|
|
||||||
Enumeration<JarEntry> ent = jfile.entries();
|
|
||||||
Set<JarEntry> history = new HashSet<>();
|
|
||||||
|
|
||||||
while (ent.hasMoreElements())
|
|
||||||
{
|
|
||||||
JarEntry entry = ent.nextElement();
|
|
||||||
|
|
||||||
if (entry.getName().endsWith(".class"))
|
|
||||||
{
|
|
||||||
JarEntry etn = new JarEntry(entry.getName().replace(".class", ".java"));
|
|
||||||
|
|
||||||
if (history.add(etn))
|
|
||||||
{
|
|
||||||
out.putNextEntry(etn);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String internalName = StringUtilities.removeRight(entry.getName(), ".class");
|
|
||||||
TypeReference type = metadataSystem.lookupType(internalName);
|
|
||||||
TypeDefinition resolvedType;
|
|
||||||
|
|
||||||
if ((type == null) || ((resolvedType = type.resolve()) == null))
|
|
||||||
{
|
|
||||||
throw new Exception("Unable to resolve type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Writer writer = new OutputStreamWriter(out);
|
|
||||||
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions);
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
out.closeEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
JarEntry etn = new JarEntry(entry.getName());
|
|
||||||
|
|
||||||
if (history.add(etn))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
history.add(etn);
|
|
||||||
out.putNextEntry(etn);
|
|
||||||
|
|
||||||
try (InputStream in = jfile.getInputStream(entry))
|
|
||||||
{
|
|
||||||
if (in != null)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
while ((count = in.read(data, 0, 1024)) != -1)
|
|
||||||
{
|
|
||||||
out.write(data, 0, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
out.closeEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ZipException ze)
|
|
||||||
{
|
|
||||||
// some jars contain duplicate pom.xml entries: ignore it
|
|
||||||
if (!ze.getMessage().contains("duplicate"))
|
|
||||||
throw ze;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author DeathMarine
|
* @author DeathMarine
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||||
|
|
||||||
import com.googlecode.d2j.smali.BaksmaliCmd;
|
import com.googlecode.d2j.smali.BaksmaliCmd;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import com.konloch.disklib.DiskReader;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
@ -52,7 +52,7 @@ public class SmaliDisassembler extends AbstractDecompiler
|
||||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||||
{
|
{
|
||||||
final String fileStart = TEMP_DIRECTORY + FS + "temp";
|
final String fileStart = TEMP_DIRECTORY + FS + "temp";
|
||||||
final String start = MiscUtils.getUniqueName(fileStart, ".class");
|
final String start = MiscUtils.getUniqueNameBroken(fileStart, ".class");
|
||||||
final File tempClass = new File(start + ".class");
|
final File tempClass = new File(start + ".class");
|
||||||
final File tempDex = new File(start + ".dex");
|
final File tempDex = new File(start + ".dex");
|
||||||
final File tempDexOut = new File(start + "-out");
|
final File tempDexOut = new File(start + "-out");
|
||||||
|
@ -69,8 +69,6 @@ public class SmaliDisassembler extends AbstractDecompiler
|
||||||
BytecodeViewer.handleException(e);
|
BytecodeViewer.handleException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ZipUtils.zipFile(tempClass, tempZip);
|
|
||||||
|
|
||||||
Dex2Jar.saveAsDex(tempClass, tempDex, true);
|
Dex2Jar.saveAsDex(tempClass, tempDex, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -106,6 +104,7 @@ public class SmaliDisassembler extends AbstractDecompiler
|
||||||
while (!found)
|
while (!found)
|
||||||
{
|
{
|
||||||
File f = Objects.requireNonNull(current.listFiles())[0];
|
File f = Objects.requireNonNull(current.listFiles())[0];
|
||||||
|
|
||||||
if (f.isDirectory())
|
if (f.isDirectory())
|
||||||
current = f;
|
current = f;
|
||||||
else
|
else
|
||||||
|
@ -113,11 +112,10 @@ public class SmaliDisassembler extends AbstractDecompiler
|
||||||
outputSmali = f;
|
outputSmali = f;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DiskReader.loadAsString(outputSmali.getAbsolutePath());
|
return DiskReader.readString(outputSmali.getAbsolutePath());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +126,8 @@ public class SmaliDisassembler extends AbstractDecompiler
|
||||||
exception += ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
exception += ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMALI + " " + DISASSEMBLER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
return SMALI + " " + DISASSEMBLER + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||||
|
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -57,13 +57,16 @@ public class DecompilerViewComponent
|
||||||
|
|
||||||
private void createMenu()
|
private void createMenu()
|
||||||
{
|
{
|
||||||
if (type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
if (type == JAVA || type == JAVA_NON_EDITABLE
|
||||||
|
|| type == JAVA_AND_BYTECODE || type == JAVA_AND_BYTECODE_NON_EDITABLE)
|
||||||
menu.add(java);
|
menu.add(java);
|
||||||
|
|
||||||
if (type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
if (type == BYTECODE || type == BYTECODE_NON_EDITABLE
|
||||||
|
|| type == JAVA_AND_BYTECODE || type == JAVA_AND_BYTECODE_NON_EDITABLE)
|
||||||
menu.add(bytecode);
|
menu.add(bytecode);
|
||||||
|
|
||||||
if (type != JAVA_NON_EDITABLE && type != BYTECODE_NON_EDITABLE)
|
if (type != JAVA_NON_EDITABLE && type != BYTECODE_NON_EDITABLE
|
||||||
|
&& type != JAVA_AND_BYTECODE_NON_EDITABLE)
|
||||||
{
|
{
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
menu.add(editable);
|
menu.add(editable);
|
||||||
|
@ -74,11 +77,8 @@ public class DecompilerViewComponent
|
||||||
|
|
||||||
public void addToGroup(ButtonGroup group)
|
public void addToGroup(ButtonGroup group)
|
||||||
{
|
{
|
||||||
if (type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
group.add(java);
|
||||||
group.add(java);
|
group.add(bytecode);
|
||||||
|
|
||||||
if (type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
|
||||||
group.add(bytecode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JMenu getMenu()
|
public JMenu getMenu()
|
||||||
|
@ -117,6 +117,7 @@ public class DecompilerViewComponent
|
||||||
JAVA_NON_EDITABLE,
|
JAVA_NON_EDITABLE,
|
||||||
BYTECODE,
|
BYTECODE,
|
||||||
BYTECODE_NON_EDITABLE,
|
BYTECODE_NON_EDITABLE,
|
||||||
JAVA_AND_BYTECODE;
|
JAVA_AND_BYTECODE,
|
||||||
|
JAVA_AND_BYTECODE_NON_EDITABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||||
|
|
||||||
|
@ -120,9 +121,9 @@ public class JFrameConsole extends JFrame
|
||||||
/**
|
/**
|
||||||
* Trims the console text to prevent killing the swing thread
|
* Trims the console text to prevent killing the swing thread
|
||||||
*/
|
*/
|
||||||
public String trimConsoleText(String s)
|
public String trimConsoleText(String text)
|
||||||
{
|
{
|
||||||
int len = s.length();
|
int len = text.length();
|
||||||
|
|
||||||
//TODO this should also be a setting eventually
|
//TODO this should also be a setting eventually
|
||||||
int max = 500_000;
|
int max = 500_000;
|
||||||
|
@ -136,12 +137,19 @@ public class JFrameConsole extends JFrame
|
||||||
new Thread(() ->
|
new Thread(() ->
|
||||||
{
|
{
|
||||||
//save to disk
|
//save to disk
|
||||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
try
|
||||||
|
{
|
||||||
|
DiskWriter.write(tempFile.getAbsolutePath(), text);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}, "Console Log Saving").start();
|
}, "Console Log Saving").start();
|
||||||
|
|
||||||
//trim
|
//trim
|
||||||
int skipped = len - max;
|
int skipped = len - max;
|
||||||
String trimmed = s.substring(0, max);
|
String trimmed = text.substring(0, max);
|
||||||
|
|
||||||
if (!trimmed.startsWith("WARNING: Skipping"))
|
if (!trimmed.startsWith("WARNING: Skipping"))
|
||||||
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
||||||
|
@ -150,7 +158,7 @@ public class JFrameConsole extends JFrame
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = -5056940543411437508L;
|
private static final long serialVersionUID = -5056940543411437508L;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
|
@ -382,10 +382,10 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
File tempFile = new File(TEMP_DIRECTORY + FS + hash + FS + name + "." + extension);
|
File tempFile = new File(TEMP_DIRECTORY + FS + hash + FS + name + "." + extension);
|
||||||
if (!tempFile.exists())
|
if (!tempFile.exists())
|
||||||
{
|
{
|
||||||
DiskWriter.replaceFileBytes(tempFile.getAbsolutePath(), content, false);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DiskWriter.write(tempFile.getAbsolutePath(), content);
|
||||||
|
|
||||||
imp.getImporter().open(tempFile);
|
imp.getImporter().open(tempFile);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -51,6 +51,7 @@ public class BytecodeViewPanel extends JPanel
|
||||||
public BytecodeViewPanel(int panelIndex, ClassViewer viewer)
|
public BytecodeViewPanel(int panelIndex, ClassViewer viewer)
|
||||||
{
|
{
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
|
|
||||||
this.panelIndex = panelIndex;
|
this.panelIndex = panelIndex;
|
||||||
this.viewer = viewer;
|
this.viewer = viewer;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,7 @@ public class BytecodeViewPanel extends JPanel
|
||||||
if (viewer.resource == null)
|
if (viewer.resource == null)
|
||||||
add(new JLabel("ERROR: Resource Viewer Missing Resource"));
|
add(new JLabel("ERROR: Resource Viewer Missing Resource"));
|
||||||
|
|
||||||
//TODO remove when bcel support is added
|
//TODO remove when bcel support is added
|
||||||
else if (viewer.resource.getResourceClassNode() == null)
|
else if (viewer.resource.getResourceClassNode() == null)
|
||||||
add(new JLabel("ERROR: Resource Viewer Missing ClassNode"));
|
add(new JLabel("ERROR: Resource Viewer Missing ClassNode"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,22 +45,26 @@ public class DecompilerSelectionPane
|
||||||
private final JMenu menu;
|
private final JMenu menu;
|
||||||
private final ButtonGroup group = new ButtonGroup();
|
private final ButtonGroup group = new ButtonGroup();
|
||||||
private final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", TranslatedComponents.NONE);
|
private final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", TranslatedComponents.NONE);
|
||||||
private final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", TranslatedComponents.HEXCODE);
|
private final JRadioButtonMenuItem hexcodeViewer = new TranslatedJRadioButtonMenuItem("Hexcode", TranslatedComponents.HEXCODE);
|
||||||
private final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
|
//decompilers
|
||||||
private final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
|
private final DecompilerViewComponent fernFlowerDecompiler = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
|
||||||
private final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
|
private final DecompilerViewComponent procyonDecompiler = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
|
||||||
private final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
|
private final DecompilerViewComponent CFRDecompiler = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
|
||||||
private final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
|
private final DecompilerViewComponent JADXDecompiler = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
|
||||||
private final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_DISASSEMBLER);
|
private final DecompilerViewComponent JDCoreDecompiler = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
|
||||||
private final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE, Decompiler.SMALI_DISASSEMBLER);
|
//disassemblers
|
||||||
private final DecompilerViewComponent bytecode = new DecompilerViewComponent("Bytecode", BYTECODE_NON_EDITABLE, Decompiler.BYTECODE_DISASSEMBLER);
|
private final DecompilerViewComponent bytecodeViewer = new DecompilerViewComponent("Bytecode", BYTECODE_NON_EDITABLE, Decompiler.BYTECODE_DISASSEMBLER);
|
||||||
private final DecompilerViewComponent asmTextify = new DecompilerViewComponent("ASM Textify", BYTECODE_NON_EDITABLE, Decompiler.ASM_TEXTIFY_DISASSEMBLER);
|
private final DecompilerViewComponent javapDisassembler = new DecompilerViewComponent("Javap", BYTECODE_NON_EDITABLE, Decompiler.JAVAP_DISASSEMBLER);
|
||||||
private final DecompilerViewComponent asmifier = new DecompilerViewComponent("ASMifier", JAVA_NON_EDITABLE, Decompiler.ASMIFIER_DECOMPILER);
|
private final DecompilerViewComponent krakatauDecompiler = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_DISASSEMBLER);
|
||||||
private final DecompilerViewComponent javap = new DecompilerViewComponent("Javap", BYTECODE_NON_EDITABLE, Decompiler.JAVAP_DISASSEMBLER);
|
private final DecompilerViewComponent smaliDisassembler = new DecompilerViewComponent("Smali", BYTECODE, Decompiler.SMALI_DISASSEMBLER);
|
||||||
|
//code-gen / etc
|
||||||
|
private final DecompilerViewComponent asmifierCodeGen = new DecompilerViewComponent("ASMifier", JAVA_AND_BYTECODE_NON_EDITABLE, Decompiler.ASMIFIER_CODE_GEN, Decompiler.ASM_DISASSEMBLER);
|
||||||
|
|
||||||
//TODO when adding new decompilers insert the DecompilerViewComponent object into here
|
//TODO when adding new decompilers insert the DecompilerViewComponent object into here
|
||||||
// also in the group, then finally the build menu
|
// also in the group, then finally the build menu
|
||||||
public List<DecompilerViewComponent> components = new ArrayList<>(Arrays.asList(procyon, CFR, JADX, JD, fern, krakatau, smali, bytecode, asmTextify, asmifier, javap));
|
public List<DecompilerViewComponent> components = new ArrayList<>(Arrays.asList(
|
||||||
|
procyonDecompiler, CFRDecompiler, JADXDecompiler, JDCoreDecompiler, fernFlowerDecompiler,
|
||||||
|
krakatauDecompiler, smaliDisassembler, bytecodeViewer, asmifierCodeGen, javapDisassembler));
|
||||||
|
|
||||||
public DecompilerSelectionPane(int paneID)
|
public DecompilerSelectionPane(int paneID)
|
||||||
{
|
{
|
||||||
|
@ -83,10 +87,10 @@ public class DecompilerSelectionPane
|
||||||
switch (paneID)
|
switch (paneID)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
group.setSelected(fern.getJava().getModel(), true);
|
group.setSelected(fernFlowerDecompiler.getJava().getModel(), true);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
group.setSelected(bytecode.getBytecode().getModel(), true);
|
group.setSelected(bytecodeViewer.getBytecode().getModel(), true);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
group.setSelected(none.getModel(), true);
|
group.setSelected(none.getModel(), true);
|
||||||
|
@ -101,12 +105,12 @@ public class DecompilerSelectionPane
|
||||||
{
|
{
|
||||||
//build the radiobutton group
|
//build the radiobutton group
|
||||||
group.add(none);
|
group.add(none);
|
||||||
group.add(hexcode);
|
group.add(hexcodeViewer);
|
||||||
components.forEach(decompilerViewComponent -> decompilerViewComponent.addToGroup(group));
|
components.forEach(decompilerViewComponent -> decompilerViewComponent.addToGroup(group));
|
||||||
|
|
||||||
//build the action commands
|
//build the action commands
|
||||||
none.setActionCommand(Decompiler.NONE.name());
|
none.setActionCommand(Decompiler.NONE.name());
|
||||||
hexcode.setActionCommand(Decompiler.HEXCODE_VIEWER.name());
|
hexcodeViewer.setActionCommand(Decompiler.HEXCODE_VIEWER.name());
|
||||||
|
|
||||||
for (DecompilerViewComponent component : components)
|
for (DecompilerViewComponent component : components)
|
||||||
{
|
{
|
||||||
|
@ -115,9 +119,9 @@ public class DecompilerSelectionPane
|
||||||
String cmd = decompiler.name();
|
String cmd = decompiler.name();
|
||||||
|
|
||||||
//TODO this is pretty janky and will break if a decompiler doesn't end with _DECOMPILER suffix
|
//TODO this is pretty janky and will break if a decompiler doesn't end with _DECOMPILER suffix
|
||||||
if (cmd.endsWith("DECOMPILER"))
|
if (cmd.endsWith("_DECOMPILER") || cmd.endsWith("_CODE_GEN"))
|
||||||
component.getJava().setActionCommand(cmd);
|
component.getJava().setActionCommand(cmd);
|
||||||
else// if(cmd.endsWith("DISASSEMBLER"))
|
else// if(cmd.endsWith("_DISASSEMBLER"))
|
||||||
component.getBytecode().setActionCommand(cmd);
|
component.getBytecode().setActionCommand(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,28 +144,27 @@ public class DecompilerSelectionPane
|
||||||
//build the menu
|
//build the menu
|
||||||
menu.add(none);
|
menu.add(none);
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
menu.add(procyon.getMenu());
|
menu.add(procyonDecompiler.getMenu());
|
||||||
menu.add(CFR.getMenu());
|
menu.add(CFRDecompiler.getMenu());
|
||||||
|
|
||||||
if (!Configuration.jadxGroupedWithSmali)
|
if (!Configuration.jadxGroupedWithSmali)
|
||||||
menu.add(JADX.getMenu());
|
menu.add(JADXDecompiler.getMenu());
|
||||||
|
|
||||||
menu.add(JD.getMenu());
|
menu.add(JDCoreDecompiler.getMenu());
|
||||||
menu.add(fern.getMenu());
|
menu.add(fernFlowerDecompiler.getMenu());
|
||||||
menu.add(krakatau.getMenu());
|
menu.add(krakatauDecompiler.getMenu());
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
|
|
||||||
if (Configuration.jadxGroupedWithSmali)
|
if (Configuration.jadxGroupedWithSmali)
|
||||||
menu.add(JADX.getMenu());
|
menu.add(JADXDecompiler.getMenu());
|
||||||
|
|
||||||
menu.add(smali.getMenu());
|
menu.add(smaliDisassembler.getMenu());
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
menu.add(bytecode.getMenu());
|
menu.add(bytecodeViewer.getMenu());
|
||||||
menu.add(javap.getMenu());
|
menu.add(javapDisassembler.getMenu());
|
||||||
menu.add(asmTextify.getMenu());
|
menu.add(asmifierCodeGen.getMenu());
|
||||||
menu.add(asmifier.getMenu());
|
|
||||||
menu.add(new JSeparator());
|
menu.add(new JSeparator());
|
||||||
menu.add(hexcode);
|
menu.add(hexcodeViewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decompiler getSelectedDecompiler()
|
public Decompiler getSelectedDecompiler()
|
||||||
|
@ -176,6 +179,7 @@ public class DecompilerSelectionPane
|
||||||
while (it.hasMoreElements())
|
while (it.hasMoreElements())
|
||||||
{
|
{
|
||||||
AbstractButton button = it.nextElement();
|
AbstractButton button = it.nextElement();
|
||||||
|
|
||||||
if (button.getActionCommand().equals(decompiler.name()))
|
if (button.getActionCommand().equals(decompiler.name()))
|
||||||
{
|
{
|
||||||
group.setSelected(button.getModel(), true);
|
group.setSelected(button.getModel(), true);
|
||||||
|
|
|
@ -19,10 +19,8 @@
|
||||||
package the.bytecode.club.bytecodeviewer.plugin;
|
package the.bytecode.club.bytecodeviewer.plugin;
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.konloch.taskmanager.Task;
|
import com.konloch.disklib.DiskReader;
|
||||||
import com.konloch.taskmanager.TaskRunnable;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
|
||||||
import org.apache.commons.compress.utils.FileNameUtils;
|
import org.apache.commons.compress.utils.FileNameUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
|
@ -188,7 +186,7 @@ public class PluginWriter extends JFrame
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
area.setText(DiskReader.loadAsString(file.getAbsolutePath()));
|
area.setText(DiskReader.readString(file.getAbsolutePath()));
|
||||||
area.setCaretPosition(0);
|
area.setCaretPosition(0);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -269,7 +267,15 @@ public class PluginWriter extends JFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskWriter.replaceFile(savePath.getAbsolutePath(), area.getText(), false);
|
try
|
||||||
|
{
|
||||||
|
DiskWriter.write(savePath.getAbsolutePath(), area.getText());
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
addRecentPlugin(savePath);
|
addRecentPlugin(savePath);
|
||||||
}, "Plugin Editor Save");
|
}, "Plugin Editor Save");
|
||||||
|
|
||||||
|
@ -306,7 +312,7 @@ public class PluginWriter extends JFrame
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//update content from latest disk data
|
//update content from latest disk data
|
||||||
content = DiskReader.loadAsString(savePath.getAbsolutePath());
|
content = DiskReader.readString(savePath.getAbsolutePath());
|
||||||
|
|
||||||
//update plugin writer UI on disk update
|
//update plugin writer UI on disk update
|
||||||
SwingUtilities.invokeLater(() ->
|
SwingUtilities.invokeLater(() ->
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.resources;
|
package the.bytecode.club.bytecodeviewer.resources;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
import the.bytecode.club.bytecodeviewer.api.BCV;
|
import the.bytecode.club.bytecodeviewer.api.BCV;
|
||||||
|
@ -31,6 +31,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||||
|
@ -258,20 +259,20 @@ public class ResourceDecompiling
|
||||||
|
|
||||||
//decompile all opened classes to zip
|
//decompile all opened classes to zip
|
||||||
decompiler.getDecompiler().decompileToZip(targetJar.getAbsolutePath(), saveAll ? MiscUtils.append(outputZip,
|
decompiler.getDecompiler().decompileToZip(targetJar.getAbsolutePath(), saveAll ? MiscUtils.append(outputZip,
|
||||||
"-" + decompiler.getDecompilerNameProgrammic() + ".zip") : outputZip.getAbsolutePath());
|
"-" + decompiler.getDecompilerNameProgrammatic() + ".zip") : outputZip.getAbsolutePath());
|
||||||
|
|
||||||
//signal to the user that BCV is finished performing that action
|
//signal to the user that BCV is finished performing that action
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void decompileCurrentlyOpenedResource(Decompiler decompiler, File outputFile, boolean saveAll)
|
public static void decompileCurrentlyOpenedResource(Decompiler decompiler, File outputFile, boolean saveAll) throws IOException
|
||||||
{
|
{
|
||||||
//signal to the user that BCV is performing an action in the background
|
//signal to the user that BCV is performing an action in the background
|
||||||
BytecodeViewer.updateBusyStatus(true);
|
BytecodeViewer.updateBusyStatus(true);
|
||||||
|
|
||||||
//decompile the currently opened resource and save it to the specified file
|
//decompile the currently opened resource and save it to the specified file
|
||||||
DiskWriter.replaceFile(saveAll ? MiscUtils.append(outputFile,
|
DiskWriter.write(saveAll ? MiscUtils.append(outputFile,
|
||||||
"-" + decompiler.getDecompilerNameProgrammic() + ".java") : outputFile.getAbsolutePath(), BCV.decompileCurrentlyOpenedClassNode(decompiler), false);
|
"-" + decompiler.getDecompilerNameProgrammatic() + ".java") : outputFile.getAbsolutePath(), BCV.decompileCurrentlyOpenedClassNode(decompiler));
|
||||||
|
|
||||||
//signal to the user that BCV is finished performing that action
|
//signal to the user that BCV is finished performing that action
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
|
|
@ -89,8 +89,8 @@ public class ClassFileContainer
|
||||||
&& !getDecompiler().equals(Decompiler.KRAKATAU_DISASSEMBLER.getDecompilerName())
|
&& !getDecompiler().equals(Decompiler.KRAKATAU_DISASSEMBLER.getDecompilerName())
|
||||||
&& !getDecompiler().equals(Decompiler.JAVAP_DISASSEMBLER.getDecompilerName())
|
&& !getDecompiler().equals(Decompiler.JAVAP_DISASSEMBLER.getDecompilerName())
|
||||||
&& !getDecompiler().equals(Decompiler.SMALI_DISASSEMBLER.getDecompilerName())
|
&& !getDecompiler().equals(Decompiler.SMALI_DISASSEMBLER.getDecompilerName())
|
||||||
&& !getDecompiler().equals(Decompiler.ASM_TEXTIFY_DISASSEMBLER.getDecompilerName())
|
&& !getDecompiler().equals(Decompiler.ASM_DISASSEMBLER.getDecompilerName())
|
||||||
&& !getDecompiler().equals(Decompiler.ASMIFIER_DECOMPILER.getDecompilerName());
|
&& !getDecompiler().equals(Decompiler.ASMIFIER_CODE_GEN.getDecompilerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
|
|
|
@ -31,6 +31,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -109,17 +110,26 @@ public class APKExport implements Exporter
|
||||||
|
|
||||||
Thread saveThread = new Thread(() ->
|
Thread saveThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
BytecodeViewer.updateBusyStatus(true);
|
try
|
||||||
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
|
||||||
|
|
||||||
Thread buildAPKThread = new Thread(() ->
|
|
||||||
{
|
{
|
||||||
APKTool.buildAPK(new File(input), file, finalContainer);
|
BytecodeViewer.updateBusyStatus(true);
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
||||||
}, "Process APK");
|
|
||||||
|
|
||||||
buildAPKThread.start();
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
||||||
|
|
||||||
|
Thread buildAPKThread = new Thread(() ->
|
||||||
|
{
|
||||||
|
APKTool.buildAPK(new File(input), file, finalContainer);
|
||||||
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
}, "Process APK");
|
||||||
|
|
||||||
|
buildAPKThread.start();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
BytecodeViewer.handleException(ex);
|
||||||
|
}
|
||||||
}, "Jar Export");
|
}, "Jar Export");
|
||||||
|
|
||||||
saveThread.start();
|
saveThread.start();
|
||||||
|
|
|
@ -29,6 +29,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||||
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||||
|
@ -73,18 +74,27 @@ public class DexExport implements Exporter
|
||||||
|
|
||||||
Thread saveAsJar = new Thread(() ->
|
Thread saveAsJar = new Thread(() ->
|
||||||
{
|
{
|
||||||
BytecodeViewer.updateBusyStatus(true);
|
try
|
||||||
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
|
||||||
|
|
||||||
Thread saveAsDex = new Thread(() ->
|
|
||||||
{
|
{
|
||||||
Dex2Jar.saveAsDex(new File(input), outputPath);
|
BytecodeViewer.updateBusyStatus(true);
|
||||||
|
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
||||||
|
|
||||||
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
||||||
|
|
||||||
|
Thread saveAsDex = new Thread(() ->
|
||||||
|
{
|
||||||
|
Dex2Jar.saveAsDex(new File(input), outputPath);
|
||||||
|
|
||||||
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
}, "Process DEX");
|
||||||
|
|
||||||
|
saveAsDex.start();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
}, "Process DEX");
|
BytecodeViewer.handleException(ex);
|
||||||
|
}
|
||||||
saveAsDex.start();
|
|
||||||
}, "Jar Export");
|
}, "Jar Export");
|
||||||
|
|
||||||
saveAsJar.start();
|
saveAsJar.start();
|
||||||
|
|
|
@ -28,6 +28,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
|
@ -65,8 +66,18 @@ public class ZipExport implements Exporter
|
||||||
|
|
||||||
Thread saveThread = new Thread(() ->
|
Thread saveThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
try
|
||||||
BytecodeViewer.updateBusyStatus(false);
|
{
|
||||||
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
BytecodeViewer.handleException(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
BytecodeViewer.updateBusyStatus(false);
|
||||||
|
}
|
||||||
}, "Jar Export");
|
}, "Jar Export");
|
||||||
|
|
||||||
saveThread.start();
|
saveThread.start();
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.resources.importing.impl;
|
package the.bytecode.club.bytecodeviewer.resources.importing.impl;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
|
@ -27,10 +27,7 @@ import the.bytecode.club.bytecodeviewer.resources.importing.Import;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
|
import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -96,10 +93,10 @@ public class XAPKResourceImporter implements Importer
|
||||||
BytecodeViewer.addResourceContainer(container); //add the resource container to BCV's total loaded files
|
BytecodeViewer.addResourceContainer(container); //add the resource container to BCV's total loaded files
|
||||||
}
|
}
|
||||||
|
|
||||||
public File exportTo(File original, String extension, byte[] bytes)
|
public File exportTo(File original, String extension, byte[] bytes) throws IOException
|
||||||
{
|
{
|
||||||
File file = new File(original.getAbsolutePath() + extension);
|
File file = new File(original.getAbsolutePath() + extension);
|
||||||
DiskWriter.replaceFileBytes(file.getAbsolutePath(), bytes, false);
|
DiskWriter.write(file.getAbsolutePath(), bytes);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ public enum TranslatedStrings
|
||||||
PRODUCT_H_NAME("Bytecode-Viewer"),
|
PRODUCT_H_NAME("Bytecode-Viewer"),
|
||||||
WEBSITE("https://bytecodeviewer.com"),
|
WEBSITE("https://bytecodeviewer.com"),
|
||||||
TBC("https://the.bytecode.club"),
|
TBC("https://the.bytecode.club"),
|
||||||
|
DEV_MODE_SIMULATED_ERROR("Developer-Mode: Simulated Error"),
|
||||||
|
|
||||||
EDITABLE,
|
EDITABLE,
|
||||||
JAVA,
|
JAVA,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 10/2/2024
|
||||||
|
*/
|
||||||
|
public class ExceptionUtils
|
||||||
|
{
|
||||||
|
public static String exceptionToString(Throwable e)
|
||||||
|
{
|
||||||
|
StringWriter exceptionWriter = new StringWriter();
|
||||||
|
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
return exceptionWriter.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package the.bytecode.club.bytecodeviewer.util;
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import com.konloch.disklib.DiskWriter;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
@ -356,7 +356,7 @@ public class JarUtils
|
||||||
|
|
||||||
String name = cn.name + ".class";
|
String name = cn.name + ".class";
|
||||||
|
|
||||||
if (!fileCollisionPrevention.add(name))
|
if (fileCollisionPrevention.add(name))
|
||||||
{
|
{
|
||||||
out.putNextEntry(new ZipEntry(name));
|
out.putNextEntry(new ZipEntry(name));
|
||||||
out.write(cw.toByteArray());
|
out.write(cw.toByteArray());
|
||||||
|
@ -390,7 +390,7 @@ public class JarUtils
|
||||||
File f = new File(name);
|
File f = new File(name);
|
||||||
f.mkdirs();
|
f.mkdirs();
|
||||||
|
|
||||||
DiskWriter.replaceFileBytes(name, cw.toByteArray(), false);
|
DiskWriter.write(name, cw.toByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -405,7 +405,7 @@ public class JarUtils
|
||||||
* @param nodeList The loaded ClassNodes
|
* @param nodeList The loaded ClassNodes
|
||||||
* @param path the exact jar output path
|
* @param path the exact jar output path
|
||||||
*/
|
*/
|
||||||
public static void saveAsJar(List<ClassNode> nodeList, String path)
|
public static void saveAsJar(List<ClassNode> nodeList, String path) throws IOException
|
||||||
{
|
{
|
||||||
try (FileOutputStream fos = new FileOutputStream(path);
|
try (FileOutputStream fos = new FileOutputStream(path);
|
||||||
JarOutputStream out = new JarOutputStream(fos))
|
JarOutputStream out = new JarOutputStream(fos))
|
||||||
|
@ -448,9 +448,5 @@ public class JarUtils
|
||||||
|
|
||||||
fileCollisionPrevention .clear();
|
fileCollisionPrevention .clear();
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
BytecodeViewer.handleException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,36 @@ public class MiscUtils
|
||||||
File tempFile;
|
File tempFile;
|
||||||
String randomString;
|
String randomString;
|
||||||
|
|
||||||
|
while (searching)
|
||||||
|
{
|
||||||
|
randomString = MiscUtils.randomString(32);
|
||||||
|
uniqueName = stringStart + randomString + fileExtension;
|
||||||
|
tempFile = new File(stringStart + randomString + fileExtension);
|
||||||
|
|
||||||
|
if (!tempFile.exists())
|
||||||
|
searching = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the file system to ensure it's a unique name
|
||||||
|
*
|
||||||
|
* @param stringStart directory it'll be in
|
||||||
|
* @param fileExtension the file extension it'll use
|
||||||
|
* @return the unique name
|
||||||
|
*/
|
||||||
|
//TODO anything using this should be updated:
|
||||||
|
// The + ".class" needs to be removed
|
||||||
|
@Deprecated
|
||||||
|
public static String getUniqueNameBroken(String stringStart, String fileExtension)
|
||||||
|
{
|
||||||
|
String uniqueName = null;
|
||||||
|
boolean searching = true;
|
||||||
|
File tempFile;
|
||||||
|
String randomString;
|
||||||
|
|
||||||
while (searching)
|
while (searching)
|
||||||
{
|
{
|
||||||
randomString = MiscUtils.randomString(32);
|
randomString = MiscUtils.randomString(32);
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.NL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 10/2/2024
|
||||||
|
*/
|
||||||
|
public class ProcessUtils
|
||||||
|
{
|
||||||
|
public static StringBuilder mergeLogs(StringBuilder out, StringBuilder err, int exitCode)
|
||||||
|
{
|
||||||
|
StringBuilder logs = new StringBuilder();
|
||||||
|
|
||||||
|
if(out.toString().trim().length() >= 1)
|
||||||
|
logs.append(TranslatedStrings.PROCESS2).append(" out:")
|
||||||
|
.append(out).append(NL).append(NL);
|
||||||
|
|
||||||
|
if(err.toString().trim().length() >= 1)
|
||||||
|
logs.append(TranslatedStrings.PROCESS2).append(" err:")
|
||||||
|
.append(err).append(NL).append(NL);
|
||||||
|
|
||||||
|
logs.append(TranslatedStrings.ERROR2).append(NL).append(NL);
|
||||||
|
logs.append(TranslatedStrings.EXIT_VALUE_IS).append(" ")
|
||||||
|
.append(exitCode).append(NL).append(NL);
|
||||||
|
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readProcessToStringBuilder(Process process, StringBuilder out, StringBuilder err) throws IOException
|
||||||
|
{
|
||||||
|
//Read out dir output
|
||||||
|
try (InputStream is = process.getInputStream();
|
||||||
|
InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader br = new BufferedReader(isr))
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
out.append(NL).append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream is = process.getErrorStream();
|
||||||
|
InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader br = new BufferedReader(isr))
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
err.append(NL).append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readProcessToStringBuilderAsync(Process process, StringBuilder out, StringBuilder err) throws IOException
|
||||||
|
{
|
||||||
|
try (InputStream is = process.getInputStream();
|
||||||
|
InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader br = new BufferedReader(isr))
|
||||||
|
{
|
||||||
|
BytecodeViewer.getTaskManager().delayLoop(25, task ->
|
||||||
|
{
|
||||||
|
if(!process.isAlive())
|
||||||
|
task.stop();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
out.append(NL).append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream is = process.getErrorStream();
|
||||||
|
InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader br = new BufferedReader(isr))
|
||||||
|
{
|
||||||
|
BytecodeViewer.getTaskManager().delayLoop(25, task ->
|
||||||
|
{
|
||||||
|
if(!process.isAlive())
|
||||||
|
task.stop();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
err.append(NL).append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runDecompilerExternal(String[] args, boolean exceptionToGUI) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(args);
|
||||||
|
Process p = pb.start();
|
||||||
|
BytecodeViewer.createdProcesses.add(p);
|
||||||
|
p.waitFor();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if(exceptionToGUI)
|
||||||
|
BytecodeViewer.handleException(e);
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.util;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.Constants;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Settings;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 10/2/2024
|
||||||
|
*/
|
||||||
|
public class TempFile
|
||||||
|
{
|
||||||
|
private File parent;
|
||||||
|
private final File file;
|
||||||
|
private String uniqueName;
|
||||||
|
private final HashSet<String> createdFilePaths = new HashSet<>();
|
||||||
|
|
||||||
|
public TempFile(File file, String uniqueName)
|
||||||
|
{
|
||||||
|
this.parent = file.getParentFile();
|
||||||
|
this.file = file;
|
||||||
|
this.uniqueName = uniqueName;
|
||||||
|
this.createdFilePaths.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getParent()
|
||||||
|
{
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile()
|
||||||
|
{
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniqueName()
|
||||||
|
{
|
||||||
|
return uniqueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newTemporaryParent()
|
||||||
|
{
|
||||||
|
setParent(createTempDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(File parent)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniqueName(String uniqueName)
|
||||||
|
{
|
||||||
|
this.uniqueName = uniqueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markAsCreatedFile(File file)
|
||||||
|
{
|
||||||
|
createdFilePaths.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup()
|
||||||
|
{
|
||||||
|
if(!Settings.DECOMPILERS_AUTOMATICALLY_CLEANUP)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//delete all the items
|
||||||
|
for(String path : createdFilePaths)
|
||||||
|
{
|
||||||
|
File toDelete = new File(path);
|
||||||
|
|
||||||
|
toDelete.delete();
|
||||||
|
|
||||||
|
if(!toDelete.getParentFile().getAbsolutePath().equalsIgnoreCase(new File(TEMP_DIRECTORY).getAbsolutePath()))
|
||||||
|
deleteFolder(toDelete.getParentFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete parent if it's not the main temp directory
|
||||||
|
if(!getParent().getAbsolutePath().equalsIgnoreCase(new File(TEMP_DIRECTORY).getAbsolutePath()))
|
||||||
|
deleteFolder(getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteFolder(File file)
|
||||||
|
{
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
|
||||||
|
if(files != null)
|
||||||
|
{
|
||||||
|
for(File subFile : files)
|
||||||
|
{
|
||||||
|
if(subFile.isDirectory())
|
||||||
|
deleteFolder(subFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public File createFileFromExtension(String extension)
|
||||||
|
{
|
||||||
|
return createFileFromExtension(true, false, extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File createFileFromExtension(boolean newUniqueName, boolean canExist, String extension)
|
||||||
|
{
|
||||||
|
File file;
|
||||||
|
|
||||||
|
String uniqueName = newUniqueName ? MiscUtils.getUniqueName("", extension) : this.uniqueName + extension;
|
||||||
|
|
||||||
|
//generate a new name until the directory no longer exists
|
||||||
|
while((file = new File(parent, uniqueName)).exists())
|
||||||
|
{
|
||||||
|
if(canExist)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.createdFilePaths.add(file.getAbsolutePath());
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TempFile createTemporaryFile(boolean newDirectory, String extension)
|
||||||
|
{
|
||||||
|
//generate a new temporary parent directory
|
||||||
|
File parent = newDirectory ? createTempDirectory() : new File(TEMP_DIRECTORY);
|
||||||
|
|
||||||
|
//make the parent directories
|
||||||
|
parent.mkdirs();
|
||||||
|
|
||||||
|
//create the temporary variables
|
||||||
|
String uniqueName;
|
||||||
|
File file = null;
|
||||||
|
|
||||||
|
//generate a new name until the directory no longer exists
|
||||||
|
while((uniqueName = MiscUtils.getUniqueName("", extension)) != null &&
|
||||||
|
(file = new File(parent, uniqueName)).exists())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uniqueName != null)
|
||||||
|
uniqueName = uniqueName.substring(0, uniqueName.length() - extension.length());
|
||||||
|
|
||||||
|
return new TempFile(file, uniqueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File createTempDirectory()
|
||||||
|
{
|
||||||
|
File directory;
|
||||||
|
|
||||||
|
//generate a new name until the directory no longer exists
|
||||||
|
while((directory = new File(TEMP_DIRECTORY, MiscUtils.randomString(32))).exists())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,53 +46,33 @@ public final class ZipUtils
|
||||||
String canonicalDestDir = new File(destinationDir).getCanonicalPath();
|
String canonicalDestDir = new File(destinationDir).getCanonicalPath();
|
||||||
|
|
||||||
if (!canonicalDestDir.endsWith(File.separator))
|
if (!canonicalDestDir.endsWith(File.separator))
|
||||||
{
|
|
||||||
canonicalDestDir += File.separator;
|
canonicalDestDir += File.separator;
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(jarPath);
|
try (JarFile jarFile = new JarFile(new File(jarPath)))
|
||||||
|
|
||||||
try (JarFile jar = new JarFile(file))
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// fist get all directories,
|
|
||||||
// then make those directory on the destination Path
|
|
||||||
/*for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) {
|
|
||||||
JarEntry entry = (JarEntry) enums.nextElement();
|
|
||||||
|
|
||||||
String fileName = destinationDir + File.separator + entry.getName();
|
|
||||||
File f = new File(fileName);
|
|
||||||
|
|
||||||
if (fileName.endsWith("/")) {
|
|
||||||
f.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//now create all files
|
//now create all files
|
||||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); )
|
for (Enumeration<JarEntry> enums = jarFile.entries();
|
||||||
|
enums.hasMoreElements(); )
|
||||||
{
|
{
|
||||||
JarEntry entry = enums.nextElement();
|
JarEntry entry = enums.nextElement();
|
||||||
|
|
||||||
String fileName = destinationDir + File.separator + entry.getName();
|
String fileName = destinationDir + File.separator + entry.getName();
|
||||||
File f = new File(fileName);
|
File file = new File(fileName);
|
||||||
|
|
||||||
if (!f.getCanonicalPath().startsWith(canonicalDestDir))
|
if (!file.getCanonicalPath().startsWith(canonicalDestDir))
|
||||||
{
|
{
|
||||||
System.out.println("Zip Slip exploit detected. Skipping entry " + entry.getName());
|
System.out.println("Zip Slip exploit detected. Skipping entry " + entry.getName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
File parent = f.getParentFile();
|
File parent = file.getParentFile();
|
||||||
|
|
||||||
if (!parent.exists())
|
if (!parent.exists())
|
||||||
{
|
|
||||||
parent.mkdirs();
|
parent.mkdirs();
|
||||||
}
|
|
||||||
|
|
||||||
if (!fileName.endsWith("/"))
|
if (!fileName.endsWith("/"))
|
||||||
{
|
{
|
||||||
try (InputStream is = jar.getInputStream(entry); FileOutputStream fos = new FileOutputStream(f))
|
try (InputStream is = jarFile.getInputStream(entry); FileOutputStream fos = new FileOutputStream(file))
|
||||||
{
|
{
|
||||||
// write contents of 'is' to 'fos'
|
// write contents of 'is' to 'fos'
|
||||||
while (is.available() > 0)
|
while (is.available() > 0)
|
||||||
|
@ -117,6 +97,7 @@ public final class ZipUtils
|
||||||
try (FileInputStream in = new FileInputStream(inputFile))
|
try (FileInputStream in = new FileInputStream(inputFile))
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
while ((len = in.read(buffer)) > 0)
|
while ((len = in.read(buffer)) > 0)
|
||||||
{
|
{
|
||||||
zos.write(buffer, 0, len);
|
zos.write(buffer, 0, len);
|
||||||
|
@ -153,9 +134,7 @@ public final class ZipUtils
|
||||||
|
|
||||||
File folder = new File(srcFile);
|
File folder = new File(srcFile);
|
||||||
if (folder.isDirectory())
|
if (folder.isDirectory())
|
||||||
{
|
|
||||||
addFolderToZip(path, srcFile, zip, ignore);
|
addFolderToZip(path, srcFile, zip, ignore);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] buf = new byte[1024];
|
byte[] buf = new byte[1024];
|
||||||
|
@ -185,10 +164,11 @@ public final class ZipUtils
|
||||||
File folder = new File(srcFile);
|
File folder = new File(srcFile);
|
||||||
|
|
||||||
String check = path.toLowerCase();
|
String check = path.toLowerCase();
|
||||||
|
|
||||||
//if(check.startsWith("decoded unknown") || check.startsWith("decoded lib") || check.startsWith("decoded
|
//if(check.startsWith("decoded unknown") || check.startsWith("decoded lib") || check.startsWith("decoded
|
||||||
// assets") || check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith
|
// assets") || check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith
|
||||||
// ("decoded apktool.yml"))
|
// ("decoded apktool.yml"))
|
||||||
if (check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded " + "apktool.yml"))
|
if (check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded apktool.yml"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//if(path.equals("original") || path.equals("classes.dex") || path.equals("apktool.yml"))
|
//if(path.equals("original") || path.equals("classes.dex") || path.equals("apktool.yml"))
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali / Dex",
|
"SMALI_DEX": "Smali / Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "مساعدي التصحيح",
|
"DEBUG_HELPERS": "مساعدي التصحيح",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "إلحاق أقواس بالتسمية",
|
"APPEND_BRACKETS_TO_LABEL": "إلحاق أقواس بالتسمية",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Шестнайсетичен код",
|
"HEXCODE": "Шестнайсетичен код",
|
||||||
"BYTECODE": "Байткод",
|
"BYTECODE": "Байткод",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Декомпилатор на байткод",
|
"BYTECODE_DECOMPILER": "Декомпилатор на байткод",
|
||||||
"DEBUG_HELPERS": "Помощници за отстраняване на грешки",
|
"DEBUG_HELPERS": "Помощници за отстраняване на грешки",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Прилагане на скоби към етикета",
|
"APPEND_BRACKETS_TO_LABEL": "Прилагане на скоби към етикета",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali/Dex",
|
"SMALI_DEX": "Smali/Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Dekompilator bajtkoda",
|
"BYTECODE_DECOMPILER": "Dekompilator bajtkoda",
|
||||||
"DEBUG_HELPERS": "Pomoćnici za ispravljanje pogrešaka",
|
"DEBUG_HELPERS": "Pomoćnici za ispravljanje pogrešaka",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Dodaj zagrade na oznaku",
|
"APPEND_BRACKETS_TO_LABEL": "Dodaj zagrade na oznaku",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytový kód",
|
"BYTECODE": "Bytový kód",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Dekompilátor bajtového kódu",
|
"BYTECODE_DECOMPILER": "Dekompilátor bajtového kódu",
|
||||||
"DEBUG_HELPERS": "Pomocníci pro ladění",
|
"DEBUG_HELPERS": "Pomocníci pro ladění",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Připojení závorek ke štítku",
|
"APPEND_BRACKETS_TO_LABEL": "Připojení závorek ke štítku",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexkode",
|
"HEXCODE": "Hexkode",
|
||||||
"BYTECODE": "Bytekode",
|
"BYTECODE": "Bytekode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
||||||
"DEBUG_HELPERS": "Hjælpemidler til fejlfinding",
|
"DEBUG_HELPERS": "Hjælpemidler til fejlfinding",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Tilføj parenteser til etiketten",
|
"APPEND_BRACKETS_TO_LABEL": "Tilføj parenteser til etiketten",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali/Dex",
|
"SMALI_DEX": "Smali/Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"ASMIFIER": "ASMifier",
|
"ASMIFIER": "ASMifier",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "Debug Helpers",
|
"DEBUG_HELPERS": "Debug Helpers",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Baitkoodi dekompilaator",
|
"BYTECODE_DECOMPILER": "Baitkoodi dekompilaator",
|
||||||
"DEBUG_HELPERS": "Kõrvaldamise abivahendid",
|
"DEBUG_HELPERS": "Kõrvaldamise abivahendid",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Sulgude lisamine etiketile",
|
"APPEND_BRACKETS_TO_LABEL": "Sulgude lisamine etiketile",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "اسمالی / دکس",
|
"SMALI_DEX": "اسمالی / دکس",
|
||||||
"HEXCODE": "کد هگز",
|
"HEXCODE": "کد هگز",
|
||||||
"BYTECODE": "کد Bytecode",
|
"BYTECODE": "کد Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "رمزگشایی Bytecode",
|
"BYTECODE_DECOMPILER": "رمزگشایی Bytecode",
|
||||||
"DEBUG_HELPERS": "راهنمای اشکال زدایی",
|
"DEBUG_HELPERS": "راهنمای اشکال زدایی",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "براکت ها را به برچسب اضافه کنید",
|
"APPEND_BRACKETS_TO_LABEL": "براکت ها را به برچسب اضافه کنید",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Heksakoodi",
|
"HEXCODE": "Heksakoodi",
|
||||||
"BYTECODE": "Bytekoodi",
|
"BYTECODE": "Bytekoodi",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytekoodin purkuohjelma",
|
"BYTECODE_DECOMPILER": "Bytekoodin purkuohjelma",
|
||||||
"DEBUG_HELPERS": "Vianmäärityksen apuohjelmat",
|
"DEBUG_HELPERS": "Vianmäärityksen apuohjelmat",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Liitä hakasulkeet etikettiin",
|
"APPEND_BRACKETS_TO_LABEL": "Liitä hakasulkeet etikettiin",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Décompilateur de bytecode",
|
"BYTECODE_DECOMPILER": "Décompilateur de bytecode",
|
||||||
"DEBUG_HELPERS": "Aides au débogage",
|
"DEBUG_HELPERS": "Aides au débogage",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Ajouter des parenthèses à l'étiquette",
|
"APPEND_BRACKETS_TO_LABEL": "Ajouter des parenthèses à l'étiquette",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "სმალი / დექსი",
|
"SMALI_DEX": "სმალი / დექსი",
|
||||||
"HEXCODE": "ჰექსკოდი",
|
"HEXCODE": "ჰექსკოდი",
|
||||||
"BYTECODE": "ბიტეკოდი",
|
"BYTECODE": "ბიტეკოდი",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode დეკომპილერი",
|
"BYTECODE_DECOMPILER": "Bytecode დეკომპილერი",
|
||||||
"DEBUG_HELPERS": "Debug Helpers",
|
"DEBUG_HELPERS": "Debug Helpers",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "დაამატეთ ფრჩხილები ლეიბლზე",
|
"APPEND_BRACKETS_TO_LABEL": "დაამატეთ ფრჩხილები ლეიბლზე",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali/Dex",
|
"SMALI_DEX": "Smali/Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"ASMIFIER": "ASMifier",
|
"ASMIFIER": "ASMifier",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode-Dekompilierer",
|
"BYTECODE_DECOMPILER": "Bytecode-Dekompilierer",
|
||||||
"DEBUG_HELPERS": "Debug-Helfer",
|
"DEBUG_HELPERS": "Debug-Helfer",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Αποσυμπιεστής bytecode",
|
"BYTECODE_DECOMPILER": "Αποσυμπιεστής bytecode",
|
||||||
"DEBUG_HELPERS": "Βοηθοί εντοπισμού σφαλμάτων",
|
"DEBUG_HELPERS": "Βοηθοί εντοπισμού σφαλμάτων",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Προσθέστε αγκύλες στην ετικέτα",
|
"APPEND_BRACKETS_TO_LABEL": "Προσθέστε αγκύλες στην ετικέτα",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "סמאלי / דקס",
|
"SMALI_DEX": "סמאלי / דקס",
|
||||||
"HEXCODE": "הקסקוד",
|
"HEXCODE": "הקסקוד",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Decompiler Bytecode",
|
"BYTECODE_DECOMPILER": "Decompiler Bytecode",
|
||||||
"DEBUG_HELPERS": "עוזרי איתור באגים",
|
"DEBUG_HELPERS": "עוזרי איתור באגים",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "הוסף סוגריים לתווית",
|
"APPEND_BRACKETS_TO_LABEL": "הוסף סוגריים לתווית",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexkód",
|
"HEXCODE": "Hexkód",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode dekompiláló",
|
"BYTECODE_DECOMPILER": "Bytecode dekompiláló",
|
||||||
"DEBUG_HELPERS": "Hibakeresési segédprogramok",
|
"DEBUG_HELPERS": "Hibakeresési segédprogramok",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Zárójelek hozzáadása a címkéhez",
|
"APPEND_BRACKETS_TO_LABEL": "Zárójelek hozzáadása a címkéhez",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Decompilatore di bytecode",
|
"BYTECODE_DECOMPILER": "Decompilatore di bytecode",
|
||||||
"DEBUG_HELPERS": "Aiuti per il debug",
|
"DEBUG_HELPERS": "Aiuti per il debug",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Aggiungere parentesi all'etichetta",
|
"APPEND_BRACKETS_TO_LABEL": "Aggiungere parentesi all'etichetta",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "スマリ",
|
"SMALI_DEX": "スマリ",
|
||||||
"HEXCODE": "ヘックスコード",
|
"HEXCODE": "ヘックスコード",
|
||||||
"BYTECODE": "バイトコード",
|
"BYTECODE": "バイトコード",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "バイトコードデコンパイラー",
|
"BYTECODE_DECOMPILER": "バイトコードデコンパイラー",
|
||||||
"DEBUG_HELPERS": "デバッグヘルパー",
|
"DEBUG_HELPERS": "デバッグヘルパー",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "ラベルに括弧をつける",
|
"APPEND_BRACKETS_TO_LABEL": "ラベルに括弧をつける",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali / Dex",
|
"SMALI_DEX": "Smali / Dex",
|
||||||
"HEXCODE": "Hekscode",
|
"HEXCODE": "Hekscode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "Penolong Debug",
|
"DEBUG_HELPERS": "Penolong Debug",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Nambah Kurung Kanggo Label",
|
"APPEND_BRACKETS_TO_LABEL": "Nambah Kurung Kanggo Label",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode dekompilētājs",
|
"BYTECODE_DECOMPILER": "Bytecode dekompilētājs",
|
||||||
"DEBUG_HELPERS": "Dzesēšanas palīgierīces",
|
"DEBUG_HELPERS": "Dzesēšanas palīgierīces",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Etiķetes pievienošana iekavās",
|
"APPEND_BRACKETS_TO_LABEL": "Etiķetes pievienošana iekavās",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Šešiaženklis kodas",
|
"HEXCODE": "Šešiaženklis kodas",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytekodo dekompiliatorius",
|
"BYTECODE_DECOMPILER": "Bytekodo dekompiliatorius",
|
||||||
"DEBUG_HELPERS": "Derinimo pagalbininkai",
|
"DEBUG_HELPERS": "Derinimo pagalbininkai",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Prie etiketės pridėkite skliaustelius",
|
"APPEND_BRACKETS_TO_LABEL": "Prie etiketės pridėkite skliaustelius",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali / Dex",
|
"SMALI_DEX": "Smali / Dex",
|
||||||
"HEXCODE": "Kod Hex",
|
"HEXCODE": "Kod Hex",
|
||||||
"BYTECODE": "Kod byk",
|
"BYTECODE": "Kod byk",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Pengurai Bytecode",
|
"BYTECODE_DECOMPILER": "Pengurai Bytecode",
|
||||||
"DEBUG_HELPERS": "Pembantu Debug",
|
"DEBUG_HELPERS": "Pembantu Debug",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Lampirkan Kurungan ke Label",
|
"APPEND_BRACKETS_TO_LABEL": "Lampirkan Kurungan ke Label",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode decompiler",
|
||||||
"DEBUG_HELPERS": "Debug helpers",
|
"DEBUG_HELPERS": "Debug helpers",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Haakjes toevoegen aan label",
|
"APPEND_BRACKETS_TO_LABEL": "Haakjes toevoegen aan label",
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
"SMALI_DEX": "Smali / Dex",
|
"SMALI_DEX": "Smali / Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
|
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "Feilsøkingshjelpere",
|
"DEBUG_HELPERS": "Feilsøkingshjelpere",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Código Hexcode",
|
"HEXCODE": "Código Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textificar",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
||||||
"DEBUG_HELPERS": "Ajudantes de Depuração",
|
"DEBUG_HELPERS": "Ajudantes de Depuração",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Anexar parênteses ao rótulo",
|
"APPEND_BRACKETS_TO_LABEL": "Anexar parênteses ao rótulo",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Codul hexagonal",
|
"HEXCODE": "Codul hexagonal",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Descompilator de Bytecode",
|
"BYTECODE_DECOMPILER": "Descompilator de Bytecode",
|
||||||
"DEBUG_HELPERS": "Ajutoare de depanare",
|
"DEBUG_HELPERS": "Ajutoare de depanare",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Adăugați paranteze la etichetă",
|
"APPEND_BRACKETS_TO_LABEL": "Adăugați paranteze la etichetă",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali/Dex",
|
"SMALI_DEX": "Smali/Dex",
|
||||||
"HEXCODE": "Шестнадцатеричный код",
|
"HEXCODE": "Шестнадцатеричный код",
|
||||||
"BYTECODE": "Байт-код",
|
"BYTECODE": "Байт-код",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Декомпилятор байт-кода",
|
"BYTECODE_DECOMPILER": "Декомпилятор байт-кода",
|
||||||
"DEBUG_HELPERS": "Помощники отладки",
|
"DEBUG_HELPERS": "Помощники отладки",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Добавить скобки к названию",
|
"APPEND_BRACKETS_TO_LABEL": "Добавить скобки к названию",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Šesťmiestny kód",
|
"HEXCODE": "Šesťmiestny kód",
|
||||||
"BYTECODE": "Bytový kód",
|
"BYTECODE": "Bytový kód",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Dekompilátor bytového kódu",
|
"BYTECODE_DECOMPILER": "Dekompilátor bytového kódu",
|
||||||
"DEBUG_HELPERS": "Pomocníci ladenia",
|
"DEBUG_HELPERS": "Pomocníci ladenia",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Pripojenie zátvoriek k štítku",
|
"APPEND_BRACKETS_TO_LABEL": "Pripojenie zátvoriek k štítku",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Šestmestna koda",
|
"HEXCODE": "Šestmestna koda",
|
||||||
"BYTECODE": "Bajtokoda",
|
"BYTECODE": "Bajtokoda",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Dekompiliator bajtkode",
|
"BYTECODE_DECOMPILER": "Dekompiliator bajtkode",
|
||||||
"DEBUG_HELPERS": "Pomočniki za odpravljanje napak",
|
"DEBUG_HELPERS": "Pomočniki za odpravljanje napak",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Dodajanje oklepajev k oznaki",
|
"APPEND_BRACKETS_TO_LABEL": "Dodajanje oklepajev k oznaki",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Código hexadecimal",
|
"HEXCODE": "Código hexadecimal",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
||||||
"DEBUG_HELPERS": "Ayudantes de depuración",
|
"DEBUG_HELPERS": "Ayudantes de depuración",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Añadir paréntesis a la etiqueta",
|
"APPEND_BRACKETS_TO_LABEL": "Añadir paréntesis a la etiqueta",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali",
|
"SMALI_DEX": "Smali",
|
||||||
"HEXCODE": "Hexkod",
|
"HEXCODE": "Hexkod",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
||||||
"DEBUG_HELPERS": "Hjälpmedel för felsökning",
|
"DEBUG_HELPERS": "Hjälpmedel för felsökning",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Lägga till parenteser till etiketten",
|
"APPEND_BRACKETS_TO_LABEL": "Lägga till parenteser till etiketten",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "สมาลี/เด็กซ์",
|
"SMALI_DEX": "สมาลี/เด็กซ์",
|
||||||
"HEXCODE": "รหัสเลขฐานสิบหก",
|
"HEXCODE": "รหัสเลขฐานสิบหก",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "ตัวช่วยดีบัก",
|
"DEBUG_HELPERS": "ตัวช่วยดีบัก",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "ต่อท้ายวงเล็บเพื่อติดป้ายกำกับ",
|
"APPEND_BRACKETS_TO_LABEL": "ต่อท้ายวงเล็บเพื่อติดป้ายกำกับ",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Смалі / Декс",
|
"SMALI_DEX": "Смалі / Декс",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Байт-код",
|
"BYTECODE": "Байт-код",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Декомпілятор байт-коду",
|
"BYTECODE_DECOMPILER": "Декомпілятор байт-коду",
|
||||||
"DEBUG_HELPERS": "Помічники з налагодження",
|
"DEBUG_HELPERS": "Помічники з налагодження",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Додайте дужки до ярлика",
|
"APPEND_BRACKETS_TO_LABEL": "Додайте дужки до ярлика",
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
"SMALI_DEX": "Smali / Dex",
|
"SMALI_DEX": "Smali / Dex",
|
||||||
"HEXCODE": "Hexcode",
|
"HEXCODE": "Hexcode",
|
||||||
"BYTECODE": "Bytecode",
|
"BYTECODE": "Bytecode",
|
||||||
"ASM_TEXTIFY": "ASM Textify",
|
"ASM_TEXTIFY": "ASM Disassembler",
|
||||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||||
"DEBUG_HELPERS": "Trình trợ giúp gỡ lỗi",
|
"DEBUG_HELPERS": "Trình trợ giúp gỡ lỗi",
|
||||||
"APPEND_BRACKETS_TO_LABEL": "Nối dấu ngoặc vào nhãn",
|
"APPEND_BRACKETS_TO_LABEL": "Nối dấu ngoặc vào nhãn",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user