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.util.List;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import the.bytecode.club.bytecodeviewer.*;
|
||||
import the.bytecode.club.bytecodeviewer.api.*;
|
||||
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.
|
||||
**
|
||||
** @author [Your-Name-Goes-Here]
|
||||
* * This is an example of a String Decrypter Java Plugin for BCV.
|
||||
* *
|
||||
* * @author [Your-Name-Goes-Here]
|
||||
**/
|
||||
|
||||
public class ExampleStringDecrypter extends Plugin {
|
||||
public class ExampleStringDecrypter extends Plugin
|
||||
{
|
||||
|
||||
@Override
|
||||
public void execute(List<ClassNode> classNodesList) {
|
||||
public void execute(List<ClassNode> classNodesList)
|
||||
{
|
||||
PluginConsole gui = new PluginConsole("Example String Decrypter Java Edition");
|
||||
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING",
|
||||
"WARNING: This will load the classes into the JVM and execute the initialize function"
|
||||
+ nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.",
|
||||
new String[]{"Continue", "Cancel"});
|
||||
MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING", "WARNING: This will load the classes into the JVM and execute the initialize function" + 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;
|
||||
|
||||
for (ClassNode cn : classNodesList) {
|
||||
try {
|
||||
|
||||
for (ClassNode cn : classNodesList)
|
||||
{
|
||||
try
|
||||
{
|
||||
//load the class node into the classloader
|
||||
BCV.getClassNodeLoader().addClass(cn);
|
||||
|
||||
for (Object o : cn.fields.toArray()) {
|
||||
|
||||
for (Object o : cn.fields.toArray())
|
||||
{
|
||||
FieldNode f = (FieldNode) o;
|
||||
|
||||
|
||||
//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
|
||||
//if the strings get decrypted on init, this allows you to dump the current values
|
||||
|
||||
if (f.name.equals("z")) {
|
||||
try {
|
||||
for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields()) {
|
||||
if (f.name.equals("z"))
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields())
|
||||
{
|
||||
String s = (String) f2.get(null);
|
||||
if (s != null && !s.isEmpty())
|
||||
gui.appendText(cn + ":" + s);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
gui.appendText("Failed loading class " + cn.name);
|
||||
e.printStackTrace();
|
||||
needsWarning = true;
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
if (needsWarning)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,12 +8,15 @@ import the.bytecode.club.bytecodeviewer.api.*;
|
|||
** @author [Your Name Goes Here]
|
||||
**/
|
||||
|
||||
public class Skeleton extends Plugin {
|
||||
public class Skeleton extends Plugin
|
||||
{
|
||||
|
||||
@Override
|
||||
public void execute(List<ClassNode> classNodesList) {
|
||||
public void execute(List<ClassNode> classNodesList)
|
||||
{
|
||||
PluginConsole gui = new PluginConsole("Skeleton Title");
|
||||
gui.setVisible(true);
|
||||
gui.appendText("executed skeleton example");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,11 +46,17 @@ public class XposedGenerator extends Plugin
|
|||
String className = viewer.getName();
|
||||
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
|
||||
|
||||
if (classnode == null)
|
||||
{
|
||||
BytecodeViewer.showMessage("Open A Classfile First");
|
||||
return;
|
||||
}
|
||||
|
||||
//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
|
||||
{
|
||||
|
@ -64,7 +70,9 @@ public class XposedGenerator extends Plugin
|
|||
//Decompile using Fern
|
||||
String decomp = decompilefern.decompileClassNode(classNode, cont);
|
||||
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
|
||||
List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
|
||||
String packgExtracted = ProcessContentExtractedPackage(decomp);
|
||||
|
@ -86,6 +94,7 @@ public class XposedGenerator extends Plugin
|
|||
|
||||
//output methods to pane box
|
||||
int result = JOptionPane.showConfirmDialog(null, myPanel, "Choose Template and Method for Xposed Module", JOptionPane.OK_CANCEL_OPTION);
|
||||
myPanel.remove();
|
||||
|
||||
if (result == JOptionPane.OK_OPTION)
|
||||
{
|
||||
|
@ -129,13 +138,6 @@ public class XposedGenerator extends Plugin
|
|||
{
|
||||
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
|
||||
String packageNameOnly = packageName.substring(8, packageName.length() - 2).trim();
|
||||
String classToHookNameOnly = classToHook;
|
||||
|
@ -151,18 +153,35 @@ public class XposedGenerator extends Plugin
|
|||
String onlyFunction = CleanUpFunction(functionSplitValues);
|
||||
|
||||
//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";
|
||||
FileWriter fw = new FileWriter(file.getAbsoluteFile());
|
||||
BufferedWriter bw = new BufferedWriter(fw);
|
||||
bw.write(XposedClassText);
|
||||
bw.write("\r\n");
|
||||
bw.close();
|
||||
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" + "\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();
|
||||
}
|
||||
}
|
||||
|
@ -308,4 +327,5 @@ public class XposedGenerator extends Plugin
|
|||
String QUOTE = "'";
|
||||
return QUOTE + aText + QUOTE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -54,6 +54,7 @@
|
|||
<java-parser.version>3.26.2</java-parser.version>
|
||||
<taskmanager.version>1.0.1</taskmanager.version>
|
||||
<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>
|
||||
|
||||
<repositories>
|
||||
|
@ -395,6 +396,11 @@
|
|||
<artifactId>google-java-format</artifactId>
|
||||
<version>${google-java-format.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.konloch</groupId>
|
||||
<artifactId>DiskLib</artifactId>
|
||||
<version>${disk-lib.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO Re-add for Graal.JS support -->
|
||||
<!--<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.GsonBuilder;
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import com.konloch.taskmanager.TaskManager;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.api.BCV;
|
||||
|
@ -588,7 +588,7 @@ public class BytecodeViewer
|
|||
|
||||
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.setVisible(true);
|
||||
}
|
||||
|
@ -693,7 +693,10 @@ public class BytecodeViewer
|
|||
*/
|
||||
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)
|
||||
//the cons to this are:
|
||||
// + 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
|
||||
//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 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 OUT = System.out;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
import javax.swing.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Whenever a key is pressed on the swing UI it should get logged here
|
||||
|
@ -121,8 +122,18 @@ public class GlobalHotKeys
|
|||
BytecodeViewer.updateBusyStatus(true);
|
||||
Thread jarExport = new Thread(() ->
|
||||
{
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
try
|
||||
{
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
BytecodeViewer.handleException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
}, "Jar Export");
|
||||
jarExport.start();
|
||||
}
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import com.konloch.disklib.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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 hasSetLanguageAsSystemLanguage = false;
|
||||
private static List<String> recentPlugins;
|
||||
private static List<String> recentFiles;
|
||||
private static List<String> recentPlugins = new ArrayList<>();
|
||||
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
|
||||
{
|
||||
try
|
||||
{
|
||||
File filesFile = new File(getBCVDirectory() + FS + "recentfiles.bcv");
|
||||
File pluginsFile = new File(getBCVDirectory() + FS + "recentplugins.bcv");
|
||||
|
||||
if (new File(FILES_NAME).exists())
|
||||
recentFiles = gson.fromJson(DiskReader.loadAsString(FILES_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentFiles = DiskReader.loadArrayList(getBCVDirectory() + FS + "recentfiles.bcv", false);
|
||||
recentFiles = gson.fromJson(DiskReader.readString(FILES_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else if (filesFile.exists())
|
||||
recentFiles = Arrays.asList(DiskReader.readArray(filesFile));
|
||||
|
||||
if (new File(PLUGINS_NAME).exists())
|
||||
recentPlugins = gson.fromJson(DiskReader.loadAsString(PLUGINS_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else
|
||||
recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + FS + "recentplugins.bcv", false);
|
||||
recentPlugins = gson.fromJson(DiskReader.readString(PLUGINS_NAME), new TypeToken<ArrayList<String>>() {}.getType());
|
||||
else if (pluginsFile.exists())
|
||||
recentPlugins = Arrays.asList(DiskReader.readArray(pluginsFile));
|
||||
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
|
@ -76,7 +85,7 @@ public class Settings
|
|||
recentFiles.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentFiles.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
|
||||
DiskWriter.replaceFile(FILES_NAME, MiscUtils.listToString(recentFiles), false);
|
||||
saveRecentFiles();
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
|
@ -84,11 +93,23 @@ public class Settings
|
|||
{
|
||||
if (recentFiles.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(FILES_NAME, MiscUtils.listToString(recentFiles), false);
|
||||
saveRecentFiles();
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveRecentFiles()
|
||||
{
|
||||
try
|
||||
{
|
||||
DiskWriter.write(FILES_NAME, MiscUtils.listToString(recentFiles));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRecentFile()
|
||||
{
|
||||
if (recentFiles.isEmpty())
|
||||
|
@ -107,7 +128,7 @@ public class Settings
|
|||
recentPlugins.remove(f.getAbsolutePath()); // already added on the list
|
||||
recentPlugins.add(0, f.getAbsolutePath());
|
||||
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);
|
||||
DiskWriter.replaceFile(PLUGINS_NAME, MiscUtils.listToString(recentPlugins), false);
|
||||
saveRecentPlugins();
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
|
@ -115,11 +136,23 @@ public class Settings
|
|||
{
|
||||
if (recentPlugins.remove(f.getAbsolutePath()))
|
||||
{
|
||||
DiskWriter.replaceFile(PLUGINS_NAME, MiscUtils.listToString(recentPlugins), false);
|
||||
saveRecentPlugins();
|
||||
resetRecentFilesMenu();
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveRecentPlugins()
|
||||
{
|
||||
try
|
||||
{
|
||||
DiskWriter.write(PLUGINS_NAME, MiscUtils.listToString(recentPlugins));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* resets the recent files menu
|
||||
*/
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer;
|
||||
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import com.konloch.disklib.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.RSTATheme;
|
||||
|
@ -27,6 +27,7 @@ import the.bytecode.club.bytecodeviewer.translation.Language;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
|
||||
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
|
||||
{
|
||||
private static final String DEPRECATED = "deprecated";
|
||||
private static boolean settingsFileExists;
|
||||
private static String[] settings;
|
||||
|
||||
public static void saveSettingsAsync()
|
||||
{
|
||||
|
@ -53,7 +56,7 @@ public class SettingsSerializer
|
|||
|
||||
try
|
||||
{
|
||||
DiskWriter.replaceFile(SETTINGS_NAME, "BCV: " + VERSION, false);
|
||||
DiskWriter.write(SETTINGS_NAME, "BCV: " + VERSION, true);
|
||||
save(BytecodeViewer.viewer.rbr.isSelected());
|
||||
save(BytecodeViewer.viewer.rsy.isSelected());
|
||||
save(BytecodeViewer.viewer.din.isSelected());
|
||||
|
@ -132,46 +135,46 @@ public class SettingsSerializer
|
|||
save(BytecodeViewer.viewer.excludeNestedTypes.isSelected());
|
||||
save(BytecodeViewer.viewer.appendBracketsToLabels.isSelected());
|
||||
save(BytecodeViewer.viewer.debugHelpers.isSelected());
|
||||
save("deprecated");
|
||||
save(DEPRECATED);
|
||||
save(BytecodeViewer.viewer.updateCheck.isSelected());
|
||||
save(BytecodeViewer.viewer.viewPane1.getSelectedDecompiler().ordinal());
|
||||
save(BytecodeViewer.viewer.viewPane2.getSelectedDecompiler().ordinal());
|
||||
save(BytecodeViewer.viewer.viewPane3.getSelectedDecompiler().ordinal());
|
||||
save(BytecodeViewer.viewer.refreshOnChange.isSelected());
|
||||
save(BytecodeViewer.viewer.isMaximized);
|
||||
save("deprecated");
|
||||
save("deprecated");
|
||||
save(DEPRECATED);
|
||||
save(DEPRECATED);
|
||||
save(Configuration.lastOpenDirectory);
|
||||
save(Configuration.python2);
|
||||
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(Configuration.library);
|
||||
save(Configuration.pingback);
|
||||
save("deprecated");
|
||||
save("deprecated");
|
||||
save("deprecated");
|
||||
save(DEPRECATED);
|
||||
save(DEPRECATED);
|
||||
save(DEPRECATED);
|
||||
save(BytecodeViewer.viewer.getFontSize());
|
||||
save(Configuration.deleteForeignLibraries);
|
||||
|
||||
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()))
|
||||
DiskWriter.writeNewLine(SETTINGS_NAME, "1");
|
||||
DiskWriter.append(SETTINGS_NAME, "1", true);
|
||||
|
||||
save(Configuration.python3);
|
||||
save(Configuration.javac);
|
||||
|
@ -184,7 +187,7 @@ public class SettingsSerializer
|
|||
save(BytecodeViewer.viewer.synchronizedViewing.isSelected());
|
||||
save(BytecodeViewer.viewer.showClassMethods.isSelected());
|
||||
save(BytecodeViewer.viewer.ren.isSelected());
|
||||
save("deprecated");
|
||||
save(DEPRECATED);
|
||||
|
||||
save(Configuration.lafTheme.name());
|
||||
save(Configuration.rstaTheme.name());
|
||||
|
@ -196,8 +199,8 @@ public class SettingsSerializer
|
|||
save(BytecodeViewer.viewer.viewPane3.isPaneEditable());
|
||||
|
||||
save(Configuration.javaTools);
|
||||
save("deprecated");
|
||||
save("deprecated");
|
||||
save(DEPRECATED);
|
||||
save(DEPRECATED);
|
||||
save(Configuration.lastSaveDirectory);
|
||||
save(Configuration.lastPluginDirectory);
|
||||
save(Configuration.python2Extra);
|
||||
|
@ -224,7 +227,7 @@ public class SettingsSerializer
|
|||
return;
|
||||
|
||||
//precache the file
|
||||
DiskReader.loadString(SETTINGS_NAME, 0, true);
|
||||
settings = DiskReader.readArray(SETTINGS_NAME);
|
||||
|
||||
//process the cached file
|
||||
Configuration.lafTheme = LAFTheme.valueOf(asString(127));
|
||||
|
@ -425,21 +428,28 @@ public class SettingsSerializer
|
|||
|
||||
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 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_NL = SEND_STACKTRACE_TO + NL + NL;
|
||||
|
||||
|
|
|
@ -69,18 +69,13 @@ public class BCVCommandLine
|
|||
{
|
||||
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
|
||||
// I'm sure the Apache CLI has a better way of navigating this
|
||||
|
||||
for(CLICommand command : COMMANDS)
|
||||
{
|
||||
System.out.println("OK: " + command.name);
|
||||
if(cmd.hasOption(command.name))
|
||||
{
|
||||
System.out.println("ON: " + command.name);
|
||||
command.runCommand(cmd);
|
||||
return;
|
||||
}
|
||||
|
@ -115,9 +110,11 @@ public class BCVCommandLine
|
|||
return;
|
||||
}
|
||||
|
||||
//wait 5 seconds to allow time for reading
|
||||
if (!cmd.hasOption("nowait"))
|
||||
SleepUtil.sleep(5 * 1000);
|
||||
|
||||
//decompiler configuration
|
||||
File input = new File(cmd.getOptionValue("i"));
|
||||
File output = new File(cmd.getOptionValue("o"));
|
||||
String decompiler = cmd.getOptionValue("decompiler");
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
|
@ -250,7 +250,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.PROCYON_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.CFR_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -302,7 +302,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.FERNFLOWER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -328,7 +328,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.KRAKATAU_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -355,7 +355,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -382,7 +382,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.JD_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -409,7 +409,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.SMALI_DISASSEMBLER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -436,7 +436,7 @@ public class CommandLineInput
|
|||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.JADX_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -462,8 +462,8 @@ public class CommandLineInput
|
|||
{
|
||||
ClassNode cn = BytecodeViewer.blindlySearchForClassNode(target);
|
||||
final ClassWriter cw = accept(cn);
|
||||
String contents = Decompiler.ASMIFIER_DECOMPILER.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.replaceFile(output.getAbsolutePath(), contents, false);
|
||||
String contents = Decompiler.ASMIFIER_CODE_GEN.getDecompiler().decompileClassNode(cn, cw.toByteArray());
|
||||
DiskWriter.write(output.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -22,5 +22,7 @@ public class CleanBootCommand extends CLICommand
|
|||
public void runCommand(CommandLine cmd)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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",
|
||||
"-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",
|
||||
|
||||
"",
|
||||
"==BCV GUI Commands==",
|
||||
"-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);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
||||
|
@ -69,15 +69,15 @@ public class JavaCompiler extends AbstractCompiler
|
|||
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;
|
||||
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();
|
||||
ProcessBuilder pb;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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.lang3.ArrayUtils;
|
||||
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 javaFile = new File(tempDirectory1.getAbsolutePath() + FS + fullyQualifiedName + ".j");
|
||||
final File tempJar = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||
final StringBuilder log = new StringBuilder();
|
||||
|
||||
//create the temp directories
|
||||
tempDirectory1.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
|
||||
{
|
||||
//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};
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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 the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.compilers.AbstractCompiler;
|
||||
|
@ -59,7 +59,7 @@ public class SmaliAssembler extends AbstractCompiler
|
|||
try
|
||||
{
|
||||
//write the file we're assembling to disk
|
||||
DiskWriter.replaceFile(tempSmali.getAbsolutePath(), contents, false);
|
||||
DiskWriter.write(tempSmali.getAbsolutePath(), contents);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -40,11 +40,19 @@ public abstract class AbstractDecompiler
|
|||
|
||||
public abstract void decompileToZip(String sourceJar, String zipName);
|
||||
|
||||
public void decompileToZipFallBack(String sourceJar, String zipName)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
public String getDecompilerName()
|
||||
{
|
||||
return decompilerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for the compressed exports (Zip / Jar)
|
||||
*/
|
||||
public String getDecompilerNameProgrammatic()
|
||||
{
|
||||
return decompilerNameProgrammatic;
|
||||
|
|
|
@ -44,8 +44,8 @@ public enum Decompiler
|
|||
JD_DECOMPILER(new JDGUIDecompiler()), //java decompiler
|
||||
JADX_DECOMPILER(new JADXDecompiler()), //java decompiler
|
||||
|
||||
ASM_TEXTIFY_DISASSEMBLER(new ASMTextifierDisassembler()), //bytecode disassembler
|
||||
ASMIFIER_DECOMPILER(new ASMifierGenerator()), //bytecode disassembler / code gen
|
||||
ASM_DISASSEMBLER(new ASMDisassembler()), //bytecode disassembler
|
||||
ASMIFIER_CODE_GEN(new ASMifierGenerator()), //bytecode disassembler / code gen
|
||||
JAVAP_DISASSEMBLER(new JavapDisassembler()); //bytecode disassembler
|
||||
|
||||
private final AbstractDecompiler decompiler;
|
||||
|
@ -63,7 +63,10 @@ public enum Decompiler
|
|||
return getDecompiler().getDecompilerName();
|
||||
}
|
||||
|
||||
public String getDecompilerNameProgrammic()
|
||||
/**
|
||||
* Used for the compressed exports (Zip / Jar)
|
||||
*/
|
||||
public String getDecompilerNameProgrammatic()
|
||||
{
|
||||
if(decompiler == null)
|
||||
return "";
|
||||
|
|
|
@ -21,19 +21,27 @@ package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
|||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
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.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
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
|
||||
*
|
||||
* @author Thiakil
|
||||
*/
|
||||
public class ASMTextifierDisassembler extends AbstractDecompiler
|
||||
public class ASMDisassembler extends AbstractDecompiler
|
||||
{
|
||||
public ASMTextifierDisassembler()
|
||||
public ASMDisassembler()
|
||||
{
|
||||
super("ASM Disassembler", "asm");
|
||||
}
|
||||
|
@ -41,13 +49,35 @@ public class ASMTextifierDisassembler extends AbstractDecompiler
|
|||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer)));
|
||||
return writer.toString();
|
||||
String exception;
|
||||
|
||||
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
|
||||
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.util.ASMifier;
|
||||
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.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JavaFormatterUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
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
|
||||
*
|
||||
|
@ -42,13 +50,35 @@ public class ASMifierGenerator extends AbstractDecompiler
|
|||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
cn.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(writer)));
|
||||
return JavaFormatterUtils.formatJavaCode(writer.toString());
|
||||
String exception;
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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.bytecode.ClassNodeDecompiler;
|
||||
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 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
|
||||
* @since 7/3/2021
|
||||
|
@ -39,11 +47,29 @@ public class BytecodeDisassembler extends AbstractDecompiler
|
|||
@Override
|
||||
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
|
||||
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.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
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.resources.ResourceContainer;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.ExceptionUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -44,15 +46,14 @@ import java.util.zip.ZipException;
|
|||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
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.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* CFR Java Wrapper
|
||||
*
|
||||
* @author GraxCode
|
||||
* Taken mostly out of Threadtear.
|
||||
* @author GraxCode (Taken mostly out of Threadtear)
|
||||
*/
|
||||
|
||||
public class CFRDecompiler extends AbstractDecompiler
|
||||
{
|
||||
|
||||
|
@ -71,59 +72,69 @@ public class CFRDecompiler extends AbstractDecompiler
|
|||
|
||||
private String decompile(ClassNode cn, String name, byte[] content)
|
||||
{
|
||||
String exception;
|
||||
|
||||
try
|
||||
{
|
||||
String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Consumer<SinkReturns.Decompiled> dumpDecompiled = d -> builder.append(d.getJava());
|
||||
|
||||
//initialize CFR
|
||||
Options options = generateOptions();
|
||||
ClassFileSource source = new BCVDataSource(options, cn, classPath, content);
|
||||
CfrDriver driver = new CfrDriver.Builder().withClassFileSource(source).withBuiltOptions(options).withOutputSink(new BCVOutputSinkFactory(dumpDecompiled)).build();
|
||||
|
||||
//decompile the class-file
|
||||
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();
|
||||
}
|
||||
catch (Throwable t)
|
||||
catch (Throwable e)
|
||||
{
|
||||
t.printStackTrace();
|
||||
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;
|
||||
exception = ExceptionUtils.exceptionToString(e);
|
||||
}
|
||||
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL
|
||||
+ TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String outJar)
|
||||
{
|
||||
try (JarFile jfile = new JarFile(new File(sourceJar));
|
||||
FileOutputStream dest = new FileOutputStream(outJar);
|
||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
||||
ZipOutputStream out = new ZipOutputStream(buffDest))
|
||||
try (JarFile jarFile = new JarFile(new File(sourceJar));
|
||||
FileOutputStream destination = new FileOutputStream(outJar);
|
||||
BufferedOutputStream buffer = new BufferedOutputStream(destination);
|
||||
ZipOutputStream zip = new ZipOutputStream(buffer))
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
|
||||
Enumeration<JarEntry> ent = jfile.entries();
|
||||
Enumeration<JarEntry> ent = jarFile.entries();
|
||||
Set<JarEntry> history = new HashSet<>();
|
||||
|
||||
while (ent.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = ent.nextElement();
|
||||
|
||||
if (entry.getName().endsWith(CLASS_SUFFIX))
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java"));
|
||||
|
||||
if (history.add(etn))
|
||||
{
|
||||
out.putNextEntry(etn);
|
||||
zip.putNextEntry(etn);
|
||||
|
||||
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
|
||||
{
|
||||
out.closeEntry();
|
||||
zip.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,34 +142,36 @@ public class CFRDecompiler extends AbstractDecompiler
|
|||
{
|
||||
try
|
||||
{
|
||||
JarEntry etn = new JarEntry(entry.getName());
|
||||
if (history.add(etn))
|
||||
JarEntry jarEntry = new JarEntry(entry.getName());
|
||||
|
||||
if (history.add(jarEntry))
|
||||
continue;
|
||||
history.add(etn);
|
||||
out.putNextEntry(etn);
|
||||
try (InputStream in = jfile.getInputStream(entry))
|
||||
|
||||
history.add(jarEntry);
|
||||
zip.putNextEntry(jarEntry);
|
||||
|
||||
try (InputStream input = jarFile.getInputStream(entry))
|
||||
{
|
||||
if (in != null)
|
||||
if (input != null)
|
||||
{
|
||||
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
|
||||
{
|
||||
out.closeEntry();
|
||||
zip.closeEntry();
|
||||
}
|
||||
}
|
||||
catch (ZipException ze)
|
||||
catch (ZipException e)
|
||||
{
|
||||
// some jars contain duplicate pom.xml entries: ignore it
|
||||
if (!ze.getMessage().contains("duplicate"))
|
||||
{
|
||||
throw ze;
|
||||
}
|
||||
if (!e.getMessage().contains("duplicate"))
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +239,8 @@ public class CFRDecompiler extends AbstractDecompiler
|
|||
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content)
|
||||
{
|
||||
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.content = content;
|
||||
}
|
||||
|
@ -247,7 +261,6 @@ public class CFRDecompiler extends AbstractDecompiler
|
|||
|
||||
return Pair.make(data, classFilePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BCVOutputSinkFactory implements OutputSinkFactory
|
||||
|
@ -274,9 +287,7 @@ public class CFRDecompiler extends AbstractDecompiler
|
|||
return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x);
|
||||
}
|
||||
|
||||
return ignore ->
|
||||
{
|
||||
};
|
||||
return ignore -> {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,19 +18,24 @@
|
|||
|
||||
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 the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
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.resources.ExternalResources;
|
||||
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 static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.FERNFLOWER;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* A FernFlower wrapper with all the options (except 2)
|
||||
|
@ -47,149 +52,126 @@ public class FernFlowerDecompiler extends AbstractDecompiler
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName)
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
File tempZip = new File(sourceJar);
|
||||
|
||||
File f = new File(TEMP_DIRECTORY + FS + "temp" + FS);
|
||||
f.mkdir();
|
||||
TempFile tempFile = null;
|
||||
String exception;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
File tempZip2 = new File(TEMP_DIRECTORY + FS + "temp" + FS + tempZip.getName());
|
||||
if (tempZip2.exists())
|
||||
tempZip2.renameTo(new File(zipName));
|
||||
if (tempOutputJar.exists())
|
||||
tempOutputJar.renameTo(destination);
|
||||
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)
|
||||
{
|
||||
return new String[]{"-rbr=" + r(BytecodeViewer.viewer.rbr.isSelected()),
|
||||
"-rsy=" + r(BytecodeViewer.viewer.rsy.isSelected()),
|
||||
"-din=" + r(BytecodeViewer.viewer.din.isSelected()),
|
||||
"-dc4=" + r(BytecodeViewer.viewer.dc4.isSelected()),
|
||||
"-das=" + r(BytecodeViewer.viewer.das.isSelected()),
|
||||
"-hes=" + r(BytecodeViewer.viewer.hes.isSelected()),
|
||||
"-hdc=" + r(BytecodeViewer.viewer.hdc.isSelected()),
|
||||
"-dgs=" + r(BytecodeViewer.viewer.dgs.isSelected()),
|
||||
"-ner=" + r(BytecodeViewer.viewer.ner.isSelected()),
|
||||
"-den=" + r(BytecodeViewer.viewer.den.isSelected()),
|
||||
"-rgn=" + r(BytecodeViewer.viewer.rgn.isSelected()),
|
||||
"-bto=" + r(BytecodeViewer.viewer.bto.isSelected()),
|
||||
"-nns=" + r(BytecodeViewer.viewer.nns.isSelected()),
|
||||
"-uto=" + r(BytecodeViewer.viewer.uto.isSelected()),
|
||||
"-udv=" + r(BytecodeViewer.viewer.udv.isSelected()),
|
||||
"-rer=" + r(BytecodeViewer.viewer.rer.isSelected()),
|
||||
"-fdi=" + r(BytecodeViewer.viewer.fdi.isSelected()),
|
||||
"-asc=" + r(BytecodeViewer.viewer.asc.isSelected()),
|
||||
"-ren=" + r(BytecodeViewer.viewer.ren.isSelected()),
|
||||
className, folder};
|
||||
return new String[]
|
||||
{
|
||||
"-rbr=" + ffOnValue(BytecodeViewer.viewer.rbr.isSelected()),
|
||||
"-rsy=" + ffOnValue(BytecodeViewer.viewer.rsy.isSelected()),
|
||||
"-din=" + ffOnValue(BytecodeViewer.viewer.din.isSelected()),
|
||||
"-dc4=" + ffOnValue(BytecodeViewer.viewer.dc4.isSelected()),
|
||||
"-das=" + ffOnValue(BytecodeViewer.viewer.das.isSelected()),
|
||||
"-hes=" + ffOnValue(BytecodeViewer.viewer.hes.isSelected()),
|
||||
"-hdc=" + ffOnValue(BytecodeViewer.viewer.hdc.isSelected()),
|
||||
"-dgs=" + ffOnValue(BytecodeViewer.viewer.dgs.isSelected()),
|
||||
"-ner=" + ffOnValue(BytecodeViewer.viewer.ner.isSelected()),
|
||||
"-den=" + ffOnValue(BytecodeViewer.viewer.den.isSelected()),
|
||||
"-rgn=" + ffOnValue(BytecodeViewer.viewer.rgn.isSelected()),
|
||||
"-bto=" + ffOnValue(BytecodeViewer.viewer.bto.isSelected()),
|
||||
"-nns=" + ffOnValue(BytecodeViewer.viewer.nns.isSelected()),
|
||||
"-uto=" + ffOnValue(BytecodeViewer.viewer.uto.isSelected()),
|
||||
"-udv=" + ffOnValue(BytecodeViewer.viewer.udv.isSelected()),
|
||||
"-rer=" + ffOnValue(BytecodeViewer.viewer.rer.isSelected()),
|
||||
"-fdi=" + ffOnValue(BytecodeViewer.viewer.fdi.isSelected()),
|
||||
"-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)
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,21 +18,23 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
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.decompilers.AbstractDecompiler;
|
||||
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.TempFile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.JADX;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* JADX Java Wrapper
|
||||
|
@ -49,96 +51,80 @@ public class JADXDecompiler extends AbstractDecompiler
|
|||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
String fileStart = TEMP_DIRECTORY + FS;
|
||||
|
||||
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();
|
||||
TempFile tempFile = null;
|
||||
String exception;
|
||||
|
||||
try
|
||||
{
|
||||
JadxArgs args = new JadxArgs();
|
||||
args.setInputFile(tempClass);
|
||||
args.setOutDir(freeDirectory);
|
||||
args.setOutDirSrc(freeDirectory);
|
||||
args.setOutDirRes(freeDirectory);
|
||||
//create the temporary files
|
||||
tempFile = TempFile.createTemporaryFile(true, ".class");
|
||||
File tempDirectory = tempFile.getParent();
|
||||
File tempClassFile = tempFile.getFile();
|
||||
|
||||
JadxDecompiler jadx = new JadxDecompiler(args);
|
||||
jadx.load();
|
||||
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
|
||||
//write the class-file with bytes
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClassFile))
|
||||
{
|
||||
String s;
|
||||
fos.write(bytes);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
s = DiskReader.loadAsString(f.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
String exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
//setup JADX Args
|
||||
JadxArgs args = new JadxArgs();
|
||||
args.setInputFile(tempClassFile);
|
||||
args.setOutDir(tempDirectory);
|
||||
args.setOutDirSrc(tempDirectory);
|
||||
args.setOutDirRes(tempDirectory);
|
||||
|
||||
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
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
|
||||
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.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Constants;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
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.PlainTextPrinter;
|
||||
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 static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||
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.JDGUI;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* JD-Core Decompiler Wrapper
|
||||
|
@ -57,38 +56,26 @@ public class JDGUIDecompiler extends AbstractDecompiler
|
|||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
TempFile tempFile = null;
|
||||
String exception;
|
||||
|
||||
try
|
||||
{
|
||||
final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
||||
tempDirectory.mkdir();
|
||||
//create the temporary files
|
||||
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");
|
||||
final File tempJava = new File(tempDirectory.getAbsolutePath() + FS + cn.name + ".java");
|
||||
//make any folders for the packages
|
||||
makeFolders(tempFile, cn);
|
||||
|
||||
if (cn.name.contains("/"))
|
||||
{
|
||||
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))
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClassFile))
|
||||
{
|
||||
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 internalPath = JDGUIClassFileUtil.ExtractInternalPath(directoryPath, pathToClass);
|
||||
|
||||
|
@ -111,28 +98,52 @@ public class JDGUIDecompiler extends AbstractDecompiler
|
|||
|
||||
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());
|
||||
}
|
||||
|
||||
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();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
|
||||
exception = ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
exception = ExceptionUtils.exceptionToString(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
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
|
||||
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;
|
||||
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import com.konloch.disklib.DiskWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
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.gui.components.JFrameConsolePrintStream;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||
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.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||
import static the.bytecode.club.bytecodeviewer.api.ExceptionUI.SEND_STACKTRACE_TO;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Javap disassembler
|
||||
* <p>
|
||||
*
|
||||
* https://github.com/Konloch/bytecode-viewer/issues/93
|
||||
*
|
||||
* @author Konloch
|
||||
|
@ -59,21 +63,25 @@ public class JavapDisassembler extends AbstractDecompiler
|
|||
if (!ExternalResources.getSingleton().hasJavaToolsSet())
|
||||
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);
|
||||
final File tempClass = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".class");
|
||||
TempFile tempFile = null;
|
||||
String exception;
|
||||
|
||||
tempDirectory.mkdir();
|
||||
JFrameConsolePrintStream sysOutBuffer;
|
||||
|
||||
DiskWriter.replaceFileBytes(tempClass.getAbsolutePath(), b, false);
|
||||
|
||||
JFrameConsolePrintStream sysOutBuffer = null;
|
||||
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
|
||||
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);
|
||||
|
||||
//invoke Javap
|
||||
main.invoke(null, (Object) new String[]{"-p", //Shows all classes and members
|
||||
"-c", //Prints out disassembled code
|
||||
//"-l", //Prints out line and local variable tables
|
||||
"-constants", //Shows static final constants
|
||||
tempClass.getAbsolutePath()});
|
||||
try
|
||||
{
|
||||
main.invoke(null, (Object) new String[]{"-p", //Shows all classes and members
|
||||
"-c", //Prints out disassembled code
|
||||
//"-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)
|
||||
{
|
||||
//TODO fallback using CLI (External Process API)
|
||||
|
||||
return TranslatedStrings.ILLEGAL_ACCESS_ERROR.toString();
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
exception = ExceptionUtils.exceptionToString(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BytecodeViewer.sm.silenceExec(false);
|
||||
tempClass.delete();
|
||||
|
||||
if(tempFile != null)
|
||||
tempFile.cleanup();
|
||||
}
|
||||
|
||||
if (sysOutBuffer != null)
|
||||
{
|
||||
sysOutBuffer.finished();
|
||||
return sysOutBuffer.getTextAreaOutputStreamOut().getBuffer().toString();
|
||||
}
|
||||
|
||||
return SEND_STACKTRACE_TO;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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.objectweb.asm.tree.ClassNode;
|
||||
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.resources.ExternalResources;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* Krakatau Java Decompiler Wrapper, requires Python 2.7
|
||||
|
@ -51,24 +50,6 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
|||
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
|
||||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
|
@ -79,104 +60,104 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
final File tempDirectory = new File(Constants.TEMP_DIRECTORY + FS + MiscUtils.randomString(32) + FS);
|
||||
final File tempJar = new File(Constants.TEMP_DIRECTORY + FS + "temp" + MiscUtils.randomString(32) + ".jar");
|
||||
|
||||
tempDirectory.mkdir();
|
||||
|
||||
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;
|
||||
StringBuilder processOut = new StringBuilder(NL + NL);
|
||||
StringBuilder processErr = new StringBuilder(NL + NL);
|
||||
int exitCode = Integer.MAX_VALUE;
|
||||
TempFile tempFile = null;
|
||||
String exception;
|
||||
|
||||
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};
|
||||
if (Configuration.python2Extra)
|
||||
pythonCommands = ArrayUtils.addAll(pythonCommands, "-2");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //love you storyyeller <3
|
||||
krakatauWorkingDirectory + FS + "decompile.py", "-skip", //love you storyyeller <3
|
||||
"-nauto", "-path", Configuration.rt + ";" + tempJar.getAbsolutePath() + buildCLIArguments(),
|
||||
"-out", tempDir.getAbsolutePath(), cn.name + ".class"));
|
||||
krakatauWorkingDirectory + FS + "decompile.py",
|
||||
"-skip", //love you storyyeller <3
|
||||
"-nauto",
|
||||
"-path", Configuration.rt + ";" + tempInputJarFile.getAbsolutePath() + buildCLIArguments(),
|
||||
"-out", tempDir.getAbsolutePath(),
|
||||
cn.name + ".class"));
|
||||
|
||||
Process process = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
||||
StringBuilder log = new StringBuilder(TranslatedStrings.PROCESS2 + NL + NL);
|
||||
|
||||
//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)
|
||||
{
|
||||
log.append(NL).append(line);
|
||||
}
|
||||
}
|
||||
//ProcessUtils.readProcessToStringBuilderAsync(process, processOut, processErr);
|
||||
ProcessUtils.readProcessToStringBuilder(process, processOut, processErr);
|
||||
|
||||
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();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr))
|
||||
{
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
log.append(NL).append(line);
|
||||
}
|
||||
}
|
||||
//handle simulated errors
|
||||
if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS)
|
||||
throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString());
|
||||
|
||||
int exitValue = process.waitFor();
|
||||
log.append(NL).append(NL).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
||||
returnString = log.toString();
|
||||
|
||||
// update the string on a successful disassemble
|
||||
returnString = DiskReader.loadAsString(tempDir.getAbsolutePath() + FS + cn.name + ".java");
|
||||
// read the java file on a successful disassemble
|
||||
return DiskReader.readString(tempOutputJavaFile.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
e.printStackTrace();
|
||||
returnString += NL + ExceptionUI.SEND_STACKTRACE_TO_NL + sw;
|
||||
exception = ProcessUtils.mergeLogs(processOut, processErr, exitCode)
|
||||
+ ExceptionUtils.exceptionToString(e);
|
||||
}
|
||||
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
|
||||
|
@ -189,7 +170,8 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -207,7 +189,8 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
|||
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(pythonCommands, "-O", //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();
|
||||
BytecodeViewer.createdProcesses.add(process);
|
||||
|
@ -221,4 +204,25 @@ public class KrakatauDecompiler extends AbstractDecompiler
|
|||
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;
|
||||
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -35,6 +35,7 @@ import the.bytecode.club.bytecodeviewer.util.ZipUtils;
|
|||
import java.io.*;
|
||||
|
||||
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
|
||||
|
@ -105,8 +106,12 @@ public class KrakatauDisassembler extends AbstractDecompiler
|
|||
log.append(NL).append(NL).append(TranslatedStrings.EXIT_VALUE_IS).append(" ").append(exitValue);
|
||||
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
|
||||
returnString = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + FS + cn.name + ".j");
|
||||
returnString = DiskReader.readString(tempDirectory.getAbsolutePath() + FS + cn.name + ".j");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -27,11 +27,13 @@ import com.strobel.decompiler.PlainTextOutput;
|
|||
import com.strobel.decompiler.languages.java.JavaFormattingOptions;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
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.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.util.*;
|
||||
|
@ -41,8 +43,7 @@ import java.util.zip.ZipException;
|
|||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PROCYON;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*;
|
||||
|
||||
/**
|
||||
* Procyon Java Decompiler Wrapper
|
||||
|
@ -50,12 +51,182 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PRO
|
|||
* @author Konloch
|
||||
* @author DeathMarine
|
||||
*/
|
||||
|
||||
public class ProcyonDecompiler extends AbstractDecompiler
|
||||
{
|
||||
|
||||
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()
|
||||
|
@ -79,165 +250,6 @@ public class ProcyonDecompiler extends AbstractDecompiler
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
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.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
@ -52,7 +52,7 @@ public class SmaliDisassembler extends AbstractDecompiler
|
|||
public String decompileClassNode(ClassNode cn, byte[] bytes)
|
||||
{
|
||||
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 tempDex = new File(start + ".dex");
|
||||
final File tempDexOut = new File(start + "-out");
|
||||
|
@ -69,8 +69,6 @@ public class SmaliDisassembler extends AbstractDecompiler
|
|||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
//ZipUtils.zipFile(tempClass, tempZip);
|
||||
|
||||
Dex2Jar.saveAsDex(tempClass, tempDex, true);
|
||||
|
||||
try
|
||||
|
@ -106,6 +104,7 @@ public class SmaliDisassembler extends AbstractDecompiler
|
|||
while (!found)
|
||||
{
|
||||
File f = Objects.requireNonNull(current.listFiles())[0];
|
||||
|
||||
if (f.isDirectory())
|
||||
current = f;
|
||||
else
|
||||
|
@ -113,11 +112,10 @@ public class SmaliDisassembler extends AbstractDecompiler
|
|||
outputSmali = f;
|
||||
found = true;
|
||||
}
|
||||
|
||||
}
|
||||
try
|
||||
{
|
||||
return DiskReader.loadAsString(outputSmali.getAbsolutePath());
|
||||
return DiskReader.readString(outputSmali.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -128,7 +126,8 @@ public class SmaliDisassembler extends AbstractDecompiler
|
|||
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
|
||||
|
|
|
@ -57,13 +57,16 @@ public class DecompilerViewComponent
|
|||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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(editable);
|
||||
|
@ -74,11 +77,8 @@ public class DecompilerViewComponent
|
|||
|
||||
public void addToGroup(ButtonGroup group)
|
||||
{
|
||||
if (type == JAVA || type == JAVA_NON_EDITABLE || type == JAVA_AND_BYTECODE)
|
||||
group.add(java);
|
||||
|
||||
if (type == BYTECODE || type == JAVA_AND_BYTECODE || type == BYTECODE_NON_EDITABLE)
|
||||
group.add(bytecode);
|
||||
group.add(java);
|
||||
group.add(bytecode);
|
||||
}
|
||||
|
||||
public JMenu getMenu()
|
||||
|
@ -117,6 +117,7 @@ public class DecompilerViewComponent
|
|||
JAVA_NON_EDITABLE,
|
||||
BYTECODE,
|
||||
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;
|
||||
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import com.konloch.disklib.DiskWriter;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
int max = 500_000;
|
||||
|
@ -136,12 +137,19 @@ public class JFrameConsole extends JFrame
|
|||
new Thread(() ->
|
||||
{
|
||||
//save to disk
|
||||
DiskWriter.replaceFile(tempFile.getAbsolutePath(), s, false);
|
||||
try
|
||||
{
|
||||
DiskWriter.write(tempFile.getAbsolutePath(), text);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, "Console Log Saving").start();
|
||||
|
||||
//trim
|
||||
int skipped = len - max;
|
||||
String trimmed = s.substring(0, max);
|
||||
String trimmed = text.substring(0, max);
|
||||
|
||||
if (!trimmed.startsWith("WARNING: Skipping"))
|
||||
trimmed = ("WARNING: Skipping " + skipped + " chars, allowing " + max + "\n\r")
|
||||
|
@ -150,7 +158,7 @@ public class JFrameConsole extends JFrame
|
|||
return trimmed;
|
||||
}
|
||||
|
||||
return s;
|
||||
return text;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5056940543411437508L;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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 the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
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);
|
||||
if (!tempFile.exists())
|
||||
{
|
||||
DiskWriter.replaceFileBytes(tempFile.getAbsolutePath(), content, false);
|
||||
|
||||
try
|
||||
{
|
||||
DiskWriter.write(tempFile.getAbsolutePath(), content);
|
||||
|
||||
imp.getImporter().open(tempFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -51,6 +51,7 @@ public class BytecodeViewPanel extends JPanel
|
|||
public BytecodeViewPanel(int panelIndex, ClassViewer viewer)
|
||||
{
|
||||
super(new BorderLayout());
|
||||
|
||||
this.panelIndex = panelIndex;
|
||||
this.viewer = viewer;
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ public class BytecodeViewPanel extends JPanel
|
|||
if (viewer.resource == null)
|
||||
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)
|
||||
add(new JLabel("ERROR: Resource Viewer Missing ClassNode"));
|
||||
}
|
||||
|
|
|
@ -45,22 +45,26 @@ public class DecompilerSelectionPane
|
|||
private final JMenu menu;
|
||||
private final ButtonGroup group = new ButtonGroup();
|
||||
private final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", TranslatedComponents.NONE);
|
||||
private final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", TranslatedComponents.HEXCODE);
|
||||
private final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
|
||||
private final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
|
||||
private final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
|
||||
private final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
|
||||
private final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
|
||||
private final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_DISASSEMBLER);
|
||||
private final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE, Decompiler.SMALI_DISASSEMBLER);
|
||||
private final DecompilerViewComponent bytecode = 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 asmifier = new DecompilerViewComponent("ASMifier", JAVA_NON_EDITABLE, Decompiler.ASMIFIER_DECOMPILER);
|
||||
private final DecompilerViewComponent javap = new DecompilerViewComponent("Javap", BYTECODE_NON_EDITABLE, Decompiler.JAVAP_DISASSEMBLER);
|
||||
private final JRadioButtonMenuItem hexcodeViewer = new TranslatedJRadioButtonMenuItem("Hexcode", TranslatedComponents.HEXCODE);
|
||||
//decompilers
|
||||
private final DecompilerViewComponent fernFlowerDecompiler = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
|
||||
private final DecompilerViewComponent procyonDecompiler = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
|
||||
private final DecompilerViewComponent CFRDecompiler = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
|
||||
private final DecompilerViewComponent JADXDecompiler = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
|
||||
private final DecompilerViewComponent JDCoreDecompiler = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
|
||||
//disassemblers
|
||||
private final DecompilerViewComponent bytecodeViewer = new DecompilerViewComponent("Bytecode", BYTECODE_NON_EDITABLE, Decompiler.BYTECODE_DISASSEMBLER);
|
||||
private final DecompilerViewComponent javapDisassembler = new DecompilerViewComponent("Javap", BYTECODE_NON_EDITABLE, Decompiler.JAVAP_DISASSEMBLER);
|
||||
private final DecompilerViewComponent krakatauDecompiler = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_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
|
||||
// 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)
|
||||
{
|
||||
|
@ -83,10 +87,10 @@ public class DecompilerSelectionPane
|
|||
switch (paneID)
|
||||
{
|
||||
case 1:
|
||||
group.setSelected(fern.getJava().getModel(), true);
|
||||
group.setSelected(fernFlowerDecompiler.getJava().getModel(), true);
|
||||
break;
|
||||
case 2:
|
||||
group.setSelected(bytecode.getBytecode().getModel(), true);
|
||||
group.setSelected(bytecodeViewer.getBytecode().getModel(), true);
|
||||
break;
|
||||
case 3:
|
||||
group.setSelected(none.getModel(), true);
|
||||
|
@ -101,12 +105,12 @@ public class DecompilerSelectionPane
|
|||
{
|
||||
//build the radiobutton group
|
||||
group.add(none);
|
||||
group.add(hexcode);
|
||||
group.add(hexcodeViewer);
|
||||
components.forEach(decompilerViewComponent -> decompilerViewComponent.addToGroup(group));
|
||||
|
||||
//build the action commands
|
||||
none.setActionCommand(Decompiler.NONE.name());
|
||||
hexcode.setActionCommand(Decompiler.HEXCODE_VIEWER.name());
|
||||
hexcodeViewer.setActionCommand(Decompiler.HEXCODE_VIEWER.name());
|
||||
|
||||
for (DecompilerViewComponent component : components)
|
||||
{
|
||||
|
@ -115,9 +119,9 @@ public class DecompilerSelectionPane
|
|||
String cmd = decompiler.name();
|
||||
|
||||
//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);
|
||||
else// if(cmd.endsWith("DISASSEMBLER"))
|
||||
else// if(cmd.endsWith("_DISASSEMBLER"))
|
||||
component.getBytecode().setActionCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
@ -140,28 +144,27 @@ public class DecompilerSelectionPane
|
|||
//build the menu
|
||||
menu.add(none);
|
||||
menu.add(new JSeparator());
|
||||
menu.add(procyon.getMenu());
|
||||
menu.add(CFR.getMenu());
|
||||
menu.add(procyonDecompiler.getMenu());
|
||||
menu.add(CFRDecompiler.getMenu());
|
||||
|
||||
if (!Configuration.jadxGroupedWithSmali)
|
||||
menu.add(JADX.getMenu());
|
||||
menu.add(JADXDecompiler.getMenu());
|
||||
|
||||
menu.add(JD.getMenu());
|
||||
menu.add(fern.getMenu());
|
||||
menu.add(krakatau.getMenu());
|
||||
menu.add(JDCoreDecompiler.getMenu());
|
||||
menu.add(fernFlowerDecompiler.getMenu());
|
||||
menu.add(krakatauDecompiler.getMenu());
|
||||
menu.add(new JSeparator());
|
||||
|
||||
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(bytecode.getMenu());
|
||||
menu.add(javap.getMenu());
|
||||
menu.add(asmTextify.getMenu());
|
||||
menu.add(asmifier.getMenu());
|
||||
menu.add(bytecodeViewer.getMenu());
|
||||
menu.add(javapDisassembler.getMenu());
|
||||
menu.add(asmifierCodeGen.getMenu());
|
||||
menu.add(new JSeparator());
|
||||
menu.add(hexcode);
|
||||
menu.add(hexcodeViewer);
|
||||
}
|
||||
|
||||
public Decompiler getSelectedDecompiler()
|
||||
|
@ -176,6 +179,7 @@ public class DecompilerSelectionPane
|
|||
while (it.hasMoreElements())
|
||||
{
|
||||
AbstractButton button = it.nextElement();
|
||||
|
||||
if (button.getActionCommand().equals(decompiler.name()))
|
||||
{
|
||||
group.setSelected(button.getModel(), true);
|
||||
|
|
|
@ -19,10 +19,8 @@
|
|||
package the.bytecode.club.bytecodeviewer.plugin;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.konloch.taskmanager.Task;
|
||||
import com.konloch.taskmanager.TaskRunnable;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import com.konloch.disklib.DiskReader;
|
||||
import com.konloch.disklib.DiskWriter;
|
||||
import org.apache.commons.compress.utils.FileNameUtils;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
|
@ -188,7 +186,7 @@ public class PluginWriter extends JFrame
|
|||
|
||||
try
|
||||
{
|
||||
area.setText(DiskReader.loadAsString(file.getAbsolutePath()));
|
||||
area.setText(DiskReader.readString(file.getAbsolutePath()));
|
||||
area.setCaretPosition(0);
|
||||
}
|
||||
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);
|
||||
}, "Plugin Editor Save");
|
||||
|
||||
|
@ -306,7 +312,7 @@ public class PluginWriter extends JFrame
|
|||
else
|
||||
{
|
||||
//update content from latest disk data
|
||||
content = DiskReader.loadAsString(savePath.getAbsolutePath());
|
||||
content = DiskReader.readString(savePath.getAbsolutePath());
|
||||
|
||||
//update plugin writer UI on disk update
|
||||
SwingUtilities.invokeLater(() ->
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.api.BCV;
|
||||
|
@ -31,6 +31,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||
|
@ -258,20 +259,20 @@ public class ResourceDecompiling
|
|||
|
||||
//decompile all opened classes to zip
|
||||
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
|
||||
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
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
|
||||
//decompile the currently opened resource and save it to the specified file
|
||||
DiskWriter.replaceFile(saveAll ? MiscUtils.append(outputFile,
|
||||
"-" + decompiler.getDecompilerNameProgrammic() + ".java") : outputFile.getAbsolutePath(), BCV.decompileCurrentlyOpenedClassNode(decompiler), false);
|
||||
DiskWriter.write(saveAll ? MiscUtils.append(outputFile,
|
||||
"-" + decompiler.getDecompilerNameProgrammatic() + ".java") : outputFile.getAbsolutePath(), BCV.decompileCurrentlyOpenedClassNode(decompiler));
|
||||
|
||||
//signal to the user that BCV is finished performing that action
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
|
|
|
@ -89,8 +89,8 @@ public class ClassFileContainer
|
|||
&& !getDecompiler().equals(Decompiler.KRAKATAU_DISASSEMBLER.getDecompilerName())
|
||||
&& !getDecompiler().equals(Decompiler.JAVAP_DISASSEMBLER.getDecompilerName())
|
||||
&& !getDecompiler().equals(Decompiler.SMALI_DISASSEMBLER.getDecompilerName())
|
||||
&& !getDecompiler().equals(Decompiler.ASM_TEXTIFY_DISASSEMBLER.getDecompilerName())
|
||||
&& !getDecompiler().equals(Decompiler.ASMIFIER_DECOMPILER.getDecompilerName());
|
||||
&& !getDecompiler().equals(Decompiler.ASM_DISASSEMBLER.getDecompilerName())
|
||||
&& !getDecompiler().equals(Decompiler.ASMIFIER_CODE_GEN.getDecompilerName());
|
||||
}
|
||||
|
||||
public String getName()
|
||||
|
|
|
@ -31,6 +31,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
@ -109,17 +110,26 @@ public class APKExport implements Exporter
|
|||
|
||||
Thread saveThread = new Thread(() ->
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
||||
|
||||
Thread buildAPKThread = new Thread(() ->
|
||||
try
|
||||
{
|
||||
APKTool.buildAPK(new File(input), file, finalContainer);
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}, "Process APK");
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
||||
|
||||
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");
|
||||
|
||||
saveThread.start();
|
||||
|
|
|
@ -29,6 +29,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.FS;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
|
||||
|
@ -73,18 +74,27 @@ public class DexExport implements Exporter
|
|||
|
||||
Thread saveAsJar = new Thread(() ->
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(true);
|
||||
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
||||
|
||||
Thread saveAsDex = new Thread(() ->
|
||||
try
|
||||
{
|
||||
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);
|
||||
}, "Process DEX");
|
||||
|
||||
saveAsDex.start();
|
||||
BytecodeViewer.handleException(ex);
|
||||
}
|
||||
}, "Jar Export");
|
||||
|
||||
saveAsJar.start();
|
||||
|
|
|
@ -28,6 +28,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
|
@ -65,8 +66,18 @@ public class ZipExport implements Exporter
|
|||
|
||||
Thread saveThread = new Thread(() ->
|
||||
{
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
try
|
||||
{
|
||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
BytecodeViewer.handleException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BytecodeViewer.updateBusyStatus(false);
|
||||
}
|
||||
}, "Jar Export");
|
||||
|
||||
saveThread.start();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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 the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
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.util.MiscUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
DiskWriter.replaceFileBytes(file.getAbsolutePath(), bytes, false);
|
||||
DiskWriter.write(file.getAbsolutePath(), bytes);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public enum TranslatedStrings
|
|||
PRODUCT_H_NAME("Bytecode-Viewer"),
|
||||
WEBSITE("https://bytecodeviewer.com"),
|
||||
TBC("https://the.bytecode.club"),
|
||||
DEV_MODE_SIMULATED_ERROR("Developer-Mode: Simulated Error"),
|
||||
|
||||
EDITABLE,
|
||||
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;
|
||||
|
||||
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.ZipFile;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
@ -356,7 +356,7 @@ public class JarUtils
|
|||
|
||||
String name = cn.name + ".class";
|
||||
|
||||
if (!fileCollisionPrevention.add(name))
|
||||
if (fileCollisionPrevention.add(name))
|
||||
{
|
||||
out.putNextEntry(new ZipEntry(name));
|
||||
out.write(cw.toByteArray());
|
||||
|
@ -390,7 +390,7 @@ public class JarUtils
|
|||
File f = new File(name);
|
||||
f.mkdirs();
|
||||
|
||||
DiskWriter.replaceFileBytes(name, cw.toByteArray(), false);
|
||||
DiskWriter.write(name, cw.toByteArray());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -405,7 +405,7 @@ public class JarUtils
|
|||
* @param nodeList The loaded ClassNodes
|
||||
* @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);
|
||||
JarOutputStream out = new JarOutputStream(fos))
|
||||
|
@ -448,9 +448,5 @@ public class JarUtils
|
|||
|
||||
fileCollisionPrevention .clear();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,36 @@ public class MiscUtils
|
|||
File tempFile;
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
if (!canonicalDestDir.endsWith(File.separator))
|
||||
{
|
||||
canonicalDestDir += File.separator;
|
||||
}
|
||||
|
||||
File file = new File(jarPath);
|
||||
|
||||
try (JarFile jar = new JarFile(file))
|
||||
try (JarFile jarFile = new JarFile(new File(jarPath)))
|
||||
{
|
||||
|
||||
// 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
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); )
|
||||
for (Enumeration<JarEntry> enums = jarFile.entries();
|
||||
enums.hasMoreElements(); )
|
||||
{
|
||||
JarEntry entry = enums.nextElement();
|
||||
|
||||
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());
|
||||
continue;
|
||||
}
|
||||
|
||||
File parent = f.getParentFile();
|
||||
File parent = file.getParentFile();
|
||||
|
||||
if (!parent.exists())
|
||||
{
|
||||
parent.mkdirs();
|
||||
}
|
||||
|
||||
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'
|
||||
while (is.available() > 0)
|
||||
|
@ -117,6 +97,7 @@ public final class ZipUtils
|
|||
try (FileInputStream in = new FileInputStream(inputFile))
|
||||
{
|
||||
int len;
|
||||
|
||||
while ((len = in.read(buffer)) > 0)
|
||||
{
|
||||
zos.write(buffer, 0, len);
|
||||
|
@ -153,9 +134,7 @@ public final class ZipUtils
|
|||
|
||||
File folder = new File(srcFile);
|
||||
if (folder.isDirectory())
|
||||
{
|
||||
addFolderToZip(path, srcFile, zip, ignore);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] buf = new byte[1024];
|
||||
|
@ -185,10 +164,11 @@ public final class ZipUtils
|
|||
File folder = new File(srcFile);
|
||||
|
||||
String check = path.toLowerCase();
|
||||
|
||||
//if(check.startsWith("decoded unknown") || check.startsWith("decoded lib") || check.startsWith("decoded
|
||||
// assets") || 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"))
|
||||
if (check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded apktool.yml"))
|
||||
return;
|
||||
|
||||
//if(path.equals("original") || path.equals("classes.dex") || path.equals("apktool.yml"))
|
||||
|
|
|
@ -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": "مساعدي التصحيح",
|
||||
"APPEND_BRACKETS_TO_LABEL": "إلحاق أقواس بالتسمية",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Шестнайсетичен код",
|
||||
"BYTECODE": "Байткод",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Декомпилатор на байткод",
|
||||
"DEBUG_HELPERS": "Помощници за отстраняване на грешки",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Прилагане на скоби към етикета",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali/Dex",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Dekompilator bajtkoda",
|
||||
"DEBUG_HELPERS": "Pomoćnici za ispravljanje pogrešaka",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Dodaj zagrade na oznaku",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytový kód",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Dekompilátor bajtového kódu",
|
||||
"DEBUG_HELPERS": "Pomocníci pro ladění",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Připojení závorek ke štítku",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexkode",
|
||||
"BYTECODE": "Bytekode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
||||
"DEBUG_HELPERS": "Hjælpemidler til fejlfinding",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Tilføj parenteser til etiketten",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali/Dex",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"ASMIFIER": "ASMifier",
|
||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||
"DEBUG_HELPERS": "Debug Helpers",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Baitkoodi dekompilaator",
|
||||
"DEBUG_HELPERS": "Kõrvaldamise abivahendid",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Sulgude lisamine etiketile",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "اسمالی / دکس",
|
||||
"HEXCODE": "کد هگز",
|
||||
"BYTECODE": "کد Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "رمزگشایی Bytecode",
|
||||
"DEBUG_HELPERS": "راهنمای اشکال زدایی",
|
||||
"APPEND_BRACKETS_TO_LABEL": "براکت ها را به برچسب اضافه کنید",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Heksakoodi",
|
||||
"BYTECODE": "Bytekoodi",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytekoodin purkuohjelma",
|
||||
"DEBUG_HELPERS": "Vianmäärityksen apuohjelmat",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Liitä hakasulkeet etikettiin",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Décompilateur de bytecode",
|
||||
"DEBUG_HELPERS": "Aides au débogage",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Ajouter des parenthèses à l'étiquette",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "სმალი / დექსი",
|
||||
"HEXCODE": "ჰექსკოდი",
|
||||
"BYTECODE": "ბიტეკოდი",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode დეკომპილერი",
|
||||
"DEBUG_HELPERS": "Debug Helpers",
|
||||
"APPEND_BRACKETS_TO_LABEL": "დაამატეთ ფრჩხილები ლეიბლზე",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali/Dex",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"ASMIFIER": "ASMifier",
|
||||
"BYTECODE_DECOMPILER": "Bytecode-Dekompilierer",
|
||||
"DEBUG_HELPERS": "Debug-Helfer",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Αποσυμπιεστής bytecode",
|
||||
"DEBUG_HELPERS": "Βοηθοί εντοπισμού σφαλμάτων",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Προσθέστε αγκύλες στην ετικέτα",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "סמאלי / דקס",
|
||||
"HEXCODE": "הקסקוד",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Decompiler Bytecode",
|
||||
"DEBUG_HELPERS": "עוזרי איתור באגים",
|
||||
"APPEND_BRACKETS_TO_LABEL": "הוסף סוגריים לתווית",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexkód",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode dekompiláló",
|
||||
"DEBUG_HELPERS": "Hibakeresési segédprogramok",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Zárójelek hozzáadása a címkéhez",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Decompilatore di bytecode",
|
||||
"DEBUG_HELPERS": "Aiuti per il debug",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Aggiungere parentesi all'etichetta",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "スマリ",
|
||||
"HEXCODE": "ヘックスコード",
|
||||
"BYTECODE": "バイトコード",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "バイトコードデコンパイラー",
|
||||
"DEBUG_HELPERS": "デバッグヘルパー",
|
||||
"APPEND_BRACKETS_TO_LABEL": "ラベルに括弧をつける",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali / Dex",
|
||||
"HEXCODE": "Hekscode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||
"DEBUG_HELPERS": "Penolong Debug",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Nambah Kurung Kanggo Label",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode dekompilētājs",
|
||||
"DEBUG_HELPERS": "Dzesēšanas palīgierīces",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Etiķetes pievienošana iekavās",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Šešiaženklis kodas",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytekodo dekompiliatorius",
|
||||
"DEBUG_HELPERS": "Derinimo pagalbininkai",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Prie etiketės pridėkite skliaustelius",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali / Dex",
|
||||
"HEXCODE": "Kod Hex",
|
||||
"BYTECODE": "Kod byk",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Pengurai Bytecode",
|
||||
"DEBUG_HELPERS": "Pembantu Debug",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Lampirkan Kurungan ke Label",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"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": "Haakjes toevoegen aan label",
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
"SMALI_DEX": "Smali / Dex",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
|
||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||
"DEBUG_HELPERS": "Feilsøkingshjelpere",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Código Hexcode",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textificar",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
||||
"DEBUG_HELPERS": "Ajudantes de Depuração",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Anexar parênteses ao rótulo",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Codul hexagonal",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Descompilator de Bytecode",
|
||||
"DEBUG_HELPERS": "Ajutoare de depanare",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Adăugați paranteze la etichetă",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali/Dex",
|
||||
"HEXCODE": "Шестнадцатеричный код",
|
||||
"BYTECODE": "Байт-код",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Декомпилятор байт-кода",
|
||||
"DEBUG_HELPERS": "Помощники отладки",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Добавить скобки к названию",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Šesťmiestny kód",
|
||||
"BYTECODE": "Bytový kód",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Dekompilátor bytového kódu",
|
||||
"DEBUG_HELPERS": "Pomocníci ladenia",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Pripojenie zátvoriek k štítku",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Šestmestna koda",
|
||||
"BYTECODE": "Bajtokoda",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Dekompiliator bajtkode",
|
||||
"DEBUG_HELPERS": "Pomočniki za odpravljanje napak",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Dodajanje oklepajev k oznaki",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Código hexadecimal",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Descompilador de Bytecode",
|
||||
"DEBUG_HELPERS": "Ayudantes de depuración",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Añadir paréntesis a la etiqueta",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Smali",
|
||||
"HEXCODE": "Hexkod",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode-dekompilering",
|
||||
"DEBUG_HELPERS": "Hjälpmedel för felsökning",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Lägga till parenteser till etiketten",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "สมาลี/เด็กซ์",
|
||||
"HEXCODE": "รหัสเลขฐานสิบหก",
|
||||
"BYTECODE": "Bytecode",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Bytecode Decompiler",
|
||||
"DEBUG_HELPERS": "ตัวช่วยดีบัก",
|
||||
"APPEND_BRACKETS_TO_LABEL": "ต่อท้ายวงเล็บเพื่อติดป้ายกำกับ",
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
"SMALI_DEX": "Смалі / Декс",
|
||||
"HEXCODE": "Hexcode",
|
||||
"BYTECODE": "Байт-код",
|
||||
"ASM_TEXTIFY": "ASM Textify",
|
||||
"ASM_TEXTIFY": "ASM Disassembler",
|
||||
"BYTECODE_DECOMPILER": "Декомпілятор байт-коду",
|
||||
"DEBUG_HELPERS": "Помічники з налагодження",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Додайте дужки до ярлика",
|
||||
|
|
|
@ -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": "Trình trợ giúp gỡ lỗi",
|
||||
"APPEND_BRACKETS_TO_LABEL": "Nối dấu ngoặc vào nhãn",
|
||||
|
|
Loading…
Reference in New Issue
Block a user