First Commit

First commit, beta 1.0, report all bugs to konloch@gmail.com or create a
thread on http://the.bytecode.club
This commit is contained in:
Kalen Kinloch 2014-10-18 16:39:09 -07:00
parent 1f33f0a8cf
commit 06ef9408a4
60 changed files with 7031 additions and 3 deletions

BIN
BytecodeViewer.jar Normal file

Binary file not shown.

View file

@ -1,4 +1,19 @@
bytecode-viewer
===============
Bytecode Viewer is a Java Bytecode Viewer, GUI FernFlower Java Decompiler, GUI Jar-Jar, Hex Viewer, Code Searcher, Debugger and more.
It's written completely in Java, and it's open sourced. It's currently being maintained and developed by Konloch.
Bytecode Viewer
Code from various projects has been used, including but not limited to:
J-RET by WaterWolf
JHexPane by Sam Koivu
JSynaxPane by Ayman Al
Commons IO by Apache
ASM by OW2
Features:
Java Decompiler - It uses a modified version of FernFlower.
Bytecode Decompiler - A modified version of J-RET's.
Hex Viewer - Powered by JHexPane.
Each Decompiler/Viewer is toggleable.
Fully Featured Search System.
A Plugin System With Built In Plugins. (Show All Strings, Malicious Code Scanner, String Decrypters, etc)
Recent Files.
And more! Give it a try for yourself!

BIN
libs/asm-all-5.0.3.jar Normal file

Binary file not shown.

BIN
libs/commons-codec-1.9.jar Normal file

Binary file not shown.

BIN
libs/commons-io-2.4.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
libs/groovy-all-2.1.7.jar Normal file

Binary file not shown.

BIN
libs/jruby.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

14
plugins/Skeleton.gy Normal file
View file

@ -0,0 +1,14 @@
import the.bytecode.club.bytecodeviewer.plugins.Plugin;
import the.bytecode.club.bytecodeviewer.plugins.PluginConsole;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
public class Skeleton extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodesList) {
PluginConsole gui = new PluginConsole("Skeleton");
gui.setVisible(true);
gui.appendText("exceuted skeleton");
}
}

15
plugins/Skeleton.rb Normal file
View file

@ -0,0 +1,15 @@
require 'java'
java_import 'the.bytecode.club.bytecodeviewer.plugins.Plugin'
java_import 'the.bytecode.club.bytecodeviewer.plugins.PluginConsole'
java_import 'java.lang.System'
java_import 'java.util.ArrayList'
java_import 'org.objectweb.asm.tree.ClassNode'
class Skeleton < Plugin
def execute(classNodeList)
gui = PluginConsole.new "Skeleton"
gui.setVisible(true)
gui.appendText("exceuted skeleton")
end
end

13
plugins/skeleton.py Normal file
View file

@ -0,0 +1,13 @@
from the.bytecode.club.bytecodeviewer.plugins import Plugin
from the.bytecode.club.bytecodeviewer.plugins import PluginConsole
from java.lang import System
from java.lang import Boolean
from java.util import ArrayList
from org.objectweb.asm.tree import ClassNode
class skeleton(Plugin):
def execute(classNodeList, poop): #for some reason it requires a second arg
gui = PluginConsole("Skeleton")
gui.setVisible(Boolean.TRUE)
gui.appendText("exceuted skeleton")

View file

@ -0,0 +1,289 @@
package com.jhe.hexed;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Created by IntelliJ IDEA.
* User: laullon
* Date: 08-abr-2003
* Time: 13:21:09
*/
public class JHexEditor extends JPanel implements FocusListener,AdjustmentListener,MouseWheelListener
{
private static final long serialVersionUID = 2289328616534802372L;
byte[] buff;
public int cursor;
protected static Font font=new Font("Monospaced",0,12);
protected int border=2;
public boolean DEBUG=false;
private JPanel panel;
private JScrollBar sb;
private int inicio=0;
private int lineas=10;
public JHexEditor(byte[] buff)
{
super();
this.buff=buff;
this.addMouseWheelListener(this);
sb=new JScrollBar(JScrollBar.VERTICAL);
sb.addAdjustmentListener(this);
sb.setMinimum(0);
sb.setMaximum(buff.length/getLineas());
JPanel p1,p2,p3;
//centro
p1=new JPanel(new BorderLayout(1,1));
p1.add(new JHexEditorHEX(this),BorderLayout.CENTER);
p1.add(new Columnas(),BorderLayout.NORTH);
// izq.
p2=new JPanel(new BorderLayout(1,1));
p2.add(new Filas(),BorderLayout.CENTER);
p2.add(new Caja(),BorderLayout.NORTH);
// der
p3=new JPanel(new BorderLayout(1,1));
p3.add(sb,BorderLayout.EAST);
p3.add(new JHexEditorASCII(this),BorderLayout.CENTER);
p3.add(new Caja(),BorderLayout.NORTH);
panel=new JPanel();
panel.setLayout(new BorderLayout(1,1));
panel.add(p1,BorderLayout.CENTER);
panel.add(p2,BorderLayout.WEST);
panel.add(p3,BorderLayout.EAST);
this.setLayout(new BorderLayout(1,1));
this.add(panel,BorderLayout.CENTER);
}
public void paint(Graphics g)
{
FontMetrics fn=getFontMetrics(font);
Rectangle rec=this.getBounds();
lineas=(rec.height/fn.getHeight())-1;
int n=(buff.length/16)-1;
if(lineas>n) { lineas=n; inicio=0; }
sb.setValues(getInicio(),+getLineas(),0,buff.length/16);
sb.setValueIsAdjusting(true);
super.paint(g);
}
protected void actualizaCursor()
{
int n=(cursor/16);
System.out.print("- "+inicio+"<"+n+"<"+(lineas+inicio)+"("+lineas+")");
if(n<inicio) inicio=n;
else if(n>=inicio+lineas) inicio=n-(lineas-1);
System.out.println(" - "+inicio+"<"+n+"<"+(lineas+inicio)+"("+lineas+")");
repaint();
}
protected int getInicio()
{
return inicio;
}
protected int getLineas()
{
return lineas;
}
protected void fondo(Graphics g,int x,int y,int s)
{
FontMetrics fn=getFontMetrics(font);
g.fillRect(((fn.stringWidth(" ")+1)*x)+border,(fn.getHeight()*y)+border,((fn.stringWidth(" ")+1)*s),fn.getHeight()+1);
}
protected void cuadro(Graphics g,int x,int y,int s)
{
FontMetrics fn=getFontMetrics(font);
g.drawRect(((fn.stringWidth(" ")+1)*x)+border,(fn.getHeight()*y)+border,((fn.stringWidth(" ")+1)*s),fn.getHeight()+1);
}
protected void printString(Graphics g,String s,int x,int y)
{
FontMetrics fn=getFontMetrics(font);
g.drawString(s,((fn.stringWidth(" ")+1)*x)+border,((fn.getHeight()*(y+1))-fn.getMaxDescent())+border);
}
public void focusGained(FocusEvent e)
{
this.repaint();
}
public void focusLost(FocusEvent e)
{
this.repaint();
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
inicio=e.getValue();
if(inicio<0) inicio=0;
repaint();
}
public void mouseWheelMoved(MouseWheelEvent e)
{
inicio+=(e.getUnitsToScroll());
if((inicio+lineas)>=buff.length/16) inicio=(buff.length/16)-lineas;
if(inicio<0) inicio=0;
repaint();
}
public void keyPressed(KeyEvent e)
{
/*switch(e.getKeyCode())
{
case 33: // rep
if(cursor>=(16*lineas)) cursor-=(16*lineas);
actualizaCursor();
break;
case 34: // fin
if(cursor<(buff.length-(16*lineas))) cursor+=(16*lineas);
actualizaCursor();
break;
case 35: // fin
cursor=buff.length-1;
actualizaCursor();
break;
case 36: // ini
cursor=0;
actualizaCursor();
break;
case 37: // <--
if(cursor!=0) cursor--;
actualizaCursor();
break;
case 38: // <--
if(cursor>15) cursor-=16;
actualizaCursor();
break;
case 39: // -->
if(cursor!=(buff.length-1)) cursor++;
actualizaCursor();
break;
case 40: // -->
if(cursor<(buff.length-16)) cursor+=16;
actualizaCursor();
break;
}*/
}
private class Columnas extends JPanel
{
private static final long serialVersionUID = -1734199617526339842L;
public Columnas()
{
this.setLayout(new BorderLayout(1,1));
}
public Dimension getPreferredSize()
{
return getMinimumSize();
}
public Dimension getMinimumSize()
{
Dimension d=new Dimension();
FontMetrics fn=getFontMetrics(font);
int h=fn.getHeight();
int nl=1;
d.setSize(((fn.stringWidth(" ")+1)*+((16*3)-1))+(border*2)+1,h*nl+(border*2)+1);
return d;
}
public void paint(Graphics g)
{
Dimension d=getMinimumSize();
g.setColor(Color.white);
g.fillRect(0,0,d.width,d.height);
g.setColor(Color.black);
g.setFont(font);
for(int n=0;n<16;n++)
{
if(n==(cursor%16)) cuadro(g,n*3,0,2);
String s="00"+Integer.toHexString(n);
s=s.substring(s.length()-2);
printString(g,s,n*3,0);
}
}
}
private class Caja extends JPanel
{
private static final long serialVersionUID = -6124062720565016834L;
public Dimension getPreferredSize()
{
return getMinimumSize();
}
public Dimension getMinimumSize()
{
Dimension d=new Dimension();
FontMetrics fn=getFontMetrics(font);
int h=fn.getHeight();
d.setSize((fn.stringWidth(" ")+1)+(border*2)+1,h+(border*2)+1);
return d;
}
}
private class Filas extends JPanel
{
private static final long serialVersionUID = 8797347523486018051L;
public Filas()
{
this.setLayout(new BorderLayout(1,1));
}
public Dimension getPreferredSize()
{
return getMinimumSize();
}
public Dimension getMinimumSize()
{
Dimension d=new Dimension();
FontMetrics fn=getFontMetrics(font);
int h=fn.getHeight();
int nl=getLineas();
d.setSize((fn.stringWidth(" ")+1)*(8)+(border*2)+1,h*nl+(border*2)+1);
return d;
}
public void paint(Graphics g)
{
Dimension d=getMinimumSize();
g.setColor(Color.white);
g.fillRect(0,0,d.width,d.height);
g.setColor(Color.black);
g.setFont(font);
int ini=getInicio();
int fin=ini+getLineas();
int y=0;
for(int n=ini;n<fin;n++)
{
if(n==(cursor/16)) cuadro(g,0,y,8);
String s="0000000000000"+Integer.toHexString(n);
s=s.substring(s.length()-8);
printString(g,s,0,y++);
}
}
}
}

View file

@ -0,0 +1,152 @@
package com.jhe.hexed;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Created by IntelliJ IDEA.
* User: laullon
* Date: 09-abr-2003
* Time: 12:47:18
*/
public class JHexEditorASCII extends JComponent implements MouseListener,KeyListener
{
private static final long serialVersionUID = 5505374841731053461L;
private JHexEditor he;
public JHexEditorASCII(JHexEditor he)
{
this.he=he;
addMouseListener(this);
addKeyListener(this);
addFocusListener(he);
}
public Dimension getPreferredSize()
{
debug("getPreferredSize()");
return getMinimumSize();
}
public Dimension getMinimumSize()
{
debug("getMinimumSize()");
Dimension d=new Dimension();
FontMetrics fn=getFontMetrics(JHexEditor.font);
int h=fn.getHeight();
int nl=he.getLineas();
d.setSize((fn.stringWidth(" ")+1)*(16)+(he.border*2)+1,h*nl+(he.border*2)+1);
return d;
}
public void paint(Graphics g)
{
debug("paint("+g+")");
debug("cursor="+he.cursor+" buff.length="+he.buff.length);
Dimension d=getMinimumSize();
g.setColor(Color.white);
g.fillRect(0,0,d.width,d.height);
g.setColor(Color.black);
g.setFont(JHexEditor.font);
//datos ascii
int ini=he.getInicio()*16;
int fin=ini+(he.getLineas()*16);
if(fin>he.buff.length) fin=he.buff.length;
int x=0;
int y=0;
for(int n=ini;n<fin;n++)
{
if(n==he.cursor)
{
g.setColor(Color.blue);
if(hasFocus()) he.fondo(g,x,y,1); else he.cuadro(g,x,y,1);
if(hasFocus()) g.setColor(Color.white); else g.setColor(Color.black);
} else
{
g.setColor(Color.black);
}
String s=""+new Character((char)he.buff[n]);
if((he.buff[n]<20)||(he.buff[n]>126)) s=""+(char)16;
he.printString(g,s,(x++),y);
if(x==16)
{
x=0;
y++;
}
}
}
private void debug(String s)
{
if(he.DEBUG) System.out.println("JHexEditorASCII ==> "+s);
}
// calcular la posicion del raton
public int calcularPosicionRaton(int x,int y)
{
FontMetrics fn=getFontMetrics(JHexEditor.font);
x=x/(fn.stringWidth(" ")+1);
y=y/fn.getHeight();
debug("x="+x+" ,y="+y);
return x+((y+he.getInicio())*16);
}
// mouselistener
public void mouseClicked(MouseEvent e)
{
debug("mouseClicked("+e+")");
he.cursor=calcularPosicionRaton(e.getX(),e.getY());
this.requestFocus();
he.repaint();
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
//KeyListener
public void keyTyped(KeyEvent e)
{
/*debug("keyTyped("+e+")");
he.buff[he.cursor]=(byte)e.getKeyChar();
if(he.cursor!=(he.buff.length-1)) he.cursor++;
he.repaint();*/
}
public void keyPressed(KeyEvent e)
{
debug("keyPressed("+e+")");
he.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
debug("keyReleased("+e+")");
}
public boolean isFocusTraversable()
{
return true;
}
}

View file

@ -0,0 +1,178 @@
package com.jhe.hexed;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Created by IntelliJ IDEA.
* User: laullon
* Date: 09-abr-2003
* Time: 12:47:32
*/
public class JHexEditorHEX extends JComponent implements MouseListener,KeyListener
{
private static final long serialVersionUID = 1481995655372014571L;
private JHexEditor he;
private int cursor=0;
public JHexEditorHEX(JHexEditor he)
{
this.he=he;
addMouseListener(this);
addKeyListener(this);
addFocusListener(he);
}
/*public Dimension getPreferredSize()
{
debug("getPreferredSize()");
return getMinimumSize();
}*/
public Dimension getMaximumSize()
{
debug("getMaximumSize()");
return getMinimumSize();
}
/*public Dimension getMinimumSize()
{
debug("getMinimumSize()");
Dimension d=new Dimension();
FontMetrics fn=getFontMetrics(he.font);
int h=fn.getHeight();
int nl=he.getLineas();
d.setSize(((fn.stringWidth(" ")+1)*+((16*3)-1))+(he.border*2)+1,h*nl+(he.border*2)+1);
return d;
}*/
public void paint(Graphics g)
{
debug("paint("+g+")");
debug("cursor="+he.cursor+" buff.length="+he.buff.length);
Dimension d=getMinimumSize();
g.setColor(Color.white);
g.fillRect(0,0,d.width,d.height);
g.setColor(Color.black);
g.setFont(JHexEditor.font);
int ini=he.getInicio()*16;
int fin=ini+(he.getLineas()*16);
if(fin>he.buff.length) fin=he.buff.length;
//datos hex
int x=0;
int y=0;
for(int n=ini;n<fin;n++)
{
if(n==he.cursor)
{
if(hasFocus())
{
g.setColor(Color.black);
he.fondo(g,(x*3),y,2);
g.setColor(Color.blue);
he.fondo(g,(x*3)+cursor,y,1);
} else
{
g.setColor(Color.blue);
he.cuadro(g,(x*3),y,2);
}
if(hasFocus()) g.setColor(Color.white); else g.setColor(Color.black);
} else
{
g.setColor(Color.black);
}
String s=("0"+Integer.toHexString(he.buff[n]));
s=s.substring(s.length()-2);
he.printString(g,s,((x++)*3),y);
if(x==16)
{
x=0;
y++;
}
}
}
private void debug(String s)
{
if(he.DEBUG) System.out.println("JHexEditorHEX ==> "+s);
}
// calcular la posicion del raton
public int calcularPosicionRaton(int x,int y)
{
FontMetrics fn=getFontMetrics(JHexEditor.font);
x=x/((fn.stringWidth(" ")+1)*3);
y=y/fn.getHeight();
debug("x="+x+" ,y="+y);
return x+((y+he.getInicio())*16);
}
// mouselistener
public void mouseClicked(MouseEvent e)
{
debug("mouseClicked("+e+")");
he.cursor=calcularPosicionRaton(e.getX(),e.getY());
this.requestFocus();
he.repaint();
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
//KeyListener
public void keyTyped(KeyEvent e)
{
debug("keyTyped("+e+")");
/*char c=e.getKeyChar();
if(((c>='0')&&(c<='9'))||((c>='A')&&(c<='F'))||((c>='a')&&(c<='f')))
{
char[] str=new char[2];
String n="00"+Integer.toHexString((int)he.buff[he.cursor]);
if(n.length()>2) n=n.substring(n.length()-2);
str[1-cursor]=n.charAt(1-cursor);
str[cursor]=e.getKeyChar();
he.buff[he.cursor]=(byte)Integer.parseInt(new String(str),16);
if(cursor!=1) cursor=1;
else if(he.cursor!=(he.buff.length-1)){ he.cursor++; cursor=0;}
he.actualizaCursor();
}*/
}
public void keyPressed(KeyEvent e)
{
debug("keyPressed("+e+")");
he.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
debug("keyReleased("+e+")");
}
public boolean isFocusTraversable()
{
return true;
}
}

View file

@ -0,0 +1,84 @@
package me.konloch.kontainer.io;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
/**
* Used to load from the disk, optional caching
*
* @author Konloch
*
*/
public class DiskReader {
public static Random random = new Random();
public static HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
/**
* Used to load from file, allows caching
*/
public synchronized static ArrayList<String> loadArrayList(String fileName, boolean cache) {
ArrayList<String> array = new ArrayList<String>();
if(!map.containsKey(fileName)) {
try {
File file = new File(fileName);
BufferedReader reader = new BufferedReader(new FileReader(file));
String add;
while((add = reader.readLine()) != null)
array.add(add);
reader.close();
if(cache)
map.put(fileName, array);
} catch(Exception e) {
e.printStackTrace();
}
} else {
array = map.get(fileName);
}
return array;
}
/**
* Used to load a string via line number
* lineNumber = -1 means random.
*/
public static String loadString(String fileName, int lineNumber, boolean cache) throws Exception {
ArrayList<String> array;
if(!map.containsKey(fileName)) {
array = new ArrayList<String>();
File file = new File(fileName);
BufferedReader reader = new BufferedReader(new FileReader(file));
String add;
while((add = reader.readLine()) != null)
array.add(add);
reader.close();
if(cache)
map.put(fileName, array);
} else {
array = map.get(fileName);
}
if(lineNumber == -1) {
int size = array.size();
return array.get(random.nextInt(size));
} else
return array.get(lineNumber);
}
}

View file

@ -0,0 +1,176 @@
package me.konloch.kontainer.io;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
/**
* This method will save to disk, if it failed it will keep trying until
* it's saved to disk
*
* @author Konloch
*
*/
public class DiskWriter {
/**
* Used to insert a difference string with preserving the file extension
* @param fileName The file name
* @param difference Normally an integer
* @return The filename with the difference inserted and the file extension preserved
*/
public static String insertFileName(String fileName, String difference) {
String[] babe = fileName.split("\\.");
int count = 0;
int math = babe.length;
String m = "";
for(String s2 : babe) {
m += s2;
if(math-2 == count)
m += difference+".";
else if(math-1 != count)
m += ".";
count++;
}
return m;
}
/**
* Writes a new line to the file, if it doesn't exist it will automatically create it.
* @param filename
* @param fileContents
* @param debug
*/
public static synchronized void writeNewLine(String filename, byte[] fileContents, boolean debug) {
PrintWriter writer = null;
String original = filename;
int counter = 0;
boolean saved = false;
while(!saved) {
try {
writer = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
writer.println(fileContents);
if(debug)
System.out.println("Saved " + filename + " to disk");
saved = true;
} catch(Exception e) {
if(debug)
System.out.println("Failed saving, trying to save as " + filename);
if(original.contains(".")) {
filename = insertFileName(original, ""+counter);
} else
filename = original + counter;
counter++;
}
}
writer.close();
}
/**
* Writes a string to the file
* @param filename
* @param lineToWrite
* @param debug
*/
public static synchronized void writeNewLine(String filename, String lineToWrite, boolean debug) {
PrintWriter writer = null;
String original = filename;
int counter = 0;
boolean saved = false;
while(!saved) {
try {
writer = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
writer.println(lineToWrite);
if(debug)
System.out.println("Saved " + filename+">"+lineToWrite + " to disk");
saved = true;
} catch(Exception e) {
if(debug)
System.out.println("Failed saving, trying to save as " + filename);
if(original.contains(".")) {
filename = insertFileName(original, ""+counter);
} else
filename = original + counter;
counter++;
}
}
writer.close();
}
/**
* Deletes the original file if it exists, then writes the fileContents[] to the file.
* @param filename
* @param fileContents
* @param debug
*/
public static synchronized void replaceFile(String filename, byte[] fileContents, boolean debug) {
File f = new File(filename);
if(f.exists())
f.delete();
PrintWriter writer = null;
String original = filename;
int counter = 0;
boolean saved = false;
while(!saved) {
try {
writer = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
writer.println(fileContents);
if(debug)
System.out.println("Saved " + filename + " to disk");
saved = true;
} catch(Exception e) {
if(debug)
System.out.println("Failed saving, trying to save as " + filename);
if(original.contains(".")) {
filename = insertFileName(original, ""+counter);
} else
filename = original + counter;
counter++;
}
}
writer.close();
}
/**
* Deletes the original file if it exists, then writes the lineToWrite to the file.
* @param filename
* @param lineToWrite
* @param debug
*/
public static synchronized void replaceFile(String filename, String lineToWrite, boolean debug) {
File f = new File(filename);
if(f.exists())
f.delete();
PrintWriter writer = null;
String original = filename;
int counter = 0;
boolean saved = false;
while(!saved) {
try {
writer = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
writer.println(lineToWrite);
if(debug)
System.out.println("Saved " + filename+">"+lineToWrite + " to disk");
saved = true;
} catch(Exception e) {
if(debug)
System.out.println("Failed saving, trying to save as " + filename + "_");
if(original.contains(".")) {
filename = insertFileName(original, ""+counter);
} else
filename = original + counter;
counter++;
}
}
writer.close();
}
}

BIN
src/resources/1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

View file

@ -0,0 +1,331 @@
package the.bytecode.club.bytecodeviewer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.swing.JDialog;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import me.konloch.kontainer.io.DiskReader;
import me.konloch.kontainer.io.DiskWriter;
import org.apache.commons.io.FileUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.gui.FileNavigationPane;
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
import the.bytecode.club.bytecodeviewer.gui.SearchingPane;
import the.bytecode.club.bytecodeviewer.gui.WorkPane;
import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
/**
* A lightweight Java Bytecode Viewer/GUI Decompiler, developed by Konloch - http://konloch.me
*
* Are you a Java Reverse Engineer? Or maybe you want to learn Java Reverse Engineering?
* Join The Bytecode Club - http://the.bytecode.club
* We're noob friendly, and censorship free.
*
* All you have to do is add a jar or class file into the workspace, select the file you want
* then it will start decompiling the class in the background, when it's done it will show
* the Source code, Bytecode and Hexcode of the class file you chose.
*
* There is also a plugin system that will allow you to interact with the loaded classfiles, for example
* you can write a String deobfuscator, a malicious code searcher, or something else you can think of.
* You can either use one of the pre-written plugins, or write your own. It supports groovy, python and
* ruby scripting. Once a plugin is activated, it will send a ClassNode ArrayList of every single
* 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
* HexViewer pane based off of Re-Java's by Sami Koivu - http://rejava.sourceforge.net/
* Java Decompiler is a modified version of FernFlower
*
* TODO:
* Fix the fucking import jar method cause it's a bitch on memory (at the.bytecode.club.bytecodeviewer.JarUtils.getNode(JarUtils.java:83))
* JSyntaxPane can be horribly slow for really big classfiles, might need to find a work around to this (create the syntaxpane object in the thread, then pass it to the GUI)s
* Make the search results clickable
* Add a tool to build a flowchart of all the classes, and what methods execute what classes, and those method, read chatlog
* Middle mouse click should close tabs
* http://i.imgur.com/yHaai9D.png
*
* 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.
* 10/6/2014 - Started modifying J-RET's UI.
* 10/6/2014 - Added several FernFlower options.
* 10/6/2014 - Fixed the class search function so it doesn't require exact class names.
* 10/6/2014 - Added save as, it'll save all of the loaded classes into one jar file (GUI Jar-Jar now).
* 10/6/2014 - Centered the select jar text inside of the file navigator.
* 10/6/2014 - Properly threaded the open jar function, now fernflower/bytecode decompiler runs in the background.
* 10/6/2014 - Added a hex viewer (Instead of using Re-Java's, I've decided to use a modified version of JHexEditor).
* 10/6/2014 - Made all of the viewer (Sourcecode, Bytecode & Hexcode toggleable).
* 10/7/2014 - Fixed the search function.
* 10/7/2014 - You can now add new files without it creating a new workspace.
* 10/7/2014 - Added new workspace button underneath File, this will reset the workspace.
* 10/7/2014 - Renamed File>Open.. to File>Add..
* 10/7/2014 - Added recent files.
* 10/7/2014 - Did some bitch work, the project has no warnings now.
* 10/7/2014 - Added waiting cursors to anything that will require waiting or loading.
* 10/8/2014 - Searching now runs in a background thread.
* 10/8/2014 - Added File>About.
* 10/8/2014 - The main GUI now starts in the middle of your screen, same with the about window.
* 10/8/2014 - Made the File Navigator Pane, Workspace Pane & Search Pane a little sexier.
* 10/9/2014 - Started on a Plugin system
* 10/9/2014 - Added a malicious code scanner plugin, based off of the one from J-RET, this searches for a multitude of classes/packages that can be used for malicious purposes.
* 10/9/2014 - Added a show all strings plugin, this grabs all the declared strings and displays them in a nice little window.
* 10/9/2014 - Fixed a bug with Bytecode Decompiler, where it would it display \r and \n as return carriages.
* 10/9/2014 - Fixed the Bytecode Decompiler>Debug Instructions option.
* 10/9/2014 - Save Class Files As is now renamed to Save Files As.
* 10/9/2014 - Save Files As now saves jar resources, not just classfiles.
* 10/9/2014 - Added an 'Are you sure' pane when you click on File>New Workspace.
* 10/9/2014 - Save Files As is no longer dependent on the File System, now if you're on windows and you have a file called AA, and one called Aa, you're fine.
* 10/11/2014 - Modified the FernFlower library, it no longer spits out System.out.println's while processing a method, this has sped it up quite a lot.
* 10/12/2014 - Fix an issue when resizing.
* 10/12/2014 - Modified the core slighty to no longer have a modularized decompiling system (since there are only 2 decompilers anyways).
* 10/12/2014 - Fixed an issue with decompiling multiple files at once.
* 10/12/2014 - The Plugin Console now shows the plugin's name on the title.
* 10/12/2014 - Debug Helpers will now debug all jump instructions by showing what instruction is on the line it's suppose to goto, example: 90. goto 120 // line 120 is PUTFIELD Animable_Sub4.anInt1593 : I
* 10/12/2014 - Now when you select an already opened file, it will automatically go to that opened pane.
* 10/14/2014 - Added the option 'exact' to the class finder.
* 10/14/2014 - Added the option 'exact' to the searcher, now it'll search for .contains when unselected.
* 10/14/2014 - Stopped the use of StringBuffer, replaced all instances with StringBuilder.
* 10/14/2014 - Added Labels and Try-Catch blocks to the Bytecode Decompiler.
* 10/14/2014 - For panes that are not selected, the corresponding decompiler will not execute.
* 10/14/2014 - Added plugin Show Main Methods, this will show every single public static void main(String[]).
* 10/14/2014 - Plugins can no longer be ran when there is no loaded classes.
* 10/14/2014 - The Malicious Code Scanner now has gui option pane before you run it.
* 10/14/2014 - Added a java/io option to the Malicious Code Scanner.
* 10/14/2014 - Added save Java files as.
* 10/15/2014 - Added save as Jar file. (Export as Jar)
* 10/15/2014 - Added the option to ASCII only strings in the Bytecode Decompiler.
* 10/15/2014 - External plugins are now fully functional, same with recent plugins.
* 10/16/2014 - Removed all refences of 'ClassContainer'.
* 10/16/2014 - Rewrote the tempfile system.
* 10/16/2014 - Moved the file import to BytecodeViewer.class.
* 10/16/2014 - Fixed a jTree updating issue.
* 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.
*
* @author Konloch
*
*/
public class BytecodeViewer {
public static MainViewerGUI viewer = null;
public static HashMap<String, ClassNode> loadedClasses = new HashMap<String, ClassNode>();
public static HashMap<String, byte[]> loadedResources = new HashMap<String, byte[]>();
private static String filesName = "recentfiles.bcv";
private static String pluginsName = "recentplugins.bcv";
private static ArrayList<String> recentFiles = DiskReader.loadArrayList(filesName, false);
private static ArrayList<String> recentPlugins = DiskReader.loadArrayList(pluginsName, false);
private static int maxRecentFiles = 25;
public static String tempDirectory = "bcv_temp\\";
public static void main(String[] args) {
cleanup();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
cleanup();
}
});
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
viewer = new MainViewerGUI();
viewer.setVisible(true);
resetRecentFilesMenu();
}
public static ClassNode getClassNode(String name) {
if(loadedClasses.containsKey(name))
return loadedClasses.get(name);
return null;
}
public static ArrayList<ClassNode> getLoadedClasses() {
ArrayList<ClassNode> a = new ArrayList<ClassNode>();
if(loadedClasses != null)
for (Entry<String, ClassNode> entry : loadedClasses.entrySet()) {
Object value = entry.getValue();
ClassNode cln = (ClassNode)value;
a.add(cln);
}
return a;
}
public static void openFiles(File[] files) {
BytecodeViewer.viewer.setC(true);
BytecodeViewer.viewer.setIcon(true);
for (final File f : files) {
final String fn = f.getName();
if (fn.endsWith(".jar")) {
try {
JarUtils.put(f, BytecodeViewer.loadedClasses);
} catch (final IOException e) {
e.printStackTrace();
}
}
else if (fn.endsWith(".class")) {
try {
final ClassNode cn = JarUtils.getNode(JarUtils.getBytes(new FileInputStream(f)));
BytecodeViewer.loadedClasses.put(cn.name, cn);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
for(File f : files)
BytecodeViewer.addRecentFile(f);
BytecodeViewer.viewer.setC(false);
BytecodeViewer.viewer.setIcon(false);
MainViewerGUI.getComponent(FileNavigationPane.class).updateTree();
}
public static void startPlugin(File plugin) {
if(!plugin.exists())
return;
try {
PluginManager.runPlugin(plugin);
} catch (Exception e) {
e.printStackTrace();
}
addRecentPlugin(plugin);
}
public static void showMessage(String message) {
JOptionPane.showMessageDialog(viewer, message);
}
@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;
if(result == 0) {
loadedResources.clear();
loadedClasses.clear();
MainViewerGUI.getComponent(FileNavigationPane.class).resetWorkspace();
MainViewerGUI.getComponent(WorkPane.class).resetWorkspace();
MainViewerGUI.getComponent(SearchingPane.class).resetWorkspace();
}
}
private static ArrayList<String> killList = new ArrayList<String>();
public static void addRecentFile(File f) {
for(int i = 0; i < recentFiles.size(); i++) { //remove dead strings
String s = recentFiles.get(i);
if(s.isEmpty() || i > maxRecentFiles)
killList.add(s);
}
if(!killList.isEmpty()) {
for(String s : killList)
recentFiles.remove(s);
killList.clear();
}
if(recentFiles.contains(f.getAbsolutePath())) //already added on the list
recentFiles.remove(f.getAbsolutePath());
if(recentFiles.size() >= maxRecentFiles)
recentFiles.remove(maxRecentFiles-1); //zero indexing
recentFiles.add(0, f.getAbsolutePath());
DiskWriter.replaceFile(filesName, quickConvert(recentFiles), false);
resetRecentFilesMenu();
}
private static ArrayList<String> killList2 = new ArrayList<String>();
public static void addRecentPlugin(File f) {
for(int i = 0; i < recentPlugins.size(); i++) { //remove dead strings
String s = recentPlugins.get(i);
if(s.isEmpty() || i > maxRecentFiles)
killList2.add(s);
}
if(!killList2.isEmpty()) {
for(String s : killList2)
recentPlugins.remove(s);
killList2.clear();
}
if(recentPlugins.contains(f.getAbsolutePath())) //already added on the list
recentPlugins.remove(f.getAbsolutePath());
if(recentPlugins.size() >= maxRecentFiles)
recentPlugins.remove(maxRecentFiles-1); //zero indexing
recentPlugins.add(0, f.getAbsolutePath());
DiskWriter.replaceFile(pluginsName, quickConvert(recentPlugins), false);
resetRecentFilesMenu();
}
public static void resetRecentFilesMenu() {
viewer.mnRecentFiles.removeAll();
for(String s : recentFiles)
if(!s.isEmpty()) {
JMenuItem m = new JMenuItem(s);
m.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuItem m = (JMenuItem)e.getSource();
openFiles(new File[]{new File(m.getText())});
}
});
viewer.mnRecentFiles.add(m);
}
viewer.mnRecentPlugins.removeAll();
for(String s : recentPlugins)
if(!s.isEmpty()) {
JMenuItem m = new JMenuItem(s);
m.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuItem m = (JMenuItem)e.getSource();
startPlugin(new File(m.getText()));
}
});
viewer.mnRecentPlugins.add(m);
}
}
private static File tempF = null;
public static void cleanup() {
tempF = new File(tempDirectory);
try {
FileUtils.deleteDirectory(tempF);
} catch (IOException e) {
e.printStackTrace();
}
tempF.mkdir();
}
private static String quickConvert(ArrayList<String> a) {
String s = "";
for(String r : a)
s += r+"\r";
return s;
}
}

View file

@ -0,0 +1,14 @@
package the.bytecode.club.bytecodeviewer;
import org.objectweb.asm.tree.ClassNode;
/**
* Used to represent whenever a file has been opened
*
* @author Konloch
*
*/
public interface FileChangeNotifier {
public void openClassFile(String name, ClassNode cn);
}

View file

@ -0,0 +1,925 @@
package the.bytecode.club.bytecodeviewer;
import java.awt.datatransfer.DataFlavor;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
/**
* This class makes it easy to drag and drop files from the operating system to
* a Java program. Any <tt>java.awt.Component</tt> can be dropped onto, but only
* <tt>javax.swing.JComponent</tt>s will indicate the drop event with a changed
* border.
* <p/>
* To use this class, construct a new <tt>FileDrop</tt> by passing it the target
* component and a <tt>Listener</tt> to receive notification when file(s) have
* been dropped. Here is an example:
* <p/>
* <code><pre>
* JPanel myPanel = new JPanel();
* new FileDrop( myPanel, new FileDrop.Listener()
* { public void filesDropped( java.io.File[] files )
* {
* // handle file drop
* ...
* } // end filesDropped
* }); // end FileDrop.Listener
* </pre></code>
* <p/>
* You can specify the border that will appear when files are being dragged by
* calling the constructor with a <tt>javax.swing.border.Border</tt>. Only
* <tt>JComponent</tt>s will show any indication with a border.
* <p/>
* You can turn on some debugging features by passing a <tt>PrintStream</tt>
* object (such as <tt>System.out</tt>) into the full constructor. A
* <tt>null</tt> value will result in no extra debugging information being
* output.
* <p/>
*
* <p>
* I'm releasing this code into the Public Domain. Enjoy.
* </p>
* <p>
* <em>Original author: Robert Harder, rharder@usa.net</em>
* </p>
* <p>
* 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
* </p>
*
* @author Robert Harder
* @author rharder@users.sf.net
* @version 1.0.1
*/
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public class FileDrop {
private transient javax.swing.border.Border normalBorder;
private transient java.awt.dnd.DropTargetListener dropListener;
/** Discover if the running JVM is modern enough to have drag and drop. */
private static Boolean supportsDnD;
// Default border color
private static java.awt.Color defaultBorderColor = new java.awt.Color(0f,
0f, 1f, 0.25f);
/**
* Constructs a {@link FileDrop} with a default light-blue border and, if
* <var>c</var> is a {@link java.awt.Container}, recursively sets all
* elements contained within as drop targets, though only the top level
* container will change borders.
*
* @param c Component on which files will be dropped.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.awt.Component c, final Listener listener) {
this(null, // Logging stream
c, // Drop target
javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2,
defaultBorderColor), // Drag border
true, // Recursive
listener);
} // end constructor
/**
* Constructor with a default border and the option to recursively set drop
* targets. If your component is a <tt>java.awt.Container</tt>, then each of
* its children components will also listen for drops, though only the
* parent will change borders.
*
* @param c Component on which files will be dropped.
* @param recursive Recursively set children as drop targets.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.awt.Component c, final boolean recursive,
final Listener listener) {
this(null, // Logging stream
c, // Drop target
javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2,
defaultBorderColor), // Drag border
recursive, // Recursive
listener);
} // end constructor
/**
* Constructor with a default border and debugging optionally turned on.
* With Debugging turned on, more status messages will be displayed to
* <tt>out</tt>. A common way to use this constructor is with
* <tt>System.out</tt> or <tt>System.err</tt>. A <tt>null</tt> value for the
* parameter <tt>out</tt> will result in no debugging output.
*
* @param out PrintStream to record debugging info or null for no debugging.
* @param out
* @param c Component on which files will be dropped.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.io.PrintStream out, final java.awt.Component c,
final Listener listener) {
this(out, // Logging stream
c, // Drop target
javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2,
defaultBorderColor), false, // Recursive
listener);
} // end constructor
/**
* Constructor with a default border, debugging optionally turned on and the
* option to recursively set drop targets. If your component is a
* <tt>java.awt.Container</tt>, then each of its children components will
* also listen for drops, though only the parent will change borders. With
* Debugging turned on, more status messages will be displayed to
* <tt>out</tt>. A common way to use this constructor is with
* <tt>System.out</tt> or <tt>System.err</tt>. A <tt>null</tt> value for the
* parameter <tt>out</tt> will result in no debugging output.
*
* @param out PrintStream to record debugging info or null for no debugging.
* @param out
* @param c Component on which files will be dropped.
* @param recursive Recursively set children as drop targets.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.io.PrintStream out, final java.awt.Component c,
final boolean recursive, final Listener listener) {
this(out, // Logging stream
c, // Drop target
javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2,
defaultBorderColor), // Drag border
recursive, // Recursive
listener);
} // end constructor
/**
* Constructor with a specified border
*
* @param c Component on which files will be dropped.
* @param dragBorder Border to use on <tt>JComponent</tt> when dragging
* occurs.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.awt.Component c,
final javax.swing.border.Border dragBorder, final Listener listener) {
this(null, // Logging stream
c, // Drop target
dragBorder, // Drag border
false, // Recursive
listener);
} // end constructor
/**
* Constructor with a specified border and the option to recursively set
* drop targets. If your component is a <tt>java.awt.Container</tt>, then
* each of its children components will also listen for drops, though only
* the parent will change borders.
*
* @param c Component on which files will be dropped.
* @param dragBorder Border to use on <tt>JComponent</tt> when dragging
* occurs.
* @param recursive Recursively set children as drop targets.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.awt.Component c,
final javax.swing.border.Border dragBorder,
final boolean recursive, final Listener listener) {
this(null, c, dragBorder, recursive, listener);
} // end constructor
/**
* Constructor with a specified border and debugging optionally turned on.
* With Debugging turned on, more status messages will be displayed to
* <tt>out</tt>. A common way to use this constructor is with
* <tt>System.out</tt> or <tt>System.err</tt>. A <tt>null</tt> value for the
* parameter <tt>out</tt> will result in no debugging output.
*
* @param out PrintStream to record debugging info or null for no debugging.
* @param c Component on which files will be dropped.
* @param dragBorder Border to use on <tt>JComponent</tt> when dragging
* occurs.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.io.PrintStream out, final java.awt.Component c,
final javax.swing.border.Border dragBorder, final Listener listener) {
this(out, // Logging stream
c, // Drop target
dragBorder, // Drag border
false, // Recursive
listener);
} // end constructor
/**
* Full constructor with a specified border and debugging optionally turned
* on. With Debugging turned on, more status messages will be displayed to
* <tt>out</tt>. A common way to use this constructor is with
* <tt>System.out</tt> or <tt>System.err</tt>. A <tt>null</tt> value for the
* parameter <tt>out</tt> will result in no debugging output.
*
* @param out PrintStream to record debugging info or null for no debugging.
* @param c Component on which files will be dropped.
* @param dragBorder Border to use on <tt>JComponent</tt> when dragging
* occurs.
* @param recursive Recursively set children as drop targets.
* @param listener Listens for <tt>filesDropped</tt>.
* @since 1.0
*/
public FileDrop(final java.io.PrintStream out, final java.awt.Component c,
final javax.swing.border.Border dragBorder,
final boolean recursive, final Listener listener) {
if (supportsDnD()) { // Make a drop listener
dropListener = new java.awt.dnd.DropTargetListener() {
public void dragEnter(final java.awt.dnd.DropTargetDragEvent evt) {
log(out, "FileDrop: dragEnter event.");
// Is this an acceptable drag event?
if (isDragOk(out, evt)) {
// If it's a Swing component, set its border
if (c instanceof javax.swing.JComponent) {
final javax.swing.JComponent jc = (javax.swing.JComponent) c;
normalBorder = jc.getBorder();
log(out, "FileDrop: normal border saved.");
jc.setBorder(dragBorder);
log(out, "FileDrop: drag border set.");
} // end if: JComponent
// Acknowledge that it's okay to enter
// evt.acceptDrag(
// java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY);
log(out, "FileDrop: event accepted.");
} // end if: drag ok
else { // Reject the drag event
evt.rejectDrag();
log(out, "FileDrop: event rejected.");
} // end else: drag not ok
} // end dragEnter
public void dragOver(final java.awt.dnd.DropTargetDragEvent evt) { // This
// is
// called
// continually
// as
// long
// as
// the
// mouse
// is
// over
// the
// drag
// target.
} // end dragOver
public void drop(final java.awt.dnd.DropTargetDropEvent evt) {
log(out, "FileDrop: drop event.");
try { // Get whatever was dropped
final java.awt.datatransfer.Transferable tr = evt
.getTransferable();
// Is it a file list?
if (tr.isDataFlavorSupported(java.awt.datatransfer.DataFlavor.javaFileListFlavor)) {
// Say we'll take it.
// evt.acceptDrop (
// java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY);
log(out, "FileDrop: file list accepted.");
// Get a useful list
final java.util.List fileList = (java.util.List) tr
.getTransferData(java.awt.datatransfer.DataFlavor.javaFileListFlavor);
final java.util.Iterator iterator = fileList.iterator();
// Convert list to array
final java.io.File[] filesTemp = new java.io.File[fileList
.size()];
fileList.toArray(filesTemp);
final java.io.File[] files = filesTemp;
// Alert listener to drop.
if (listener != null) {
listener.filesDropped(files);
}
// Mark that drop is completed.
evt.getDropTargetContext().dropComplete(true);
log(out, "FileDrop: drop complete.");
} // end if: file list
else // this section will check for a reader flavor.
{
// Thanks, Nathan!
// BEGIN 2007-09-12 Nathan Blomquist -- Linux
// (KDE/Gnome) support added.
final DataFlavor[] flavors = tr
.getTransferDataFlavors();
boolean handled = false;
for (int zz = 0; zz < flavors.length; zz++) {
if (flavors[zz].isRepresentationClassReader()) {
// Say we'll take it.
// evt.acceptDrop (
// java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE
// );
evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY);
log(out, "FileDrop: reader accepted.");
final Reader reader = flavors[zz]
.getReaderForText(tr);
final BufferedReader br = new BufferedReader(
reader);
if (listener != null) {
listener.filesDropped(createFileArray(
br, out));
}
// Mark that drop is completed.
evt.getDropTargetContext().dropComplete(
true);
log(out, "FileDrop: drop complete.");
handled = true;
break;
}
}
if (!handled) {
log(out,
"FileDrop: not a file list or reader - abort.");
evt.rejectDrop();
}
// END 2007-09-12 Nathan Blomquist -- Linux
// (KDE/Gnome) support added.
} // end else: not a file list
} // end try
catch (final java.io.IOException io) {
log(out, "FileDrop: IOException - abort:");
io.printStackTrace(out);
evt.rejectDrop();
} // end catch IOException
catch (final java.awt.datatransfer.UnsupportedFlavorException ufe) {
log(out,
"FileDrop: UnsupportedFlavorException - abort:");
ufe.printStackTrace(out);
evt.rejectDrop();
} // end catch: UnsupportedFlavorException
finally {
// If it's a Swing component, reset its border
if (c instanceof javax.swing.JComponent) {
final javax.swing.JComponent jc = (javax.swing.JComponent) c;
jc.setBorder(normalBorder);
log(out, "FileDrop: normal border restored.");
} // end if: JComponent
} // end finally
} // end drop
public void dragExit(final java.awt.dnd.DropTargetEvent evt) {
log(out, "FileDrop: dragExit event.");
// If it's a Swing component, reset its border
if (c instanceof javax.swing.JComponent) {
final javax.swing.JComponent jc = (javax.swing.JComponent) c;
jc.setBorder(normalBorder);
log(out, "FileDrop: normal border restored.");
} // end if: JComponent
} // end dragExit
public void dropActionChanged(
final java.awt.dnd.DropTargetDragEvent evt) {
log(out, "FileDrop: dropActionChanged event.");
// Is this an acceptable drag event?
if (isDragOk(out, evt)) { // evt.acceptDrag(
// java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE
// );
evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY);
log(out, "FileDrop: event accepted.");
} // end if: drag ok
else {
evt.rejectDrag();
log(out, "FileDrop: event rejected.");
} // end else: drag not ok
} // end dropActionChanged
}; // end DropTargetListener
// Make the component (and possibly children) drop targets
makeDropTarget(out, c, recursive);
} // end if: supports dnd
else {
log(out, "FileDrop: Drag and drop is not supported with this JVM");
} // end else: does not support DnD
} // end constructor
private static boolean supportsDnD() { // Static Boolean
if (supportsDnD == null) {
boolean support = false;
try {
final Class arbitraryDndClass = Class
.forName("java.awt.dnd.DnDConstants");
support = true;
} // end try
catch (final Exception e) {
support = false;
} // end catch
supportsDnD = new Boolean(support);
} // end if: first time through
return supportsDnD.booleanValue();
} // end supportsDnD
// BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
private static String ZERO_CHAR_STRING = "" + (char) 0;
private static File[] createFileArray(final BufferedReader bReader,
final PrintStream out) {
try {
final java.util.List list = new java.util.ArrayList();
java.lang.String line = null;
while ((line = bReader.readLine()) != null) {
try {
// kde seems to append a 0 char to the end of the reader
if (ZERO_CHAR_STRING.equals(line)) {
continue;
}
final java.io.File file = new java.io.File(
new java.net.URI(line));
list.add(file);
} catch (final Exception ex) {
log(out, "Error with " + line + ": " + ex.getMessage());
}
}
return (java.io.File[]) list.toArray(new File[list.size()]);
} catch (final IOException ex) {
log(out, "FileDrop: IOException");
}
return new File[0];
}
// END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
private void makeDropTarget(final java.io.PrintStream out,
final java.awt.Component c, final boolean recursive) {
// Make drop target
final java.awt.dnd.DropTarget dt = new java.awt.dnd.DropTarget();
try {
dt.addDropTargetListener(dropListener);
} // end try
catch (final java.util.TooManyListenersException e) {
e.printStackTrace();
log(out,
"FileDrop: Drop will not work due to previous error. Do you have another listener attached?");
} // end catch
// Listen for hierarchy changes and remove the drop target when the
// parent gets cleared out.
c.addHierarchyListener(new java.awt.event.HierarchyListener() {
public void hierarchyChanged(final java.awt.event.HierarchyEvent evt) {
log(out, "FileDrop: Hierarchy changed.");
final java.awt.Component parent = c.getParent();
if (parent == null) {
c.setDropTarget(null);
log(out, "FileDrop: Drop target cleared from component.");
} // end if: null parent
else {
new java.awt.dnd.DropTarget(c, dropListener);
log(out, "FileDrop: Drop target added to component.");
} // end else: parent not null
} // end hierarchyChanged
}); // end hierarchy listener
if (c.getParent() != null) {
new java.awt.dnd.DropTarget(c, dropListener);
}
if (recursive && (c instanceof java.awt.Container)) {
// Get the container
final java.awt.Container cont = (java.awt.Container) c;
// Get it's components
final java.awt.Component[] comps = cont.getComponents();
// Set it's components as listeners also
for (int i = 0; i < comps.length; i++) {
makeDropTarget(out, comps[i], recursive);
}
} // end if: recursively set components as listener
} // end dropListener
/** Determine if the dragged data is a file list. */
private boolean isDragOk(final java.io.PrintStream out,
final java.awt.dnd.DropTargetDragEvent evt) {
boolean ok = false;
// Get data flavors being dragged
final java.awt.datatransfer.DataFlavor[] flavors = evt
.getCurrentDataFlavors();
// See if any of the flavors are a file list
int i = 0;
while (!ok && i < flavors.length) {
// BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support
// added.
// Is the flavor a file list?
final DataFlavor curFlavor = flavors[i];
if (curFlavor
.equals(java.awt.datatransfer.DataFlavor.javaFileListFlavor)
|| curFlavor.isRepresentationClassReader()) {
ok = true;
}
// END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support
// added.
i++;
} // end while: through flavors
// If logging is enabled, show data flavors
if (out != null) {
if (flavors.length == 0) {
log(out, "FileDrop: no data flavors.");
}
for (i = 0; i < flavors.length; i++) {
log(out, flavors[i].toString());
}
} // end if: logging enabled
return ok;
} // end isDragOk
/** Outputs <tt>message</tt> to <tt>out</tt> if it's not null. */
private static void log(final java.io.PrintStream out, final String message) { // Log
// message
// if
// requested
if (out != null) {
out.println(message);
}
} // end log
/**
* Removes the drag-and-drop hooks from the component and optionally from
* the all children. You should call this if you add and remove components
* after you've set up the drag-and-drop. This will recursively unregister
* all components contained within <var>c</var> if <var>c</var> is a
* {@link java.awt.Container}.
*
* @param c The component to unregister as a drop target
* @since 1.0
*/
public static boolean remove(final java.awt.Component c) {
return remove(null, c, true);
} // end remove
/**
* Removes the drag-and-drop hooks from the component and optionally from
* the all children. You should call this if you add and remove components
* after you've set up the drag-and-drop.
*
* @param out Optional {@link java.io.PrintStream} for logging drag and drop
* messages
* @param c The component to unregister
* @param recursive Recursively unregister components within a container
* @since 1.0
*/
public static boolean remove(final java.io.PrintStream out,
final java.awt.Component c, final boolean recursive) { // Make sure
// we support
// dnd.
if (supportsDnD()) {
log(out, "FileDrop: Removing drag-and-drop hooks.");
c.setDropTarget(null);
if (recursive && (c instanceof java.awt.Container)) {
final java.awt.Component[] comps = ((java.awt.Container) c)
.getComponents();
for (int i = 0; i < comps.length; i++) {
remove(out, comps[i], recursive);
}
return true;
} // end if: recursive
else
return false;
} // end if: supports DnD
else
return false;
} // end remove
/* ******** I N N E R I N T E R F A C E L I S T E N E R ******** */
/**
* Implement this inner interface to listen for when files are dropped. For
* example your class declaration may begin like this: <code><pre>
* public class MyClass implements FileDrop.Listener
* ...
* public void filesDropped( java.io.File[] files )
* {
* ...
* } // end filesDropped
* ...
* </pre></code>
*
* @since 1.1
*/
public static interface Listener {
/**
* This method is called when files have been successfully dropped.
*
* @param files An array of <tt>File</tt>s that were dropped.
* @since 1.0
*/
public abstract void filesDropped(java.io.File[] files);
} // end inner-interface Listener
/* ******** I N N E R C L A S S ******** */
/**
* This is the event that is passed to the
* {@link FileDropListener#filesDropped filesDropped(...)} method in your
* {@link FileDropListener} when files are dropped onto a registered drop
* target.
*
* <p>
* I'm releasing this code into the Public Domain. Enjoy.
* </p>
*
* @author Robert Harder
* @author rob@iharder.net
* @version 1.2
*/
public static class Event extends java.util.EventObject {
private static final long serialVersionUID = -2175361562828864378L;
private final java.io.File[] files;
/**
* Constructs an {@link Event} with the array of files that were dropped
* and the {@link FileDrop} that initiated the event.
*
* @param files The array of files that were dropped
* @source The event source
* @since 1.1
*/
public Event(final java.io.File[] files, final Object source) {
super(source);
this.files = files;
} // end constructor
/**
* Returns an array of files that were dropped on a registered drop
* target.
*
* @return array of files that were dropped
* @since 1.1
*/
public java.io.File[] getFiles() {
return files;
} // end getFiles
} // end inner class Event
/* ******** I N N E R C L A S S ******** */
/**
* At last an easy way to encapsulate your custom objects for dragging and
* dropping in your Java programs! When you need to create a
* {@link java.awt.datatransfer.Transferable} object, use this class to wrap
* your object. For example:
*
* <pre>
* <code>
* ...
* MyCoolClass myObj = new MyCoolClass();
* Transferable xfer = new TransferableObject( myObj );
* ...
* </code>
* </pre>
*
* Or if you need to know when the data was actually dropped, like when
* you're moving data out of a list, say, you can use the
* {@link TransferableObject.Fetcher} inner class to return your object Just
* in Time. For example:
*
* <pre>
* <code>
* ...
* final MyCoolClass myObj = new MyCoolClass();
*
* TransferableObject.Fetcher fetcher = new TransferableObject.Fetcher()
* { public Object getObject(){ return myObj; }
* }; // end fetcher
*
* Transferable xfer = new TransferableObject( fetcher );
* ...
* </code>
* </pre>
*
* The {@link java.awt.datatransfer.DataFlavor} associated with
* {@link TransferableObject} has the representation class
* <tt>net.iharder.dnd.TransferableObject.class</tt> and MIME type
* <tt>application/x-net.iharder.dnd.TransferableObject</tt>. This data
* flavor is accessible via the static {@link #DATA_FLAVOR} property.
*
*
* <p>
* I'm releasing this code into the Public Domain. Enjoy.
* </p>
*
* @author Robert Harder
* @author rob@iharder.net
* @version 1.2
*/
public static class TransferableObject implements
java.awt.datatransfer.Transferable {
/**
* The MIME type for {@link #DATA_FLAVOR} is
* <tt>application/x-net.iharder.dnd.TransferableObject</tt>.
*
* @since 1.1
*/
public final static String MIME_TYPE = "application/x-net.iharder.dnd.TransferableObject";
/**
* The default {@link java.awt.datatransfer.DataFlavor} for
* {@link TransferableObject} has the representation class
* <tt>net.iharder.dnd.TransferableObject.class</tt> and the MIME type
* <tt>application/x-net.iharder.dnd.TransferableObject</tt>.
*
* @since 1.1
*/
public final static java.awt.datatransfer.DataFlavor DATA_FLAVOR = new java.awt.datatransfer.DataFlavor(
FileDrop.TransferableObject.class, MIME_TYPE);
private Fetcher fetcher;
private Object data;
private java.awt.datatransfer.DataFlavor customFlavor;
/**
* Creates a new {@link TransferableObject} that wraps <var>data</var>.
* Along with the {@link #DATA_FLAVOR} associated with this class, this
* creates a custom data flavor with a representation class determined
* from <code>data.getClass()</code> and the MIME type
* <tt>application/x-net.iharder.dnd.TransferableObject</tt>.
*
* @param data The data to transfer
* @since 1.1
*/
public TransferableObject(final Object data) {
this.data = data;
this.customFlavor = new java.awt.datatransfer.DataFlavor(
data.getClass(), MIME_TYPE);
} // end constructor
/**
* Creates a new {@link TransferableObject} that will return the object
* that is returned by <var>fetcher</var>. No custom data flavor is set
* other than the default {@link #DATA_FLAVOR}.
*
* @see Fetcher
* @param fetcher The {@link Fetcher} that will return the data object
* @since 1.1
*/
public TransferableObject(final Fetcher fetcher) {
this.fetcher = fetcher;
} // end constructor
/**
* Creates a new {@link TransferableObject} that will return the object
* that is returned by <var>fetcher</var>. Along with the
* {@link #DATA_FLAVOR} associated with this class, this creates a
* custom data flavor with a representation class <var>dataClass</var>
* and the MIME type
* <tt>application/x-net.iharder.dnd.TransferableObject</tt>.
*
* @see Fetcher
* @param dataClass The {@link java.lang.Class} to use in the custom
* data flavor
* @param fetcher The {@link Fetcher} that will return the data object
* @since 1.1
*/
public TransferableObject(final Class dataClass, final Fetcher fetcher) {
this.fetcher = fetcher;
this.customFlavor = new java.awt.datatransfer.DataFlavor(dataClass,
MIME_TYPE);
} // end constructor
/**
* Returns the custom {@link java.awt.datatransfer.DataFlavor}
* associated with the encapsulated object or <tt>null</tt> if the
* {@link Fetcher} constructor was used without passing a
* {@link java.lang.Class}.
*
* @return The custom data flavor for the encapsulated object
* @since 1.1
*/
public java.awt.datatransfer.DataFlavor getCustomDataFlavor() {
return customFlavor;
} // end getCustomDataFlavor
/* ******** T R A N S F E R A B L E M E T H O D S ******** */
/**
* Returns a two- or three-element array containing first the custom
* data flavor, if one was created in the constructors, second the
* default {@link #DATA_FLAVOR} associated with
* {@link TransferableObject}, and third the
* {@link java.awt.datatransfer.DataFlavor.stringFlavor}.
*
* @return An array of supported data flavors
* @since 1.1
*/
public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() {
if (customFlavor != null)
return new java.awt.datatransfer.DataFlavor[] { customFlavor,
DATA_FLAVOR,
java.awt.datatransfer.DataFlavor.stringFlavor }; // end
// flavors
// array
else
return new java.awt.datatransfer.DataFlavor[] { DATA_FLAVOR,
java.awt.datatransfer.DataFlavor.stringFlavor }; // end
// flavors
// array
} // end getTransferDataFlavors
/**
* Returns the data encapsulated in this {@link TransferableObject}. If
* the {@link Fetcher} constructor was used, then this is when the
* {@link Fetcher#getObject getObject()} method will be called. If the
* requested data flavor is not supported, then the
* {@link Fetcher#getObject getObject()} method will not be called.
*
* @param flavor The data flavor for the data to return
* @return The dropped data
* @since 1.1
*/
public Object getTransferData(
final java.awt.datatransfer.DataFlavor flavor)
throws java.awt.datatransfer.UnsupportedFlavorException,
java.io.IOException {
// Native object
if (flavor.equals(DATA_FLAVOR))
return fetcher == null ? data : fetcher.getObject();
// String
if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor))
return fetcher == null ? data.toString() : fetcher.getObject()
.toString();
// We can't do anything else
throw new java.awt.datatransfer.UnsupportedFlavorException(flavor);
} // end getTransferData
/**
* Returns <tt>true</tt> if <var>flavor</var> is one of the supported
* flavors. Flavors are supported using the <code>equals(...)</code>
* method.
*
* @param flavor The data flavor to check
* @return Whether or not the flavor is supported
* @since 1.1
*/
public boolean isDataFlavorSupported(
final java.awt.datatransfer.DataFlavor flavor) {
// Native object
if (flavor.equals(DATA_FLAVOR))
return true;
// String
if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor))
return true;
// We can't do anything else
return false;
} // end isDataFlavorSupported
/* ******** I N N E R I N T E R F A C E F E T C H E R ******** */
/**
* Instead of passing your data directly to the
* {@link TransferableObject} constructor, you may want to know exactly
* when your data was received in case you need to remove it from its
* source (or do anyting else to it). When the {@link #getTransferData
* getTransferData(...)} method is called on the
* {@link TransferableObject}, the {@link Fetcher}'s {@link #getObject
* getObject()} method will be called.
*
* @author Robert Harder
* @copyright 2001
* @version 1.1
* @since 1.1
*/
public static interface Fetcher {
/**
* Return the object being encapsulated in the
* {@link TransferableObject}.
*
* @return The dropped object
* @since 1.1
*/
public abstract Object getObject();
} // end inner interface Fetcher
} // end class TransferableObject
} // end class FileDrop

View file

@ -0,0 +1,135 @@
package the.bytecode.club.bytecodeviewer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
/**
* Loading and saving jars
*
* @author Konloch
* @author WaterWolf
*
*/
public class JarUtils {
private static JarInputStream jis;
private static JarEntry entry;
public static void put(final File jarFile, final HashMap<String, ClassNode> clazzList) throws IOException {
jis = new JarInputStream(new FileInputStream(jarFile));
while ((entry = jis.getNextJarEntry()) != null) {
final String name = entry.getName();
if (!name.endsWith(".class")) {
BytecodeViewer.loadedResources.put(name, getBytes(jis));
jis.closeEntry();
continue;
}
final ClassNode cn = getNode(getBytes(jis));
clazzList.put(cn.name, cn);
jis.closeEntry();
}
jis.close();
}
private static ByteArrayOutputStream baos = null;
private static byte[] buffer = null;
private static int a = 0;
public static byte[] getBytes(final InputStream is) throws IOException {
baos = new ByteArrayOutputStream();
buffer = new byte[1024];
a = 0;
while ((a = is.read(buffer)) != -1) {
baos.write(buffer, 0, a);
}
baos.close();
buffer = null;
return baos.toByteArray();
}
private static ClassReader cr = null;
private static ClassNode cn = null;
public static ClassNode getNode(final byte[] bytez) {
cr = new ClassReader(bytez);
cn = new ClassNode();
cr.accept(cn, ClassReader.EXPAND_FRAMES);
cr = null;
return cn;
}
public static void saveAsJar(ArrayList<ClassNode> nodeList, String path, String manifest) {
try {
JarOutputStream out = new JarOutputStream(new FileOutputStream(path));
for (ClassNode cn : nodeList) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
out.putNextEntry(new ZipEntry(cn.name + ".class"));
out.write(cw.toByteArray());
out.closeEntry();
}
out.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
out.write((manifest.trim()+"\r\n\r\n").getBytes());
out.closeEntry();
for (Entry<String, byte[]> entry : BytecodeViewer.loadedResources.entrySet()) {
String filename = entry.getKey();
if(!filename.startsWith("META-INF")) {
out.putNextEntry(new ZipEntry(filename));
out.write(entry.getValue());
out.closeEntry();
}
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void saveAsJar(ArrayList<ClassNode> nodeList, String path) {
try {
JarOutputStream out = new JarOutputStream(new FileOutputStream(path));
for (ClassNode cn : nodeList) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
out.putNextEntry(new ZipEntry(cn.name + ".class"));
out.write(cw.toByteArray());
out.closeEntry();
}
for (Entry<String, byte[]> entry : BytecodeViewer.loadedResources.entrySet()) {
String filename = entry.getKey();
if(!filename.startsWith("META-INF")) {
out.putNextEntry(new ZipEntry(filename));
out.write(entry.getValue());
out.closeEntry();
}
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,381 @@
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,76 @@
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,14 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import org.objectweb.asm.Type;
/**
* Container class for type and name. Used to pass arguments and local variables around
*
* @author Waterwolf
*
*/
public class TypeAndName {
public Type type = null;
public String name = null;
}

View file

@ -0,0 +1,152 @@
package the.bytecode.club.bytecodeviewer.decompilers.java;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.JarUtils;
/**
* A complete FernFlower launcher with all the options (except 2)
*
* @author Konloch
* @author WaterWolf
*
*/
public class FernFlowerDecompiler {
public void decompileToZip(String zipName) {
File tempZip = new File(BytecodeViewer.tempDirectory + "temp.zip");
if(tempZip.exists())
tempZip.delete();
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath());
de.fernflower.main.decompiler.ConsoleDecompiler.main(new String[] {tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/"});
File tempZip2 = new File(BytecodeViewer.tempDirectory + "./temp/"+tempZip.getName());
if(tempZip2.exists())
tempZip2.renameTo(new File(zipName));
tempZip.delete();
new File(BytecodeViewer.tempDirectory + "./temp/").delete();
}
public String decompileClassNode(final ClassNode cn) {
final ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
String fileStart = BytecodeViewer.tempDirectory + "temp";
int fileNumber = getClassNumber(fileStart, ".class");
final File tempClass = new File(fileStart+fileNumber+".class");
try {
final FileOutputStream fos = new FileOutputStream(tempClass);
fos.write(cw.toByteArray());
fos.close();
} catch (final IOException e) {
e.printStackTrace();
}
de.fernflower.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), "."));
tempClass.delete();
final File outputJava = new File("temp"+fileNumber+".java");
if (outputJava.exists()) {
final String nl = System.getProperty("line.separator");
final StringBuffer javaSrc = new StringBuffer();
try {
final BufferedReader br = new BufferedReader(new FileReader(outputJava));
String line;
while ((line = br.readLine()) != null) {
javaSrc.append(line + nl);
}
br.close();
} catch (final IOException e) {
e.printStackTrace();
}
outputJava.delete();
return javaSrc.toString();
}
return "FernFlower error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com";
}
File tempF = null;
public int getClassNumber(String start, String ext) {
boolean b = true;
int i = 0;
while(b) {
tempF = new File(start + i + ext);
if(!tempF.exists())
b = false;
else
i++;
}
return i;
}
private String[] generateMainMethod(String className, String folder) {
boolean rbr = BytecodeViewer.viewer.rbr.isSelected();
boolean rsy = BytecodeViewer.viewer.rsy.isSelected();
boolean din = BytecodeViewer.viewer.din.isSelected();
boolean dc4 = BytecodeViewer.viewer.dc4.isSelected();
boolean das = BytecodeViewer.viewer.das.isSelected();
boolean hes = BytecodeViewer.viewer.hes.isSelected();
boolean hdc = BytecodeViewer.viewer.hdc.isSelected();
boolean dgs = BytecodeViewer.viewer.dgs.isSelected();
boolean ner = BytecodeViewer.viewer.ner.isSelected();
boolean den = BytecodeViewer.viewer.den.isSelected();
boolean rgn = BytecodeViewer.viewer.rgn.isSelected();
boolean bto = BytecodeViewer.viewer.bto.isSelected();
boolean nns = BytecodeViewer.viewer.nns.isSelected();
boolean uto = BytecodeViewer.viewer.uto.isSelected();
boolean udv = BytecodeViewer.viewer.udv.isSelected();
boolean rer = BytecodeViewer.viewer.rer.isSelected();
boolean fdi = BytecodeViewer.viewer.fdi.isSelected();
boolean asc = BytecodeViewer.viewer.asc.isSelected();
return new String[] {
"-rbr="+r(rbr),
"-rsy="+r(rsy),
"-din="+r(din),
"-dc4="+r(dc4),
"-das="+r(das),
"-hes="+r(hes),
"-hdc="+r(hdc),
"-dgs="+r(dgs),
"-ner="+r(ner),
"-den="+r(den),
"-rgn="+r(rgn),
"-bto="+r(bto),
"-nns="+r(nns),
"-uto="+r(uto),
"-udv="+r(udv),
"-rer="+r(rer),
"-fdi="+r(fdi),
"-asc="+r(asc),
className,
folder};
}
private String r(boolean b) {
if(b) {
return "1";
} else {
return "0";
}
}
}

View file

@ -0,0 +1,28 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.CardLayout;
import javax.swing.JTextArea;
import java.awt.Color;
public class AboutWindow extends JFrame {
public AboutWindow() {
setSize(new Dimension(403, 407));
setType(Type.UTILITY);
setTitle("Bytecode Viewer - About");
getContentPane().setLayout(new CardLayout(0, 0));
JTextArea txtrBytecodeViewerIs = new JTextArea();
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\r\nLimitations:\r\n Syntax highlighting on files that are\r\nbigger than 10K lines can take a while to\r\nload, you may want to disable the syntax\r\nhighlighting for large files.\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);
}
private static final long serialVersionUID = -8230501978224923296L;
}

View file

@ -0,0 +1,281 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.util.ArrayList;
import static javax.swing.ScrollPaneConstants.*;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.ParagraphView;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
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.java.FernFlowerDecompiler;
/**
* This represents the opened classfile.
*
* @author Konloch
* @author WaterWolf
*
*/
public class ClassViewer extends JPanel {
private boolean sourcePane = false, bytecodePane = false, hexPane = false;
/**
* Whoever wrote this function, THANK YOU!
* @param splitter
* @param proportion
* @return
*/
public static JSplitPane setDividerLocation(final JSplitPane splitter,
final double proportion) {
if (splitter.isShowing()) {
if(splitter.getWidth() > 0 && splitter.getHeight() > 0) {
splitter.setDividerLocation(proportion);
}
else {
splitter.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent ce) {
splitter.removeComponentListener(this);
setDividerLocation(splitter, proportion);
}
});
}
}
else {
splitter.addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent e) {
if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 &&
splitter.isShowing()) {
splitter.removeHierarchyListener(this);
setDividerLocation(splitter, proportion);
}
}
});
}
return splitter;
}
private static final long serialVersionUID = -8650495368920680024L;
ArrayList<MethodData> lnData = new ArrayList<MethodData>();
String name;
ClassNode cn;
JSplitPane sp;
JSplitPane sp2;
JEditorPane bytecode = new JEditorPane(), decomp = new JEditorPane();
JScrollPane bcScroll;
public ClassViewer(final String name, final ClassNode cn) {
sourcePane = BytecodeViewer.viewer.sourcePane.isSelected();
bytecodePane = BytecodeViewer.viewer.bytecodePane.isSelected();
hexPane = BytecodeViewer.viewer.hexPane.isSelected();
boolean bytecodeSyntax = BytecodeViewer.viewer.bycSyntax.isSelected();
boolean sourcecodeSyntax = BytecodeViewer.viewer.srcSyntax.isSelected();
this.name = name;
this.cn = cn;
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);
final ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
JHexEditor hex = new JHexEditor(cw.toByteArray());
JScrollPane penis;
if(hexPane) {
penis = new JScrollPane(hex);
} else {
penis = new JScrollPane();
}
penis.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
this.sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, penis);
this.add(sp2, BorderLayout.CENTER);
hex.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
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) {
resetDivider();
}
});
}
public void resetDivider() {
if(!sourcePane) {
sp.setResizeWeight(0);
} else if(!bytecodePane) {
sp.setResizeWeight(1);
} else {
sp.setResizeWeight(0.5);
}
if(hexPane) {
if(!sourcePane && !bytecodePane)
sp2 = setDividerLocation(sp2, 0);
else
sp2 = setDividerLocation(sp2, 0.7);
} else {
sp2 = setDividerLocation(sp2, 1);
}
}
PaneUpdaterThread t;
public void startPaneUpdater() {
t = new PaneUpdaterThread(bytecode, decomp) {
@Override
public void doShit() {
final BytecodeDecompiler bc_dc = new BytecodeDecompiler();
final FernFlowerDecompiler ff_dc = new FernFlowerDecompiler();
final String b = bc_dc.decompileClassNode(cn);
final String s = ff_dc.decompileClassNode(cn);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if(bytecodePane)
p1.setText(b);
if(sourcePane)
p2.setText(s);
p1.setCaretPosition(0);
p2.setCaretPosition(0);
BytecodeViewer.viewer.setIcon(false);
}
});
}
};
t.start();
}
public static class MethodData {
public String name, desc;
public int srcLN, bytecodeLN;
@Override
public boolean equals(final Object o) {
return equals((MethodData) o);
}
public boolean equals(final MethodData md) {
return this.name.equals(md.name) && this.desc.equals(md.desc);
}
public String constructPattern() {
final StringBuffer pattern = new StringBuffer();
pattern.append(name + " *\\(");
final org.objectweb.asm.Type[] types = org.objectweb.asm.Type
.getArgumentTypes(desc);
pattern.append("(.*)");
for (int i = 0; i < types.length; i++) {
final Type type = types[i];
final String clazzName = type.getClassName();
pattern.append(clazzName.substring(clazzName.lastIndexOf(".") + 1)
+ "(.*)");
}
pattern.append("\\) *\\{");
return pattern.toString();
}
}
class WrapEditorKit extends StyledEditorKit {
private static final long serialVersionUID = 1719109651258205346L;
ViewFactory defaultFactory = new WrapColumnFactory();
@Override
public ViewFactory getViewFactory() {
return defaultFactory;
}
}
class WrapColumnFactory implements ViewFactory {
public View create(final Element elem) {
final String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ParagraphElementName))
return new NoWrapParagraphView(elem);
else if (kind.equals(AbstractDocument.SectionElementName))
return new BoxView(elem, View.Y_AXIS);
else if (kind.equals(StyleConstants.ComponentElementName))
return new ComponentView(elem);
else if (kind.equals(StyleConstants.IconElementName))
return new IconView(elem);
}
// default to text display
return new LabelView(elem);
}
}
public class NoWrapParagraphView extends ParagraphView {
public NoWrapParagraphView(final Element elem) {
super(elem);
}
@Override
public void layout(final int width, final int height) {
super.layout(Short.MAX_VALUE, height);
}
@Override
public float getMinimumSpan(final int axis) {
return super.getPreferredSpan(axis);
}
}
}

View file

@ -0,0 +1,54 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JButton;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.JarUtils;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.JTextArea;
public class ExportJar extends JFrame {
public ExportJar(final String jarPath) {
setSize(new Dimension(250, 277));
setResizable(false);
setTitle("Save As Jar..");
JButton btnNewButton = new JButton("Save As Jar..");
btnNewButton.setMaximumSize(new Dimension(999, 23));
btnNewButton.setMinimumSize(new Dimension(999, 23));
btnNewButton.setSize(new Dimension(999, 0));
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane);
JLabel lblMetainfmanifestmf = new JLabel("META-INF/MANIFEST.MF:");
scrollPane.setColumnHeaderView(lblMetainfmanifestmf);
final JTextArea mani = new JTextArea();
mani.setText("Manifest-Version: 1.0\r\nClass-Path: .\r\nMain-Class: ");
scrollPane.setViewportView(mani);
getContentPane().add(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
BytecodeViewer.viewer.setC(true);
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), jarPath, mani.getText());
BytecodeViewer.viewer.setC(false);
dispose();
}
});
this.setLocationRelativeTo(null);
}
private static final long serialVersionUID = -2662514582647810868L;
}

View file

@ -0,0 +1,366 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BorderLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*;
@SuppressWarnings("serial")
public class FileNavigationPane extends VisibleComponent implements FileDrop.Listener {
FileChangeNotifier fcn;
JCheckBox exact = new JCheckBox("Exact");
MyTreeNode treeRoot = new MyTreeNode("Root");
MyTree tree;
public FileNavigationPane(final FileChangeNotifier fcn) {
super("ClassNavigation");
setTitle("Files");
this.fcn = fcn;
getContentPane().setLayout(new BorderLayout());
this.tree = new MyTree(treeRoot);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
this.tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(final TreeSelectionEvent arg0) {
final TreePath path = arg0.getPath();
if (((TreeNode)path.getLastPathComponent()).getChildCount() > 0)
return;
final StringBuffer nameBuffer = new StringBuffer();
for (int i = 1;i < path.getPathCount(); i++) {
nameBuffer.append(path.getPathComponent(i));
if (i < path.getPathCount()-1) {
nameBuffer.append("/");
}
}
final ClassNode cn = BytecodeViewer.getClassNode(nameBuffer.toString());
if (cn != null) {
openClassFileToWorkSpace(nameBuffer.toString(), cn);
}
}
});
final String quickSearchText = "Quick class search";
final JTextField quickSearch = new JTextField(quickSearchText);
quickSearch.setForeground(Color.gray);
quickSearch.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
final String qt = quickSearch.getText();
quickSearch.setText("");
String[] path = null;
if (qt.contains(".")) {
path = qt.split("\\.");
}
else {
path = new String[] {qt};
}
MyTreeNode curNode = treeRoot;
pathLoop:
for (int i = 0;i < path.length; i++) {
final String pathName = path[i];
final boolean isLast = i == path.length-1;
for (int c = 0; c < curNode.getChildCount(); c++) {
final MyTreeNode child = (MyTreeNode) curNode.getChildAt(c);
if(!exact.isSelected()) {
if (((String)child.getUserObject()).toLowerCase().contains(pathName.toLowerCase())) {
curNode = child;
if (isLast) {
final TreePath pathn = new TreePath(curNode.getPath());
tree.setSelectionPath(pathn);
tree.makeVisible(pathn);
tree.scrollPathToVisible(pathn);
System.out.println("Found! " + curNode);
break pathLoop;
}
continue pathLoop;
}
} else {
if (((String)child.getUserObject()).equals(pathName)) {
curNode = child;
if (isLast) {
final TreePath pathn = new TreePath(curNode.getPath());
tree.setSelectionPath(pathn);
tree.makeVisible(pathn);
tree.scrollPathToVisible(pathn);
System.out.println("Found! " + curNode);
break pathLoop;
}
continue pathLoop;
}
}
}
System.out.println("Could not find " + pathName);
break;
}
}
}
});
quickSearch.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent arg0) {
if (quickSearch.getText().equals(quickSearchText)) {
quickSearch.setText("");
quickSearch.setForeground(Color.black);
}
}
@Override
public void focusLost(final FocusEvent arg0) {
if (quickSearch.getText().isEmpty()) {
quickSearch.setText(quickSearchText);
quickSearch.setForeground(Color.gray);
}
}
});
JPanel p2 = new JPanel();
p2.setLayout(new BorderLayout());
p2.add(quickSearch, BorderLayout.NORTH);
p2.add(exact, BorderLayout.SOUTH);
getContentPane().add(p2, BorderLayout.SOUTH);
this.setVisible(true);
new FileDrop(this, this);
}
public void openClassFileToWorkSpace(final String name, final ClassNode node) {
fcn.openClassFile(name, node);
}
@Override
public void filesDropped(final File[] files) {
if (files.length < 1)
return;
BytecodeViewer.openFiles(files);
}
public void updateTree() {
treeRoot.removeAllChildren();
for (final Entry<String, ClassNode> entry : BytecodeViewer.loadedClasses.entrySet()) {
String name = entry.getKey();
final String[] spl = name.split("\\/");
if (spl.length < 2) {
treeRoot.add(new MyTreeNode(name));
}
else {
MyTreeNode parent = treeRoot;
for (final String s : spl) {
MyTreeNode child = null;
for (int i = 0;i < parent.getChildCount(); i++) {
if (((MyTreeNode) parent.getChildAt(i)).getUserObject().equals(s)) {
child = (MyTreeNode) parent.getChildAt(i);
break;
}
}
if (child == null) {
child = new MyTreeNode(s);
parent.add(child);
}
parent = child;
}
}
}
treeRoot.sort();
tree.expandPath(new TreePath(tree.getModel().getRoot()));
tree.updateUI();
//expandAll(tree, true);
}
// If expand is true, expands all nodes in the tree.
// Otherwise, collapses all nodes in the tree.
public void expandAll(final JTree tree, final boolean expand) {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
@SuppressWarnings("rawtypes")
private void expandAll(final JTree tree, final TreePath parent,
final boolean expand) {
// Traverse children
final TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (final Enumeration e = node.children(); e.hasMoreElements();) {
final TreeNode n = (TreeNode) e.nextElement();
final TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
public class MyTree extends JTree {
private static final long serialVersionUID = -2355167326094772096L;
DefaultMutableTreeNode treeRoot;
public MyTree(final DefaultMutableTreeNode treeRoot) {
super(treeRoot);
this.treeRoot = treeRoot;
}
StringMetrics m = null;
@Override
public void paint(final Graphics g) {
super.paint(g);
if(m == null) {
m = new StringMetrics((Graphics2D)g);
}
if (treeRoot.getChildCount() < 1) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.white);
String s = "Drag class/jar here";
g.drawString(s, ((int)((getWidth()/2)-(m.getWidth(s)/2))), getHeight()/2);
}
}
}
public class MyTreeNode extends DefaultMutableTreeNode {
private static final long serialVersionUID = -8817777566176729571L;
public MyTreeNode(final Object o) {
super(o);
}
@Override
public void insert(final MutableTreeNode newChild, final int childIndex) {
super.insert(newChild, childIndex);
}
public void sort() {
recursiveSort(this);
}
@SuppressWarnings("unchecked")
private void recursiveSort(final MyTreeNode node) {
Collections.sort(node.children, nodeComparator);
final Iterator<MyTreeNode> it = node.children.iterator();
while (it.hasNext()) {
final MyTreeNode nextNode = it.next();
if (nextNode.getChildCount() > 0) {
recursiveSort(nextNode);
}
}
}
protected Comparator<MyTreeNode> nodeComparator = new Comparator<MyTreeNode> () {
@Override
public int compare(final MyTreeNode o1, final MyTreeNode o2) {
// To make sure nodes with children are always on top
final int firstOffset = o1.getChildCount() > 0 ? -1000 : 0;
final int secondOffset = o2.getChildCount() > 0 ? 1000 : 0;
return o1.toString().compareToIgnoreCase(o2.toString()) + firstOffset + secondOffset;
}
@Override
public boolean equals(final Object obj) {
return false;
}
@Override
public int hashCode() {
final int hash = 7;
return hash;
}
};
}
/**
*
* @author http://stackoverflow.com/a/18450804
*
*/
class StringMetrics {
Font font;
FontRenderContext context;
public StringMetrics(Graphics2D g2) {
font = g2.getFont();
context = g2.getFontRenderContext();
}
Rectangle2D getBounds(String message) {
return font.getStringBounds(message, context);
}
double getWidth(String message) {
Rectangle2D bounds = getBounds(message);
return bounds.getWidth();
}
double getHeight(String message) {
Rectangle2D bounds = getBounds(message);
return bounds.getHeight();
}
}
public void resetWorkspace() {
treeRoot.removeAllChildren();
tree.repaint();
tree.updateUI();
}
}

View file

@ -0,0 +1,584 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.BoxLayout;
import javax.swing.JMenuBar;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import javax.swing.JScrollPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import javax.swing.JCheckBoxMenuItem;
import org.apache.commons.codec.binary.Base64;
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.java.FernFlowerDecompiler;
import the.bytecode.club.bytecodeviewer.plugins.AllatoriStringDecrypter;
import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
import the.bytecode.club.bytecodeviewer.plugins.ShowAllStrings;
import the.bytecode.club.bytecodeviewer.plugins.ShowMainMethods;
import the.bytecode.club.bytecodeviewer.plugins.ZKMStringDecrypter;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
public class MainViewerGUI extends JFrame implements FileChangeNotifier {
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>();
public JCheckBoxMenuItem rbr = new JCheckBoxMenuItem("Hide bridge methods");
public JCheckBoxMenuItem rsy = new JCheckBoxMenuItem("Hide synthetic class members");
public JCheckBoxMenuItem din = new JCheckBoxMenuItem("Decompile inner classes");
public JCheckBoxMenuItem dc4 = new JCheckBoxMenuItem("Collapse 1.4 class references");
public JCheckBoxMenuItem das = new JCheckBoxMenuItem("Decompile assertions");
public JCheckBoxMenuItem hes = new JCheckBoxMenuItem("Hide empty super invocation");
public JCheckBoxMenuItem hdc = new JCheckBoxMenuItem("Hide empty default constructor");
public JCheckBoxMenuItem dgs = new JCheckBoxMenuItem("Decompile generic signatures");
public JCheckBoxMenuItem ner = new JCheckBoxMenuItem("Assume return not throwing exceptions");
public JCheckBoxMenuItem den = new JCheckBoxMenuItem("Decompile enumerations");
public JCheckBoxMenuItem rgn = new JCheckBoxMenuItem("Remove getClass() invocation");
public JCheckBoxMenuItem bto = new JCheckBoxMenuItem("Interpret int 1 as boolean true");
public JCheckBoxMenuItem nns = new JCheckBoxMenuItem("Allow for not set synthetic attribute");
public JCheckBoxMenuItem uto = new JCheckBoxMenuItem("Consider nameless types as java.lang.Object");
public JCheckBoxMenuItem udv = new JCheckBoxMenuItem("Reconstruct variable names from debug info");
public JCheckBoxMenuItem rer = new JCheckBoxMenuItem("Remove empty exception ranges");
public JCheckBoxMenuItem fdi = new JCheckBoxMenuItem("Deinline finally structures");
public JCheckBoxMenuItem asc = new JCheckBoxMenuItem("Allow only ASCII characters in strings");
private final JSeparator separator_2 = new JSeparator();
public JCheckBoxMenuItem srcSyntax = new JCheckBoxMenuItem("Source Code Syntax");
public JCheckBoxMenuItem bycSyntax = new JCheckBoxMenuItem("Bytecode Syntax");
JCheckBoxMenuItem sourcePane = new JCheckBoxMenuItem("Source Pane");
JCheckBoxMenuItem bytecodePane = new JCheckBoxMenuItem("Bytecode Pane");
JCheckBoxMenuItem hexPane = new JCheckBoxMenuItem("Hex Pane");
private final JMenuItem mntmNewWorkspace = new JMenuItem("New Workspace");
public JMenu mnRecentFiles = new JMenu("Recent Files");
private final JMenuItem mntmNewMenuItem = new JMenuItem("Save Java Files As..");
private final JMenuItem mntmAbout = new JMenuItem("About");
private AboutWindow aboutWindow = new AboutWindow();
private final JSeparator separator_3 = new JSeparator();
private final JMenu mnNewMenu_1 = new JMenu("Plugins");
private final JMenuItem mntmStartExternalPlugin = new JMenuItem("Open Plugin..");
private final JSeparator separator_4 = new JSeparator();
public JMenu mnRecentPlugins = new JMenu("Recent Plugins");
private final JSeparator separator_5 = new JSeparator();
private final JMenuItem mntmStartZkmString = new JMenuItem("ZKM String Decrypter");
private final JMenuItem mntmNewMenuItem_1 = new JMenuItem("Malicious Code Scanner");
private final JMenuItem mntmNewMenuItem_2 = new JMenuItem("Allatori String Decrypter");
private final JMenuItem mntmShowAllStrings = new JMenuItem("Show All Strings");
private final JMenuItem mntmShowMainMethods = new JMenuItem("Show Main Methods");
private final JMenuItem mntmNewMenuItem_3 = new JMenuItem("Save As Jar..");
private JMenuBar menuBar = new JMenuBar();
public JCheckBoxMenuItem chckbxmntmNewCheckItem = new JCheckBoxMenuItem("Allow only ASCII characters in strings");
private final JMenuItem mntmReplaceStrings = new JMenuItem("Replace Strings");
private final JMenuItem mntmNewMenuItem_4 = new JMenuItem("");
public void setC(boolean busy) {
if(busy) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
for(Component c : this.getComponents())
c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
sp1.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
sp2.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
for(VisibleComponent c : rfComps) {
c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
if(c instanceof WorkPane) {
WorkPane w = (WorkPane)c;
for(Component c2 : w.tabs.getComponents())
c2.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}
} else {
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
for(Component c : this.getComponents())
c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
sp1.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
sp2.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
for(VisibleComponent c : rfComps) {
c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if(c instanceof WorkPane) {
WorkPane w = (WorkPane)c;
for(Component c2 : w.tabs.getComponents())
c2.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
}
public void setIcon(final boolean busy) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if(busy) {
try {
mntmNewMenuItem_4.setIcon(new ImageIcon(getClass().getResource("/resources/1.gif")));
} catch(NullPointerException e) {
mntmNewMenuItem_4.setIcon(new ImageIcon(b642IMG("R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7"), ""));
}
} else
mntmNewMenuItem_4.setIcon(null);
mntmNewMenuItem_4.updateUI();
}
});
}
/**
* Decodes a Base64 String as a BufferedImage
*/
public BufferedImage b642IMG(String imageString) {
BufferedImage image = null;
byte[] imageByte;
try {
imageByte = Base64.decodeBase64(imageString);
ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
image = ImageIO.read(bis);
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
public MainViewerGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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);
bycSyntax.setSelected(true);
debugHelpers.setSelected(true);
sourcePane.setSelected(true);
bytecodePane.setSelected(true);
setJMenuBar(menuBar);
JMenu mnNewMenu = new JMenu("File");
menuBar.add(mnNewMenu);
final JFrame This = this;
mntmNewWorkspace.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
BytecodeViewer.resetWorkSpace();
}
});
JMenuItem mntmLoadJar = new JMenuItem("Add..");
mntmLoadJar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new JarZipClassFileFilter());
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showOpenDialog(This);
if (returnVal == JFileChooser.APPROVE_OPTION)
try {
BytecodeViewer.viewer.setC(true);
BytecodeViewer.openFiles(new File[]{fc.getSelectedFile()});
BytecodeViewer.viewer.setC(false);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
mnNewMenu.add(mntmLoadJar);
mnNewMenu.add(mntmNewWorkspace);
JMenuItem mntmSave = new JMenuItem("Save Files As..");
mntmSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new ZipFileFilter());
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
BytecodeViewer.viewer.setC(true);
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
BytecodeViewer.viewer.setC(false);
}
}
});
mnNewMenu.add(separator_3);
mntmNewMenuItem_3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new JarFileFilter());
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
new ExportJar(file.getAbsolutePath()).setVisible(true);
}
}
});
mnNewMenu.add(mntmNewMenuItem_3);
mnNewMenu.add(mntmSave);
mntmNewMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new ZipFileFilter());
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
BytecodeViewer.viewer.setC(true);
FernFlowerDecompiler d = new FernFlowerDecompiler();
d.decompileToZip(file.getAbsolutePath());
BytecodeViewer.viewer.setC(false);
}
}
});
mnNewMenu.add(mntmNewMenuItem);
JSeparator separator = new JSeparator();
mnNewMenu.add(separator);
mnNewMenu.add(mnRecentFiles);
JSeparator separator_1 = new JSeparator();
mnNewMenu.add(separator_1);
mntmAbout.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
aboutWindow.setVisible(true);
}
});
mnNewMenu.add(mntmAbout);
JMenuItem mntmExit = new JMenuItem("Exit");
mnNewMenu.add(mntmExit);
JMenu mnView = new JMenu("View");
menuBar.add(mnView);
mnView.add(sourcePane);
mnView.add(bytecodePane);
mnView.add(hexPane);
mnView.add(separator_2);
mnView.add(srcSyntax);
mnView.add(bycSyntax);
JMenu mnDecompilerSettings = new JMenu("Java Decompiler");
menuBar.add(mnDecompilerSettings);
mnDecompilerSettings.add(rbr);
mnDecompilerSettings.add(rsy);
mnDecompilerSettings.add(din);
mnDecompilerSettings.add(dc4);
mnDecompilerSettings.add(das);
mnDecompilerSettings.add(hes);
mnDecompilerSettings.add(hdc);
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);
JMenu mnBytecodeDecompilerSettings = new JMenu("Bytecode Decompiler");
menuBar.add(mnBytecodeDecompilerSettings);
mnBytecodeDecompilerSettings.add(debugHelpers);
mnBytecodeDecompilerSettings.add(debugInstructions);
mnBytecodeDecompilerSettings.add(chckbxmntmNewCheckItem);
menuBar.add(mnNewMenu_1);
mnNewMenu_1.add(mntmStartExternalPlugin);
mnNewMenu_1.add(separator_4);
mnNewMenu_1.add(mnRecentPlugins);
mnNewMenu_1.add(separator_5);
mnNewMenu_1.add(mntmNewMenuItem_1);
mnNewMenu_1.add(mntmShowMainMethods);
mnNewMenu_1.add(mntmShowAllStrings);
mntmReplaceStrings.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(!BytecodeViewer.loadedClasses.isEmpty())
new ReplaceStringsOptions().setVisible(true);
else
System.out.println("Plugin not ran, put some classes in first.");
}
});
mnNewMenu_1.add(mntmReplaceStrings);
mnNewMenu_1.add(mntmNewMenuItem_2);
mnNewMenu_1.add(mntmStartZkmString);
menuBar.add(mntmNewMenuItem_4);
mntmStartExternalPlugin.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new GroovyPythonRubyFileFilter());
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showOpenDialog(This);
if (returnVal == JFileChooser.APPROVE_OPTION)
try {
BytecodeViewer.viewer.setC(true);
BytecodeViewer.startPlugin(fc.getSelectedFile());
BytecodeViewer.viewer.setC(false);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
mntmStartZkmString.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PluginManager.runPlugin(new ZKMStringDecrypter());
}
});
mntmNewMenuItem_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PluginManager.runPlugin(new AllatoriStringDecrypter());
}
});
mntmNewMenuItem_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!BytecodeViewer.loadedClasses.isEmpty())
new MaliciousCodeScannerOptions().setVisible(true);
else
System.out.println("Plugin not ran, put some classes in first.");
}
});
mntmShowAllStrings.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PluginManager.runPlugin(new ShowAllStrings());
}
});
mntmShowMainMethods.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PluginManager.runPlugin(new ShowMainMethods());
}
});
setSize(new Dimension(800, 400));
setTitle("Bytecode Viewer - http://the.bytecode.club - @Konloch");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
JScrollPane scrollPane = new JScrollPane();
scrollPane.setMaximumSize(new Dimension(12000, 32767));
//scrollPane.setViewportView(tree);
FileNavigationPane cn = new FileNavigationPane(this);
cn.setMinimumSize(new Dimension(200, 50));
//panel.add(cn);
SearchingPane s = new SearchingPane(this);
s.setPreferredSize(new Dimension(200, 50));
s.setMinimumSize(new Dimension(200, 50));
s.setMaximumSize(new Dimension(200, 2147483647));
//panel.add(s);
sp1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, cn, s);
//panel.add(sp1);
cn.setPreferredSize(new Dimension(200, 50));
cn.setMaximumSize(new Dimension(200, 2147483647));
WorkPane cv = new WorkPane(this);
sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp1, cv);
getContentPane().add(sp2);
sp2.setResizeWeight(0.05);
sp1.setResizeWeight(0.5);
rfComps.add(cn);
rfComps.add(s);
rfComps.add(cv);
this.setLocationRelativeTo(null);
}
@Override
public void openClassFile(final String name, final ClassNode cn) {
for (final VisibleComponent vc : rfComps) {
vc.openClassFile(name, cn);
}
}
@SuppressWarnings("unchecked")
public static <T> T getComponent(final Class<T> clazz) {
for (final VisibleComponent vc : rfComps) {
if (vc.getClass() == clazz)
return (T) vc;
}
return null;
}
public class GroovyPythonRubyFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
String extension = getExtension(f);
if (extension != null)
return (extension.equals("gy") || extension.equals("groovy") ||
extension.equals("py") || extension.equals("python") ||
extension.equals("rb") || extension.equals("ruby"));
return false;
}
@Override
public String getDescription() {
return "Groovy, Python or Ruby plugins.";
}
public String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1)
ext = s.substring(i+1).toLowerCase();
return ext;
}
}
public class JarZipClassFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
String extension = getExtension(f);
if (extension != null)
return (extension.equals("jar") || extension.equals("zip") || extension.equals("class"));
return false;
}
@Override
public String getDescription() {
return "Class Files or Zip/Jar Archives";
}
public String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1)
ext = s.substring(i+1).toLowerCase();
return ext;
}
}
public class ZipFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
String extension = getExtension(f);
if (extension != null)
return (extension.equals("zip"));
return false;
}
@Override
public String getDescription() {
return "Zip Archives";
}
public String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1)
ext = s.substring(i+1).toLowerCase();
return ext;
}
}
public class JarFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
String extension = getExtension(f);
if (extension != null)
return (extension.equals("jar"));
return false;
}
@Override
public String getDescription() {
return "Jar Archives";
}
public String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1)
ext = s.substring(i+1).toLowerCase();
return ext;
}
}
}

View file

@ -0,0 +1,78 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JCheckBox;
import javax.swing.JButton;
import the.bytecode.club.bytecodeviewer.plugins.MaliciousCodeScanner;
import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MaliciousCodeScannerOptions extends JFrame {
public MaliciousCodeScannerOptions() {
setSize(new Dimension(250, 277));
setResizable(false);
setTitle("Malicious Code Scanner Options");
getContentPane().setLayout(null);
final JCheckBox chckbxJavalangreflection = new JCheckBox("java/lang/reflection");
chckbxJavalangreflection.setSelected(true);
chckbxJavalangreflection.setBounds(6, 7, 232, 23);
getContentPane().add(chckbxJavalangreflection);
final JCheckBox chckbxJavanet = new JCheckBox("java/net");
chckbxJavanet.setSelected(true);
chckbxJavanet.setBounds(6, 59, 232, 23);
getContentPane().add(chckbxJavanet);
final JCheckBox chckbxJavaio = new JCheckBox("java/io");
chckbxJavaio.setBounds(6, 85, 232, 23);
getContentPane().add(chckbxJavaio);
final JCheckBox chckbxJavalangruntime = new JCheckBox("java/lang/Runtime");
chckbxJavalangruntime.setSelected(true);
chckbxJavalangruntime.setBounds(6, 33, 232, 23);
getContentPane().add(chckbxJavalangruntime);
final JCheckBox chckbxLdcContainswww = new JCheckBox("LDC contains 'www.'");
chckbxLdcContainswww.setSelected(true);
chckbxLdcContainswww.setBounds(6, 111, 232, 23);
getContentPane().add(chckbxLdcContainswww);
final JCheckBox chckbxLdcContainshttp = new JCheckBox("LDC contains 'http://'");
chckbxLdcContainshttp.setSelected(true);
chckbxLdcContainshttp.setBounds(6, 137, 232, 23);
getContentPane().add(chckbxLdcContainshttp);
final JCheckBox chckbxLdcContainshttps = new JCheckBox("LDC contains 'https://'");
chckbxLdcContainshttps.setSelected(true);
chckbxLdcContainshttps.setBounds(6, 163, 232, 23);
getContentPane().add(chckbxLdcContainshttps);
final JCheckBox chckbxLdcMatchesIp = new JCheckBox("LDC matches IP regex");
chckbxLdcMatchesIp.setSelected(true);
chckbxLdcMatchesIp.setBounds(6, 189, 232, 23);
getContentPane().add(chckbxLdcMatchesIp);
JButton btnNewButton = new JButton("Start Scanning");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
PluginManager.runPlugin(new MaliciousCodeScanner(chckbxJavalangreflection.isSelected(),
chckbxJavalangruntime.isSelected(), chckbxJavanet.isSelected(), chckbxJavaio.isSelected(),
chckbxLdcContainswww.isSelected(), chckbxLdcContainshttp.isSelected(), chckbxLdcContainshttps.isSelected(),
chckbxLdcMatchesIp.isSelected()));
dispose();
}
});
btnNewButton.setBounds(6, 219, 232, 23);
getContentPane().add(btnNewButton);
this.setLocationRelativeTo(null);
}
private static final long serialVersionUID = -2662514582647810868L;
}

View file

@ -0,0 +1,28 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JEditorPane;
/**
* Allows us to run a background thread then update the two JEditorPanes
*
* @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();
@Override
public void run() {
doShit();
}
}

View file

@ -0,0 +1,73 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
import the.bytecode.club.bytecodeviewer.plugins.ReplaceStrings;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JCheckBox;
public class ReplaceStringsOptions extends JFrame {
public ReplaceStringsOptions() {
setSize(new Dimension(250, 176));
setResizable(false);
setTitle("Replace Strings");
getContentPane().setLayout(null);
JButton btnNewButton = new JButton("Start Replacing");
btnNewButton.setBounds(6, 115, 232, 23);
getContentPane().add(btnNewButton);
JLabel lblNewLabel = new JLabel("Original LDC:");
lblNewLabel.setBounds(6, 40, 67, 14);
getContentPane().add(lblNewLabel);
textField = new JTextField();
textField.setBounds(80, 37, 158, 20);
getContentPane().add(textField);
textField.setColumns(10);
JLabel lblNewLabel_1 = new JLabel("New LDC:");
lblNewLabel_1.setBounds(6, 65, 77, 14);
getContentPane().add(lblNewLabel_1);
textField_1 = new JTextField();
textField_1.setColumns(10);
textField_1.setBounds(80, 62, 158, 20);
getContentPane().add(textField_1);
JLabel lblNewLabel_2 = new JLabel("Class:");
lblNewLabel_2.setBounds(6, 90, 46, 14);
getContentPane().add(lblNewLabel_2);
textField_2 = new JTextField();
textField_2.setToolTipText("* will search all classes");
textField_2.setText("*");
textField_2.setBounds(80, 87, 158, 20);
getContentPane().add(textField_2);
textField_2.setColumns(10);
final JCheckBox chckbxNewCheckBox = new JCheckBox("Replace All Contains");
chckbxNewCheckBox.setToolTipText("If it's unticked, it will check if the string equals, if its ticked it will check if it contains, then replace the original LDC part of the string.");
chckbxNewCheckBox.setBounds(6, 7, 232, 23);
getContentPane().add(chckbxNewCheckBox);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
PluginManager.runPlugin(new ReplaceStrings(textField.getText(), textField_1.getText(), textField_2.getText(), chckbxNewCheckBox.isSelected()));
dispose();
}
});
this.setLocationRelativeTo(null);
}
private static final long serialVersionUID = -2662514582647810868L;
private JTextField textField;
private JTextField textField_1;
private JTextField textField_2;
}

View file

@ -0,0 +1,217 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.searching.*;
/**
* A pane dedicating to searching the loaded files.
*
* @author Konloch
* @author WaterWolf
*
*/
@SuppressWarnings("rawtypes")
public class SearchingPane extends VisibleComponent {
private static final long serialVersionUID = -1098524689236993932L;
FileChangeNotifier fcn;
JCheckBox exact = new JCheckBox("Exact");
DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Root");
JTree tree;
SearchType searchType = null;
JComboBox searchRadiusBox;
public JButton search = new JButton("Search");
BackgroundSearchThread t = new BackgroundSearchThread(true) {
@Override
public void doSearch() {
// empty
}
};
@SuppressWarnings("unchecked")
public SearchingPane(final FileChangeNotifier fcn) {
super("Search");
this.fcn = fcn;
final JPanel optionPanel = new JPanel(new BorderLayout());
final JPanel searchRadiusOpt = new JPanel(new BorderLayout());
final JPanel searchOpts = new JPanel(new GridLayout(2, 1));
searchRadiusOpt.add(new JLabel("Search from "), BorderLayout.WEST);
DefaultComboBoxModel model = new DefaultComboBoxModel();
for (final SearchRadius st : SearchRadius.values()) {
model.addElement(st);
}
searchRadiusBox = new JComboBox(model);
searchRadiusOpt.add(searchRadiusBox, BorderLayout.CENTER);
searchOpts.add(searchRadiusOpt);
model = new DefaultComboBoxModel();
for (final SearchType st : SearchType.values()) {
model.addElement(st);
}
final JComboBox typeBox = new JComboBox(model);
final JPanel searchOptPanel = new JPanel();
final ItemListener il = new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent arg0) {
searchOptPanel.removeAll();
searchType = (SearchType) typeBox.getSelectedItem();
searchOptPanel.add(searchType.details.getPanel());
searchOptPanel.revalidate();
searchOptPanel.repaint();
}
};
typeBox.addItemListener(il);
typeBox.setSelectedItem(SearchType.LDC);
il.itemStateChanged(null);
searchOpts.add(typeBox);
optionPanel.add(searchOpts, BorderLayout.NORTH);
JPanel p2 = new JPanel();
p2.setLayout(new BorderLayout());
p2.add(searchOptPanel, BorderLayout.NORTH);
p2.add(exact, BorderLayout.SOUTH);
optionPanel.add(p2, BorderLayout.CENTER);
search.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
treeRoot.removeAllChildren();
searchType = (SearchType) typeBox.getSelectedItem();
final SearchRadius radius = (SearchRadius) searchRadiusBox.getSelectedItem();
final SearchResultNotifier srn = new SearchResultNotifier() {
@Override
public void notifyOfResult(final ClassNode clazz,
final MethodNode method, final AbstractInsnNode insn) {
treeRoot.add(new DefaultMutableTreeNode(clazz.name + "." + method.name));
}
};
if (radius == SearchRadius.All_Classes) {
if(t.finished) {
t = new BackgroundSearchThread() {
@Override
public void doSearch() {
for (ClassNode cln : BytecodeViewer.getLoadedClasses())
searchType.details.search(cln, srn, exact.isSelected());
MainViewerGUI.getComponent(SearchingPane.class).search.setEnabled(true);
MainViewerGUI.getComponent(SearchingPane.class).search.setText("Search");
tree.expandPath(new TreePath(tree.getModel().getRoot()));
tree.updateUI();
}
};
MainViewerGUI.getComponent(SearchingPane.class).search.setEnabled(false);
MainViewerGUI.getComponent(SearchingPane.class).search.setText("Searching, please wait..");
t.start();
} else { //this should really never be called.
BytecodeViewer.showMessage("You currently have a search performing in the background, please wait for that to finish.");
}
}
else if (radius == SearchRadius.Current_Class) {
final ClassViewer cv = MainViewerGUI.getComponent(WorkPane.class).getCurrentClass();
if (cv != null) {
searchType.details.search(cv.cn, srn, exact.isSelected());
}
}
}
});
optionPanel.add(search, BorderLayout.SOUTH);
this.tree = new JTree(treeRoot);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(optionPanel, BorderLayout.NORTH);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
this.tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(final TreeSelectionEvent arg0) {
final TreePath path = arg0.getPath();
if ( ((TreeNode)path.getLastPathComponent()).getChildCount() > 0)
return;
final String clazzName = path.getLastPathComponent().toString();
final ClassNode fN = BytecodeViewer.getClassNode(clazzName);
if (fN != null) {
MainViewerGUI.getComponent(FileNavigationPane.class).openClassFileToWorkSpace(clazzName, fN);
}
}
});
this.setVisible(true);
}
public enum SearchType {
LDC (new LDCSearch()),
Regex (new RegexSearch()),
MethodCall (new MethodCallSearch()),
FieldCall (new FieldCallSearch());
public final SearchTypeDetails details;
SearchType(final SearchTypeDetails details) {
this.details = details;
}
}
public enum SearchRadius {
All_Classes,
Current_Class;
}
public void resetWorkspace() {
treeRoot.removeAllChildren();
tree.updateUI();
}
}

View file

@ -0,0 +1,186 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;
/**
* Component to be used as tabComponent;
* Contains a JLabel to show the text and
* a JButton to close the tab it belongs to
*
* @author Konloch
* @author WaterWolf
*
*/
public class TabbedPane extends JPanel {
private static final long serialVersionUID = -4774885688297538774L;
private final JTabbedPane pane;
final JButton button = new TabButton();
public TabbedPane(final JTabbedPane pane) {
//unset default FlowLayout' gaps
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
if (pane == null)
throw new NullPointerException("TabbedPane is null");
this.pane = pane;
setOpaque(false);
//make JLabel read titles from JTabbedPane
final JLabel label = new JLabel() {
private static final long serialVersionUID = -5511025206527893360L;
@Override
public String getText() {
final int i = pane.indexOfTabComponent(TabbedPane.this);
if (i != -1)
return pane.getTitleAt(i);
return null;
}
};
add(label);
//add more space between the label and the button
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
//tab button
add(button);
//add more space to the top of the component
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
pane.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent arg0) {
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent arg0) {
}
@Override
public void mouseReleased(MouseEvent e) {
//final Component component = e.getComponent();
// if(component instanceof JTabbedPane) {
if(e.getModifiers() == 8) {
for(Component c : pane.getComponents()) {
if(c.getMousePosition() != null && c instanceof JPanel) {
System.out.println("gotten here...");
/*BytecodeViewer.viewer.getComponent(WorkPane.class).tabs.remove(component);
final int i = BytecodeViewer.viewer.getComponent(WorkPane.class).tabs.indexOfTabComponent(c);
if (i != -1)
BytecodeViewer.viewer.getComponent(WorkPane.class).tabs.remove(i);
BytecodeViewer.viewer.getComponent(WorkPane.class).tabs.updateUI();
BytecodeViewer.viewer.getComponent(WorkPane.class).tabs.repaint();
*////if(c.getComponentAt((int)c.getMousePosition().getX(), (int)c.getMousePosition().getY())button.)
// button.doClick();
}
//System.out.println(c.getMousePosition() + ":" + e.getX());
//System.out.println(c.getWidth() + ":" + e.getX());
//if( e.getX() >= &&
// e.getY())
// button.doClick();
}
}
}
//}
});
}
private class TabButton extends JButton implements ActionListener {
private static final long serialVersionUID = -4492967978286454159L;
public TabButton() {
final int size = 17;
setPreferredSize(new Dimension(size, size));
setToolTipText("Close this tab");
//Make the button looks the same for all Laf's
setUI(new BasicButtonUI());
//Make it transparent
setContentAreaFilled(false);
//No need to be focusable
setFocusable(false);
setBorder(BorderFactory.createEtchedBorder());
setBorderPainted(false);
//Making nice rollover effect
//we use the same listener for all buttons
addMouseListener(buttonMouseListener);
setRolloverEnabled(true);
//Close the proper tab by clicking the button
addActionListener(this);
}
public void actionPerformed(final ActionEvent e) {
final int i = pane.indexOfTabComponent(TabbedPane.this);
if (i != -1) {
pane.remove(i);
}
}
//we don't want to update UI for this button
@Override
public void updateUI() {
}
//paint the cross
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g.create();
//shift the image for pressed buttons
if (getModel().isPressed()) {
g2.translate(1, 1);
}
g2.setStroke(new BasicStroke(2));
g2.setColor(Color.BLACK);
if (getModel().isRollover()) {
g2.setColor(Color.MAGENTA);
}
final int delta = 6;
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
g2.dispose();
}
}
private final static MouseListener buttonMouseListener = new MouseAdapter() {
@Override
public void mouseEntered(final MouseEvent e) {
final Component component = e.getComponent();
if (component instanceof AbstractButton) {
final AbstractButton button = (AbstractButton) component;
button.setBorderPainted(true);
}
}
@Override
public void mouseExited(final MouseEvent e) {
final Component component = e.getComponent();
if (component instanceof AbstractButton) {
final AbstractButton button = (AbstractButton) component;
button.setBorderPainted(false);
}
}
};
}

View file

@ -0,0 +1,35 @@
package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JInternalFrame;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
/**
* Used to represent all the panes inside of Bytecode Viewer, this is temp code
* that was included from porting in J-RET, this needs to be re-written.
*
* @author Konloch
* @author WaterWolf
*
*/
public abstract class VisibleComponent extends JInternalFrame implements FileChangeNotifier {
private static final long serialVersionUID = -6453413772343643526L;
public VisibleComponent(final String title) {
super(title, false, false, false, false);
this.setFrameIcon(null);
}
@SuppressWarnings("unused")
private VisibleComponent() { //because we want to enforce the title argument
}
@Override
public void openClassFile(final String name, final ClassNode cn) {}
}

View file

@ -0,0 +1,156 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.lang.reflect.Field;
import java.util.HashMap;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import jsyntaxpane.DefaultSyntaxKit;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
/**
* The pane that contains all of the classes as tabs.
*
* @author Konloch
* @author WaterWolf
*
*/
public class WorkPane extends VisibleComponent implements ActionListener {
private static final long serialVersionUID = 6542337997679487946L;
FileChangeNotifier fcn;
JTabbedPane tabs;
JPanel buttonPanel;
JButton refreshClass;
HashMap<String, Integer> workingOn = new HashMap<String, Integer>();
public static int SyntaxFontHeight = 12;
public WorkPane(final FileChangeNotifier fcn) {
super("WorkPanel");
setTitle("Work Space");
DefaultSyntaxKit.initKit();
Font defFont = null;
try {
final Field defFontField = DefaultSyntaxKit.class.getDeclaredField("DEFAULT_FONT");
defFontField.setAccessible(true);
defFont = (Font) defFontField.get(null);
} catch (final Exception e) {
e.printStackTrace();
}
SyntaxFontHeight = defFont.getSize();
this.tabs = new JTabbedPane();
this.fcn = fcn;
getContentPane().setLayout(new BorderLayout());
getContentPane().add(tabs, BorderLayout.CENTER);
buttonPanel = new JPanel(new FlowLayout());
refreshClass = new JButton("Refresh class");
refreshClass.addActionListener(this);
buttonPanel.add(refreshClass);
buttonPanel.setVisible(false);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
tabs.addContainerListener(new ContainerListener() {
@Override
public void componentAdded(final ContainerEvent e) {
}
@Override
public void componentRemoved(final ContainerEvent e) {
final Component c = e.getChild();
if (c instanceof ClassViewer) {
workingOn.remove(((ClassViewer)c).name);
}
}
});
tabs.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent arg0) {
buttonPanel.setVisible(tabs.getSelectedIndex() != -1);
}
});
this.setVisible(true);
}
int tabCount = 0;
public void addWorkingFile(final String name, final ClassNode cn) {
if(!BytecodeViewer.viewer.hexPane.isSelected() &&
!BytecodeViewer.viewer.sourcePane.isSelected() &&
!BytecodeViewer.viewer.bytecodePane.isSelected()) {
BytecodeViewer.showMessage("You currently have no viewing panes selected.");
return;
}
if (!workingOn.containsKey(name)) {
final Component tabComp = new ClassViewer(name, cn);
tabs.add(tabComp);
final int tabCount = tabs.indexOfComponent(tabComp);
workingOn.put(name, tabCount);
tabs.setTabComponentAt(tabCount, new TabbedPane(tabs));
tabs.setSelectedIndex(tabCount);
} else {
tabs.setSelectedIndex(workingOn.get(name));
}
}
@Override
public void openClassFile(final String name, final ClassNode cn) {
addWorkingFile(name, cn);
}
public ClassViewer getCurrentClass() {
return (ClassViewer) tabs.getSelectedComponent();
}
@Override
public void actionPerformed(final ActionEvent arg0) {
final JButton src = (JButton) arg0.getSource();
if (src == refreshClass) {
final Component tabComp = tabs.getSelectedComponent();
if (tabComp != null) {
BytecodeViewer.viewer.setC(true);
((ClassViewer)tabComp).startPaneUpdater();
BytecodeViewer.viewer.setC(false);
}
}
}
public void resetWorkspace() {
tabs.removeAll();
tabs.updateUI();
}
}

View file

@ -0,0 +1,23 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
/**
* Coming soon.
*
* @author Konloch
*
*/
public class AllatoriStringDecrypter extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
for(ClassNode classNode : classNodeList) {
}
}
}

View file

@ -0,0 +1,88 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
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.
*
* @author Konloch
* @author WaterWolf
*
*/
public class MaliciousCodeScanner extends Plugin {
public boolean
ORE,
ONE,
ORU,
OIO,
LWW,
LHT,
LHS,
LIP;
public MaliciousCodeScanner(boolean reflect, boolean runtime, boolean net, boolean io,
boolean www, boolean http, boolean https, boolean ip) {
ORE = reflect;
ONE = net;
ORU = runtime;
OIO = io;
LWW = www;
LHT = http;
LHS = https;
LIP = ip;
}
@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;
InsnList iList = m.instructions;
for(AbstractInsnNode a : iList.toArray()) {
if (a instanceof MethodInsnNode) {
final MethodInsnNode min = (MethodInsnNode) a;
if ((ORE && min.owner.startsWith("java/lang/reflect")) ||
(ONE && min.owner.startsWith("java/net")) ||
(ORU && min.owner.equals("java/lang/Runtime")) ||
(OIO && min.owner.startsWith("java/io")))
{
frame.appendText("Found Method call to " + min.owner + "." + min.name + "(" + min.desc + ") at " + classNode.name + "." +m.name+"("+m.desc+")");
}
}
if (a instanceof LdcInsnNode) {
if(((LdcInsnNode)a).cst instanceof String) {
final String s = (String) ((LdcInsnNode)a).cst;
if ((LWW && s.contains("www.")) ||
(LHT && s.contains("http://")) ||
(LHS && s.contains("https://")) ||
(ORE && s.contains("java/lang/Runtime")) ||
(ORE && s.contains("java.lang.Runtime")) ||
(LIP && s.matches("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b")))
{
frame.appendText("Found LDC \"" + s + "\" at " + classNode.name + "." +m.name+"("+m.desc+")");
}
}
}
}
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}
}

View file

@ -0,0 +1,37 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* A simple plugin class, it will run the plugin in a background thread.
*
* @author Konloch
*
*/
public abstract class Plugin extends Thread {
@Override
public void run() {
BytecodeViewer.viewer.setIcon(true);
try {
if(!BytecodeViewer.getLoadedClasses().isEmpty())
execute(BytecodeViewer.getLoadedClasses());
else
System.out.println("Plugin not ran, put some classes in first.");
} catch(Exception e) {
e.printStackTrace();
} finally {
finished = true;
BytecodeViewer.viewer.setIcon(false);
}
}
public boolean finished = false;
public abstract void execute(ArrayList<ClassNode> classNodeList);
}

View file

@ -0,0 +1,36 @@
package the.bytecode.club.bytecodeviewer.plugins;
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import javax.swing.JTextArea;
/**
* A simple console GUI.
*
* @author Konloch
*
*/
public class PluginConsole extends JFrame {
JTextArea textArea = new JTextArea();
public PluginConsole(String pluginName) {
setTitle("Bytecode Viewer - Plugin Console - " + pluginName);
setSize(new Dimension(542, 316));
JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(textArea);
this.setLocationRelativeTo(null);
}
public void appendText(String t) {
textArea.setText((textArea.getText().isEmpty() ? "" : textArea.getText()+"\r\n")+t);
textArea.setCaretPosition(textArea.getLineCount());
}
private static final long serialVersionUID = -6556940545421437508L;
}

View file

@ -0,0 +1,106 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* Supports loading of groovy, python or ruby scripts.
*
* Only allows one plugin to be running at once.
*
* @author Konloch
*
*/
public class PluginManager {
private static Plugin pluginInstance;
public static void runPlugin(Plugin newPluginInstance) {
if(pluginInstance == null || pluginInstance.finished) {
pluginInstance = newPluginInstance;
pluginInstance.start(); //start the thread
} else if(!pluginInstance.finished) {
BytecodeViewer.showMessage("There is currently another plugin running right now, please wait for that to finish executing.");
}
}
public static void runPlugin(File f) throws Exception {
Plugin p = null;
if(f.getName().endsWith(".gy") || f.getName().endsWith(".groovy")) {
p = loadGroovyScript(f);
}
if(f.getName().endsWith(".py") || f.getName().endsWith(".python")) {
p = loadPythonScript(f);
}
if(f.getName().endsWith(".rb") || f.getName().endsWith(".ruby")) {
p = loadRubyScript(f);
}
if(p != null) {
runPlugin(p);
}
}
/**
* Loads a groovy file as a Script
* @param file
* @return
* @throws Exception
*/
private static Plugin loadGroovyScript(File file) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
if(engine == null)
throw new Exception("Cannot find Groovy script engine! Please contact Konloch.");
Reader reader = new FileReader(file);
engine.eval(reader);
return (Plugin)engine.eval("new " + file.getName().replace(".gy", "").replace(".groovy", "") + "();");
}
/**
* Loads a python file as a Script
* @param file
* @return
* @throws Exception
*/
private static Plugin loadPythonScript(File file) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
if(engine == null)
throw new Exception("Cannot find Jython script engine! Please contact Konloch.");
Reader reader = new FileReader(file);
engine.eval(reader);
return (Plugin)engine.eval(file.getName().replace(".py", "").replace(".python", "") + "()");
}
/**
* Loads a ruby file as a Script
* @param file
* @return
* @throws Exception
*/
private static Plugin loadRubyScript(File file) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
if(engine == null)
throw new Exception("Cannot find jRuby script engine! Please contact Konloch.");
Reader reader = new FileReader(file);
engine.eval(reader);
return (Plugin)engine.eval(file.getName().replace(".rb", "").replace(".ruby", "") + ".new");
}
}

View file

@ -0,0 +1,116 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
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.
*
* @author Konloch
*
*/
public class ReplaceStrings extends Plugin {
PluginConsole frame = new PluginConsole("Replace Strings");
String originalLDC;
String newLDC;
String className;
boolean contains;
public ReplaceStrings(String originalLDC, String newLDC, String className, boolean contains) {
this.originalLDC = originalLDC;
this.newLDC = newLDC;
this.className = className;
this.contains = contains;
}
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
BytecodeViewer.viewer.setC(true);
if(!className.equals("*")) {
for(ClassNode classNode : classNodeList) {
if(classNode.name.equals(className))
scanClassNode(classNode);
}
} else {
for(ClassNode classNode : classNodeList) {
scanClassNode(classNode);
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}
public void scanClassNode(ClassNode classNode) {
for(Object o : classNode.fields.toArray()) {
FieldNode f = (FieldNode) o;
Object v = f.value;
if(v instanceof String) {
String s = (String)v;
if(contains) {
if(s.contains(originalLDC))
f.value = ((String)f.value).replaceAll(originalLDC, newLDC);
} else {
if(s.equals(originalLDC))
f.value = newLDC;
}
}
if(v instanceof String[]) {
for(int i = 0; i < ((String[])v).length; i++) {
String s = ((String[])v)[i];
if(contains) {
if(s.contains(originalLDC)) {
f.value = ((String[])f.value)[i].replaceAll(originalLDC, newLDC);
String ugh = s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
frame.appendText(classNode.name + "." +f.name+""+f.desc+" -> \"" + ugh + "\" replaced with \"" + s.replaceAll(originalLDC, newLDC) + "\"");
}
} else {
if(s.equals(originalLDC)) {
((String[])f.value)[i] = newLDC;
String ugh = s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
frame.appendText(classNode.name + "." +f.name+""+f.desc+" -> \"" + ugh + "\" replaced with \"" + newLDC + "\"");
}
}
}
}
}
for(Object o : classNode.methods.toArray()) {
MethodNode m = (MethodNode) o;
InsnList iList = m.instructions;
for(AbstractInsnNode a : iList.toArray()) {
if (a instanceof LdcInsnNode) {
if(((LdcInsnNode)a).cst instanceof String) {
final String s = (String) ((LdcInsnNode)a).cst;
if(contains) {
if(s.contains(originalLDC)) {
((LdcInsnNode)a).cst = ((String)((LdcInsnNode)a).cst).replaceAll(originalLDC, newLDC);
String ugh = s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
frame.appendText(classNode.name + "." +m.name+""+m.desc+" -> \"" + ugh + "\" replaced with \"" + s.replaceAll(originalLDC, newLDC) + "\"");
}
} else {
if(s.equals(originalLDC)) {
((LdcInsnNode)a).cst = newLDC;
String ugh = s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
frame.appendText(classNode.name + "." +m.name+""+m.desc+" -> \"" + ugh + "\" replaced with \"" + newLDC + "\"");
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,64 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
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
*
* @author Konloch
*
*/
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;
Object v = f.value;
if(v instanceof String) {
String s = (String)v;
if(!s.isEmpty())
frame.appendText(classNode.name + "." +f.name+""+f.desc+" -> \"" + s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r") + "\"");
}
if(v instanceof String[]) {
for(int i = 0; i < ((String[])v).length; i++) {
String s = ((String[])v)[i];
if(!s.isEmpty())
frame.appendText(classNode.name + "." +f.name+""+f.desc+"["+i+"] -> \"" + s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r") + "\"");
}
}
}
for(Object o : classNode.methods.toArray()) {
MethodNode m = (MethodNode) o;
InsnList iList = m.instructions;
for(AbstractInsnNode a : iList.toArray()) {
if (a instanceof LdcInsnNode) {
if(((LdcInsnNode)a).cst instanceof String) {
final String s = (String) ((LdcInsnNode)a).cst;
if(!s.isEmpty())
frame.appendText(classNode.name + "." +m.name+""+m.desc+" -> \"" + s.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r") + "\"");
}
}
}
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}
}

View file

@ -0,0 +1,35 @@
package the.bytecode.club.bytecodeviewer.plugins;
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[])
*
* @author Konloch
*
*/
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;
if(m.name.equals("main") && m.desc.equals("([Ljava/lang/String;)V"))
frame.appendText(classNode.name + "." +m.name+""+m.desc);
}
}
BytecodeViewer.viewer.setC(false);
frame.setVisible(true);
}
}

View file

@ -0,0 +1,23 @@
package the.bytecode.club.bytecodeviewer.plugins;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode;
/**
* Coming soon.
*
* @author Konloch
*
*/
public class ZKMStringDecrypter extends Plugin {
@Override
public void execute(ArrayList<ClassNode> classNodeList) {
for(ClassNode classNode : classNodeList) {
}
}
}

View file

@ -0,0 +1,34 @@
package the.bytecode.club.bytecodeviewer.searching;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/**
* A simple class to make searching run in a background thread.
*
* @author Konloch
*
*/
public abstract class BackgroundSearchThread extends Thread {
public BackgroundSearchThread() {
}
public BackgroundSearchThread(boolean finished) {
this.finished = finished;
}
public boolean finished = false;
public abstract void doSearch();
@Override
public void run() {
BytecodeViewer.viewer.setIcon(true);
doSearch();
finished = true;
BytecodeViewer.viewer.setIcon(false);
}
}

View file

@ -0,0 +1,100 @@
package the.bytecode.club.bytecodeviewer.searching;
import java.awt.GridLayout;
import java.util.Iterator;
import java.util.ListIterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
/**
* Field call searching
*
* @author Water Wolf
*
*/
public class FieldCallSearch implements SearchTypeDetails {
JTextField mOwner = new JTextField(""), mName = new JTextField(""), mDesc = new JTextField("");
JPanel myPanel = null;
@Override
public JPanel getPanel() {
if (myPanel == null) {
myPanel = new JPanel(new GridLayout(3, 2));
myPanel.add(new JLabel("Owner: "));
myPanel.add(mOwner);
myPanel.add(new JLabel("Name: "));
myPanel.add(mName);
myPanel.add(new JLabel("Desc: "));
myPanel.add(mDesc);
}
return myPanel;
}
@Override
public void search(final ClassNode node, final SearchResultNotifier srn, boolean exact) {
@SuppressWarnings("unchecked")
final Iterator<MethodNode> methods = node.methods.iterator();
String owner = mOwner.getText();
if (owner.isEmpty()) {
owner = null;
}
String name = mName.getText();
if (name.isEmpty()) {
name = null;
}
String desc = mDesc.getText();
if (desc.isEmpty()) {
desc = null;
}
while (methods.hasNext()) {
final MethodNode method = methods.next();
final InsnList insnlist = method.instructions;
@SuppressWarnings("unchecked")
final ListIterator<AbstractInsnNode> instructions = insnlist.iterator();
while (instructions.hasNext()) {
final AbstractInsnNode insnNode = instructions.next();
if (insnNode instanceof FieldInsnNode) {
final FieldInsnNode min = (FieldInsnNode) insnNode;
if(name == null && owner == null && desc == null)
continue;
if(exact) {
if (name != null && !name.equals(min.name)) {
continue;
}
if (owner != null && !owner.equals(min.owner)) {
continue;
}
if (desc != null && !desc.equals(min.desc)) {
continue;
}
srn.notifyOfResult(node, method, insnNode);
} else {
if (name != null && !name.contains(min.name)) {
continue;
}
if (owner != null && !owner.contains(min.owner)) {
continue;
}
if (desc != null && !desc.contains(min.desc)) {
continue;
}
srn.notifyOfResult(node, method, insnNode);
}
}
}
}
}
}

View file

@ -0,0 +1,66 @@
package the.bytecode.club.bytecodeviewer.searching;
import java.awt.GridLayout;
import java.util.Iterator;
import java.util.ListIterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
/**
* LDC Searching
*
* @author WaterWolf
*
*/
public class LDCSearch implements SearchTypeDetails {
JTextField searchText = new JTextField("");
JPanel myPanel = null;
@Override
public JPanel getPanel() {
if (myPanel == null) {
myPanel = new JPanel(new GridLayout(1, 2));
myPanel.add(new JLabel("Search String: "));
myPanel.add(searchText);
}
return myPanel;
}
@SuppressWarnings("unchecked")
@Override
public void search(final ClassNode node, final SearchResultNotifier srn, boolean exact) {
final Iterator<MethodNode> methods = node.methods.iterator();
final String srchText = searchText.getText();
if(srchText.isEmpty())
return;
while (methods.hasNext()) {
final MethodNode method = methods.next();
final InsnList insnlist = method.instructions;
final ListIterator<AbstractInsnNode> instructions = insnlist.iterator();
while (instructions.hasNext()) {
final AbstractInsnNode insnNode = instructions.next();
if (insnNode instanceof LdcInsnNode) {
final Object ldcObject = ((LdcInsnNode) insnNode).cst;
final String ldcString = ldcObject.toString();
if ((exact && ldcString.equals(srchText)) ||
(!exact && ldcString.contains(srchText)))
{
srn.notifyOfResult(node, method, insnNode);
}
}
}
}
}
}

View file

@ -0,0 +1,99 @@
package the.bytecode.club.bytecodeviewer.searching;
import java.awt.GridLayout;
import java.util.Iterator;
import java.util.ListIterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Method call searching
*
* @author WaterWolf
*
*/
public class MethodCallSearch implements SearchTypeDetails {
JTextField mOwner = new JTextField(""), mName = new JTextField(""), mDesc = new JTextField("");
JPanel myPanel = null;
@Override
public JPanel getPanel() {
if (myPanel == null) {
myPanel = new JPanel(new GridLayout(3, 2));
myPanel.add(new JLabel("Owner: "));
myPanel.add(mOwner);
myPanel.add(new JLabel("Name: "));
myPanel.add(mName);
myPanel.add(new JLabel("Desc: "));
myPanel.add(mDesc);
}
return myPanel;
}
@SuppressWarnings("unchecked")
@Override
public void search(final ClassNode node, final SearchResultNotifier srn, boolean exact) {
final Iterator<MethodNode> methods = node.methods.iterator();
String owner = mOwner.getText();
if (owner.isEmpty()) {
owner = null;
}
String name = mName.getText();
if (name.isEmpty()) {
name = null;
}
String desc = mDesc.getText();
if (desc.isEmpty()) {
desc = null;
}
while (methods.hasNext()) {
final MethodNode method = methods.next();
final InsnList insnlist = method.instructions;
final ListIterator<AbstractInsnNode> instructions = insnlist.iterator();
while (instructions.hasNext()) {
final AbstractInsnNode insnNode = instructions.next();
if (insnNode instanceof MethodInsnNode) {
final MethodInsnNode min = (MethodInsnNode) insnNode;
if(name == null && owner == null && desc == null)
continue;
if(exact) {
if (name != null && !name.equals(min.name)) {
continue;
}
if (owner != null && !owner.equals(min.owner)) {
continue;
}
if (desc != null && !desc.equals(min.desc)) {
continue;
}
srn.notifyOfResult(node, method, insnNode);
} else {
if (name != null && !name.contains(min.name)) {
continue;
}
if (owner != null && !owner.contains(min.owner)) {
continue;
}
if (desc != null && !desc.contains(min.desc)) {
continue;
}
srn.notifyOfResult(node, method, insnNode);
}
}
}
}
}
}

View file

@ -0,0 +1,381 @@
package the.bytecode.club.bytecodeviewer.searching;
import java.rmi.UnexpectedException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
/**
* An instruction finder that finds regex patterns in a method's instruction
* list and returns an array with the found instructions.
*
* @author Frédéric Hannes
*
*/
public class RegexInsnFinder {
private static String[] opcodes = new String[] { "NOP", "ACONST_NULL",
"ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", "ICONST_3",
"ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0",
"FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH",
"LDC", "LDC_W", "LDC2_W", "ILOAD", "LLOAD", "FLOAD", "DLOAD",
"ALOAD", "ILOAD_0", "ILOAD_1", "ILOAD_2", "ILOAD_3", "LLOAD_0",
"LLOAD_1", "LLOAD_2", "LLOAD_3", "FLOAD_0", "FLOAD_1", "FLOAD_2",
"FLOAD_3", "DLOAD_0", "DLOAD_1", "DLOAD_2", "DLOAD_3", "ALOAD_0",
"ALOAD_1", "ALOAD_2", "ALOAD_3", "IALOAD", "LALOAD", "FALOAD",
"DALOAD", "AALOAD", "BALOAD", "CALOAD", "SALOAD", "ISTORE",
"LSTORE", "FSTORE", "DSTORE", "ASTORE", "ISTORE_0", "ISTORE_1",
"ISTORE_2", "ISTORE_3", "LSTORE_0", "LSTORE_1", "LSTORE_2",
"LSTORE_3", "FSTORE_0", "FSTORE_1", "FSTORE_2", "FSTORE_3",
"DSTORE_0", "DSTORE_1", "DSTORE_2", "DSTORE_3", "ASTORE_0",
"ASTORE_1", "ASTORE_2", "ASTORE_3", "IASTORE", "LASTORE",
"FASTORE", "DASTORE", "AASTORE", "BASTORE", "CASTORE", "SASTORE",
"POP", "POP2", "DUP", "DUP_X1", "DUP_X2", "DUP2", "DUP2_X1",
"DUP2_X2", "SWAP", "IADD", "LADD", "FADD", "DADD", "ISUB", "LSUB",
"FSUB", "DSUB", "IMUL", "LMUL", "FMUL", "DMUL", "IDIV", "LDIV",
"FDIV", "DDIV", "IREM", "LREM", "FREM", "DREM", "INEG", "LNEG",
"FNEG", "DNEG", "ISHL", "LSHL", "ISHR", "LSHR", "IUSHR", "LUSHR",
"IAND", "LAND", "IOR", "LOR", "IXOR", "LXOR", "IINC", "I2L", "I2F",
"I2D", "L2I", "L2F", "L2D", "F2I", "F2L", "F2D", "D2I", "D2L",
"D2F", "I2B", "I2C", "I2S", "LCMP", "FCMPL", "FCMPG", "DCMPL",
"DCMPG", "IFEQ", "IFNE", "IFLT", "IFGE", "IFGT", "IFLE",
"IF_ICMPEQ", "IF_ICMPNE", "IF_ICMPLT", "IF_ICMPGE", "IF_ICMPGT",
"IF_ICMPLE", "IF_ACMPEQ", "IF_ACMPNE", "GOTO", "JSR", "RET",
"TABLESWITCH", "LOOKUPSWITCH", "IRETURN", "LRETURN", "FRETURN",
"DRETURN", "ARETURN", "RETURN", "GETSTATIC", "PUTSTATIC",
"GETFIELD", "PUTFIELD", "INVOKEVIRTUAL", "INVOKESPECIAL",
"INVOKESTATIC", "INVOKEINTERFACE", "INVOKEDYNAMIC", "NEW",
"NEWARRAY", "ANEWARRAY", "ARRAYLENGTH", "ATHROW", "CHECKCAST",
"INSTANCEOF", "MONITORENTER", "MONITOREXIT", "WIDE",
"MULTIANEWARRAY", "IFNULL", "IFNONNULL", "GOTO_W", "JSR_W" };
private static String[] opcodesVar = new String[] { "ILOAD", "LLOAD",
"FLOAD", "DLOAD", "ALOAD", "ISTORE", "LSTORE", "FSTORE", "DSTORE",
"ASTORE", "RET" };
private static String opcodeVars = buildRegexItems(opcodesVar);
private static String[] opcodesInt = new String[] { "BIPUSH", "SIPUSH",
"NEWARRAY" };
private static String opcodesInts = buildRegexItems(opcodesInt);
private static String[] opcodesField = new String[] { "GETSTATIC",
"PUTSTATIC", "GETFIELD", "PUTFIELD" };
private static String opcodesFields = buildRegexItems(opcodesField);
private static String[] opcodesMethod = new String[] { "INVOKEVIRTUAL",
"INVOKESPECIAL", "INVOKESTATIC", "INVOKEINTERFACE", "INVOKEDYNAMIC" };
private static String opcodesMethods = buildRegexItems(opcodesMethod);
private static String[] opcodesType = new String[] { "NEW", "ANEWARRAY",
"ARRAYLENGTH", "CHECKCAST", "INSTANCEOF" };
private static String opcodesTypes = buildRegexItems(opcodesType);
private static String[] opcodesIf = new String[] { "IFEQ", "IFNE", "IFLT",
"IFGE", "IFGT", "IFLE", "IF_ICMPEQ", "IF_ICMPNE", "IF_ICMPLT",
"IF_ICMPGE", "IF_ICMPGT", "IF_ICMPLE", "IF_ACMPEQ", "IF_ACMPNE" };
private static String opcodesIfs = buildRegexItems(opcodesIf, false, false);
private static String[] opcodesAny = new String[] { "NOP", "ACONST_NULL",
"ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", "ICONST_3",
"ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0",
"FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH",
"LDC", "LDC_W", "LDC2_W", "ILOAD", "LLOAD", "FLOAD", "DLOAD",
"ALOAD", "IALOAD", "LALOAD", "FALOAD", "DALOAD", "AALOAD",
"BALOAD", "CALOAD", "SALOAD", "ISTORE", "LSTORE", "FSTORE",
"DSTORE", "ASTORE", "IASTORE", "LASTORE", "FASTORE", "DASTORE",
"AASTORE", "BASTORE", "CASTORE", "SASTORE", "POP", "POP2", "DUP",
"DUP_X1", "DUP_X2", "DUP2", "DUP2_X1", "DUP2_X2", "SWAP", "IADD",
"LADD", "FADD", "DADD", "ISUB", "LSUB", "FSUB", "DSUB", "IMUL",
"LMUL", "FMUL", "DMUL", "IDIV", "LDIV", "FDIV", "DDIV", "IREM",
"LREM", "FREM", "DREM", "INEG", "LNEG", "FNEG", "DNEG", "ISHL",
"LSHL", "ISHR", "LSHR", "IUSHR", "LUSHR", "IAND", "LAND", "IOR",
"LOR", "IXOR", "LXOR", "IINC", "I2L", "I2F", "I2D", "L2I", "L2F",
"L2D", "F2I", "F2L", "F2D", "D2I", "D2L", "D2F", "I2B", "I2C",
"I2S", "LCMP", "FCMPL", "FCMPG", "DCMPL", "DCMPG", "IFEQ", "IFNE",
"IFLT", "IFGE", "IFGT", "IFLE", "IF_ICMPEQ", "IF_ICMPNE",
"IF_ICMPLT", "IF_ICMPGE", "IF_ICMPGT", "IF_ICMPLE", "IF_ACMPEQ",
"IF_ACMPNE", "GOTO", "JSR", "RET", "TABLESWITCH", "LOOKUPSWITCH",
"IRETURN", "LRETURN", "FRETURN", "DRETURN", "ARETURN", "RETURN",
"GETSTATIC", "PUTSTATIC", "GETFIELD", "PUTFIELD", "INVOKEVIRTUAL",
"INVOKESPECIAL", "INVOKESTATIC", "INVOKEINTERFACE",
"INVOKEDYNAMIC", "NEW", "NEWARRAY", "ANEWARRAY", "ARRAYLENGTH",
"ATHROW", "CHECKCAST", "INSTANCEOF", "MONITORENTER", "MONITOREXIT",
"MULTIANEWARRAY", "IFNULL", "IFNONNULL" };
private static String opcodesAnys = buildRegexItems(opcodesAny, false, false);
private static String buildRegexItems(final String[] items, final boolean capture, final boolean stdRepl) {
if (items.length == 0)
return "()";
String result = (stdRepl ? "\\b" : "") + "(" + (capture ? "" : "?:") + items[0];
for (int i = 1; i < items.length; i++) {
result += "|" + items[i];
}
result += ")";
return result;
}
private static String buildRegexItems(final String[] items) {
return buildRegexItems(items, true, true);
}
private static String processRegex(final String regex) {
String result = regex.trim();
result = result.replaceAll("\\bANYINSN *", opcodesAnys);
result = result.replaceAll(opcodesInts + "\\\\\\{\\s*(\\d+)\\s*\\\\\\} *",
"$1\\\\{$2\\\\} ");
result = result.replaceAll(opcodesInts + " *", "$1\\\\{\\\\d+\\\\} ");
result = result.replaceAll("\\bLDC\\\\\\{(.*?)\\\\\\}(?<!\\\\\\\\\\}) *",
"LDC\\\\{$1\\\\}(?<!\\\\\\\\\\\\}) ");
result = result.replaceAll("\\bLDC *", "LDC\\\\{.*?\\\\}(?<!\\\\\\\\\\\\}) ");
result = result.replaceAll(opcodeVars + "(_\\d+) *", "$1$2 ");
result = result.replaceAll(opcodeVars + "(?!_) *", "$1_\\\\d+ ");
result = result.replaceAll("\\bIINC\\\\\\{\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\\\\\} *",
"IINC\\\\{$1,$2\\\\} ");
result = result.replaceAll("\\bIINC\\\\\\{\\s*(\\d+)\\s*\\\\\\} *",
"IINC\\\\{\\d+,$1\\\\} ");
result = result.replaceAll("\\bIINC *", "IINC\\\\{\\d+,\\d+\\\\} ");
result = result.replaceAll(opcodesFields +
"\\\\\\{\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*\\\\\\} *",
"$1\\\\{$2,$3,$4\\\\} ");
result = result.replaceAll(opcodesFields
+ "\\\\\\{((?:.(?!,))*)\\\\\\} *", "$1\\\\{$2,.*?,.*?\\\\} ");
result = result.replaceAll(opcodesFields + " *", "$1\\\\{.*?\\\\} ");
result = result.replaceAll(opcodesMethods
+ "\\\\\\{\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*\\\\\\} *",
"$1\\\\{$2,$3,$4\\\\} ");
result = result.replaceAll(opcodesMethods
+ "\\\\\\{((?:.(?!,))*)\\\\\\} *", "$1\\\\{$2,.*?,.*?\\\\} ");
result = result.replaceAll(opcodesMethods + " *",
"$1\\\\{.*?,.*?,.*?\\\\} ");
result = result.replaceAll(opcodesTypes + "\\\\\\{\\s*(.*?)\\s*\\\\\\} +",
"$1\\\\{$2\\\\} ");
result = result.replaceAll(opcodesTypes + " +", "$1\\\\{\\\\.*?\\\\} ");
result = result.replaceAll("\\bMULTIANEWARRAY\\\\\\{\\s*(\\d+)\\s*,\\s*(.*?)\\s*\\\\\\} *",
"MULTIANEWARRAY\\\\{$1,$2\\\\} ");
result = result.replaceAll("\\bMULTIANEWARRAY\\\\\\{\\s*(.*?)\\s*\\\\\\} *",
"MULTIANEWARRAY\\\\{\\d+,$1\\\\} ");
result = result.replaceAll("\\bMULTIANEWARRAY *", "MULTIANEWARRAY\\\\{\\\\\\d+,.*?\\\\} ");
result = result.replaceAll("\\bIFINSN *", opcodesIfs + " ");
return result;
}
private MethodNode mn;
private AbstractInsnNode[] origInstructions;
private AbstractInsnNode[] instructions;
private int[] offsets;
private String insnString;
public RegexInsnFinder (final ClassNode clazz, final MethodNode method) {
setMethod(clazz, method);
}
@SuppressWarnings("unchecked")
private AbstractInsnNode[] cleanInsn(final InsnList insnList) {
final List<AbstractInsnNode> il = new ArrayList<AbstractInsnNode>();
final Iterator<AbstractInsnNode> iIt = insnList.iterator();
while (iIt.hasNext()) {
final AbstractInsnNode node = iIt.next();
if (node.getOpcode() >= 0) {
il.add(node);
}
}
return il.toArray(new AbstractInsnNode[il.size()]);
}
/**
* Refreshes the internal instruction list when you have made changes to the method.
*/
public void refresh() {
origInstructions = cleanInsn(mn.instructions);
final List<AbstractInsnNode> il = new ArrayList<AbstractInsnNode>();
for (final AbstractInsnNode ain : mn.instructions.toArray())
if (ain.getOpcode() >= 0) {
il.add(ain);
}
instructions = il.toArray(new AbstractInsnNode[il.size()]);
offsets = new int[instructions.length];
insnString = "";
for (int i = 0; i < instructions.length; i++) {
offsets[i] = -1;
final AbstractInsnNode ain = instructions[i];
if (ain.getOpcode() >= 0) {
if (ain.getOpcode() >= opcodes.length) {
try {
throw new UnexpectedException(
"Unknown opcode encountered: "
+ ain.getOpcode());
} catch (final UnexpectedException e) {
e.printStackTrace();
}
}
offsets[i] = insnString.length();
insnString += opcodes[ain.getOpcode()];
switch (ain.getType()) {
case AbstractInsnNode.INT_INSN:
final IntInsnNode iin = (IntInsnNode) ain;
insnString += "{" + iin.operand + "}";
break;
case AbstractInsnNode.LDC_INSN:
final LdcInsnNode lin = (LdcInsnNode) ain;
insnString += "{" + lin.cst.toString().replace("}", "\\}")
+ "}";
break;
case AbstractInsnNode.VAR_INSN:
final VarInsnNode vin = (VarInsnNode) ain;
insnString += "_" + vin.var;
break;
case AbstractInsnNode.IINC_INSN:
final IincInsnNode iiin = (IincInsnNode) ain;
insnString += "{" + iiin.var + "," + iiin.incr + "}";
break;
case AbstractInsnNode.FIELD_INSN:
final FieldInsnNode fin = (FieldInsnNode) ain;
insnString += "{" + fin.desc + "," + fin.owner + ","
+ fin.name + "}";
break;
case AbstractInsnNode.METHOD_INSN:
final MethodInsnNode min = (MethodInsnNode) ain;
insnString += "{" + min.desc + "," + min.owner + ","
+ min.name + "}";
break;
case AbstractInsnNode.TYPE_INSN:
final TypeInsnNode tin = (TypeInsnNode) ain;
insnString += "{" + tin.desc + "}";
break;
case AbstractInsnNode.MULTIANEWARRAY_INSN:
final MultiANewArrayInsnNode manain = (MultiANewArrayInsnNode) ain;
insnString += "{" + manain.dims + "," + manain.desc + "}";
break;
}
insnString += " ";
}
}
}
public void setMethod(final ClassNode ci, final MethodNode mi) {
this.mn = mi;
refresh();
}
private AbstractInsnNode[] makeResult(final int start, final int end) {
int startIndex = 0;
int endIndex = -1;
for (int i = 0; i < offsets.length - 1; i++) {
final int offset = offsets[i];
if (offset == start) {
startIndex = i;
}
if ((offset < end) && (offsets[i + 1] >= end)) {
endIndex = i;
break;
}
}
if (endIndex == -1) {
endIndex = offsets.length - 1;
}
final int length = endIndex - startIndex + 1;
final AbstractInsnNode[] result = new AbstractInsnNode[length];
System.arraycopy(origInstructions, startIndex, result, 0, length);
return result;
}
/**
* Searches for a regex in the instruction list and returns the first match.
* @param regex the regular expression
* @return the matching instructions
*/
public AbstractInsnNode[] find(final String regex) {
try {
final Matcher regexMatcher = Pattern.compile(processRegex(regex),
Pattern.MULTILINE).matcher(insnString);
if (regexMatcher.find())
return makeResult(regexMatcher.start(), regexMatcher.end());
} catch (final PatternSyntaxException ex) {
ex.printStackTrace();
}
return new AbstractInsnNode[0];
}
/**
* Searches a regex in an instruction list and returns all matches.
* @param regex the regular expression
* @return a list with all sets of matching instructions
*/
public List<AbstractInsnNode[]> findAll(final String regex) {
final List<AbstractInsnNode[]> results = new ArrayList<AbstractInsnNode[]>();
try {
final Matcher regexMatcher = Pattern.compile(processRegex(regex),
Pattern.MULTILINE).matcher(insnString);
while (regexMatcher.find()) {
results.add(makeResult(regexMatcher.start(), regexMatcher.end()));
}
} catch (final PatternSyntaxException ex) {
ex.printStackTrace();
}
return results;
}
/**
* Searches for a regex in the instruction list and returns all groups for the first match.
* @param regex the regular expression
* @return the groups with matching instructions
*/
public AbstractInsnNode[][] findGroups(final String regex) {
try {
final Matcher regexMatcher = Pattern.compile(processRegex(regex),
Pattern.MULTILINE).matcher(insnString);
if (regexMatcher.find()) {
final AbstractInsnNode[][] result = new AbstractInsnNode[regexMatcher.groupCount() + 1][0];
for (int i = 0; i <= regexMatcher.groupCount(); i++) {
result[i] = makeResult(regexMatcher.start(i), regexMatcher.end(i));
}
return result;
}
} catch (final PatternSyntaxException ex) {
ex.printStackTrace();
}
return new AbstractInsnNode[0][0];
}
/**
* Searches for a regex in the instruction list and returns all groups for all matches.
* @param regex the regular expression
* @return a list with all sets of groups with matching instructions
*/
public List<AbstractInsnNode[][]> findAllGroups(final String regex) {
final List<AbstractInsnNode[][]> results = new ArrayList<AbstractInsnNode[][]>();
try {
final Matcher regexMatcher = Pattern.compile(processRegex(regex),
Pattern.MULTILINE).matcher(insnString);
if (regexMatcher.find()) {
final AbstractInsnNode[][] result = new AbstractInsnNode[regexMatcher.groupCount() + 1][0];
for (int i = 0; i <= regexMatcher.groupCount(); i++) {
result[i] = makeResult(regexMatcher.start(i), regexMatcher.end(i));
}
results.add(result);
}
} catch (final PatternSyntaxException ex) {
ex.printStackTrace();
}
return results;
}
}

View file

@ -0,0 +1,61 @@
package the.bytecode.club.bytecodeviewer.searching;
import java.awt.GridLayout;
import java.util.Iterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Regex Searching
*
* @author WaterWolf
*
*/
public class RegexSearch implements SearchTypeDetails {
JTextField searchText = new JTextField("");
JPanel myPanel = null;
private static RegexInsnFinder regexFinder;
@Override
public JPanel getPanel() {
if (myPanel == null) {
myPanel = new JPanel(new GridLayout(1, 2));
myPanel.add(new JLabel("Search Regex: "));
myPanel.add(searchText);
}
return myPanel;
}
@SuppressWarnings("unchecked")
@Override
public void search(final ClassNode node, final SearchResultNotifier srn, boolean exact) {
final Iterator<MethodNode> methods = node.methods.iterator();
final String srchText = searchText.getText();
if(srchText.isEmpty())
return;
while (methods.hasNext()) {
final MethodNode method = methods.next();
if (regexFinder == null) {
regexFinder = new RegexInsnFinder(node, method);
}
else {
regexFinder.setMethod(node, method);
}
if (regexFinder.find(srchText).length > 0) {
srn.notifyOfResult(node, method, null);
}
}
}
}

View file

@ -0,0 +1,17 @@
package the.bytecode.club.bytecodeviewer.searching;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Used to update the search pane that there's been a result found.
*
* @author WaterWolf
*
*/
public interface SearchResultNotifier {
public void notifyOfResult(ClassNode clazz, MethodNode method,
AbstractInsnNode insn);
}

View file

@ -0,0 +1,18 @@
package the.bytecode.club.bytecodeviewer.searching;
import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode;
/**
* Search type details
*
* @author WaterWolf
*
*/
public interface SearchTypeDetails {
public JPanel getPanel();
public void search(ClassNode node, SearchResultNotifier srn, boolean exact);
}

View file

@ -0,0 +1,489 @@
package the.bytecode.club.bytecodeviewer.searching.commons;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IntInsnNode;
/**
*
* Class containing bytecode search conditions and couple of helper methods to make them
*
* @author Waterwolf
*
**/
public class AnalyzerFactory implements Opcodes {
public static InsnAnalyzer makeOpcodeCond(final int opcode) {
return new InsnAnalyzer() {
@Override
public boolean accept(final AbstractInsnNode node) {
return node.getOpcode() == opcode;
}
};
}
public static InsnAnalyzer makeFieldCond(final int opcode,
final String type) {
return new InsnAnalyzer() {
@Override
public boolean accept(final AbstractInsnNode node) {
if (node instanceof FieldInsnNode)
return node.getOpcode() == opcode && ((FieldInsnNode) node).desc.equals(type);
else
return false;
}
};
}
public static InsnAnalyzer makeFieldOwnerCond(final int opcode,
final String owner) {
return new InsnAnalyzer() {
@Override
public boolean accept(final AbstractInsnNode node) {
if (node instanceof FieldInsnNode)
return node.getOpcode() == opcode && ((FieldInsnNode) node).owner.equals(owner);
else
return false;
}
};
}
public static InsnAnalyzer makeFieldRegexCond(final int opcode,
final String regex) {
return new InsnAnalyzer() {
@Override
public boolean accept(final AbstractInsnNode node) {
if (node instanceof FieldInsnNode)
return node.getOpcode() == opcode && ((FieldInsnNode) node).desc.matches(regex);
else
return false;
}
};
}
public static InsnAnalyzer makeIntCond(final int opcode,
final int value) {
return new InsnAnalyzer() {
@Override
public boolean accept(final AbstractInsnNode node) {
if (node instanceof IntInsnNode)
return node.getOpcode() == opcode && ((IntInsnNode) node).operand == value;
else
return false;
}
};
}
/**
* An instruction condition for a GETFIELD instruction with signature Z.
*/
public final static InsnAnalyzer GETFIELD_Z =
makeFieldCond(GETFIELD, "Z");
/**
* An instruction condition for a PUTFIELD instruction with signature Z.
*/
public final static InsnAnalyzer PUTFIELD_Z =
makeFieldCond(PUTFIELD, "Z");
/**
* An instruction condition for a GETSTATIC instruction with signature Z.
*/
public final static InsnAnalyzer GETSTATIC_Z =
makeFieldCond(GETSTATIC, "Z");
/**
* An instruction condition for a PUTSTATIC instruction with signature Z.
*/
public final static InsnAnalyzer PUTSTATIC_Z =
makeFieldCond(PUTSTATIC, "Z");
/**
* An instruction condition for a GETFIELD instruction with signature [Z.
*/
public final static InsnAnalyzer GETFIELD_ZA =
makeFieldCond(GETFIELD, "[Z");
/**
* An instruction condition for a PUTFIELD instruction with signature [Z.
*/
public final static InsnAnalyzer PUTFIELD_ZA =
makeFieldCond(PUTFIELD, "[Z");
/**
* An instruction condition for a GETSTATIC instruction with signature [Z.
*/
public final static InsnAnalyzer GETSTATIC_ZA =
makeFieldCond(GETSTATIC, "[Z");
/**
* An instruction condition for a PUTSTATIC instruction with signature [Z.
*/
public final static InsnAnalyzer PUTSTATIC_ZA =
makeFieldCond(PUTSTATIC, "[Z");
/**
* An instruction condition for a GETFIELD instruction with signature [[Z.
*/
public final static InsnAnalyzer GETFIELD_ZAA =
makeFieldCond(GETFIELD, "[[Z");
/**
* An instruction condition for a PUTFIELD instruction with signature [[Z.
*/
public final static InsnAnalyzer PUTFIELD_ZAA =
makeFieldCond(PUTFIELD, "[[Z");
/**
* An instruction condition for a GETSTATIC instruction with signature [[Z.
*/
public final static InsnAnalyzer GETSTATIC_ZAA =
makeFieldCond(GETSTATIC, "[[Z");
/**
* An instruction condition for a PUTSTATIC instruction with signature [[Z.
*/
public final static InsnAnalyzer PUTSTATIC_ZAA =
makeFieldCond(PUTSTATIC, "[[Z");
/**
* An instruction condition for a GETFIELD instruction with signature B.
*/
public final static InsnAnalyzer GETFIELD_B =
makeFieldCond(GETFIELD, "B");
/**
* An instruction condition for a PUTFIELD instruction with signature B.
*/
public final static InsnAnalyzer PUTFIELD_B =
makeFieldCond(PUTFIELD, "B");
/**
* An instruction condition for a GETSTATIC instruction with signature B.
*/
public final static InsnAnalyzer GETSTATIC_B =
makeFieldCond(GETSTATIC, "B");
/**
* An instruction condition for a PUTSTATIC instruction with signature B.
*/
public final static InsnAnalyzer PUTSTATIC_B =
makeFieldCond(PUTSTATIC, "B");
/**
* An instruction condition for a GETFIELD instruction with signature [B.
*/
public final static InsnAnalyzer GETFIELD_BA =
makeFieldCond(GETFIELD, "[B");
/**
* An instruction condition for a PUTFIELD instruction with signature [B.
*/
public final static InsnAnalyzer PUTFIELD_BA =
makeFieldCond(PUTFIELD, "[B");
/**
* An instruction condition for a GETSTATIC instruction with signature [B.
*/
public final static InsnAnalyzer GETSTATIC_BA =
makeFieldCond(GETSTATIC, "[B");
/**
* An instruction condition for a PUTSTATIC instruction with signature [B.
*/
public final static InsnAnalyzer PUTSTATIC_BA =
makeFieldCond(PUTSTATIC, "[B");
/**
* An instruction condition for a GETFIELD instruction with signature [[B.
*/
public final static InsnAnalyzer GETFIELD_BAA =
makeFieldCond(GETFIELD, "[[B");
/**
* An instruction condition for a PUTFIELD instruction with signature [[B.
*/
public final static InsnAnalyzer PUTFIELD_BAA =
makeFieldCond(PUTFIELD, "[[B");
/**
* An instruction condition for a GETSTATIC instruction with signature [[B.
*/
public final static InsnAnalyzer GETSTATIC_BAA =
makeFieldCond(GETSTATIC, "[[B");
/**
* An instruction condition for a PUTSTATIC instruction with signature [[B.
*/
public final static InsnAnalyzer PUTSTATIC_BAA =
makeFieldCond(PUTSTATIC, "[[B");
/**
* An instruction condition for a GETFIELD instruction with signature C.
*/
public final static InsnAnalyzer GETFIELD_C =
makeFieldCond(GETFIELD, "C");
/**
* An instruction condition for a PUTFIELD instruction with signature C.
*/
public final static InsnAnalyzer PUTFIELD_C =
makeFieldCond(PUTFIELD, "C");
/**
* An instruction condition for a GETSTATIC instruction with signature C.
*/
public final static InsnAnalyzer GETSTATIC_C =
makeFieldCond(GETSTATIC, "C");
/**
* An instruction condition for a PUTSTATIC instruction with signature C.
*/
public final static InsnAnalyzer PUTSTATIC_C =
makeFieldCond(PUTSTATIC, "C");
/**
* An instruction condition for a GETFIELD instruction with signature [C.
*/
public final static InsnAnalyzer GETFIELD_CA =
makeFieldCond(GETFIELD, "[C");
/**
* An instruction condition for a PUTFIELD instruction with signature [C.
*/
public final static InsnAnalyzer PUTFIELD_CA =
makeFieldCond(PUTFIELD, "[C");
/**
* An instruction condition for a GETSTATIC instruction with signature [C.
*/
public final static InsnAnalyzer GETSTATIC_CA =
makeFieldCond(GETSTATIC, "[C");
/**
* An instruction condition for a PUTSTATIC instruction with signature [C.
*/
public final static InsnAnalyzer PUTSTATIC_CA =
makeFieldCond(PUTSTATIC, "[C");
/**
* An instruction condition for a GETFIELD instruction with signature [[C.
*/
public final static InsnAnalyzer GETFIELD_CAA =
makeFieldCond(GETFIELD, "[[C");
/**
* An instruction condition for a PUTFIELD instruction with signature [[C.
*/
public final static InsnAnalyzer PUTFIELD_CAA =
makeFieldCond(PUTFIELD, "[[C");
/**
* An instruction condition for a GETSTATIC instruction with signature [[C.
*/
public final static InsnAnalyzer GETSTATIC_CAA =
makeFieldCond(GETSTATIC, "[[C");
/**
* An instruction condition for a PUTSTATIC instruction with signature [[C.
*/
public final static InsnAnalyzer PUTSTATIC_CAA =
makeFieldCond(PUTSTATIC, "[[C");
/**
* An instruction condition for a GETFIELD instruction with signature S.
*/
public final static InsnAnalyzer GETFIELD_S =
makeFieldCond(GETFIELD, "S");
/**
* An instruction condition for a PUTFIELD instruction with signature S.
*/
public final static InsnAnalyzer PUTFIELD_S =
makeFieldCond(PUTFIELD, "S");
/**
* An instruction condition for a GETSTATIC instruction with signature S.
*/
public final static InsnAnalyzer GETSTATIC_S =
makeFieldCond(GETSTATIC, "S");
/**
* An instruction condition for a PUTSTATIC instruction with signature S.
*/
public final static InsnAnalyzer PUTSTATIC_S =
makeFieldCond(PUTSTATIC, "S");
/**
* An instruction condition for a GETFIELD instruction with signature [S.
*/
public final static InsnAnalyzer GETFIELD_SA =
makeFieldCond(GETFIELD, "[S");
/**
* An instruction condition for a PUTFIELD instruction with signature [S.
*/
public final static InsnAnalyzer PUTFIELD_SA =
makeFieldCond(PUTFIELD, "[S");
/**
* An instruction condition for a GETSTATIC instruction with signature [S.
*/
public final static InsnAnalyzer GETSTATIC_SA =
makeFieldCond(GETSTATIC, "[S");
/**
* An instruction condition for a PUTSTATIC instruction with signature [S.
*/
public final static InsnAnalyzer PUTSTATIC_SA =
makeFieldCond(PUTSTATIC, "[S");
/**
* An instruction condition for a GETFIELD instruction with signature [[S.
*/
public final static InsnAnalyzer GETFIELD_SAA =
makeFieldCond(GETFIELD, "[[S");
/**
* An instruction condition for a PUTFIELD instruction with signature [[S.
*/
public final static InsnAnalyzer PUTFIELD_SAA =
makeFieldCond(PUTFIELD, "[[S");
/**
* An instruction condition for a GETSTATIC instruction with signature [[S.
*/
public final static InsnAnalyzer GETSTATIC_SAA =
makeFieldCond(GETSTATIC, "[[S");
/**
* An instruction condition for a PUTSTATIC instruction with signature [[S.
*/
public final static InsnAnalyzer PUTSTATIC_SAA =
makeFieldCond(PUTSTATIC, "[[S");
public final static InsnAnalyzer GETFIELD_I =
makeFieldCond(GETFIELD, "I");
public final static InsnAnalyzer PUTFIELD_I =
makeFieldCond(PUTFIELD, "I");
public final static InsnAnalyzer GETSTATIC_I =
makeFieldCond(GETSTATIC, "I");
public final static InsnAnalyzer PUTSTATIC_I =
makeFieldCond(PUTSTATIC, "I");
public final static InsnAnalyzer GETFIELD_IA =
makeFieldCond(GETFIELD, "[I");
public final static InsnAnalyzer PUTFIELD_IA =
makeFieldCond(PUTFIELD, "[I");
public final static InsnAnalyzer GETSTATIC_IA =
makeFieldCond(GETSTATIC, "[I");
public final static InsnAnalyzer PUTSTATIC_IA =
makeFieldCond(PUTSTATIC, "[I");
public final static InsnAnalyzer GETFIELD_IAA =
makeFieldCond(GETFIELD, "[[I");
public final static InsnAnalyzer PUTFIELD_IAA =
makeFieldCond(PUTFIELD, "[[I");
public final static InsnAnalyzer GETSTATIC_IAA =
makeFieldCond(GETSTATIC, "[[I");
public final static InsnAnalyzer PUTSTATIC_IAA =
makeFieldCond(PUTSTATIC, "[[I");
public final static InsnAnalyzer GETFIELD_J =
makeFieldCond(GETFIELD, "J");
public final static InsnAnalyzer PUTFIELD_J =
makeFieldCond(PUTFIELD, "J");
public final static InsnAnalyzer GETSTATIC_J =
makeFieldCond(GETSTATIC, "J");
public final static InsnAnalyzer PUTSTATIC_J =
makeFieldCond(PUTSTATIC, "J");
public final static InsnAnalyzer GETFIELD_JA =
makeFieldCond(GETFIELD, "[J");
public final static InsnAnalyzer PUTFIELD_JA =
makeFieldCond(PUTFIELD, "[J");
public final static InsnAnalyzer GETSTATIC_JA =
makeFieldCond(GETSTATIC, "[J");
public final static InsnAnalyzer PUTSTATIC_JA =
makeFieldCond(PUTSTATIC, "[J");
public final static InsnAnalyzer GETFIELD_JAA =
makeFieldCond(GETFIELD, "[[J");
public final static InsnAnalyzer PUTFIELD_JAA =
makeFieldCond(PUTFIELD, "[[J");
public final static InsnAnalyzer GETSTATIC_JAA =
makeFieldCond(GETSTATIC, "[[J");
public final static InsnAnalyzer PUTSTATIC_JAA =
makeFieldCond(PUTSTATIC, "[[J");
public final static InsnAnalyzer GETFIELD_F =
makeFieldCond(GETFIELD, "F");
public final static InsnAnalyzer PUTFIELD_F =
makeFieldCond(PUTFIELD, "F");
public final static InsnAnalyzer GETSTATIC_F =
makeFieldCond(GETSTATIC, "F");
public final static InsnAnalyzer PUTSTATIC_F =
makeFieldCond(PUTSTATIC, "F");
public final static InsnAnalyzer GETFIELD_FA =
makeFieldCond(GETFIELD, "[F");
public final static InsnAnalyzer PUTFIELD_FA =
makeFieldCond(PUTFIELD, "[F");
public final static InsnAnalyzer GETSTATIC_FA =
makeFieldCond(GETSTATIC, "[F");
public final static InsnAnalyzer PUTSTATIC_FA =
makeFieldCond(PUTSTATIC, "[F");
public final static InsnAnalyzer GETFIELD_FAA =
makeFieldCond(GETFIELD, "[[F");
public final static InsnAnalyzer PUTFIELD_FAA =
makeFieldCond(PUTFIELD, "[[F");
public final static InsnAnalyzer GETSTATIC_FAA =
makeFieldCond(GETSTATIC, "[[F");
public final static InsnAnalyzer PUTSTATIC_FAA =
makeFieldCond(PUTSTATIC, "[[F");
public final static InsnAnalyzer GETFIELD_D =
makeFieldCond(GETFIELD, "D");
public final static InsnAnalyzer PUTFIELD_D =
makeFieldCond(PUTFIELD, "D");
public final static InsnAnalyzer GETSTATIC_D =
makeFieldCond(GETSTATIC, "D");
public final static InsnAnalyzer PUTSTATIC_D =
makeFieldCond(PUTSTATIC, "D");
public final static InsnAnalyzer GETFIELD_DA =
makeFieldCond(GETFIELD, "[D");
public final static InsnAnalyzer PUTFIELD_DA =
makeFieldCond(PUTFIELD, "[D");
public final static InsnAnalyzer GETSTATIC_DA =
makeFieldCond(GETSTATIC, "[D");
public final static InsnAnalyzer PUTSTATIC_DA =
makeFieldCond(PUTSTATIC, "[D");
public final static InsnAnalyzer GETFIELD_DAA =
makeFieldCond(GETFIELD, "[[D");
public final static InsnAnalyzer PUTFIELD_DAA =
makeFieldCond(PUTFIELD, "[[D");
public final static InsnAnalyzer GETSTATIC_DAA =
makeFieldCond(GETSTATIC, "[[D");
public final static InsnAnalyzer PUTSTATIC_DAA =
makeFieldCond(PUTSTATIC, "[[D");
public final static InsnAnalyzer GETFIELD_L =
makeFieldRegexCond(GETFIELD, "L.*;");
public final static InsnAnalyzer PUTFIELD_L =
makeFieldRegexCond(PUTFIELD, "L.*;");
public final static InsnAnalyzer GETSTATIC_L =
makeFieldRegexCond(GETSTATIC, "L.*;");
public final static InsnAnalyzer PUTSTATIC_L =
makeFieldRegexCond(PUTSTATIC, "L.*;");
public final static InsnAnalyzer GETFIELD_LA =
makeFieldRegexCond(GETFIELD, "\\[L.*;");
public final static InsnAnalyzer PUTFIELD_LA =
makeFieldRegexCond(PUTFIELD, "\\[L.*;");
public final static InsnAnalyzer GETSTATIC_LA =
makeFieldRegexCond(GETSTATIC, "\\[L.*;");
public final static InsnAnalyzer PUTSTATIC_LA =
makeFieldRegexCond(PUTSTATIC, "\\[L.*;");
public final static InsnAnalyzer GETFIELD_LAA =
makeFieldRegexCond(GETFIELD, "\\[\\[L.*;");
public final static InsnAnalyzer PUTFIELD_LAA =
makeFieldRegexCond(PUTFIELD, "\\[\\[L.*;");
public final static InsnAnalyzer GETSTATIC_LAA =
makeFieldRegexCond(GETSTATIC, "\\[\\[L.*;");
public final static InsnAnalyzer PUTSTATIC_LAA =
makeFieldRegexCond(PUTSTATIC, "\\[\\[L.*;");
public final static InsnAnalyzer GETFIELD_String =
makeFieldCond(GETFIELD, "Ljava/lang/String;");
public final static InsnAnalyzer PUTFIELD_String =
makeFieldCond(PUTFIELD, "Ljava/lang/String;");
public final static InsnAnalyzer GETSTATIC_String =
makeFieldCond(GETSTATIC, "Ljava/lang/String;");
public final static InsnAnalyzer PUTSTATIC_String =
makeFieldCond(PUTSTATIC, "Ljava/lang/String;");
public final static InsnAnalyzer GETFIELD_StringA =
makeFieldCond(GETFIELD, "[Ljava/lang/String;");
public final static InsnAnalyzer PUTFIELD_StringA =
makeFieldCond(PUTFIELD, "[Ljava/lang/String;");
public final static InsnAnalyzer GETSTATIC_StringA =
makeFieldCond(GETSTATIC, "[Ljava/lang/String;");
public final static InsnAnalyzer PUTSTATIC_StringA =
makeFieldCond(PUTSTATIC, "[Ljava/lang/String;");
public final static InsnAnalyzer GETFIELD_StringAA =
makeFieldCond(GETFIELD, "[[Ljava/lang/String;");
public final static InsnAnalyzer PUTFIELD_StringAA =
makeFieldCond(PUTFIELD, "[[Ljava/lang/String;");
public final static InsnAnalyzer GETSTATIC_StringAA =
makeFieldCond(GETSTATIC, "[[Ljava/lang/String;");
public final static InsnAnalyzer PUTSTATIC_StringAA =
makeFieldCond(PUTSTATIC, "[[Ljava/lang/String;");
}

View file

@ -0,0 +1,14 @@
package the.bytecode.club.bytecodeviewer.searching.commons;
import org.objectweb.asm.tree.AbstractInsnNode;
/**
*
* Bytecode instruction search baseclass
*
* @author Waterwolf
*
*/
public interface InsnAnalyzer {
public boolean accept(AbstractInsnNode node);
}

View file

@ -0,0 +1,171 @@
package the.bytecode.club.bytecodeviewer.searching.commons;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Class that searches bytecode instructions using given search conditions.
*
* @author WaterWolf
* @author Matthew Bovard
*
*/
public class InstructionSearcher {
private final InsnList list;
private AbstractInsnNode current;
public InstructionSearcher(final MethodNode m) {
this.list = m.instructions;
this.current = list.getFirst();
}
public AbstractInsnNode getCurrent() {
return current;
}
public void setCurrent(final AbstractInsnNode in) {
current = in;
}
public AbstractInsnNode getNext(final int opcode) {
return getNext(AnalyzerFactory.makeOpcodeCond(opcode));
}
public AbstractInsnNode getNext(final InsnAnalyzer analyzer) {
while (current != null) {
if (analyzer.accept(current)) {
final AbstractInsnNode old = current;
current = current.getNext();
return old;
}
current = current.getNext();
}
return null;
}
public AbstractInsnNode getNext() {
if (current == null)
return null;
current = current.getNext();
while (current != null && current.getOpcode() == -1) {
current = current.getNext();
}
return current;
}
public AbstractInsnNode getPrevious(final InsnAnalyzer analyzer) {
while (current != null) {
if (analyzer.accept(current)) {
final AbstractInsnNode old = current;
current = current.getPrevious();
return old;
}
current = current.getPrevious();
}
return null;
}
public AbstractInsnNode getPrevious(final int opcode) {
return getPrevious(AnalyzerFactory.makeOpcodeCond(opcode));
}
public AbstractInsnNode getPrevious() {
current = current.getPrevious();
while (current.getOpcode() == -1) {
current = current.getPrevious();
}
return current;
}
public LdcInsnNode getNextLDC(final Object cst) {
AbstractInsnNode in;
while ((in = getNext(Opcodes.LDC)) != null) {
final LdcInsnNode ln = (LdcInsnNode) in;
if (ln.cst.equals(cst)) return ln;
}
return null;
}
public LdcInsnNode getPreviousLDC(final Object cst) {
AbstractInsnNode in;
while ((in = getPrevious(Opcodes.LDC)) != null) {
final LdcInsnNode ln = (LdcInsnNode) in;
if (ln.cst.equals(cst))
return ln;
}
return null;
}
public IntInsnNode getNextInt(final int opcode, final int i) {
return (IntInsnNode) this.getNext(AnalyzerFactory.makeIntCond(opcode, i));
}
public IntInsnNode getPreviousInt(final int opcode, final int i) {
return (IntInsnNode) this.getPrevious(AnalyzerFactory.makeIntCond(opcode, i));
}
/**
* @param opcode One of Opcodes.BIPUSH/Opcodes.SIPUSH
* @param value Value to look for
* @return
*/
public IntInsnNode getNextPush(final int opcode, final int value) {
AbstractInsnNode in;
while ((in = getNext(opcode)) != null) {
final IntInsnNode iin = (IntInsnNode) in;
if (iin.operand == value) return iin;
}
return null;
}
public List<AbstractInsnNode> analyze(final int opcode) {
reset();
final List<AbstractInsnNode> list = new ArrayList<AbstractInsnNode>();
AbstractInsnNode in;
while ((in = getNext(opcode)) != null) {
list.add(in);
}
return list;
}
public int getIndex() {
return list.indexOf(current);
}
public void setIndex(final int index) {
current = list.get(index);
}
/**
* Resets us back to the first instruction
*/
public void reset() {
current = list.getFirst();
}
public void resetToEnd() {
current = list.getLast();
}
public void insert(final AbstractInsnNode location, final AbstractInsnNode insn) {
this.list.insert(location, insn);
}
public int computePosition(final AbstractInsnNode node) {
AbstractInsnNode poller = list.getFirst();
int index = 0;
while ((poller = poller.getNext()) != null) {
if (poller.equals(node))
return index;
index++;
}
return -1;
}
}