1.3 released

10/22/2014 - Imported Bibl's Bytecode Decompiler from CFIDE.
10/22/2014 - Did some changes to the Bytecode Decompiler.
10/23/2014 - Added CFR settings.
10/23/2014 - Updated FernFlower to Intellij's Open Sourced version of
FernFlower.
10/24/2014 - Fixed FernFlower save Java files as zip.
10/29/2014 - Added version checker.
10/29/2014 - Added Procyon settings.
10/29/2014 - When saving as jars or zips, it'll automatically append the
file extension if it's not added.
10/29/2014 - All the built in plugins no longer set the cursor to busy.
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
This commit is contained in:
Kalen Kinloch 2014-10-29 19:02:29 -07:00
parent 069246a297
commit 30dc40a095
28 changed files with 1422 additions and 579 deletions

BIN
BytecodeViewer Beta 1.3.jar Normal file

Binary file not shown.

BIN
libs/byteanalysis-1.0.jar Normal file

Binary file not shown.

BIN
libs/fernflower2014.jar Normal file

Binary file not shown.

Binary file not shown.

View File

@ -2,9 +2,12 @@ package the.bytecode.club.bytecodeviewer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
@ -44,9 +47,10 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
* class loaded in the file system to the execute function, this allows the user to handle it
* completely using ASM.
*
* Bytecode Decompiler, File Navigation Pane, Search Pane and Work Pane based off of J-RET by WaterWolf - https://github.com/Waterwolf/Java-ReverseEngineeringTool
* File Navigation Pane, Search Pane and Work Pane based off of J-RET by WaterWolf - https://github.com/Waterwolf/Java-ReverseEngineeringTool
* HexViewer pane based off of Re-Java's by Sami Koivu - http://rejava.sourceforge.net/
* Java Decompiler is a modified version of FernFlower
* Java Decompiler is a modified version of FernFlower, Procyon and CFR.
* Bytecode Decompiler base & ByteAnalysis lib by Bibl. -
*
* TODO:
* Fix the fucking import jar method cause it's a bitch on memory (at the.bytecode.club.bytecodeviewer.JarUtils.getNode(JarUtils.java:83))
@ -56,6 +60,8 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
* Middle mouse click should close tabs
* http://i.imgur.com/yHaai9D.png
*
*
* ----Beta 1.0-----:
* 10/4/2014 - Designed a POC GUI, still needs a lot of work.
* 10/4/2014 - Started importing J-RET's backend.
* 10/5/2014 - Finished importing J-RET's backend.
@ -114,9 +120,23 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
* 10/16/2014 - Now if you try search with an empty string, it won't search.
* 10/16/2014 - Added Replace Strings plugin.
* 10/16/2014 - Added a loading icon that displays whenever a background task is being executed.
* ----Beta 1.1-----:
* 10/19/2014 - Fixed harcoded \\.
* ----Beta 1.2-----:
* 10/19/2014 - Started importing Procyon and CFR decompilers.
* 10/19/2014 - Partially finished importing Procyon and CFR, just need to finish export java files as zip.
* ----Beta 1.3-----:
* 10/22/2014 - Imported Bibl's Bytecode Decompiler from CFIDE.
* 10/22/2014 - Did some changes to the Bytecode Decompiler.
* 10/23/2014 - Added CFR settings.
* 10/23/2014 - Updated FernFlower to Intellij's Open Sourced version of FernFlower.
* 10/24/2014 - Fixed FernFlower save Java files as zip.
* 10/29/2014 - Added version checker.
* 10/29/2014 - Added Procyon settings.
* 10/29/2014 - When saving as jars or zips, it'll automatically append the file extension if it's not added.
* 10/29/2014 - All the built in plugins no longer set the cursor to busy.
* 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.
*
* @author Konloch
*
@ -135,6 +155,7 @@ public class BytecodeViewer {
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";
public static void main(String[] args) {
cleanup();
@ -144,14 +165,32 @@ public class BytecodeViewer {
cleanup();
}
});
Thread versionChecker = new Thread() {
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION").openConnection();
connection.setUseCaches(false);
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String version = reader.readLine();
reader.close();
if(!BytecodeViewer.version.equals(version))
showMessage("You're running an outdated version of Bytecode Viewer, current version: " + BytecodeViewer.version + ", latest version: " + version);
} catch(Exception e) {
e.printStackTrace();
}
}
};
versionChecker.start();
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
viewer = new MainViewerGUI();
viewer.setVisible(true);
resetRecentFilesMenu();
viewer.setVisible(true);
}
public static ClassNode getClassNode(String name) {
@ -180,7 +219,7 @@ public class BytecodeViewer {
if (fn.endsWith(".jar")) {
try {
JarUtils.put(f, BytecodeViewer.loadedClasses);
} catch (final IOException e) {
} catch (final Exception e) {
e.printStackTrace();
}
@ -223,15 +262,17 @@ public class BytecodeViewer {
@SuppressWarnings("deprecation")
public static void resetWorkSpace() {
JOptionPane pane = new JOptionPane("Are you sure you want to reset the workspace?\n\rIt will also reset your file navigator and search.");
Object[] options = new String[] { "Yes", "No" };
pane.setOptions(options);
JDialog dialog = pane.createDialog(viewer, "Bytecode Viewer - Reset Workspace");
dialog.show();
Object obj = pane.getValue();
int result = -1;
for (int k = 0; k < options.length; k++)
if (options[k].equals(obj))
result = k;
Object[] options = new String[] { "Yes", "No" };
pane.setOptions(options);
JDialog dialog = pane.createDialog(viewer, "Bytecode Viewer - Reset Workspace");
dialog.show();
Object obj = pane.getValue();
int result = -1;
for (int k = 0; k < options.length; k++)
if (options[k].equals(obj))
result = k;
if(result == 0) {
loadedResources.clear();
loadedClasses.clear();
@ -318,16 +359,14 @@ public class BytecodeViewer {
public static void cleanup() {
tempF = new File(tempDirectory);
try {
Thread.sleep(100);
FileUtils.deleteDirectory(tempF);
Thread.sleep(100);
} catch (Exception e) {
}
while(!tempF.exists()) { //keep making dirs
try {
tempF.mkdir();
Thread.sleep(100);
Thread.sleep(1);
} catch (Exception e) {
}
}

View File

@ -1,381 +0,0 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import org.apache.commons.lang3.StringEscapeUtils;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.searching.commons.InstructionSearcher;
/**
* A Bytecode decompiler
*
* @author Konloch
* @author WaterWolf
*
*/
public class BytecodeDecompiler {
public static String[] opcodeStrings;
public static String[] typeStrings;
static {
opcodeStrings = new String[256];
for (final Field f : Opcodes.class.getFields()) {
try {
final Object oo = f.get(null);
if (oo instanceof Integer) {
final int oi = ((Integer)oo);
if (oi < 256 && oi >= 0) {
opcodeStrings[oi] = f.getName().toLowerCase();
}
}
} catch (final IllegalArgumentException e) {
e.printStackTrace();
} catch (final IllegalAccessException e) {
e.printStackTrace();
}
}
typeStrings = new String[100];
for (final Field f : AbstractInsnNode.class.getFields()) {
if (!(f.getName().endsWith("_INSN"))) {
continue;
}
try {
final Object oo = f.get(null);
if (oo instanceof Integer) {
final int oi = ((Integer)oo);
if (oi < 256 && oi >= 0) {
typeStrings[oi] = f.getName().toLowerCase();
}
}
} catch (final IllegalArgumentException e) {
e.printStackTrace();
} catch (final IllegalAccessException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("unchecked")
public String decompileClassNode(final ClassNode cn) {
final StringBuilder classBuilder = new StringBuilder();
final ClassStringBuilder cb = new ClassStringBuilder(classBuilder);
final String cnm = cn.name;
String package_ = null;
String class_ = null;
if (cnm.contains("/")) {
package_ = cnm.substring(0, cnm.lastIndexOf("/"));
class_ = cnm.substring(cnm.lastIndexOf("/")+1);
}
else {
class_ = cnm;
}
if (package_ != null) {
cb.appendnl("package " + package_ + ";", 2);
}
cb.append(Modifier.toString(cn.access) + " class " + class_ + " ");
if (cn.superName != null) {
cb.append("extends " + cn.superName + " ");
}
if (cn.interfaces.size() > 0) {
cb.append("implements ");
final Iterator<String> sit = cn.interfaces.iterator();
while (sit.hasNext()) {
final String s = sit.next();
cb.append(s);
if (sit.hasNext()) {
cb.append(", ");
} else {
cb.append(" ");
}
}
}
cb.appendnl("{");
cb.increase();
cb.appendnl();
final Iterator<FieldNode> fni = cn.fields.iterator();
while (fni.hasNext()) {
final FieldNode fn = fni.next();
cb.appendnl(Modifier.toString(fn.access) + " " + Type.getType(fn.desc).getClassName() + " " + fn.name + ";");
}
cb.appendnl();
final Iterator<MethodNode> mni = cn.methods.iterator();
while (mni.hasNext()) {
final MethodNode mn = mni.next();
final String mnm = mn.name;
if (!mnm.equals("<clinit>")) {
cb.append(Modifier.toString(mn.access) + " ");
}
if (mnm.equals("<init>")) {
cb.append(class_);
}
else if (mnm.equals("<clinit>")) {
cb.append("static {");
if (BytecodeViewer.viewer.debugHelpers.isSelected())
cb.appendnl(" // <clinit>");
else
cb.appendnl();
}
else {
cb.append(Type.getReturnType(mn.desc).getClassName() + " ");
cb.append(mnm);
}
TypeAndName[] args = new TypeAndName[0];
if (!mnm.equals("<clinit>")) {
cb.append("(");
// TODO desc
final Type[] argTypes = Type.getArgumentTypes(mn.desc);
args = new TypeAndName[argTypes.length];
for (int i = 0;i < argTypes.length; i++) {
final Type type = argTypes[i];
final TypeAndName tan = new TypeAndName();
final String argName = "arg" + i;
tan.name = argName;
tan.type = type;
args[i] = tan;
cb.append(type.getClassName() + " " + argName + (i < argTypes.length-1 ? ", " : ""));
}
cb.appendnl(") {");
}
cb.increase();
try {
decompileMethod(cb, args, mn, cn);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
cb.decrease();
cb.appendnl("}");
cb.appendnl();
}
cb.decrease();
cb.appendnl("}");
return classBuilder.toString();
}
public void decompileMethod(final ClassStringBuilder builder, final TypeAndName[] args, final MethodNode mn, final ClassNode parent) throws UnsupportedEncodingException {
final InstructionSearcher is = new InstructionSearcher(mn);
//AbstractInsnNode next = is.getCurrent();
for(Object e : mn.tryCatchBlocks.toArray()) {
TryCatchBlockNode t = (TryCatchBlockNode)e;
String type = t.type;
LabelNode start = t.start;
LabelNode end = t.end;
LabelNode handler = t.handler;
builder.appendnl("trycatch block L" + start.hashCode() + " to L" + end.hashCode() + " handled by L" + handler.hashCode() + " exception type: " + type);
}
int index = 0;
for(AbstractInsnNode next : mn.instructions.toArray()) {
if (next.getOpcode() == -1) {
if(next instanceof LabelNode) {
LabelNode l = (LabelNode)next;
builder.appendnl(index++ + ". L" +l.hashCode());
} else {
builder.appendnl(index++ + ". nop //actually an unimplement opcode, please contact Konloch"); //lets just set it as nop for now.
}
//next = is.getNext();
continue;
}
builder.append(index++ + ". " + opcodeStrings[next.getOpcode()] + " ");
if (next instanceof FieldInsnNode) {
final FieldInsnNode fin = (FieldInsnNode) next;
builder.append(fin.owner + " " + fin.name + " " + fin.desc);
}
else if (next instanceof MethodInsnNode) {
final MethodInsnNode min = (MethodInsnNode) next;
builder.append(min.owner + " " + min.name + " " + min.desc);
}
else if (next instanceof VarInsnNode) {
final VarInsnNode vin = (VarInsnNode) next;
builder.append(vin.var);
if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
if (vin.var == 0 && !Modifier.isStatic(mn.access)) {
builder.append(" // reference to self");
}
else {
final int refIndex = vin.var - (Modifier.isStatic(mn.access) ? 0 : 1);
if (refIndex >= 0 && refIndex < args.length-1) {
builder.append(" // reference to " + args[refIndex].name);
}
}
}
}
else if (next instanceof IntInsnNode) {
final IntInsnNode iin = (IntInsnNode) next;
builder.append(iin.operand);
}
else if (next instanceof JumpInsnNode) {
final JumpInsnNode jin = (JumpInsnNode) next;
builder.append(is.computePosition(jin.label));
switch (next.getOpcode()) {
case Opcodes.IF_ICMPLT:
builder.append(" // if val1 less than val2 jump");
break;
}
}
else if (next instanceof LdcInsnNode) {
final LdcInsnNode lin = (LdcInsnNode) next;
if(lin.cst instanceof String) {
String s = ((String)lin.cst).replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r").replaceAll("\\\"", "\\\\\"");
if(BytecodeViewer.viewer.chckbxmntmNewCheckItem.isSelected())
builder.append("\"" + StringEscapeUtils.escapeJava(s) + "\"");
else
builder.append("\"" + s + "\"");
} else {
String s = lin.cst.toString().replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r").replaceAll("\\\"", "\\\\\"");
if(BytecodeViewer.viewer.chckbxmntmNewCheckItem.isSelected())
builder.append("\"" + StringEscapeUtils.escapeJava(s) + "\"");
else
builder.append("\"" + s + "\"");
}
}
else if (next instanceof IincInsnNode) {
final IincInsnNode iin = (IincInsnNode) next;
builder.append("var " + iin.var + " by " + iin.incr);
}
else if (next instanceof TypeInsnNode) {
final TypeInsnNode tin = (TypeInsnNode) next;
builder.append(tin.desc);
}
else {
/*
switch (next.getOpcode()) {
case Opcodes.IF_ICMPLT:
buffer.append(" // ");
break;
}
*/
}
if (BytecodeViewer.viewer.debugInstructions.isSelected()) {
builder.append(" // " + typeStrings[next.getType()] + " ");
}
if (BytecodeViewer.viewer.debugHelpers.isSelected() &&
next instanceof JumpInsnNode)
{
final JumpInsnNode jin = (JumpInsnNode) next;
builder.append(" // line " + is.computePosition(jin.label) + " is " + printInstruction(is.computePosition(jin.label), mn, is).trim());
}
builder.appendnl();
}
}
public static String printInstruction(int line, MethodNode mn, InstructionSearcher is) {
for(int i = 0; i < mn.instructions.size(); i++) {
AbstractInsnNode next = mn.instructions.get(i);
if(line == i)
if(next.getOpcode() != -1) {
return beatifyAbstractInsnNode(next, is);
}
}
return "Unable to find, please contact konloch.";
}
public static String beatifyAbstractInsnNode(AbstractInsnNode next, InstructionSearcher is) {
String insn = "";
if(next.getOpcode() != -1)
insn =opcodeStrings[next.getOpcode()] + " ";
else if(next instanceof LabelNode) {
LabelNode l = (LabelNode)next;
insn = "L" +l.hashCode();
}
if (next instanceof FieldInsnNode) {
final FieldInsnNode fin = (FieldInsnNode) next;
insn += fin.owner + " " + fin.name + " " + fin.desc;
}
else if (next instanceof MethodInsnNode) {
final MethodInsnNode min = (MethodInsnNode) next;
insn += min.owner + " " + min.name + " " + min.desc;
}
else if (next instanceof VarInsnNode) {
final VarInsnNode vin = (VarInsnNode) next;
insn += vin.var;
}
else if (next instanceof IntInsnNode) {
final IntInsnNode iin = (IntInsnNode) next;
insn += iin.operand;
}
else if (next instanceof JumpInsnNode) {
final JumpInsnNode jin = (JumpInsnNode) next;
insn += is.computePosition(jin.label);
}
else if (next instanceof LdcInsnNode) {
final LdcInsnNode lin = (LdcInsnNode) next;
if(lin.cst instanceof String)
insn += "\"" + ((String) lin.cst).replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r") + "\"";
else
insn += "\"" + lin.cst + "\"";
}
else if (next instanceof IincInsnNode) {
final IincInsnNode iin = (IincInsnNode) next;
insn += "var " + iin.var + " by " + iin.incr;
}
else if (next instanceof TypeInsnNode) {
final TypeInsnNode tin = (TypeInsnNode) next;
insn += tin.desc;
}
else {
}
return insn;
}
}

View File

@ -0,0 +1,128 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InnerClassNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
*
* @author Konloch
* @author Bibl
*
*/
public class ClassNodeDecompiler {
public static String decompile(ClassNode cn) {
return decompileClassNode(new PrefixedStringBuilder(), new ArrayList<String>(), cn).toString();
}
@SuppressWarnings("unchecked")
protected static PrefixedStringBuilder decompileClassNode(PrefixedStringBuilder sb, ArrayList<String> decompiledClasses, ClassNode cn) {
ArrayList<String> unableToDecompile = new ArrayList<String>();
decompiledClasses.add(cn.name);
sb.append(getAccessString(cn.access));
sb.append(" ");
sb.append(cn.name);
if (cn.superName != null && !cn.superName.equals("java/lang/Object")) {
sb.append(" extends " + cn.superName);
}
int amountOfInterfaces = cn.interfaces.size();
if (amountOfInterfaces > 0) {
sb.append(" implements ");
sb.append(cn.interfaces.get(0));
if (amountOfInterfaces > 1) {
// sb.append(",");
}
for (int i = 1; i < amountOfInterfaces; i++) {
sb.append(", ");
sb.append(cn.interfaces.get(i));
}
}
sb.append(" {"+BytecodeViewer.nl);
for (FieldNode fn : (List<FieldNode>)cn.fields) {
sb.append(BytecodeViewer.nl+" ");
FieldNodeDecompiler.decompile(sb, fn);
}
if (cn.fields.size() > 0) {
sb.append(BytecodeViewer.nl);
}
for (MethodNode mn : (List<MethodNode>)cn.methods) {
sb.append(BytecodeViewer.nl);
MethodNodeDecompiler.decompile(sb, mn, cn);
}
for (Object o : cn.innerClasses) {
InnerClassNode innerClassNode = (InnerClassNode) o;
String innerClassName = innerClassNode.name;
if ((innerClassName != null) && !decompiledClasses.contains(innerClassName)) {
decompiledClasses.add(innerClassName);
ClassNode cn1 = BytecodeViewer.getClassNode(innerClassName);
if (cn1 != null) {
sb.appendPrefix(" ");
sb.append(BytecodeViewer.nl+BytecodeViewer.nl);
sb = decompileClassNode(sb, decompiledClasses, cn1);
sb.trimPrefix(5);
sb.append(BytecodeViewer.nl);
} else {
unableToDecompile.add(innerClassName);
}
}
}
if(!unableToDecompile.isEmpty()) {
sb.append("//the following inner classes couldn't be decompiled: ");
for(String s : unableToDecompile)
sb.append(s + " ");
sb.append(BytecodeViewer.nl);
}
sb.append("}");
// System.out.println("Wrote end for " + cn.name + " with prefix length: " + sb.prefix.length());
return sb;
}
public static String getAccessString(int access) {
List<String> tokens = new ArrayList<String>();
if ((access & Opcodes.ACC_PUBLIC) != 0)
tokens.add("public");
if ((access & Opcodes.ACC_PRIVATE) != 0)
tokens.add("private");
if ((access & Opcodes.ACC_PROTECTED) != 0)
tokens.add("protected");
if ((access & Opcodes.ACC_FINAL) != 0)
tokens.add("final");
if ((access & Opcodes.ACC_SYNTHETIC) != 0)
tokens.add("synthetic");
// if ((access & Opcodes.ACC_SUPER) != 0)
// tokens.add("super"); implied by invokespecial insn
if ((access & Opcodes.ACC_ABSTRACT) != 0)
tokens.add("abstract");
if ((access & Opcodes.ACC_INTERFACE) != 0)
tokens.add("interface");
if ((access & Opcodes.ACC_ENUM) != 0)
tokens.add("enum");
if ((access & Opcodes.ACC_ANNOTATION) != 0)
tokens.add("annotation");
if (!tokens.contains("interface") && !tokens.contains("enum") && !tokens.contains("annotation"))
tokens.add("class");
if (tokens.size() == 0)
return "[Error parsing]";
// hackery delimeters
StringBuilder sb = new StringBuilder(tokens.get(0));
for (int i = 1; i < tokens.size(); i++) {
sb.append(" ");
sb.append(tokens.get(i));
}
return sb.toString();
}
}

View File

@ -1,76 +0,0 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
/**
* The buffer where decompiler classes output generated source
*
* @author Waterwolf
*
*/
public class ClassStringBuilder {
private final StringBuilder builder;
public final IndentationLevel iLevel;
private static final String nl = System.getProperty("line.separator");
private static final int TAB_SPACES = 4;
private boolean isNewline = true;
public ClassStringBuilder(final StringBuilder builder) {
this.builder = builder;
this.iLevel = new IndentationLevel();
}
public void append(final Object obj) {
if (isNewline) {
for (int i = 0;i < TAB_SPACES*iLevel.indentation; i++) {
builder.append(" ");
}
}
builder.append(obj);
isNewline = false;
}
public void appendnl(final String s) {
appendnl(s, 1);
}
public void appendnl() {
appendnl("", 1);
}
public void appendnl(final String s, final int nlAmount) {
append(s);
for (int i = 0;i < nlAmount; i++) {
builder.append(nl);
}
if (nlAmount > 0) {
isNewline = true;
}
}
public int increase() {
return iLevel.increase();
}
public int decrease() {
return iLevel.decrease();
}
public int get() {
return iLevel.get();
}
public static class IndentationLevel {
private int indentation = 0;
public int increase() {
return ++indentation;
}
public int decrease() {
return --indentation;
}
public int get() {
return indentation;
}
}
}

View File

@ -0,0 +1,72 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.FieldNode;
/**
*
* @author Konloch
* @author Bibl
*
*/
public class FieldNodeDecompiler {
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb, FieldNode f) {
String s = getAccessString(f.access);
sb.append(s);
if (s.length() > 0)
sb.append(" ");
sb.append(Type.getType(f.desc).getClassName());
sb.append(" ");
sb.append(f.name);
if (f.value != null) {
sb.append(" = ");
if (f.value instanceof String) {
sb.append("\"");
sb.append(f.value);
sb.append("\"");
} else {
sb.append(f.value);
sb.append(" (");
sb.append(f.value.getClass().getCanonicalName());
sb.append(")");
}
}
sb.append(";");
return sb;
}
private static String getAccessString(int access) {
List<String> tokens = new ArrayList<String>();
if ((access & Opcodes.ACC_PUBLIC) != 0)
tokens.add("public");
if ((access & Opcodes.ACC_PRIVATE) != 0)
tokens.add("private");
if ((access & Opcodes.ACC_PROTECTED) != 0)
tokens.add("protected");
if ((access & Opcodes.ACC_SYNTHETIC) != 0)
tokens.add("synthetic");
if ((access & Opcodes.ACC_STATIC) != 0)
tokens.add("static");
if ((access & Opcodes.ACC_FINAL) != 0)
tokens.add("final");
if ((access & Opcodes.ACC_TRANSIENT) != 0)
tokens.add("transient");
if ((access & Opcodes.ACC_VOLATILE) != 0)
tokens.add("volatile");
if (tokens.size() == 0)
return "";
// hackery delimeters
StringBuilder sb = new StringBuilder(tokens.get(0));
for (int i = 1; i < tokens.size(); i++) {
sb.append(" ");
sb.append(tokens.get(i));
}
return sb.toString();
}
}

View File

@ -0,0 +1,177 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.util.Arrays;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import eu.bibl.banalysis.filter.InstructionFilter;
import eu.bibl.banalysis.filter.OpcodeFilter;
import eu.bibl.banalysis.filter.insn.FieldInstructionFilter;
import eu.bibl.banalysis.filter.insn.IincInstructionFilter;
import eu.bibl.banalysis.filter.insn.InsnInstructionFilter;
import eu.bibl.banalysis.filter.insn.JumpInstructionFilter;
import eu.bibl.banalysis.filter.insn.LdcInstructionFilter;
import eu.bibl.banalysis.filter.insn.MethodInstructionFilter;
import eu.bibl.banalysis.filter.insn.MultiANewArrayInstructionFilter;
import eu.bibl.banalysis.filter.insn.TypeInstructionFilter;
import eu.bibl.banalysis.filter.insn.VarInstructionFilter;
/**
* Pattern filter holder and stepper.
* @author Bibl
*
*/
public class InstructionPattern implements Opcodes {
/** Last instruction-match position pointer **/
protected int pointer;
/** Filters/patterns/search criteria. **/
protected InstructionFilter[] filters;
/** Last match found cache. **/
protected AbstractInsnNode[] lastMatch;
/**
* Construct a new pattern from the specified instructions.
* @param insns {@link AbstractInsnNode} pattern array.
*/
public InstructionPattern(AbstractInsnNode[] insns) {
filters = translate(insns);
lastMatch = new AbstractInsnNode[insns.length];
}
/**
* Construct a new pattern from the specified opcode.
* @param opcodes Opcodes to convert to {@link OpcodeFilter}s.
*/
public InstructionPattern(int[] opcodes) {
filters = new InstructionFilter[opcodes.length];
lastMatch = new AbstractInsnNode[opcodes.length];
for(int i = 0; i < opcodes.length; i++) {
filters[i] = new OpcodeFilter(opcodes[i]);
}
}
/**
* Construct an absolute pattern from user-defined filters.
* @param filters User-defined {@link InstructionFilter}s.
*/
public InstructionPattern(InstructionFilter[] filters) {
this.filters = filters;
lastMatch = new AbstractInsnNode[filters.length];
}
/**
* Steps through the instruction list checking if the current instruction ended a successful pattern-match sequence.
* @param ain {@link AbstractInsnNode} to check.
* @return True if this instruction successfully completed the pattern.
*/
public boolean accept(AbstractInsnNode ain) {
if (pointer >= filters.length)
reset();
InstructionFilter filter = filters[pointer];
if (filter.accept(ain)) {
lastMatch[pointer] = ain;
if (pointer >= (filters.length - 1)) {
return true;
}
pointer++;
} else {
reset();
}
return false;
}
/**
* @return Last pattern sequence match equivilent from the inputted {@link AbstractInsnNode}s.
*/
public AbstractInsnNode[] getLastMatch() {
return lastMatch;
}
/**
* Resets the instruction pointer and clears the last match cache data.
*/
public void resetMatch() {
reset();
AbstractInsnNode[] match = lastMatch;
lastMatch = new AbstractInsnNode[match.length];
}
/**
* Sets the current instruction pointer to 0 (start of pattern).
*/
public void reset() {
pointer = 0;
}
/**
* Converts an array of {@link AbstractInsnNode}s to their {@link InstructionFilter} counterparts.
* @param ains {@link AbstractInsnNode}s to convert.
* @return Array of {@link InstructionFilter}s.
*/
public static InstructionFilter[] translate(AbstractInsnNode[] ains) {
InstructionFilter[] filters = new InstructionFilter[ains.length];
for(int i = 0; i < ains.length; i++) {
filters[i] = translate(ains[i]);
}
return filters;
}
/**
* Translate a single {@link AbstractInsnNode} to an {@link InstructionFilter}.
* @param ain Instruction to convert.
* @return A filter an an equivilent to the inputted instruction.
*/
public static InstructionFilter translate(AbstractInsnNode ain) {
if (ain instanceof LdcInsnNode) {
return new LdcInstructionFilter(((LdcInsnNode) ain).cst);
} else if (ain instanceof TypeInsnNode) {
return new TypeInstructionFilter(ain.getOpcode(), ((TypeInsnNode) ain).desc);
} else if (ain instanceof FieldInsnNode) {
return new FieldInstructionFilter(ain.getOpcode(), ((FieldInsnNode) ain).owner, ((FieldInsnNode) ain).name, ((FieldInsnNode) ain).desc);
} else if (ain instanceof MethodInsnNode) {
return new MethodInstructionFilter(ain.getOpcode(), ((MethodInsnNode) ain).owner, ((MethodInsnNode) ain).name, ((MethodInsnNode) ain).desc);
} else if (ain instanceof VarInsnNode) {
return new VarInstructionFilter(ain.getOpcode(), ((VarInsnNode) ain).var);
} else if (ain instanceof InsnNode) {
return new InsnInstructionFilter(ain.getOpcode());
} else if (ain instanceof IincInsnNode) {
return new IincInstructionFilter(((IincInsnNode) ain).incr, ((IincInsnNode) ain).var);
} else if (ain instanceof JumpInsnNode) {
return new JumpInstructionFilter(ain.getOpcode());
} else if (ain instanceof LabelNode) {
return InstructionFilter.ACCEPT_ALL; // TODO: Cache labels and check. // TODO: That's a fucking stupid idea.
} else if (ain instanceof MultiANewArrayInsnNode) {
return new MultiANewArrayInstructionFilter(((MultiANewArrayInsnNode) ain).desc, ((MultiANewArrayInsnNode) ain).dims);
} else {
return InstructionFilter.ACCEPT_ALL;
}
}
public static void main(String[] args) {
AbstractInsnNode[] ains = new AbstractInsnNode[] {
new LdcInsnNode("ldc"),
new VarInsnNode(ASTORE, 0),
new LdcInsnNode("ldc") };
InstructionPattern pattern = new InstructionPattern(new AbstractInsnNode[] {
new LdcInsnNode("ldc"),
new VarInsnNode(-1, -1) });
for(AbstractInsnNode ain : ains) {
if (pattern.accept(ain)) {
System.out.println(Arrays.toString(pattern.getLastMatch()));
}
}
}
}

View File

@ -0,0 +1,289 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.apache.commons.lang3.StringEscapeUtils;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LineNumberNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.TypeAndName;
import eu.bibl.banalysis.asm.desc.OpcodeInfo;
/**
*
* @author Konloch
* @author Bibl
*
*/
public class InstructionPrinter {
/** The MethodNode to print **/
protected MethodNode mNode;
private TypeAndName[] args;
protected int[] pattern;
protected boolean match;
protected InstructionSearcher searcher;
protected List<AbstractInsnNode> matchedInsns;
protected Map<LabelNode, Integer> labels;
public InstructionPrinter(MethodNode m, TypeAndName[] args) {
this.args = args;
mNode = m;
labels = new HashMap<LabelNode, Integer>();
// matchedInsns = new ArrayList<AbstractInsnNode>(); // ingnored because match = false
match = false;
}
public InstructionPrinter(MethodNode m, InstructionPattern pattern, TypeAndName[] args) {
this.args = args;
mNode = m;
labels = new HashMap<LabelNode, Integer>();
searcher = new InstructionSearcher(m.instructions, pattern);
match = searcher.search();
if (match) {
for(AbstractInsnNode[] ains : searcher.getMatches()) {
for(AbstractInsnNode ain : ains) {
matchedInsns.add(ain);
}
}
}
}
/**
* Creates the print
* @return The print as an ArrayList
*/
public ArrayList<String> createPrint() {
ArrayList<String> info = new ArrayList<String>();
ListIterator<?> it = mNode.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode ain = (AbstractInsnNode) it.next();
String line = "";
if (ain instanceof VarInsnNode) {
line = printVarInsnNode((VarInsnNode) ain, it);
} else if (ain instanceof IntInsnNode) {
line = printIntInsnNode((IntInsnNode) ain, it);
} else if (ain instanceof FieldInsnNode) {
line = printFieldInsnNode((FieldInsnNode) ain, it);
} else if (ain instanceof MethodInsnNode) {
line = printMethodInsnNode((MethodInsnNode) ain, it);
} else if (ain instanceof LdcInsnNode) {
line = printLdcInsnNode((LdcInsnNode) ain, it);
} else if (ain instanceof InsnNode) {
line = printInsnNode((InsnNode) ain, it);
} else if (ain instanceof JumpInsnNode) {
line = printJumpInsnNode((JumpInsnNode) ain, it);
} else if (ain instanceof LineNumberNode) {
line = printLineNumberNode((LineNumberNode) ain, it);
} else if (ain instanceof LabelNode) {
line = printLabelnode((LabelNode) ain);
} else if (ain instanceof TypeInsnNode) {
line = printTypeInsnNode((TypeInsnNode) ain);
} else if (ain instanceof FrameNode) {
line = "";
} else if (ain instanceof IincInsnNode) {
line = printIincInsnNode((IincInsnNode) ain);
} else if (ain instanceof TableSwitchInsnNode) {
line = printTableSwitchInsnNode((TableSwitchInsnNode) ain);
} else if (ain instanceof LookupSwitchInsnNode) {
line = printLookupSwitchInsnNode((LookupSwitchInsnNode) ain);
} else {
line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " + ain.toString();
}
if (!line.equals("")) {
if (match)
if (matchedInsns.contains(ain))
line = " -> " + line;
info.add(line);
}
}
return info;
}
protected String printVarInsnNode(VarInsnNode vin, ListIterator<?> it) {
StringBuilder sb = new StringBuilder();
sb.append(nameOpcode(vin.getOpcode()));
sb.append(vin.var);
if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
if (vin.var == 0 && !Modifier.isStatic(mNode.access)) {
sb.append(" // reference to self");
} else {
final int refIndex = vin.var - (Modifier.isStatic(mNode.access) ? 0 : 1);
if (refIndex >= 0 && refIndex < args.length-1) {
sb.append(" // reference to " + args[refIndex].name);
}
}
}
return sb.toString();
}
protected String printIntInsnNode(IntInsnNode iin, ListIterator<?> it) {
return nameOpcode(iin.getOpcode()) + " " + iin.operand;
}
protected String printFieldInsnNode(FieldInsnNode fin, ListIterator<?> it) {
return nameOpcode(fin.getOpcode()) + " " + fin.owner + "." + fin.name + ":" + Type.getType(fin.desc).getClassName();
}
protected String printMethodInsnNode(MethodInsnNode min, ListIterator<?> it) {
StringBuilder sb = new StringBuilder();
sb.append(nameOpcode(min.getOpcode()) + " " + min.owner + " " + min.name + "(");
if(Type.getType(min.desc).getClassName() == null ||
Type.getType(min.desc).getClassName().equalsIgnoreCase("null"))
{
//sb.append(min.desc);
} else {
sb.append(Type.getType(min.desc).getClassName());
}
sb.append(");");
return sb.toString();
}
protected String printLdcInsnNode(LdcInsnNode ldc, ListIterator<?> it) {
if(BytecodeViewer.viewer.chckbxmntmNewCheckItem.isSelected()) { //ascii only
if (ldc.cst instanceof String)
return nameOpcode(ldc.getOpcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";
return nameOpcode(ldc.getOpcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")";
} else {
if (ldc.cst instanceof String)
return nameOpcode(ldc.getOpcode()) + " \"" + ((String)ldc.cst).replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r").replaceAll("\\\"", "\\\\\"") + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";
return nameOpcode(ldc.getOpcode()) + " " + ldc.cst + " (" + ldc.cst.getClass().getCanonicalName() + ")";
}
}
protected String printInsnNode(InsnNode in, ListIterator<?> it) {
return nameOpcode(in.getOpcode());
}
protected String printJumpInsnNode(JumpInsnNode jin, ListIterator<?> it) {
String line = nameOpcode(jin.getOpcode()) + " L" + resolveLabel(jin.label);
return line;
}
protected String printLineNumberNode(LineNumberNode lin, ListIterator<?> it) {
return "";
}
protected String printLabelnode(LabelNode label) {
return "L" + resolveLabel(label);
}
protected String printTypeInsnNode(TypeInsnNode tin) {
try {
return nameOpcode(tin.getOpcode()) + " " + Type.getType(tin.desc).getClassName();
} catch(Exception e) {
e.printStackTrace();
}
return "//error";
}
protected String printIincInsnNode(IincInsnNode iin) {
return nameOpcode(iin.getOpcode()) + " " + iin.var + " " + iin.incr;
}
protected String printTableSwitchInsnNode(TableSwitchInsnNode tin) {
String line = nameOpcode(tin.getOpcode()) + " \n";
List<?> labels = tin.labels;
int count = 0;
for (int i = tin.min; i < tin.max; i++) {
line += " val: " + i + " -> " + "L" + resolveLabel((LabelNode) labels.get(count++)) + "\n";
}
line += " default" + " -> L" + resolveLabel(tin.dflt) + "";
return line;
}
protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin) {
String line = nameOpcode(lin.getOpcode()) + ": \n";
List<?> keys = lin.keys;
List<?> labels = lin.labels;
for (int i = 0; i < keys.size(); i++) {
int key = (Integer) keys.get(i);
LabelNode label = (LabelNode) labels.get(i);
line += " val: " + key + " -> " + "L" + resolveLabel(label) + "\n";
}
line += " default" + " -> L" + resolveLabel(lin.dflt) + "";
return line;
}
protected String nameOpcode(int opcode) {
return " " + OpcodeInfo.OPCODES.get(opcode).toLowerCase();
}
protected int resolveLabel(LabelNode label) {
if (labels.containsKey(label)) {
return labels.get(label);
} else {
int newLabelIndex = labels.size() + 1;
labels.put(label, newLabelIndex);
return newLabelIndex;
}
}
/**
* Creates the print
* @return The print as a string array
*/
public String[] getLines() {
ArrayList<String> lines = createPrint();
return lines.toArray(new String[lines.size()]);
}
/**
* Static method to print
* @param lines To print
*/
public static void consolePrint(String[] lines) {
for(String line : lines) {
System.out.println(line);
}
}
public static void saveTo(File file, InstructionPrinter printer) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
for(String s : printer.createPrint()) {
bw.write(s);
bw.newLine();
}
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,58 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LineNumberNode;
/**
*
* @author Bibl
*
*/
public class InstructionSearcher implements Opcodes {
protected InsnList insns;
protected InstructionPattern pattern;
protected List<AbstractInsnNode[]> matches;
public InstructionSearcher(InsnList insns, int[] opcodes) {
this(insns, new InstructionPattern(opcodes));
}
public InstructionSearcher(InsnList insns, AbstractInsnNode[] ains) {
this(insns, new InstructionPattern(ains));
}
public InstructionSearcher(InsnList insns, InstructionPattern pattern) {
this.insns = insns;
this.pattern = pattern;
matches = new ArrayList<AbstractInsnNode[]>();
}
public boolean search() {
for(AbstractInsnNode ain : insns.toArray()) {
if (ain instanceof LineNumberNode || ain instanceof FrameNode)
continue;
if (pattern.accept(ain)) {
matches.add(pattern.getLastMatch());
pattern.resetMatch();
}
}
return size() != 0;
}
public List<AbstractInsnNode[]> getMatches() {
return matches;
}
public int size() {
return matches.size();
}
}

View File

@ -0,0 +1,162 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.TypeAndName;
/**
*
* @author Konloch
* @author Bibl
*
*/
public class MethodNodeDecompiler {
@SuppressWarnings("unused")
public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb, MethodNode m, ClassNode cn) {
String package_ = null;
String class_ = null;
if (cn.name.contains("/")) {
package_ = cn.name.substring(0, cn.name.lastIndexOf("/"));
class_ = cn.name.substring(cn.name.lastIndexOf("/")+1);
} else {
class_ = cn.name;
}
String s = getAccessString(m.access);
sb.append(" ");
sb.append(s);
if (s.length() > 0)
sb.append(" ");
System.out.println(m.name);
if (m.name.equals("<init>")) {
sb.append(class_);
} else if (m.name.equals("<clinit>")) {
} else {
sb.append(m.name);
}
TypeAndName[] args = new TypeAndName[0];
if (!m.name.equals("<clinit>")) {
sb.append("(");
final Type[] argTypes = Type.getArgumentTypes(m.desc);
args = new TypeAndName[argTypes.length];
for (int i = 0;i < argTypes.length; i++) {
final Type type = argTypes[i];
final TypeAndName tan = new TypeAndName();
final String argName = "arg" + i;
tan.name = argName;
tan.type = type;
args[i] = tan;
sb.append(type.getClassName() + " " + argName + (i < argTypes.length-1 ? ", " : ""));
}
sb.append(")");
}
int amountOfThrows = m.exceptions.size();
if (amountOfThrows > 0) {
sb.append(" throws ");
sb.append(m.exceptions.get(0));// exceptions is list<string>
for (int i = 1; i < amountOfThrows; i++) {
sb.append(", ");
sb.append(m.exceptions.get(i));
}
}
if (s.contains("abstract")) {
sb.append(" {}"+BytecodeViewer.nl);
} else {
sb.append(" {");
if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
if(m.name.equals("<clinit>"))
sb.append(" // <clinit>");
else if(m.name.equals("<init>"))
sb.append(" // <init>");
}
sb.append(BytecodeViewer.nl);
InstructionPrinter insnPrinter = new InstructionPrinter(m, args);
for (Object o : m.tryCatchBlocks) {
TryCatchBlockNode tcbn = (TryCatchBlockNode) o;
sb.append(" ");
sb.append("TryCatch: L");
sb.append(insnPrinter.resolveLabel(tcbn.start));
sb.append(" to L");
sb.append(insnPrinter.resolveLabel(tcbn.end));
sb.append(" handled by L");
sb.append(insnPrinter.resolveLabel(tcbn.handler));
sb.append(": ");
if(tcbn.type != null)
sb.append(tcbn.type);
else
sb.append("Type is null.");
sb.append(BytecodeViewer.nl);
}
for (String insn : insnPrinter.createPrint()) {
sb.append(" ");
sb.append(insn);
sb.append(BytecodeViewer.nl);
}
sb.append(" }"+BytecodeViewer.nl);
}
return sb;
}
private static String getAccessString(int access) {
// public, protected, private, abstract, static,
// final, synchronized, native & strictfp are permitted
List<String> tokens = new ArrayList<String>();
if ((access & Opcodes.ACC_PUBLIC) != 0)
tokens.add("public");
if ((access & Opcodes.ACC_PRIVATE) != 0)
tokens.add("private");
if ((access & Opcodes.ACC_PROTECTED) != 0)
tokens.add("protected");
if ((access & Opcodes.ACC_STATIC) != 0)
tokens.add("static");
if ((access & Opcodes.ACC_ABSTRACT) != 0)
tokens.add("abstract");
if ((access & Opcodes.ACC_FINAL) != 0)
tokens.add("final");
if ((access & Opcodes.ACC_SYNCHRONIZED) != 0)
tokens.add("synchronized");
if ((access & Opcodes.ACC_NATIVE) != 0)
tokens.add("native");
if ((access & Opcodes.ACC_STRICT) != 0)
tokens.add("strictfp");
if ((access & Opcodes.ACC_BRIDGE) != 0)
tokens.add("bridge");
if ((access & Opcodes.ACC_VARARGS) != 0)
tokens.add("varargs");
if (tokens.size() == 0)
return "";
// hackery delimeters
StringBuilder sb = new StringBuilder(tokens.get(0));
for (int i = 1; i < tokens.size(); i++) {
sb.append(" ");
sb.append(tokens.get(i));
}
return sb.toString();
}
}

View File

@ -0,0 +1,55 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
/**
*
* @author Bibl
*
*/
public class PrefixedStringBuilder {
protected StringBuilder sb;
protected String prefix;
public PrefixedStringBuilder() {
sb = new StringBuilder();
}
public PrefixedStringBuilder append(String s) {
sb.append(s);
if (s.contains("\n") && (prefix != null) && (prefix.length() > 0))// insert the prefix at every new line, overridable
sb.append(prefix);
return this;
}
public PrefixedStringBuilder append(Object o) {
return append(o.toString());
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void trimPrefix(int amount) {
if (prefix == null)
return;
if (prefix.length() < amount)
return;
prefix = prefix.substring(0, prefix.length() - amount);
}
public void appendPrefix(String s) {
if (prefix == null)
prefix = "";
prefix += s;
}
public String getPrefix() {
return prefix;
}
@Override
public String toString() {
return sb.toString();
}
}

View File

@ -11,4 +11,4 @@ import org.objectweb.asm.Type;
public class TypeAndName {
public Type type = null;
public String name = null;
}
}

View File

@ -11,7 +11,12 @@ import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.JarUtils;
/**
*
* @author Konloch
*
*/
public class CFRDecompiler extends JavaDecompiler {
@ -73,7 +78,93 @@ public class CFRDecompiler extends JavaDecompiler {
return new String[] {
filePath,
"--outputdir",
outputPath
outputPath,
"--decodeenumswitch",
String.valueOf(BytecodeViewer.viewer.decodeenumswitch.isSelected()),
"--sugarenums",
String.valueOf(BytecodeViewer.viewer.sugarenums.isSelected()),
"--decodestringswitch",
String.valueOf(BytecodeViewer.viewer.decodestringswitch.isSelected()),
"--arrayiter",
String.valueOf(BytecodeViewer.viewer.arrayiter.isSelected()),
"--collectioniter",
String.valueOf(BytecodeViewer.viewer.collectioniter.isSelected()),
"--innerclasses",
String.valueOf(BytecodeViewer.viewer.innerclasses.isSelected()),
"--removeboilerplate",
String.valueOf(BytecodeViewer.viewer.removeboilerplate.isSelected()),
"--removeinnerclasssynthetics",
String.valueOf(BytecodeViewer.viewer.removeinnerclasssynthetics.isSelected()),
"--decodelambdas",
String.valueOf(BytecodeViewer.viewer.decodelambdas.isSelected()),
"--hidebridgemethods",
String.valueOf(BytecodeViewer.viewer.hidebridgemethods.isSelected()),
"--liftconstructorinit",
String.valueOf(BytecodeViewer.viewer.liftconstructorinit.isSelected()),
"--removedeadmethods",
String.valueOf(BytecodeViewer.viewer.removedeadmethods.isSelected()),
"--removebadgenerics",
String.valueOf(BytecodeViewer.viewer.removebadgenerics.isSelected()),
"--sugarasserts",
String.valueOf(BytecodeViewer.viewer.sugarasserts.isSelected()),
"--sugarboxing",
String.valueOf(BytecodeViewer.viewer.sugarboxing.isSelected()),
"--showversion",
String.valueOf(BytecodeViewer.viewer.showversion.isSelected()),
"--decodefinally",
String.valueOf(BytecodeViewer.viewer.decodefinally.isSelected()),
"--tidymonitors",
String.valueOf(BytecodeViewer.viewer.tidymonitors.isSelected()),
"--lenient",
String.valueOf(BytecodeViewer.viewer.lenient.isSelected()),
"--dumpclasspath",
String.valueOf(BytecodeViewer.viewer.dumpclasspath.isSelected()),
"--comments",
String.valueOf(BytecodeViewer.viewer.comments.isSelected()),
"--forcetopsort",
String.valueOf(BytecodeViewer.viewer.forcetopsort.isSelected()),
"--forcetopsortaggress",
String.valueOf(BytecodeViewer.viewer.forcetopsortaggress.isSelected()),
"--stringbuffer",
String.valueOf(BytecodeViewer.viewer.stringbuffer.isSelected()),
"--stringbuilder",
String.valueOf(BytecodeViewer.viewer.stringbuilder.isSelected()),
"--silent",
String.valueOf(BytecodeViewer.viewer.silent.isSelected()),
"--recover",
String.valueOf(BytecodeViewer.viewer.recover.isSelected()),
"--eclipse",
String.valueOf(BytecodeViewer.viewer.eclipse.isSelected()),
"--override",
String.valueOf(BytecodeViewer.viewer.override.isSelected()),
"--showinferrable",
String.valueOf(BytecodeViewer.viewer.showinferrable.isSelected()),
"--aexagg",
String.valueOf(BytecodeViewer.viewer.aexagg.isSelected()),
"--forcecondpropagate",
String.valueOf(BytecodeViewer.viewer.forcecondpropagate.isSelected()),
"--hideutf",
String.valueOf(BytecodeViewer.viewer.hideutf.isSelected()),
"--hidelongstrings",
String.valueOf(BytecodeViewer.viewer.hidelongstrings.isSelected()),
"--commentmonitors",
String.valueOf(BytecodeViewer.viewer.commentmonitor.isSelected()),
"--allowcorrecting",
String.valueOf(BytecodeViewer.viewer.allowcorrecting.isSelected()),
"--labelledblocks",
String.valueOf(BytecodeViewer.viewer.labelledblocks.isSelected()),
"--j14classobj",
String.valueOf(BytecodeViewer.viewer.j14classobj.isSelected()),
"--hidelangimports",
String.valueOf(BytecodeViewer.viewer.hidelangimports.isSelected()),
"--recovertypeclash",
String.valueOf(BytecodeViewer.viewer.recoverytypeclash.isSelected()),
"--recovertypehints",
String.valueOf(BytecodeViewer.viewer.recoverytypehints.isSelected()),
"--forcereturningifs",
String.valueOf(BytecodeViewer.viewer.forceturningifs.isSelected()),
"--forloopaggcapture",
String.valueOf(BytecodeViewer.viewer.forloopaggcapture.isSelected()),
};
}
@ -98,7 +189,7 @@ public class CFRDecompiler extends JavaDecompiler {
for(File f : new File(fuckery).listFiles()) {
//put contents into a zipfile
}*/
BytecodeViewer.showMessage("CFRDecompiler currently doesn't decompile as zip, please wait till 1.3 of Bytecode Viewer.");
BytecodeViewer.showMessage("CFRDecompiler currently doesn't decompile as zip, please wait till Beta 1.4 of Bytecode Viewer.");
}

View File

@ -28,9 +28,12 @@ public class FernFlowerDecompiler extends JavaDecompiler {
if(tempZip.exists())
tempZip.delete();
File f = new File(BytecodeViewer.tempDirectory + "./temp/");
f.mkdir();
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath());
de.fernflower.main.decompiler.ConsoleDecompiler.main(new String[] {tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/"});
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(new String[] {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));
@ -59,7 +62,7 @@ public class FernFlowerDecompiler extends JavaDecompiler {
e.printStackTrace();
}
de.fernflower.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), "."));
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), "."));
tempClass.delete();

View File

@ -4,6 +4,12 @@ import java.io.File;
import org.objectweb.asm.tree.ClassNode;
/**
*
* @author Konloch
*
*/
public abstract class JavaDecompiler {
public abstract String decompileClassNode(ClassNode cn);

View File

@ -13,6 +13,7 @@ import org.objectweb.asm.tree.ClassNode;
import com.strobel.decompiler.DecompilationOptions;
import com.strobel.decompiler.DecompilerSettings;
import com.strobel.decompiler.PlainTextOutput;
import com.strobel.decompiler.languages.java.JavaFormattingOptions;
import com.strobel.assembler.InputTypeLoader;
import com.strobel.assembler.metadata.Buffer;
import com.strobel.assembler.metadata.ITypeLoader;
@ -54,6 +55,22 @@ 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());
LuytenTypeLoader typeLoader = new LuytenTypeLoader();
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
TypeReference type = metadataSystem.lookupType(tempClass.getCanonicalPath());
@ -120,7 +137,7 @@ public class ProcyonDecompiler extends JavaDecompiler {
tempZip.delete();
new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp").delete();*/
BytecodeViewer.showMessage("ProcyonDecompiler currently doesn't decompile as zip, please wait till 1.3 of Bytecode Viewer.");
BytecodeViewer.showMessage("ProcyonDecompiler currently doesn't decompile as zip, please wait till Beta 1.4 of Bytecode Viewer.");
}

View File

@ -34,7 +34,7 @@ import org.objectweb.asm.tree.ClassNode;
import com.jhe.hexed.JHexEditor;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.BytecodeDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.CFRDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.FernFlowerDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.ProcyonDecompiler;
@ -94,8 +94,8 @@ public class ClassViewer extends JPanel {
ClassNode cn;
JSplitPane sp;
JSplitPane sp2;
JEditorPane bytecode = new JEditorPane(), decomp = new JEditorPane();
JScrollPane bcScroll;
public JPanel bytePanel = new JPanel(new BorderLayout());
public JPanel decompPanel = new JPanel(new BorderLayout());
public ClassViewer(final String name, final ClassNode cn) {
sourcePane = BytecodeViewer.viewer.sourcePane.isSelected();
@ -108,29 +108,7 @@ public class ClassViewer extends JPanel {
this.setName(name);
this.setLayout(new BorderLayout());
final JPanel dcPanel = new JPanel(new BorderLayout());
final JScrollPane dcScroll = new JScrollPane(decomp);
if(sourcePane) {
dcPanel.add(dcScroll, BorderLayout.CENTER);
}
final JPanel bcPanel = new JPanel(new BorderLayout());
if(bytecodePane) {
bcScroll = new JScrollPane(bytecode);
} else {
bcScroll = new JScrollPane();
}
bcPanel.add(bcScroll, BorderLayout.CENTER);
if(bytecodePane && bytecodeSyntax)
bytecode.setContentType("text/java");
if(sourcePane && sourcecodeSyntax)
decomp.setContentType("text/java");
this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, dcPanel, bcPanel);
this.sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, decompPanel, bytePanel);
final ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
JHexEditor hex = new JHexEditor(cw.toByteArray());
@ -148,8 +126,9 @@ public class ClassViewer extends JPanel {
hex.setSize(0, Integer.MAX_VALUE);
resetDivider();
BytecodeViewer.viewer.setIcon(true);
bytecode.setText("Decompiling, please wait..");
decomp.setText("Decompiling, please wait..");
//
startPaneUpdater();
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
@ -176,18 +155,16 @@ public class ClassViewer extends JPanel {
}
}
final BytecodeDecompiler bc_dc = new BytecodeDecompiler();
final FernFlowerDecompiler ff_dc = new FernFlowerDecompiler();
final ProcyonDecompiler proc_dc = new ProcyonDecompiler();
final CFRDecompiler cfr_dc = new CFRDecompiler();
static FernFlowerDecompiler ff_dc = new FernFlowerDecompiler();
static ProcyonDecompiler proc_dc = new ProcyonDecompiler();
static CFRDecompiler cfr_dc = new CFRDecompiler();
PaneUpdaterThread t;
public void startPaneUpdater() {
t = new PaneUpdaterThread(bytecode, decomp) {
t = new PaneUpdaterThread() {
String s = "";
@Override
public void doShit() {
final String b = bc_dc.decompileClassNode(cn);
final String b = ClassNodeDecompiler.decompile(cn);
if(BytecodeViewer.viewer.decompilerGroup.isSelected(BytecodeViewer.viewer.fernflowerDec.getModel()))
s = ff_dc.decompileClassNode(cn);
@ -198,12 +175,29 @@ public class ClassViewer extends JPanel {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JEditorPane
bytecode = new JEditorPane(),
decomp = new JEditorPane();
JScrollPane
bytecodeScroll = new JScrollPane(bytecode),
decompScroll = new JScrollPane(decomp);
if(bytecodePane && BytecodeViewer.viewer.bycSyntax.isSelected())
bytecode.setContentType("text/java");
if(sourcePane && BytecodeViewer.viewer.srcSyntax.isSelected())
decomp.setContentType("text/java");
if(bytecodePane)
p1.setText(b);
bytecode.setText(b);
if(sourcePane)
p2.setText(s);
p1.setCaretPosition(0);
p2.setCaretPosition(0);
decomp.setText(s);
bytePanel.add(bytecodeScroll);
decompPanel.add(decompScroll);
bytecode.setCaretPosition(0);
decomp.setCaretPosition(0);
BytecodeViewer.viewer.setIcon(false);
}
});

View File

@ -27,7 +27,6 @@ import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
import the.bytecode.club.bytecodeviewer.JarUtils;
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.BytecodeDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.CFRDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.FernFlowerDecompiler;
import the.bytecode.club.bytecodeviewer.decompilers.java.ProcyonDecompiler;
@ -49,9 +48,12 @@ import javax.swing.JRadioButtonMenuItem;
public class MainViewerGUI extends JFrame implements FileChangeNotifier {
final FernFlowerDecompiler ff_dc = new FernFlowerDecompiler();
final ProcyonDecompiler proc_dc = new ProcyonDecompiler();
final CFRDecompiler cfr_dc = new CFRDecompiler();
private static final long serialVersionUID = 1851409230530948543L;
public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers");
public JCheckBoxMenuItem debugInstructions = new JCheckBoxMenuItem("Debug Instructions");
private JSplitPane sp1;
private JSplitPane sp2;
static ArrayList<VisibleComponent> rfComps = new ArrayList<VisibleComponent>();
@ -105,7 +107,68 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public final JRadioButtonMenuItem procyonDec = new JRadioButtonMenuItem("Procyon");
public final JRadioButtonMenuItem cfrDec = new JRadioButtonMenuItem("CFR");
public final ButtonGroup decompilerGroup = new ButtonGroup();
private final JMenu mnNewMenu_3 = new JMenu("CFR");
private final JMenu mnNewMenu_4 = new JMenu("Procyon");
public final JCheckBoxMenuItem decodeenumswitch = new JCheckBoxMenuItem("Decode Enum Switch");
public final JCheckBoxMenuItem sugarenums = new JCheckBoxMenuItem("SugarEnums");
public final JCheckBoxMenuItem decodestringswitch = new JCheckBoxMenuItem("Decode String Switch");
public final JCheckBoxMenuItem arrayiter = new JCheckBoxMenuItem("Arrayiter");
public final JCheckBoxMenuItem collectioniter = new JCheckBoxMenuItem("Collectioniter");
public final JCheckBoxMenuItem innerclasses = new JCheckBoxMenuItem("Inner Classes");
public final JCheckBoxMenuItem removeboilerplate = new JCheckBoxMenuItem("Remove Boiler Plate");
public final JCheckBoxMenuItem removeinnerclasssynthetics = new JCheckBoxMenuItem("Remove Inner Class Synthetics");
public final JCheckBoxMenuItem decodelambdas = new JCheckBoxMenuItem("Decode Lambdas");
public final JCheckBoxMenuItem hidebridgemethods = new JCheckBoxMenuItem("Hide Bridge Methods");
public final JCheckBoxMenuItem liftconstructorinit = new JCheckBoxMenuItem("Lift Constructor Init");
public final JCheckBoxMenuItem removedeadmethods = new JCheckBoxMenuItem("Remove Dead Methods");
public final JCheckBoxMenuItem removebadgenerics = new JCheckBoxMenuItem("Remove Bad Generics");
public final JCheckBoxMenuItem sugarasserts = new JCheckBoxMenuItem("Sugar Asserts");
public final JCheckBoxMenuItem sugarboxing = new JCheckBoxMenuItem("Sugar Boxing");
public final JCheckBoxMenuItem showversion = new JCheckBoxMenuItem("Show Version");
public final JCheckBoxMenuItem decodefinally = new JCheckBoxMenuItem("Decode Finally");
public final JCheckBoxMenuItem tidymonitors = new JCheckBoxMenuItem("Tidy Monitors");
public final JCheckBoxMenuItem lenient = new JCheckBoxMenuItem("Lenient");
public final JCheckBoxMenuItem dumpclasspath = new JCheckBoxMenuItem("Dump Classpath");
public final JCheckBoxMenuItem comments = new JCheckBoxMenuItem("Comments");
public final JCheckBoxMenuItem forcetopsort = new JCheckBoxMenuItem("Force Top Sort");
public final JCheckBoxMenuItem forcetopsortaggress = new JCheckBoxMenuItem("Force Top Sort Aggress");
public final JCheckBoxMenuItem stringbuffer = new JCheckBoxMenuItem("String Buffer");
public final JCheckBoxMenuItem stringbuilder = new JCheckBoxMenuItem("String Builder");
public final JCheckBoxMenuItem silent = new JCheckBoxMenuItem("Silent");
public final JCheckBoxMenuItem recover = new JCheckBoxMenuItem("Recover");
public final JCheckBoxMenuItem eclipse = new JCheckBoxMenuItem("Eclipse");
public final JCheckBoxMenuItem override = new JCheckBoxMenuItem("Override");
public final JCheckBoxMenuItem showinferrable = new JCheckBoxMenuItem("Show Inferrable");
public final JCheckBoxMenuItem aexagg = new JCheckBoxMenuItem("Aexagg");
public final JCheckBoxMenuItem forcecondpropagate = new JCheckBoxMenuItem("Force Cond Propagate");
public final JCheckBoxMenuItem hideutf = new JCheckBoxMenuItem("Hide UTF");
public final JCheckBoxMenuItem hidelongstrings = new JCheckBoxMenuItem("Hide Long Strings");
public final JCheckBoxMenuItem commentmonitor = new JCheckBoxMenuItem("Comment Monitors");
public final JCheckBoxMenuItem allowcorrecting = new JCheckBoxMenuItem("Allow Correcting");
public final JCheckBoxMenuItem labelledblocks = new JCheckBoxMenuItem("Labelled Blocks");
public final JCheckBoxMenuItem j14classobj = new JCheckBoxMenuItem("J14ClassOBJ");
public final JCheckBoxMenuItem hidelangimports = new JCheckBoxMenuItem("Hide Lang Imports");
public final JCheckBoxMenuItem recoverytypeclash = new JCheckBoxMenuItem("Recover Type Clash");
public final JCheckBoxMenuItem recoverytypehints = new JCheckBoxMenuItem("Recover Type Hints");
public final JCheckBoxMenuItem forceturningifs = new JCheckBoxMenuItem("Force Returning IFs");
public final JCheckBoxMenuItem forloopaggcapture = new JCheckBoxMenuItem("For Loop AGG Capture");
public final JCheckBoxMenuItem forceexceptionprune = new JCheckBoxMenuItem("Force Exception Prune");
public final JCheckBoxMenuItem chckbxmntmShowDebugLine = new JCheckBoxMenuItem("Show Debug Line Numbers");
public final JCheckBoxMenuItem chckbxmntmSimplifyMemberReferences = new JCheckBoxMenuItem("Simplify Member References");
public final JCheckBoxMenuItem mnMergeVariables = new JCheckBoxMenuItem("Merge Variables");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_1 = new JCheckBoxMenuItem("Unicode Output Enabled");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_2 = new JCheckBoxMenuItem("Retain Pointless Switches");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_3 = new JCheckBoxMenuItem("Include Line Numbers In Bytecode");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_4 = new JCheckBoxMenuItem("Include Error Diagnostics");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_5 = new JCheckBoxMenuItem("Retain Redundant Casts");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_6 = new JCheckBoxMenuItem("Always Generate Exception Variable For Catch Blocks");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_7 = new JCheckBoxMenuItem("Show Synthetic Members");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_8 = new JCheckBoxMenuItem("Force Explicit Type Arguments");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_9 = new JCheckBoxMenuItem("Force Explicit Imports");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_10 = new JCheckBoxMenuItem("Flatten Switch Blocks");
public final JCheckBoxMenuItem chckbxmntmNewCheckItem_11 = new JCheckBoxMenuItem("Exclude Nested Types");
public void setC(boolean busy) {
if(busy) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
@ -177,32 +240,21 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
return image;
}
final BytecodeDecompiler bc_dc = new BytecodeDecompiler();
final FernFlowerDecompiler ff_dc = new FernFlowerDecompiler();
final ProcyonDecompiler proc_dc = new ProcyonDecompiler();
final CFRDecompiler cfr_dc = new CFRDecompiler();
public MainViewerGUI() {
public MainViewerGUI() {
decompilerGroup.add(fernflowerDec);
decompilerGroup.add(procyonDec);
decompilerGroup.add(cfrDec);
decompilerGroup.setSelected(procyonDec.getModel(), true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//fernflower
rbr.setSelected(true);
rsy.setSelected(false);
din.setSelected(true);
dc4.setSelected(true);
das.setSelected(true);
hes.setSelected(true);
hdc.setSelected(true);
dgs.setSelected(false);
ner.setSelected(true);
den.setSelected(true);
rgn.setSelected(true);
bto.setSelected(true);
nns.setSelected(true);
uto.setSelected(true);
udv.setSelected(true);
rer.setSelected(true);
fdi.setSelected(true);
asc.setSelected(false);
srcSyntax.setSelected(true);
@ -210,6 +262,52 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
debugHelpers.setSelected(true);
sourcePane.setSelected(true);
bytecodePane.setSelected(true);
//cfr
decodeenumswitch.setSelected(true);
sugarenums.setSelected(true);
decodestringswitch.setSelected(true);
arrayiter.setSelected(true);
collectioniter.setSelected(true);
innerclasses.setSelected(true);
removeboilerplate.setSelected(true);
removeinnerclasssynthetics.setSelected(true);
decodelambdas.setSelected(true);
hidebridgemethods.setSelected(true);
liftconstructorinit.setSelected(true);
removedeadmethods.setSelected(true);
removebadgenerics.setSelected(true);
sugarasserts.setSelected(true);
sugarboxing.setSelected(true);
showversion.setSelected(true);
decodefinally.setSelected(true);
tidymonitors.setSelected(true);
lenient.setSelected(false);
dumpclasspath.setSelected(false);
comments.setSelected(true);
forcetopsort.setSelected(true);
forcetopsortaggress.setSelected(true);
forceexceptionprune.setSelected(true);
stringbuffer.setSelected(false);
stringbuilder.setSelected(true);
silent.setSelected(true);
recover.setSelected(true);
eclipse.setSelected(true);
override.setSelected(true);
showinferrable.setSelected(true);
aexagg.setSelected(true);
forcecondpropagate.setSelected(true);
hideutf.setSelected(true);
hidelongstrings.setSelected(false);
commentmonitor.setSelected(false);
allowcorrecting.setSelected(true);
labelledblocks.setSelected(true);
j14classobj.setSelected(false);
hidelangimports.setSelected(true);
recoverytypeclash.setSelected(true);
recoverytypehints.setSelected(true);
forceturningifs.setSelected(true);
forloopaggcapture.setSelected(true);
//procyon
setJMenuBar(menuBar);
@ -273,7 +371,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
new ExportJar(file.getAbsolutePath()).setVisible(true);
String path = file.getAbsolutePath();
if(!path.endsWith(".jar"))
path = path + ".jar";
new ExportJar(path).setVisible(true);
}
}
});
@ -290,12 +391,15 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
BytecodeViewer.viewer.setC(true);
String path = file.getAbsolutePath();
if(!path.endsWith(".zip"))
path = path + ".zip";
if(BytecodeViewer.viewer.decompilerGroup.isSelected(BytecodeViewer.viewer.fernflowerDec.getModel()))
ff_dc.decompileToZip(file.getAbsolutePath());
ff_dc.decompileToZip(path);
else if(BytecodeViewer.viewer.decompilerGroup.isSelected(BytecodeViewer.viewer.procyonDec.getModel()))
proc_dc.decompileToZip(file.getAbsolutePath());
proc_dc.decompileToZip(path);
else if(BytecodeViewer.viewer.decompilerGroup.isSelected(BytecodeViewer.viewer.cfrDec.getModel()))
cfr_dc.decompileToZip(file.getAbsolutePath());
cfr_dc.decompileToZip(path);
BytecodeViewer.viewer.setC(false);
}
}
@ -342,24 +446,152 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_2.add(fernflowerDec);
menuBar.add(mnNewMenu_4);
mnNewMenu_4.add(chckbxmntmNewCheckItem_6);
mnNewMenu_4.add(chckbxmntmNewCheckItem_11);
mnNewMenu_4.add(chckbxmntmShowDebugLine);
mnNewMenu_4.add(chckbxmntmNewCheckItem_3);
mnNewMenu_4.add(chckbxmntmNewCheckItem_4);
mnNewMenu_4.add(chckbxmntmNewCheckItem_7);
mnNewMenu_4.add(chckbxmntmSimplifyMemberReferences);
mnNewMenu_4.add(mnMergeVariables);
mnNewMenu_4.add(chckbxmntmNewCheckItem_8);
mnNewMenu_4.add(chckbxmntmNewCheckItem_9);
mnNewMenu_4.add(chckbxmntmNewCheckItem_10);
mnNewMenu_4.add(chckbxmntmNewCheckItem_2);
mnNewMenu_4.add(chckbxmntmNewCheckItem_5);
mnNewMenu_4.add(chckbxmntmNewCheckItem_1);
menuBar.add(mnNewMenu_3);
mnNewMenu_3.add(decodeenumswitch);
mnNewMenu_3.add(sugarenums);
mnNewMenu_3.add(decodestringswitch);
mnNewMenu_3.add(arrayiter);
mnNewMenu_3.add(collectioniter);
mnNewMenu_3.add(innerclasses);
mnNewMenu_3.add(removeboilerplate);
mnNewMenu_3.add(removeinnerclasssynthetics);
mnNewMenu_3.add(decodelambdas);
mnNewMenu_3.add(hidebridgemethods);
mnNewMenu_3.add(liftconstructorinit);
mnNewMenu_3.add(removedeadmethods);
mnNewMenu_3.add(removebadgenerics);
mnNewMenu_3.add(sugarasserts);
mnNewMenu_3.add(sugarboxing);
mnNewMenu_3.add(showversion);
mnNewMenu_3.add(decodefinally);
mnNewMenu_3.add(tidymonitors);
mnNewMenu_3.add(lenient);
mnNewMenu_3.add(dumpclasspath);
mnNewMenu_3.add(comments);
mnNewMenu_3.add(forcetopsort);
mnNewMenu_3.add(forcetopsortaggress);
mnNewMenu_3.add(forceexceptionprune);
mnNewMenu_3.add(stringbuffer);
mnNewMenu_3.add(stringbuilder);
mnNewMenu_3.add(silent);
mnNewMenu_3.add(recover);
mnNewMenu_3.add(eclipse);
mnNewMenu_3.add(override);
mnNewMenu_3.add(showinferrable);
mnNewMenu_3.add(aexagg);
mnNewMenu_3.add(forcecondpropagate);
mnNewMenu_3.add(hideutf);
mnNewMenu_3.add(hidelongstrings);
mnNewMenu_3.add(commentmonitor);
mnNewMenu_3.add(allowcorrecting);
mnNewMenu_3.add(labelledblocks);
mnNewMenu_3.add(j14classobj);
mnNewMenu_3.add(hidelangimports);
mnNewMenu_3.add(recoverytypeclash);
mnNewMenu_3.add(recoverytypehints);
mnNewMenu_3.add(forceturningifs);
mnNewMenu_3.add(forloopaggcapture);
JMenu mnDecompilerSettings = new JMenu("FernFlower");
menuBar.add(mnDecompilerSettings);
dc4.setSelected(true);
mnDecompilerSettings.add(dc4);
nns.setSelected(true);
mnDecompilerSettings.add(nns);
ner.setSelected(true);
mnDecompilerSettings.add(ner);
bto.setSelected(true);
mnDecompilerSettings.add(bto);
rgn.setSelected(true);
mnDecompilerSettings.add(rgn);
rer.setSelected(true);
mnDecompilerSettings.add(rer);
mnDecompilerSettings.add(rbr);
mnDecompilerSettings.add(rsy);
mnDecompilerSettings.add(din);
mnDecompilerSettings.add(dc4);
mnDecompilerSettings.add(das);
hes.setSelected(true);
mnDecompilerSettings.add(hes);
hdc.setSelected(true);
mnDecompilerSettings.add(hdc);
mnDecompilerSettings.add(din);
mnDecompilerSettings.add(das);
mnDecompilerSettings.add(dgs);
mnDecompilerSettings.add(ner);
mnDecompilerSettings.add(den);
mnDecompilerSettings.add(rgn);
mnDecompilerSettings.add(bto);
mnDecompilerSettings.add(nns);
mnDecompilerSettings.add(uto);
mnDecompilerSettings.add(udv);
mnDecompilerSettings.add(rer);
mnDecompilerSettings.add(fdi);
mnDecompilerSettings.add(asc);
@ -368,8 +600,6 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnBytecodeDecompilerSettings.add(debugHelpers);
mnBytecodeDecompilerSettings.add(debugInstructions);
mnBytecodeDecompilerSettings.add(chckbxmntmNewCheckItem);
menuBar.add(mnNewMenu_1);
@ -445,7 +675,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
});
setSize(new Dimension(800, 400));
setTitle("Bytecode Viewer - http://the.bytecode.club - @Konloch");
setTitle("Bytecode Viewer " + BytecodeViewer.version + " - http://the.bytecode.club - @Konloch");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
JScrollPane scrollPane = new JScrollPane();

View File

@ -1,22 +1,13 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JEditorPane;
/**
* Allows us to run a background thread then update the two JEditorPanes
* Allows us to run a background thread
*
* @author Konloch
*
*/
public abstract class PaneUpdaterThread extends Thread {
JEditorPane p1;
JEditorPane p2;
public PaneUpdaterThread(JEditorPane p1, JEditorPane p2) {
this.p1 = p1;
this.p2 = p2;
}
public abstract void doShit();

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Coming soon.
*
@ -18,6 +20,7 @@ public class AllatoriStringDecrypter extends Plugin {
for(ClassNode classNode : classNodeList) {
}
BytecodeViewer.showMessage("This is a planned feature.");
}
}

View File

@ -9,8 +9,6 @@ import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* The idea/core was based off of J-RET's Malicious Code Searcher
* I improved it, and added more stuff to search for.
@ -47,7 +45,6 @@ public class MaliciousCodeScanner extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
PluginConsole frame = new PluginConsole("Malicious Code Scanner");
BytecodeViewer.viewer.setC(true);
for(ClassNode classNode : classNodeList) {
for(Object o : classNode.methods.toArray()) {
MethodNode m = (MethodNode) o;
@ -81,7 +78,6 @@ public class MaliciousCodeScanner extends Plugin {
}
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}

View File

@ -9,8 +9,6 @@ import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Replaces all string and string[] instances with whatever.
*
@ -35,8 +33,6 @@ public class ReplaceStrings extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
BytecodeViewer.viewer.setC(true);
if(!className.equals("*")) {
for(ClassNode classNode : classNodeList) {
if(classNode.name.equals(className))
@ -47,8 +43,6 @@ public class ReplaceStrings extends Plugin {
scanClassNode(classNode);
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}

View File

@ -9,8 +9,6 @@ import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Simply shows all the non-empty strings in every single class
*
@ -23,7 +21,6 @@ public class ShowAllStrings extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
PluginConsole frame = new PluginConsole("Show All Strings");
BytecodeViewer.viewer.setC(true);
for(ClassNode classNode : classNodeList) {
for(Object o : classNode.fields.toArray()) {
FieldNode f = (FieldNode) o;
@ -57,7 +54,6 @@ public class ShowAllStrings extends Plugin {
}
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}

View File

@ -5,8 +5,6 @@ import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Simply shows all classes that have a public static void main(String[])
*
@ -19,7 +17,6 @@ public class ShowMainMethods extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
PluginConsole frame = new PluginConsole("Show Main Methods");
BytecodeViewer.viewer.setC(true);
for(ClassNode classNode : classNodeList) {
for(Object o : classNode.methods.toArray()) {
MethodNode m = (MethodNode) o;
@ -28,7 +25,6 @@ public class ShowMainMethods extends Plugin {
frame.appendText(classNode.name + "." +m.name+""+m.desc);
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Coming soon.
*
@ -18,6 +20,7 @@ public class ZKMStringDecrypter extends Plugin {
for(ClassNode classNode : classNodeList) {
}
BytecodeViewer.showMessage("This is a planned feature.");
}
}