Merge branch 'Konloch:master' into go-to-enhancement

This commit is contained in:
Cody 2024-10-07 17:28:30 -06:00 committed by GitHub
commit 9860c9d63c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

AI 샘플 코드 생성 중입니다

Loading...
87 changed files with 1621 additions and 1230 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": "إلحاق أقواس بالتسمية",

View File

@ -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": "Прилагане на скоби към етикета",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": "براکت ها را به برچسب اضافه کنید",

View File

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

View File

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

View File

@ -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": "დაამატეთ ფრჩხილები ლეიბლზე",

View File

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

View File

@ -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": "Προσθέστε αγκύλες στην ετικέτα",

View File

@ -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": "הוסף סוגריים לתווית",

View File

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

View File

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

View File

@ -90,7 +90,7 @@
"SMALI_DEX": "スマリ",
"HEXCODE": "ヘックスコード",
"BYTECODE": "バイトコード",
"ASM_TEXTIFY": "ASM Textify",
"ASM_TEXTIFY": "ASM Disassembler",
"BYTECODE_DECOMPILER": "バイトコードデコンパイラー",
"DEBUG_HELPERS": "デバッグヘルパー",
"APPEND_BRACKETS_TO_LABEL": "ラベルに括弧をつける",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": "Добавить скобки к названию",

View File

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

View File

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

View File

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

View File

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

View File

@ -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": "ต่อท้ายวงเล็บเพื่อติดป้ายกำกับ",

View File

@ -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": "Додайте дужки до ярлика",

View File

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