parent
46bee607aa
commit
7d09510194
14 changed files with 236 additions and 67 deletions
|
@ -1,9 +1,6 @@
|
|||
package me.konloch.kontainer.io;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
|
@ -132,13 +129,13 @@ public class DiskWriter {
|
|||
* @param fileContents
|
||||
* @param debug
|
||||
*/
|
||||
public static synchronized void replaceFile(String filename,
|
||||
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();
|
||||
PrintWriter writer = null;
|
||||
|
||||
String original = filename;
|
||||
int counter = 0;
|
||||
|
||||
|
@ -146,10 +143,10 @@ public class DiskWriter {
|
|||
int failSafe = 0;
|
||||
while (!saved && failSafe++ <= 42069)
|
||||
{
|
||||
try {
|
||||
writer = new PrintWriter(new BufferedWriter(new FileWriter(
|
||||
filename, true)));
|
||||
writer.println(Arrays.toString(fileContents));
|
||||
try(FileOutputStream stream = new FileOutputStream(new File(filename)))
|
||||
{
|
||||
stream.write(fileContents);
|
||||
stream.flush();
|
||||
if (debug)
|
||||
System.out.println("Saved " + filename + " to disk");
|
||||
saved = true;
|
||||
|
@ -164,7 +161,6 @@ public class DiskWriter {
|
|||
counter++;
|
||||
}
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,11 +15,14 @@ import java.io.File;
|
|||
public class Configuration
|
||||
{
|
||||
public static String python2 = "";
|
||||
public static String python2Extra = "";
|
||||
public static String python3 = "";
|
||||
public static String python3Extra = "";
|
||||
public static String rt = "";
|
||||
public static String library = "";
|
||||
public static String javac = "";
|
||||
public static String java = "";
|
||||
public static String javaTools = "";
|
||||
public static File krakatauTempDir;
|
||||
public static File krakatauTempJar;
|
||||
public static boolean displayParentInTab = false; //also change in the main GUI
|
||||
|
|
|
@ -191,6 +191,8 @@ public class SettingsSerializer
|
|||
save(BytecodeViewer.viewer.viewPane1.isPaneEditable());
|
||||
save(BytecodeViewer.viewer.viewPane2.isPaneEditable());
|
||||
save(BytecodeViewer.viewer.viewPane3.isPaneEditable());
|
||||
|
||||
save(Configuration.javaTools);
|
||||
} catch (Exception e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
@ -348,6 +350,8 @@ public class SettingsSerializer
|
|||
BytecodeViewer.viewer.viewPane1.setPaneEditable(asBoolean(131));
|
||||
BytecodeViewer.viewer.viewPane2.setPaneEditable(asBoolean(132));
|
||||
BytecodeViewer.viewer.viewPane3.setPaneEditable(asBoolean(133));
|
||||
|
||||
Configuration.javaTools = asString(134);
|
||||
} catch (Exception e) {
|
||||
//ignore because errors are expected, first start up and outdated settings.
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -46,15 +46,8 @@ public class KrakatauAssembler extends InternalCompiler
|
|||
|
||||
@Override
|
||||
public byte[] compile(String contents, String name) {
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
|
||||
ExternalResources.getSingleton().selectPython2();
|
||||
}
|
||||
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set Python!");
|
||||
if(!ExternalResources.getSingleton().hasSetPythonCommand())
|
||||
return null;
|
||||
}
|
||||
|
||||
String origName = MiscUtils.randomString(20);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
|||
*
|
||||
* @author Thiakil
|
||||
*/
|
||||
public class ASMTextifierDecompiler extends InternalDecompiler
|
||||
public class ASMTextifierDisassembler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
|
@ -0,0 +1,106 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import me.konloch.kontainer.io.DiskWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.Constants;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ExternalResources;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
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.KONLOCH;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://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/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* Javap disassembler
|
||||
*
|
||||
* https://github.com/Konloch/bytecode-viewer/issues/93
|
||||
*
|
||||
* @author Konloch
|
||||
* @since 07/11/2021
|
||||
*/
|
||||
|
||||
public class JavapDisassembler extends InternalDecompiler
|
||||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b)
|
||||
{
|
||||
if(!ExternalResources.getSingleton().hasJavaToolsSet())
|
||||
return "Set Java Tools Path!";
|
||||
|
||||
final File tempDirectory = new File(Constants.tempDirectory + fs + MiscUtils.randomString(32) + fs);
|
||||
tempDirectory.mkdir();
|
||||
final File tempClass = new File(Constants.tempDirectory + fs + "temp" + MiscUtils.randomString(32) + ".class");
|
||||
|
||||
DiskWriter.replaceFileBytes(tempClass.getAbsolutePath(), b, false);
|
||||
|
||||
SystemConsole sysOut = null;
|
||||
try
|
||||
{
|
||||
URLClassLoader child = new URLClassLoader(
|
||||
new URL[] {new File(Configuration.javaTools).toURI().toURL()},
|
||||
this.getClass().getClassLoader()
|
||||
);
|
||||
//Class<?> javap = child.loadClass("com.sun.tools.javap.Main");
|
||||
Class<?> javap = Class.forName("com.sun.tools.javap.Main", true, child);
|
||||
Method main = javap.getMethod("main", String[].class);
|
||||
Object cl = javap.newInstance();
|
||||
|
||||
//pipe sys out
|
||||
sysOut = new SystemConsole("");
|
||||
|
||||
//invoke Javap
|
||||
main.invoke(cl, (Object) new String[]{"-c", "-l", "-constants", tempClass.getAbsolutePath()});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
tempClass.delete();
|
||||
}
|
||||
|
||||
if(sysOut != null)
|
||||
{
|
||||
sysOut.finished();
|
||||
return sysOut.getTextAreaOutputStreamOut().getBuffer().toString();
|
||||
}
|
||||
|
||||
return KONLOCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
|
||||
}
|
||||
}
|
|
@ -149,21 +149,15 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
|
||||
ExternalResources.getSingleton().selectPython2();
|
||||
}
|
||||
if(!ExternalResources.getSingleton().hasSetPythonCommand())
|
||||
return "You need to set your Python 2.7 path!";
|
||||
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your JRE RT Library." +
|
||||
"\r\n(C:\\Program Files (x86)\\Java\\jre7\\lib\\rt.jar)");
|
||||
ExternalResources.getSingleton().selectJRERTLibrary();
|
||||
}
|
||||
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set Python!");
|
||||
return "Set your paths";
|
||||
}
|
||||
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set RT.jar!");
|
||||
return "Set your paths";
|
||||
|
@ -240,10 +234,8 @@ public class KrakatauDecompiler extends InternalDecompiler
|
|||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
|
||||
ExternalResources.getSingleton().selectPython2();
|
||||
}
|
||||
if(!ExternalResources.getSingleton().hasSetPythonCommand())
|
||||
return;
|
||||
|
||||
ExternalResources.getSingleton().rtCheck();
|
||||
if (Configuration.rt.isEmpty()) {
|
||||
|
|
|
@ -47,15 +47,8 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
{
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
|
||||
ExternalResources.getSingleton().selectPython2();
|
||||
}
|
||||
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set Python!");
|
||||
return "Set your paths";
|
||||
}
|
||||
if(!ExternalResources.getSingleton().hasSetPythonCommand())
|
||||
return "You need to set your Python 2.7 path!";
|
||||
|
||||
String s = "Bytecode Viewer Version: " + VERSION + nl + nl +
|
||||
"Please send this to konloch@gmail.com. " + nl + nl;
|
||||
|
@ -120,10 +113,8 @@ public class KrakatauDisassembler extends InternalDecompiler
|
|||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
if (Configuration.python2.isEmpty()) {
|
||||
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
|
||||
ExternalResources.getSingleton().selectPython2();
|
||||
}
|
||||
if(!ExternalResources.getSingleton().hasSetPythonCommand())
|
||||
return;
|
||||
|
||||
String ran = MiscUtils.randomString(32);
|
||||
final File tempDirectory = new File(Constants.tempDirectory + fs + ran + fs);
|
||||
|
|
|
@ -83,6 +83,16 @@ public class JFrameConsolePrintStream extends JFrameConsole
|
|||
System.setOut(Constants.OUT);
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamErr()
|
||||
{
|
||||
return textAreaOutputStreamErr;
|
||||
}
|
||||
|
||||
public JTextAreaOutputStream getTextAreaOutputStreamOut()
|
||||
{
|
||||
return textAreaOutputStreamOut;
|
||||
}
|
||||
|
||||
private void update()
|
||||
{
|
||||
if(System.currentTimeMillis()-lastUpdate <= 50)
|
||||
|
|
|
@ -55,4 +55,9 @@ public class JTextAreaOutputStream extends OutputStream
|
|||
sb.append((char) b);
|
||||
og.write(b);
|
||||
}
|
||||
|
||||
public StringBuilder getBuffer()
|
||||
{
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,12 @@ public class DecompilerSelectionPane
|
|||
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 javap = new DecompilerViewComponent("JavaP", BYTECODE_NON_EDITABLE, Decompiler.JAVAP_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));
|
||||
procyon, CFR, JADX, JD, fern, krakatau, smali, bytecode, asmTextify, javap));
|
||||
|
||||
public DecompilerSelectionPane(int paneID)
|
||||
{
|
||||
|
@ -82,16 +83,8 @@ public class DecompilerSelectionPane
|
|||
{
|
||||
//build the radiobutton group
|
||||
group.add(none);
|
||||
procyon.addToGroup(group);
|
||||
CFR.addToGroup(group);
|
||||
JADX.addToGroup(group);
|
||||
JD.addToGroup(group);
|
||||
fern.addToGroup(group);
|
||||
krakatau.addToGroup(group);
|
||||
smali.addToGroup(group);
|
||||
bytecode.addToGroup(group);
|
||||
asmTextify.addToGroup(group);
|
||||
group.add(hexcode);
|
||||
components.forEach(decompilerViewComponent -> decompilerViewComponent.addToGroup(group));
|
||||
|
||||
//build the action commands
|
||||
none.setActionCommand(Decompiler.NONE.name());
|
||||
|
@ -137,6 +130,7 @@ public class DecompilerSelectionPane
|
|||
menu.add(smali.getMenu());
|
||||
menu.add(new JSeparator());
|
||||
menu.add(bytecode.getMenu());
|
||||
menu.add(javap.getMenu());
|
||||
menu.add(asmTextify.getMenu());
|
||||
menu.add(new JSeparator());
|
||||
menu.add(hexcode);
|
||||
|
|
|
@ -6,7 +6,10 @@ import the.bytecode.club.bytecodeviewer.SettingsSerializer;
|
|||
import the.bytecode.club.bytecodeviewer.util.DialogueUtils;
|
||||
import the.bytecode.club.bytecodeviewer.util.JRTExtractor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Objects;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
||||
|
@ -83,6 +86,37 @@ public class ExternalResources
|
|||
return Configuration.java;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the python command has been set
|
||||
*/
|
||||
public boolean hasJavaToolsSet()
|
||||
{
|
||||
return !getJavaTools(false).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-detect the Java command
|
||||
*/
|
||||
public String getJavaTools(boolean blockTillSelected)
|
||||
{
|
||||
boolean empty = Configuration.javaTools.isEmpty();
|
||||
|
||||
if(!empty)
|
||||
return Configuration.javaTools;
|
||||
|
||||
//TODO auto-detect the Java path
|
||||
boolean block = true;
|
||||
while (Configuration.javaTools.isEmpty() && block)
|
||||
{
|
||||
BytecodeViewer.showMessage("You need to set your Java Tools path, this requires the JDK to be downloaded." +
|
||||
nl + "(C:/Program Files/Java/JDK_xx/lib/tools.jar)");
|
||||
ExternalResources.getSingleton().selectJavaTools();
|
||||
block = !blockTillSelected; //signal block flag off
|
||||
}
|
||||
|
||||
return Configuration.javaTools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the python command has been set
|
||||
*/
|
||||
|
@ -106,13 +140,19 @@ public class ExternalResources
|
|||
//check using python CLI flag
|
||||
try
|
||||
{
|
||||
//TODO read the version output to verify python 2
|
||||
//read the version output to verify python 2
|
||||
ProcessBuilder pb = new ProcessBuilder("python", "-2", "--version");
|
||||
pb.start();
|
||||
Process p = pb.start();
|
||||
p.waitFor();
|
||||
|
||||
Configuration.python2 = "python -2"; //python is set
|
||||
//set python path
|
||||
if(readProcess(p).toLowerCase().contains("python 2"))
|
||||
{
|
||||
Configuration.python2 = "python";
|
||||
Configuration.python2Extra = "-2";
|
||||
return Configuration.python2;
|
||||
}
|
||||
}
|
||||
catch (Exception e) { } //ignore
|
||||
finally
|
||||
{
|
||||
|
@ -122,13 +162,18 @@ public class ExternalResources
|
|||
//check if 'python' command is bound as python 2.X
|
||||
try
|
||||
{
|
||||
//TODO read the version output to verify python 2
|
||||
//read the version output to verify python 2
|
||||
ProcessBuilder pb = new ProcessBuilder("python", "--version");
|
||||
pb.start();
|
||||
Process p = pb.start();
|
||||
p.waitFor();
|
||||
|
||||
Configuration.python2 = "python"; //python is set
|
||||
//set python path
|
||||
if(readProcess(p).toLowerCase().contains("python 2"))
|
||||
{
|
||||
Configuration.python2 = "python";
|
||||
return Configuration.python2;
|
||||
}
|
||||
}
|
||||
catch (Exception e) { } //ignore
|
||||
finally
|
||||
{
|
||||
|
@ -217,6 +262,19 @@ public class ExternalResources
|
|||
SettingsSerializer.saveSettingsAsync();
|
||||
}
|
||||
|
||||
public void selectJavaTools()
|
||||
{
|
||||
final File file = DialogueUtils.fileChooser("Select Java Tools Jar",
|
||||
"Java Tools Jar (Inside Of JDK 'C:/Program Files/Java/JDK_xx/lib/tools.jar')",
|
||||
"everything");
|
||||
|
||||
if(file == null)
|
||||
return;
|
||||
|
||||
Configuration.javaTools = file.getAbsolutePath();
|
||||
SettingsSerializer.saveSettingsAsync();
|
||||
}
|
||||
|
||||
public void selectOptionalLibraryFolder()
|
||||
{
|
||||
final File file = DialogueUtils.fileChooser("Select Library Folder",
|
||||
|
@ -278,4 +336,21 @@ public class ExternalResources
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author https://stackoverflow.com/a/16714180
|
||||
*/
|
||||
public String readProcess(Process process) throws IOException
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
builder.append(line);
|
||||
builder.append(System.getProperty("line.separator"));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class XAPKResourceImporter implements Importer
|
|||
public File exportTo(File original, String extension, byte[] bytes)
|
||||
{
|
||||
File file = new File(original.getAbsolutePath() + extension);
|
||||
DiskWriter.replaceFile(file.getAbsolutePath(), bytes, false);
|
||||
DiskWriter.replaceFileBytes(file.getAbsolutePath(), bytes, false);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ public class JarUtils
|
|||
File f = new File(name);
|
||||
f.mkdirs();
|
||||
|
||||
DiskWriter.replaceFile(name, cw.toByteArray(), false);
|
||||
DiskWriter.replaceFileBytes(name, cw.toByteArray(), false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue