diff --git a/BytecodeViewer Beta 1.4.jar b/BytecodeViewer Beta 1.4.jar new file mode 100644 index 00000000..18a1f546 Binary files /dev/null and b/BytecodeViewer Beta 1.4.jar differ diff --git a/README.txt b/README.txt index 168f79da..fdf232cb 100644 --- a/README.txt +++ b/README.txt @@ -109,6 +109,12 @@ Changelog: 10/29/2014 - Tried to fix the issue with JSyntaxPane by making it create the object in a background thread, it still freezes the UI. Changes kept for later implementation of another syntax highlighter. 10/29/2014 - Sped up start up time --- Beta 1.3.1 ---: -10/29/2014 - Replaced JSyntaxPane with RSyntaxArea, this sadly removes the search feature inside of source/bytecode files, I'll implement a search function soon. +10/29/2014 - Replaced JSyntaxPane with RSyntaxArea, this sadly removes the search feature inside of source/bytecode files, I'll implement a search function soon. (This also fixes the JRE 1.8 issue) 10/29/2014 - Added a new decompiler option to append brackets to labels. -10/31/2014 - Fixed an issue with the decompiler still running when the source code pane isn't toggled. \ No newline at end of file +10/31/2014 - Fixed an issue with the decompiler still running when the source code pane isn't toggled. +--- Beta 1.4 ---: +11/1/2014 - Fixed FernFlower save Java files on Unix. +11/1/2014 - FernFlower now uses the settings for save Java files. +11/1/2014 - Added Procyon save Java files (It uses the settings). +11/1/2014 - Updated CFR to cfr_0_89. +11/1/2014 - Added CFR save Java files (It uses the settings), however it relies on the file system, because of this if there is heavy name obfuscation, it could mess up for windows. diff --git a/VERSION b/VERSION index 0aa8e35f..86d106c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Beta 1.3.1 \ No newline at end of file +Beta 1.4 \ No newline at end of file diff --git a/libs/cfr_0_88.jar b/libs/cfr_0_89.jar similarity index 71% rename from libs/cfr_0_88.jar rename to libs/cfr_0_89.jar index a4694d34..17ea02fe 100644 Binary files a/libs/cfr_0_88.jar and b/libs/cfr_0_89.jar differ diff --git a/libs/jsyntaxpane-0.9.5-b29 (1).jar b/libs/jsyntaxpane-0.9.5-b29 (1).jar deleted file mode 100644 index 8bca1f6e..00000000 Binary files a/libs/jsyntaxpane-0.9.5-b29 (1).jar and /dev/null differ diff --git a/libs/rsyntaxtextarea.jar b/libs/rsyntaxtextarea.jar new file mode 100644 index 00000000..e6f415ce Binary files /dev/null and b/libs/rsyntaxtextarea.jar differ diff --git a/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index c2b925e0..39da77ef 100644 --- a/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -138,9 +138,15 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager; * 10/29/2014 - Tried to fix the issue with JSyntaxPane by making it create the object in a background thread, it still freezes the UI. Changes kept for later implementation of another syntax highlighter. * 10/29/2014 - Sped up start up time. * ----Beta 1.3.1-----: - * 10/29/2014 - Replaced JSyntaxPane with RSyntaxArea, this sadly removes the search feature inside of source/bytecode files, I'll implement a search function soon. + * 10/29/2014 - Replaced JSyntaxPane with RSyntaxArea, this sadly removes the search feature inside of source/bytecode files, I'll implement a search function soon. (This also fixes the JRE 1.8 issue) * 10/29/2014 - Added a new decompiler option to append brackets to labels. * 10/31/2014 - Fixed an issue with the decompiler still running when the source code pane isn't toggled. + * ----Beta 1.4-----: + * 11/1/2014 - Fixed FernFlower save Java files on Unix. + * 11/1/2014 - FernFlower now uses the settings for save Java files. + * 11/1/2014 - Added Procyon save Java files (It uses the settings). + * 11/1/2014 - Updated CFR to cfr_0_89. + * 11/1/2014 - Added CFR save Java files (It uses the settings), however it relies on the file system, because of this if there is heavy name obfuscation, it could mess up for windows. * * @author Konloch * @@ -156,10 +162,10 @@ public class BytecodeViewer { private static ArrayList recentFiles = DiskReader.loadArrayList(filesName, false); private static ArrayList recentPlugins = DiskReader.loadArrayList(pluginsName, false); private static int maxRecentFiles = 25; - public static String tempDirectory = "bcv_temp"; public static String fs = System.getProperty("file.separator"); public static String nl = System.getProperty("line.separator"); - public static String version = "Beta 1.3.1"; + public static String tempDirectory = "bcv_temp"; + public static String version = "Beta 1.4"; public static void main(String[] args) { cleanup(); diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/java/CFRDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/java/CFRDecompiler.java index 65502df1..9c055d2b 100644 --- a/src/the/bytecode/club/bytecodeviewer/decompilers/java/CFRDecompiler.java +++ b/src/the/bytecode/club/bytecodeviewer/decompilers/java/CFRDecompiler.java @@ -1,9 +1,17 @@ package the.bytecode.club.bytecodeviewer.decompilers.java; +import java.io.Closeable; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Deque; +import java.util.LinkedList; import java.util.Random; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import me.konloch.kontainer.io.DiskReader; @@ -11,6 +19,7 @@ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.JarUtils; /** * @@ -168,29 +177,82 @@ public class CFRDecompiler extends JavaDecompiler { }; } + byte[] buffer = new byte[1024]; @Override public void decompileToZip(String zipName) { - /* File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp.jar"); if(tempZip.exists()) tempZip.delete(); JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath()); - String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp"; - String fuckery = fuckery(fileStart); + org.benf.cfr.reader.Main.main(generateMainMethod(tempZip.getAbsolutePath(), fuckery)); - + tempZip.delete(); - - for(File f : new File(fuckery).listFiles()) { - //put contents into a zipfile - }*/ - BytecodeViewer.showMessage("CFRDecompiler currently doesn't decompile as zip, please wait till Beta 1.4 of Bytecode Viewer."); - + File fuck = new File(fuckery); + + try { + zip(fuck, new File(zipName)); + } catch (IOException e) { + e.printStackTrace(); + } + + fuck.delete(); } + + @SuppressWarnings("resource") + public void zip(File directory, File zipfile) throws IOException { + java.net.URI base = directory.toURI(); + Deque queue = new LinkedList(); + queue.push(directory); + OutputStream out = new FileOutputStream(zipfile); + Closeable res = out; + try { + ZipOutputStream zout = new ZipOutputStream(out); + res = zout; + while (!queue.isEmpty()) { + directory = queue.pop(); + for (File kid : directory.listFiles()) { + String name = base.relativize(kid.toURI()).getPath(); + if (kid.isDirectory()) { + queue.push(kid); + name = name.endsWith("/") ? name : name + "/"; + zout.putNextEntry(new ZipEntry(name)); + } else { + zout.putNextEntry(new ZipEntry(name)); + copy(kid, zout); + zout.closeEntry(); + } + } + } + } finally { + res.close(); + out.close(); + } + } + private static void copy(InputStream in, OutputStream out) throws IOException { + byte[] buffer = new byte[1024]; + while (true) { + int readCount = in.read(buffer); + if (readCount < 0) { + break; + } + out.write(buffer, 0, readCount); + } + } + + private static void copy(File file, OutputStream out) throws IOException { + InputStream in = new FileInputStream(file); + try { + copy(in, out); + } finally { + in.close(); + } + } + } diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/java/FernFlowerDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/java/FernFlowerDecompiler.java index ab73c65c..eb9ebb13 100644 --- a/src/the/bytecode/club/bytecodeviewer/decompilers/java/FernFlowerDecompiler.java +++ b/src/the/bytecode/club/bytecodeviewer/decompilers/java/FernFlowerDecompiler.java @@ -28,12 +28,12 @@ public class FernFlowerDecompiler extends JavaDecompiler { if(tempZip.exists()) tempZip.delete(); - File f = new File(BytecodeViewer.tempDirectory + "./temp/"); + File f = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs +"temp" + BytecodeViewer.fs); f.mkdir(); JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath()); - org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(new String[] {tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/"}); + org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/")); File tempZip2 = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs +tempZip.getName()); if(tempZip2.exists()) tempZip2.renameTo(new File(zipName)); diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/java/ProcyonDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/java/ProcyonDecompiler.java index e1157c7e..fb864767 100644 --- a/src/the/bytecode/club/bytecodeviewer/decompilers/java/ProcyonDecompiler.java +++ b/src/the/bytecode/club/bytecodeviewer/decompilers/java/ProcyonDecompiler.java @@ -1,15 +1,27 @@ package the.bytecode.club.bytecodeviewer.decompilers.java; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; import java.io.StringWriter; +import java.io.Writer; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipException; +import java.util.zip.ZipOutputStream; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; +import com.strobel.core.StringUtilities; import com.strobel.decompiler.DecompilationOptions; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; @@ -17,11 +29,13 @@ import com.strobel.decompiler.languages.java.JavaFormattingOptions; import com.strobel.assembler.InputTypeLoader; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; +import com.strobel.assembler.metadata.JarTypeLoader; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.JarUtils; /** * @@ -32,6 +46,26 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer; public class ProcyonDecompiler extends JavaDecompiler { + public DecompilerSettings getDecompilerSettings() { + DecompilerSettings settings = new DecompilerSettings(); + settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.chckbxmntmNewCheckItem_6.isSelected()); + settings.setExcludeNestedTypes(BytecodeViewer.viewer.chckbxmntmNewCheckItem_11.isSelected()); + settings.setShowDebugLineNumbers(BytecodeViewer.viewer.chckbxmntmShowDebugLine.isSelected()); + settings.setIncludeLineNumbersInBytecode(BytecodeViewer.viewer.chckbxmntmNewCheckItem_3.isSelected()); + settings.setIncludeErrorDiagnostics(BytecodeViewer.viewer.chckbxmntmNewCheckItem_4.isSelected()); + settings.setShowSyntheticMembers(BytecodeViewer.viewer.chckbxmntmNewCheckItem_7.isSelected()); + settings.setSimplifyMemberReferences(BytecodeViewer.viewer.chckbxmntmSimplifyMemberReferences.isSelected()); + settings.setMergeVariables(BytecodeViewer.viewer.mnMergeVariables.isSelected()); + settings.setForceExplicitTypeArguments(BytecodeViewer.viewer.chckbxmntmNewCheckItem_8.isSelected()); + settings.setForceExplicitImports(BytecodeViewer.viewer.chckbxmntmNewCheckItem_9.isSelected()); + settings.setFlattenSwitchBlocks(BytecodeViewer.viewer.chckbxmntmNewCheckItem_10.isSelected()); + settings.setRetainPointlessSwitches(BytecodeViewer.viewer.chckbxmntmNewCheckItem_2.isSelected()); + settings.setRetainRedundantCasts(BytecodeViewer.viewer.chckbxmntmNewCheckItem_5.isSelected()); + settings.setUnicodeOutputEnabled(BytecodeViewer.viewer.chckbxmntmNewCheckItem_1.isSelected()); + settings.setFormattingOptions(JavaFormattingOptions.createDefault()); + return settings; + } + @Override public String decompileClassNode(ClassNode cn) { try { @@ -54,22 +88,7 @@ public class ProcyonDecompiler extends JavaDecompiler { } - DecompilerSettings settings = new DecompilerSettings(); - settings.setAlwaysGenerateExceptionVariableForCatchBlocks(BytecodeViewer.viewer.chckbxmntmNewCheckItem_6.isSelected()); - settings.setExcludeNestedTypes(BytecodeViewer.viewer.chckbxmntmNewCheckItem_11.isSelected()); - settings.setShowDebugLineNumbers(BytecodeViewer.viewer.chckbxmntmShowDebugLine.isSelected()); - settings.setIncludeLineNumbersInBytecode(BytecodeViewer.viewer.chckbxmntmNewCheckItem_3.isSelected()); - settings.setIncludeErrorDiagnostics(BytecodeViewer.viewer.chckbxmntmNewCheckItem_4.isSelected()); - settings.setShowSyntheticMembers(BytecodeViewer.viewer.chckbxmntmNewCheckItem_7.isSelected()); - settings.setSimplifyMemberReferences(BytecodeViewer.viewer.chckbxmntmSimplifyMemberReferences.isSelected()); - settings.setMergeVariables(BytecodeViewer.viewer.mnMergeVariables.isSelected()); - settings.setForceExplicitTypeArguments(BytecodeViewer.viewer.chckbxmntmNewCheckItem_8.isSelected()); - settings.setForceExplicitImports(BytecodeViewer.viewer.chckbxmntmNewCheckItem_9.isSelected()); - settings.setFlattenSwitchBlocks(BytecodeViewer.viewer.chckbxmntmNewCheckItem_10.isSelected()); - settings.setRetainPointlessSwitches(BytecodeViewer.viewer.chckbxmntmNewCheckItem_2.isSelected()); - settings.setRetainRedundantCasts(BytecodeViewer.viewer.chckbxmntmNewCheckItem_5.isSelected()); - settings.setUnicodeOutputEnabled(BytecodeViewer.viewer.chckbxmntmNewCheckItem_1.isSelected()); - settings.setFormattingOptions(JavaFormattingOptions.createDefault()); + DecompilerSettings settings = getDecompilerSettings(); LuytenTypeLoader typeLoader = new LuytenTypeLoader(); MetadataSystem metadataSystem = new MetadataSystem(typeLoader); @@ -98,48 +117,101 @@ public class ProcyonDecompiler extends JavaDecompiler { @Override public void decompileToZip(String zipName) { - /*File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp.jar"); + File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp.jar"); if(tempZip.exists()) tempZip.delete(); JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath()); - File zip = new File(zipName); + try { + doSaveJarDecompiled(tempZip, new File(zipName)); + } catch (Exception e) { + e.printStackTrace(); + } - try { - final FileOutputStream stream = new FileOutputStream(zip); - - try { - final OutputStreamWriter writer = new OutputStreamWriter(stream); - final PlainTextOutput p = new PlainTextOutput(writer); - - try { - Decompiler.decompile( - tempZip.getAbsolutePath(), - p, - DecompilerSettings.javaDefaults() - ); - } finally { - writer.close(); - } - } - finally { - stream.close(); - } - } catch(Exception e) { - e.printStackTrace(); - } + //tempZip.delete(); + //new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp").delete(); - File tempZip2 = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs +tempZip.getName()); - if(tempZip2.exists()) - tempZip2.renameTo(new File(zipName)); - - tempZip.delete(); - new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp").delete();*/ - - BytecodeViewer.showMessage("ProcyonDecompiler currently doesn't decompile as zip, please wait till Beta 1.4 of Bytecode Viewer."); + //BytecodeViewer.showMessage("ProcyonDecompiler currently doesn't decompile as zip, please wait till Beta 1.4 of Bytecode Viewer."); } + + /** + * + * @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 ent = jfile.entries(); + Set 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 = null; + 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) { + try { + int count; + while ((count = in.read(data, 0, 1024)) != -1) { + out.write(data, 0, count); + } + } finally { + in.close(); + } + } + } finally { + out.closeEntry(); + } + } catch (ZipException ze) { + // some jar-s contain duplicate pom.xml entries: ignore it + if (!ze.getMessage().contains("duplicate")) { + throw ze; + } + } + } + } + } + } /** diff --git a/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java b/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java index b82826e5..378104b5 100644 --- a/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java +++ b/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java @@ -17,7 +17,7 @@ public class AboutWindow extends JFrame { txtrBytecodeViewerIs.setDisabledTextColor(Color.BLACK); txtrBytecodeViewerIs.setWrapStyleWord(true); getContentPane().add(txtrBytecodeViewerIs, "name_140466526081695"); - txtrBytecodeViewerIs.setText("Bytecode Viewer is an open source program\r\ndeveloped by Konloch (konloch@gmail.com)\r\n\r\nIt uses code from the following:\r\n J-RET by WaterWolf\r\n JHexPane by Sam Koivu\r\n JSyntaxPane by Ayman Al\r\n Commons IO by Apache\r\n ASM by OW2\r\n CFIDE by Bibl\r\n FernFlower by Stiver\r\n Procyon by Mstrobel\r\n CFR by Lee Benfield\r\n\r\nIf you're interested in Java Reverse\r\nEngineering, join The Bytecode Club\r\nhttp://the.bytecode.club"); + txtrBytecodeViewerIs.setText("Bytecode Viewer is an open source program\r\ndeveloped by Konloch (konloch@gmail.com)\r\n\r\nIt uses code from the following:\r\n J-RET by WaterWolf\r\n JHexPane by Sam Koivu\r\n RSyntaxTextArea by Bobbylight\r\n Commons IO by Apache\r\n ASM by OW2\r\n CFIDE by Bibl\r\n FernFlower by Stiver\r\n Procyon by Mstrobel\r\n CFR by Lee Benfield\r\n\r\nIf you're interested in Java Reverse\r\nEngineering, join The Bytecode Club\r\nhttp://the.bytecode.club"); txtrBytecodeViewerIs.setEnabled(false); this.setResizable(false); this.setLocationRelativeTo(null);