2.6.0 Released
01/06/2015 - Now saves if maximized or not. 01/07/2015 - For all save as functions, it will now append the correct extension if not added by the user. 01/07/2015 - You can no longer use use the save functions if no classes are loaded (fixes a crash issue). 01/07/2015 - Moved the Update Check to the Settings menu. 01/08/2015 - Added an extremely basic code sqeuence diagram plugin. 01/08/2015 - Updated CFR to CFR_0.93.jar 01/08/2015 - Threaded the Add files function. 01/08/2015 - Finally implemented Kontainer's HTTPRequest wrapper now that I've open sourced it. 01/08/2015 - Set the panes to be non-editable. 01/08/2015 - Sexified the view pane selection. 01/08/2015 - Started working on Smali Editing support, finished decompiler so far. 01/09/2015 - Fixed a bug with saving. 01/09/2015 - Added add entire directory. 01/09/2015 - Fixed import .DEX files. 01/10/2015 - Finished Smali Editing. 01/10/2015 - Fixed a class opening issue with sychronization. 01/11/2015 - Threaded all of the save functions. 01/11/2015 - Removed all instances of the setCursor to busy. 01/11/2015 - Added are you sure you wish to overwrite this existing file to all the other save functions. 01/11/2015 - All of the decompiling names are now randomly generated instead of a counting number. 01/11/2015 - Updated CFR to CFR_0.94.jar 01/11/2015 - Updated to the latest version of FernFlower. 01/11/2015 - Fixed an extension appending issue with save Java file.
This commit is contained in:
parent
410196fcd0
commit
9d93f1ee0b
30 changed files with 1376 additions and 262 deletions
Binary file not shown.
26
README.txt
26
README.txt
|
@ -1,4 +1,4 @@
|
||||||
Bytecode Viewer is an Advanced Lightweight Java Bytecode Viewer, GUI APK Decompiler, GUI DEX Decompiler, GUI Procyon Java Decompiler, GUI CFR Java Decompiler, GUI FernFlower Java Decompiler, GUI Jar-Jar, Hex Viewer, Code Searcher, Debugger and more.
|
Bytecode Viewer is an Advanced Lightweight Java Bytecode Viewer, GUI APK Decompiler, GUI DEX Decompiler, GUI Procyon Java Decompiler, GUI CFR Java Decompiler, GUI FernFlower Java Decompiler, GUI DEX2Jar, GUI Jar2DEX, 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.
|
It's written completely in Java, and it's open sourced. It's currently being maintained and developed by Konloch.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
@ -237,3 +237,27 @@ Changelog:
|
||||||
01/06/2015 - Fixed a search function with Android APKs.
|
01/06/2015 - Fixed a search function with Android APKs.
|
||||||
--- 2.5.2 ---:
|
--- 2.5.2 ---:
|
||||||
01/06/2015 - Completely fixed the search function with Android APKs.
|
01/06/2015 - Completely fixed the search function with Android APKs.
|
||||||
|
--- 2.6.0 ---:
|
||||||
|
01/06/2015 - Now saves if maximized or not.
|
||||||
|
01/07/2015 - For all save as functions, it will now append the correct extension if not added by the user.
|
||||||
|
01/07/2015 - You can no longer use use the save functions if no classes are loaded (fixes a crash issue).
|
||||||
|
01/07/2015 - Moved the Update Check to the Settings menu.
|
||||||
|
01/08/2015 - Added an extremely basic code sqeuence diagram plugin.
|
||||||
|
01/08/2015 - Updated CFR to CFR_0.93.jar
|
||||||
|
01/08/2015 - Threaded the Add files function.
|
||||||
|
01/08/2015 - Finally implemented Kontainer's HTTPRequest wrapper now that I've open sourced it.
|
||||||
|
01/08/2015 - Set the panes to be non-editable.
|
||||||
|
01/08/2015 - Sexified the view pane selection.
|
||||||
|
01/08/2015 - Started working on Smali Editing support, finished decompiler so far.
|
||||||
|
01/09/2015 - Fixed a bug with saving.
|
||||||
|
01/09/2015 - Added add entire directory.
|
||||||
|
01/09/2015 - Fixed import .DEX files.
|
||||||
|
01/10/2015 - Finished Smali Editing.
|
||||||
|
01/10/2015 - Fixed a class opening issue with sychronization.
|
||||||
|
01/11/2015 - Threaded all of the save functions.
|
||||||
|
01/11/2015 - Removed all instances of the setCursor to busy.
|
||||||
|
01/11/2015 - Added are you sure you wish to overwrite this existing file to all the other save functions.
|
||||||
|
01/11/2015 - All of the decompiling names are now randomly generated instead of a counting number.
|
||||||
|
01/11/2015 - Updated CFR to CFR_0.94.jar
|
||||||
|
01/11/2015 - Updated to the latest version of FernFlower.
|
||||||
|
01/11/2015 - Fixed an extension appending issue with save Java file.
|
BIN
libs/baksmali-2.0.3.jar
Normal file
BIN
libs/baksmali-2.0.3.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
libs/cfr_0_94.jar
Normal file
BIN
libs/cfr_0_94.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
libs/jgraphx.jar
Normal file
BIN
libs/jgraphx.jar
Normal file
Binary file not shown.
BIN
libs/smali-2.0.3-obf-patched.jar
Normal file
BIN
libs/smali-2.0.3-obf-patched.jar
Normal file
Binary file not shown.
253
src/me/konloch/kontainer/io/HTTPRequest.java
Normal file
253
src/me/konloch/kontainer/io/HTTPRequest.java
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
package me.konloch.kontainer.io;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.Proxy;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for Java SE classes to write/read an HTTP Request
|
||||||
|
*
|
||||||
|
* @author Konloch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class HTTPRequest {
|
||||||
|
|
||||||
|
public URL url;
|
||||||
|
private int timeout = 30000;
|
||||||
|
private String cookie;
|
||||||
|
private String referer;
|
||||||
|
private String postData;
|
||||||
|
private String useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0";
|
||||||
|
private Proxy proxy;
|
||||||
|
private boolean setFollowRedirects = true;
|
||||||
|
private BufferedReader reader;
|
||||||
|
private DataOutputStream writer;
|
||||||
|
private HttpURLConnection connection;
|
||||||
|
private Set<Entry<String, List<String>>> lastConnectionHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new HTTPRequest object
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
public HTTPRequest(URL url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a referer to send to the web server
|
||||||
|
*/
|
||||||
|
public void setReferer(String referer) {
|
||||||
|
this.referer = referer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a cookie string to send to the web server
|
||||||
|
*/
|
||||||
|
public void setCookie(String cookie) {
|
||||||
|
this.cookie = cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets post data to send to the web server
|
||||||
|
*/
|
||||||
|
public void setPostData(String postData) {
|
||||||
|
this.postData = postData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a custom useragent, default 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0'
|
||||||
|
*/
|
||||||
|
public void setUseragent(String useragent) {
|
||||||
|
this.useragent = useragent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the seconds till timeout, default 30,000 milliseconds
|
||||||
|
*/
|
||||||
|
public void setTimeout(int timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a proxy to connect through
|
||||||
|
*/
|
||||||
|
public void setProxy(Proxy proxy) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get the headers the webserver sent on our last connection
|
||||||
|
*/
|
||||||
|
public Set<Entry<String, List<String>>> getLastConnectionHeaders() {
|
||||||
|
return lastConnectionHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default follow redirects are enabled
|
||||||
|
*/
|
||||||
|
public void setFollowRedirects(boolean setFollowRedirects) {
|
||||||
|
this.setFollowRedirects = setFollowRedirects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to set up the connection to read the content.
|
||||||
|
*/
|
||||||
|
private void setup() throws Exception {
|
||||||
|
if(proxy != null)
|
||||||
|
connection = (HttpURLConnection) url.openConnection(proxy);
|
||||||
|
else
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
if(cookie != null)
|
||||||
|
connection.setRequestProperty("Cookie", cookie);
|
||||||
|
if(referer != null)
|
||||||
|
connection.addRequestProperty("Referer", referer);
|
||||||
|
|
||||||
|
connection.setRequestProperty("User-Agent", useragent);
|
||||||
|
connection.setReadTimeout(timeout);
|
||||||
|
connection.setConnectTimeout(timeout);
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
HttpURLConnection.setFollowRedirects(setFollowRedirects);
|
||||||
|
|
||||||
|
if(postData != null) {
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setDoInput(true);
|
||||||
|
writer = new DataOutputStream(connection.getOutputStream());
|
||||||
|
writer.writeBytes(postData);
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the entire page and returns a string array
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String[] read() throws Exception {
|
||||||
|
ArrayList<String> st;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
st = new ArrayList<String>();
|
||||||
|
String s;
|
||||||
|
while((s = reader.readLine()) != null)
|
||||||
|
st.add(s);
|
||||||
|
|
||||||
|
lastConnectionHeaders = connection.getHeaderFields().entrySet();
|
||||||
|
} catch(Exception e) {
|
||||||
|
cleanup();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return st.toArray(new String[st.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads as many lines as expected unless it reaches the end.
|
||||||
|
* @param linesToRead
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String[] read(int linesToRead) throws Exception {
|
||||||
|
ArrayList<String> st;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
st = new ArrayList<String>();
|
||||||
|
for(int i = 0; i < linesToRead; i++) {
|
||||||
|
String s = reader.readLine();
|
||||||
|
if(s != null)
|
||||||
|
st.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastConnectionHeaders = connection.getHeaderFields().entrySet();
|
||||||
|
} catch(Exception e) {
|
||||||
|
cleanup();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return st.toArray(new String[st.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only reads the first line
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String readSingle() throws Exception {
|
||||||
|
String s;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
s = reader.readLine();
|
||||||
|
|
||||||
|
lastConnectionHeaders = connection.getHeaderFields().entrySet();
|
||||||
|
} catch(Exception e) {
|
||||||
|
cleanup();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads until it reaches the expected line then it returns it.
|
||||||
|
* @param linesToRead
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String readSingle(int linesToRead) throws Exception {
|
||||||
|
String s;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
for(int i = 0; i < linesToRead-1; i++)
|
||||||
|
reader.readLine();
|
||||||
|
|
||||||
|
s = reader.readLine();
|
||||||
|
|
||||||
|
lastConnectionHeaders = connection.getHeaderFields().entrySet();
|
||||||
|
} catch(Exception e) {
|
||||||
|
cleanup();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to clean up the connection, closes the connections and nulls the objects
|
||||||
|
*/
|
||||||
|
private void cleanup() {
|
||||||
|
try { reader.close(); } catch(Exception e) {}
|
||||||
|
try { writer.close(); } catch(Exception e) {}
|
||||||
|
try { connection.disconnect(); } catch(Exception e) {}
|
||||||
|
reader = null;
|
||||||
|
writer = null;
|
||||||
|
connection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,15 +4,12 @@ import java.awt.Desktop;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -28,12 +25,15 @@ import javax.swing.UIManager;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import me.konloch.kontainer.io.DiskWriter;
|
||||||
|
import me.konloch.kontainer.io.HTTPRequest;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.imgscalr.Scalr;
|
import org.imgscalr.Scalr;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.Smali;
|
||||||
|
import the.bytecode.club.bytecodeviewer.gui.ClassViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.FileNavigationPane;
|
import the.bytecode.club.bytecodeviewer.gui.FileNavigationPane;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
import the.bytecode.club.bytecodeviewer.gui.MainViewerGUI;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.SearchingPane;
|
import the.bytecode.club.bytecodeviewer.gui.SearchingPane;
|
||||||
|
@ -65,11 +65,10 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* The import jar method eats up a lot of memory, look into some how reducing this.
|
* The import jar method eats up a lot of memory, look into some how reducing this.
|
||||||
* Add a tool to build a flowchart of all the classes, and what methods execute what classes, and those method, read chatlog
|
|
||||||
* Add obfuscation:
|
* Add obfuscation:
|
||||||
* Add integer boxing and other obfuscation methods contra implemented
|
* - Add integer boxing and other obfuscation methods contra implemented
|
||||||
* Insert unadded/debug opcodes to try to fuck up decompilers
|
* - Insert unadded/debug opcodes to try to fuck up decompilers
|
||||||
* ClassAnylyzterAdapter
|
* - ClassAnylyzterAdapter
|
||||||
* Add progress bars on saving all zips/java decompile jar
|
* Add progress bars on saving all zips/java decompile jar
|
||||||
* Add the jump/save mark system Ida Pro has.
|
* Add the jump/save mark system Ida Pro has.
|
||||||
* Add class annotations to bytecode decompiler.
|
* Add class annotations to bytecode decompiler.
|
||||||
|
@ -259,6 +258,30 @@ import the.bytecode.club.bytecodeviewer.plugins.PluginManager;
|
||||||
* 01/06/2015 - Fixed a search function with Android APKs.
|
* 01/06/2015 - Fixed a search function with Android APKs.
|
||||||
* -----2.5.2-----:
|
* -----2.5.2-----:
|
||||||
* 01/06/2015 - Fixed another issue with LDC searching for Android APKs.
|
* 01/06/2015 - Fixed another issue with LDC searching for Android APKs.
|
||||||
|
* -----2.6.0-----:
|
||||||
|
* 01/06/2015 - Now saves if maximized or not.
|
||||||
|
* 01/07/2015 - For all save as functions, it will now append the correct extension if not added by the user.
|
||||||
|
* 01/07/2015 - You can no longer use use the save functions if no classes are loaded (fixes a crash issue).
|
||||||
|
* 01/07/2015 - Moved the Update Check to the Settings menu.
|
||||||
|
* 01/08/2015 - Added an extremely basic code sqeuence diagram plugin.
|
||||||
|
* 01/08/2015 - Updated CFR to CFR_0.93.jar
|
||||||
|
* 01/08/2015 - Threaded the Add files function.
|
||||||
|
* 01/08/2015 - Finally implemented Kontainer's HTTPRequest wrapper now that I've open sourced it.
|
||||||
|
* 01/08/2015 - Set the panes to be non-editable.
|
||||||
|
* 01/08/2015 - Sexified the view pane selection.
|
||||||
|
* 01/08/2015 - Started working on Smali Editing support, finished decompiler so far.
|
||||||
|
* 01/09/2015 - Fixed a bug with saving.
|
||||||
|
* 01/09/2015 - Added add entire directory.
|
||||||
|
* 01/09/2015 - Fixed import .DEX files.
|
||||||
|
* 01/10/2015 - Finished Smali Editing.
|
||||||
|
* 01/10/2015 - Fixed a class opening issue with sychronization.
|
||||||
|
* 01/11/2015 - Threaded all of the save functions.
|
||||||
|
* 01/11/2015 - Removed all instances of the setCursor to busy.
|
||||||
|
* 01/11/2015 - Added are you sure you wish to overwrite this existing file to all the other save functions.
|
||||||
|
* 01/11/2015 - All of the decompiling names are now randomly generated instead of a counting number.
|
||||||
|
* 01/11/2015 - Updated CFR to CFR_0.94.jar
|
||||||
|
* 01/11/2015 - Updated to the latest version of FernFlower.
|
||||||
|
* 01/11/2015 - Fixed an extension appending issue with save Java file.
|
||||||
*
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
*
|
*
|
||||||
|
@ -279,7 +302,7 @@ public class BytecodeViewer {
|
||||||
private static ArrayList<String> recentFiles = DiskReader.loadArrayList(filesName, false);
|
private static ArrayList<String> recentFiles = DiskReader.loadArrayList(filesName, false);
|
||||||
private static ArrayList<String> recentPlugins = DiskReader.loadArrayList(pluginsName, false);
|
private static ArrayList<String> recentPlugins = DiskReader.loadArrayList(pluginsName, false);
|
||||||
public static boolean runningObfuscation = false;
|
public static boolean runningObfuscation = false;
|
||||||
public static String version = "2.5.2";
|
public static String version = "2.6.0";
|
||||||
private static long start = System.currentTimeMillis();
|
private static long start = System.currentTimeMillis();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -312,30 +335,11 @@ public class BytecodeViewer {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
HttpURLConnection connection = (HttpURLConnection) new URL(
|
HTTPRequest r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION"));
|
||||||
"https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION")
|
final String version = r.readSingle();
|
||||||
.openConnection();
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setRequestProperty("User-Agent",
|
|
||||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0");
|
|
||||||
BufferedReader reader = new BufferedReader(
|
|
||||||
new InputStreamReader(connection.getInputStream()));
|
|
||||||
final String version = reader.readLine();
|
|
||||||
reader.close();
|
|
||||||
if (!BytecodeViewer.version.equals(version)) {
|
if (!BytecodeViewer.version.equals(version)) {
|
||||||
connection = (HttpURLConnection) new URL(
|
r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION"));
|
||||||
"https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/README.txt")
|
String[] readme = r.read();
|
||||||
.openConnection();
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setRequestProperty("User-Agent",
|
|
||||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0");
|
|
||||||
reader = new BufferedReader(
|
|
||||||
new InputStreamReader(connection.getInputStream()));
|
|
||||||
ArrayList<String> readme = new ArrayList<String>();
|
|
||||||
String s;
|
|
||||||
while((s = reader.readLine()) != null)
|
|
||||||
readme.add(s);
|
|
||||||
reader.close();
|
|
||||||
|
|
||||||
String changelog = "Unable to load change log, please try again later."+nl;
|
String changelog = "Unable to load change log, please try again later."+nl;
|
||||||
boolean trigger = false;
|
boolean trigger = false;
|
||||||
|
@ -343,9 +347,7 @@ public class BytecodeViewer {
|
||||||
if(st.equals("--- "+version+" ---:")) {
|
if(st.equals("--- "+version+" ---:")) {
|
||||||
changelog = "";
|
changelog = "";
|
||||||
trigger = true;
|
trigger = true;
|
||||||
}
|
} else if(trigger == true) {
|
||||||
|
|
||||||
if(trigger == true && !st.equals("--- "+version+" ---:")) {
|
|
||||||
if(st.startsWith("--- "))
|
if(st.startsWith("--- "))
|
||||||
trigger = false;
|
trigger = false;
|
||||||
else
|
else
|
||||||
|
@ -488,6 +490,15 @@ public class BytecodeViewer {
|
||||||
System.out.println("Start up took " + ((System.currentTimeMillis() - start) / 1000) + " seconds");
|
System.out.println("Start up took " + ((System.currentTimeMillis() - start) / 1000) + " seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//because Smali and Baksmali System.exit if it failed
|
||||||
|
public static void exit(int i) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassNode getCurrentlyOpenedClassNode() {
|
||||||
|
return viewer.workPane.getCurrentClass().cn;
|
||||||
|
}
|
||||||
|
|
||||||
public static ClassNode getClassNode(String name) {
|
public static ClassNode getClassNode(String name) {
|
||||||
if (loadedClasses.containsKey(name))
|
if (loadedClasses.containsKey(name))
|
||||||
return loadedClasses.get(name);
|
return loadedClasses.get(name);
|
||||||
|
@ -495,10 +506,8 @@ public class BytecodeViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateNode(ClassNode oldNode, ClassNode newNode) {
|
public static void updateNode(ClassNode oldNode, ClassNode newNode) {
|
||||||
for (ClassNode c : BytecodeViewer.getLoadedClasses()) {
|
BytecodeViewer.loadedClasses.remove(oldNode.name);
|
||||||
if (c.name.equals(oldNode.name))
|
BytecodeViewer.loadedClasses.put(oldNode.name, newNode);
|
||||||
c = newNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList<ClassNode> getLoadedClasses() {
|
public static ArrayList<ClassNode> getLoadedClasses() {
|
||||||
|
@ -512,19 +521,58 @@ public class BytecodeViewer {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openFiles(File[] files, boolean recentFiles) {
|
//called whenever a save function is executed
|
||||||
|
public static boolean compileSmali(boolean message) {
|
||||||
|
if(getLoadedClasses().isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(java.awt.Component c : BytecodeViewer.viewer.workPane.getLoadedViewers()) {
|
||||||
|
if(c instanceof ClassViewer) {
|
||||||
|
ClassViewer cv = (ClassViewer) c;
|
||||||
|
Object smali[] = cv.getSmali();
|
||||||
|
ClassNode origNode = (ClassNode) smali[0];
|
||||||
|
String smaliText = (String) smali[1];
|
||||||
|
if(smali != null) {
|
||||||
|
byte[] smaliCompiled = Smali.compile(smaliText);
|
||||||
|
if(smaliCompiled != null) {
|
||||||
|
ClassNode newNode = JarUtils.getNode(smaliCompiled);
|
||||||
|
System.out.println(origNode.name+":"+newNode.name);
|
||||||
|
BytecodeViewer.updateNode(origNode, newNode);
|
||||||
|
} else {
|
||||||
|
BytecodeViewer.showMessage("There has been an error with assembling your Smali code, please check this. Class: " + origNode.name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message)
|
||||||
|
BytecodeViewer.showMessage("Compiled Successfully.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean update = true;
|
||||||
|
public static void openFiles(final File[] files, boolean recentFiles) {
|
||||||
if(recentFiles)
|
if(recentFiles)
|
||||||
for (File f : files)
|
for (File f : files)
|
||||||
BytecodeViewer.addRecentFile(f);
|
BytecodeViewer.addRecentFile(f);
|
||||||
|
|
||||||
BytecodeViewer.viewer.setIcon(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
boolean update = true;
|
update = true;
|
||||||
|
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
for (final File f : files) {
|
for (final File f : files) {
|
||||||
final String fn = f.getName();
|
final String fn = f.getName();
|
||||||
if(!f.exists()) {
|
if(!f.exists()) {
|
||||||
update = false;
|
update = false;
|
||||||
showMessage("The file " + f.getAbsolutePath() + " could not be found.");
|
showMessage("The file " + f.getAbsolutePath() + " could not be found.");
|
||||||
|
} else {
|
||||||
|
if(f.isDirectory()) {
|
||||||
|
openFiles(f.listFiles(), false);
|
||||||
} else {
|
} else {
|
||||||
if (fn.endsWith(".jar") || fn.endsWith(".zip")) {
|
if (fn.endsWith(".jar") || fn.endsWith(".zip")) {
|
||||||
try {
|
try {
|
||||||
|
@ -552,10 +600,7 @@ public class BytecodeViewer {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
update = false;
|
update = false;
|
||||||
}
|
}
|
||||||
} else if(fn.endsWith(".apk")) {
|
} else if(fn.endsWith(".apk") || fn.endsWith(".dex")) {
|
||||||
Thread t = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
String name = getRandomizedName()+".jar";
|
String name = getRandomizedName()+".jar";
|
||||||
File output = new File(tempDirectory + fs + name);
|
File output = new File(tempDirectory + fs + name);
|
||||||
|
@ -565,14 +610,14 @@ public class BytecodeViewer {
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
t.start();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
} finally {
|
||||||
BytecodeViewer.viewer.setIcon(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
|
|
||||||
if(update)
|
if(update)
|
||||||
|
@ -581,6 +626,10 @@ public class BytecodeViewer {
|
||||||
} catch(java.lang.NullPointerException e) {
|
} catch(java.lang.NullPointerException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
public static void startPlugin(File plugin) {
|
public static void startPlugin(File plugin) {
|
||||||
if (!plugin.exists())
|
if (!plugin.exists())
|
||||||
|
|
113
src/the/bytecode/club/bytecodeviewer/CoolClassAdapter.java
Normal file
113
src/the/bytecode/club/bytecodeviewer/CoolClassAdapter.java
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
|
import org.objectweb.asm.AnnotationVisitor;
|
||||||
|
import org.objectweb.asm.Attribute;
|
||||||
|
import org.objectweb.asm.ClassAdapter;
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.FieldVisitor;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
|
||||||
|
public class CoolClassAdapter extends ClassAdapter {
|
||||||
|
|
||||||
|
String oldName;
|
||||||
|
String newName;
|
||||||
|
|
||||||
|
public CoolClassAdapter(ClassVisitor cv, String oldName, String newName) {
|
||||||
|
super(cv);
|
||||||
|
this.oldName = oldName;
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||||
|
if(name != null)
|
||||||
|
name = name.replace(oldName, newName);
|
||||||
|
if(signature != null)
|
||||||
|
signature = signature.replace(oldName, newName);
|
||||||
|
if(superName != null)
|
||||||
|
superName = superName.replace(oldName, newName);
|
||||||
|
if(interfaces != null)
|
||||||
|
for(int i = 0; i < interfaces.length; i++)
|
||||||
|
interfaces[i] = interfaces[i].replace(oldName, newName);
|
||||||
|
|
||||||
|
cv.visit(49, access, name, signature, superName, interfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
|
if(desc != null)
|
||||||
|
desc = desc.replace(oldName, newName);
|
||||||
|
return cv.visitAnnotation(desc, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitAttribute(Attribute attr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||||
|
if(name != null)
|
||||||
|
name = name.replace(oldName, newName);
|
||||||
|
if(desc != null)
|
||||||
|
desc = desc.replace(oldName, newName);
|
||||||
|
if(signature != null)
|
||||||
|
signature = signature.replace(oldName, newName);
|
||||||
|
|
||||||
|
return cv.visitField(access, name, desc, signature, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||||
|
if(name != null)
|
||||||
|
name = name.replace(oldName, newName);
|
||||||
|
if(outerName != null)
|
||||||
|
outerName = outerName.replace(oldName, newName);
|
||||||
|
if(innerName != null)
|
||||||
|
innerName = innerName.replace(oldName, newName);
|
||||||
|
|
||||||
|
cv.visitInnerClass(name, outerName, innerName, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||||
|
if(name != null)
|
||||||
|
name = name.replace(oldName, newName);
|
||||||
|
if(desc != null)
|
||||||
|
desc = desc.replace(oldName, newName);
|
||||||
|
if(signature != null)
|
||||||
|
signature = signature.replace(oldName, newName);
|
||||||
|
|
||||||
|
if(exceptions != null)
|
||||||
|
for(int i = 0; i < exceptions.length; i++)
|
||||||
|
exceptions[i] = exceptions[i].replace(oldName, newName);
|
||||||
|
|
||||||
|
//return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitOuterClass(String owner, String name, String desc) {
|
||||||
|
if(owner != null)
|
||||||
|
owner = owner.replace(oldName, newName);
|
||||||
|
if(name != null)
|
||||||
|
name = name.replace(oldName, newName);
|
||||||
|
if(desc != null)
|
||||||
|
desc = desc.replace(oldName, newName);
|
||||||
|
|
||||||
|
cv.visitOuterClass(owner, name, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitSource(String source, String debug) {
|
||||||
|
if(source != null)
|
||||||
|
source = source.replace(oldName, newName);
|
||||||
|
cv.visitSource(source, debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,23 +11,29 @@ import java.io.File;
|
||||||
|
|
||||||
public class Dex2Jar {
|
public class Dex2Jar {
|
||||||
|
|
||||||
public static void dex2Jar(File input, File output) {
|
public static synchronized void dex2Jar(File input, File output) {
|
||||||
try {
|
try {
|
||||||
com.googlecode.dex2jar.tools.Dex2jarCmd.main(new String[]{"--force", input.getAbsolutePath()});
|
com.googlecode.dex2jar.tools.Dex2jarCmd.main(new String[]{"--force", input.getAbsolutePath()});
|
||||||
String realOutput = input.getName().replaceAll(".apk", "-dex2jar.jar");
|
String realOutput = input.getName().replaceAll(".dex", "-dex2jar.jar").replaceAll(".apk", "-dex2jar.jar");
|
||||||
File realOutputF = new File(realOutput);
|
File realOutputF = new File(realOutput);
|
||||||
realOutputF.renameTo(output);
|
realOutputF.renameTo(output);
|
||||||
|
File realOutputF2 = new File(realOutput);
|
||||||
|
while(realOutputF2.exists())
|
||||||
|
realOutputF2.delete();
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveAsDex(File input, File output) {
|
public static synchronized void saveAsDex(File input, File output) {
|
||||||
try {
|
try {
|
||||||
com.googlecode.dex2jar.tools.Jar2Dex.main(new String[]{"--force", input.getAbsolutePath()});
|
com.googlecode.dex2jar.tools.Jar2Dex.main(new String[]{"--force", input.getAbsolutePath()});
|
||||||
String realOutput = input.getName().replaceAll(".jar", "-jar2dex.dex");
|
String realOutput = input.getName().replaceAll(".jar", "-jar2dex.dex");
|
||||||
File realOutputF = new File(realOutput);
|
File realOutputF = new File(realOutput);
|
||||||
realOutputF.renameTo(output);
|
realOutputF.renameTo(output);
|
||||||
|
File realOutputF2 = new File(realOutput);
|
||||||
|
while(realOutputF2.exists())
|
||||||
|
realOutputF2.delete();
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,14 +64,10 @@ public class JarUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ByteArrayOutputStream baos = null;
|
|
||||||
private static byte[] buffer = null;
|
|
||||||
private static int a = 0;
|
|
||||||
|
|
||||||
public static byte[] getBytes(final InputStream is) throws IOException {
|
public static byte[] getBytes(final InputStream is) throws IOException {
|
||||||
baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
a = 0;
|
int a = 0;
|
||||||
while ((a = is.read(buffer)) != -1) {
|
while ((a = is.read(buffer)) != -1) {
|
||||||
baos.write(buffer, 0, a);
|
baos.write(buffer, 0, a);
|
||||||
}
|
}
|
||||||
|
@ -80,16 +76,13 @@ public class JarUtils {
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClassReader cr = null;
|
|
||||||
private static ClassNode cn = null;
|
|
||||||
|
|
||||||
public static ClassNode getNode(final byte[] bytez) {
|
public static ClassNode getNode(final byte[] bytez) {
|
||||||
cr = new ClassReader(bytez);
|
ClassReader cr = new ClassReader(bytez);
|
||||||
cn = new ClassNode();
|
ClassNode cn = new ClassNode();
|
||||||
try {
|
try {
|
||||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
cr.accept(cn, ClassReader.SKIP_FRAMES);
|
cr.accept(cn, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE);
|
||||||
}
|
}
|
||||||
cr = null;
|
cr = null;
|
||||||
return cn;
|
return cn;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer;
|
package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
import me.konloch.kontainer.io.DiskReader;
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
import me.konloch.kontainer.io.DiskWriter;
|
import me.konloch.kontainer.io.DiskWriter;
|
||||||
|
|
||||||
|
@ -107,6 +109,8 @@ public class Settings {
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
||||||
else if(BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
|
else if(BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
||||||
|
else if(BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Smali.getModel()))
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "6", false);
|
||||||
|
|
||||||
if(BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
|
if(BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false);
|
||||||
|
@ -120,6 +124,8 @@ public class Settings {
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
||||||
else if(BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
|
else if(BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
||||||
|
else if(BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Smali.getModel()))
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "6", false);
|
||||||
|
|
||||||
if(BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
|
if(BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false);
|
||||||
|
@ -133,8 +139,13 @@ public class Settings {
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "4", false);
|
||||||
else if(BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
|
else if(BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "5", false);
|
||||||
|
else if(BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Smali.getModel()))
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "6", false);
|
||||||
|
|
||||||
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.refreshOnChange.isSelected()), false);
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.refreshOnChange.isSelected()), false);
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.isMaximized), false);
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.autoCompileSmali.isSelected()), false);
|
||||||
|
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()), false);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
}
|
}
|
||||||
|
@ -235,6 +246,9 @@ public class Settings {
|
||||||
BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Bytecode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Bytecode.getModel(), true);
|
||||||
else if(decompiler == 5)
|
else if(decompiler == 5)
|
||||||
BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Hexcode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Hexcode.getModel(), true);
|
||||||
|
else if(decompiler == 6)
|
||||||
|
BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Smali.getModel(), true);
|
||||||
|
|
||||||
decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 82, false));
|
decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 82, false));
|
||||||
if(decompiler == 0)
|
if(decompiler == 0)
|
||||||
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2None.getModel(), true);
|
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2None.getModel(), true);
|
||||||
|
@ -248,6 +262,9 @@ public class Settings {
|
||||||
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Bytecode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Bytecode.getModel(), true);
|
||||||
else if(decompiler == 5)
|
else if(decompiler == 5)
|
||||||
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Hexcode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Hexcode.getModel(), true);
|
||||||
|
else if(decompiler == 6)
|
||||||
|
BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Smali.getModel(), true);
|
||||||
|
|
||||||
decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 83, false));
|
decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 83, false));
|
||||||
if(decompiler == 0)
|
if(decompiler == 0)
|
||||||
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3None.getModel(), true);
|
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3None.getModel(), true);
|
||||||
|
@ -261,8 +278,18 @@ public class Settings {
|
||||||
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Bytecode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Bytecode.getModel(), true);
|
||||||
else if(decompiler == 5)
|
else if(decompiler == 5)
|
||||||
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Hexcode.getModel(), true);
|
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Hexcode.getModel(), true);
|
||||||
|
else if(decompiler == 6)
|
||||||
|
BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Smali.getModel(), true);
|
||||||
|
|
||||||
BytecodeViewer.viewer.refreshOnChange.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 84, false)));
|
BytecodeViewer.viewer.refreshOnChange.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 84, false)));
|
||||||
|
|
||||||
|
boolean bool = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 85, false));
|
||||||
|
if(bool) {
|
||||||
|
BytecodeViewer.viewer.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||||
|
BytecodeViewer.viewer.isMaximized = true;
|
||||||
|
}
|
||||||
|
BytecodeViewer.viewer.autoCompileSmali.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 86, false)));
|
||||||
|
BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 87, false)));
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
//ignore because errors are expected, first start up and outdated settings.
|
//ignore because errors are expected, first start up and outdated settings.
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
@ -14,6 +17,61 @@ import javax.swing.filechooser.FileFilter;
|
||||||
*/
|
*/
|
||||||
public final class ZipUtils {
|
public final class ZipUtils {
|
||||||
|
|
||||||
|
public static final int BUFFER = 2048;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unzip files to path.
|
||||||
|
*
|
||||||
|
* @param zipFileName the zip file name
|
||||||
|
* @param fileExtractPath the file extract path
|
||||||
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
|
*/
|
||||||
|
public static void unzipFilesToPath(String jarPath, String destinationDir) throws IOException {
|
||||||
|
File file = new File(jarPath);
|
||||||
|
JarFile jar = new JarFile(file);
|
||||||
|
|
||||||
|
// fist get all directories,
|
||||||
|
// then make those directory on the destination Path
|
||||||
|
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||||
|
JarEntry entry = (JarEntry) enums.nextElement();
|
||||||
|
|
||||||
|
String fileName = destinationDir + File.separator + entry.getName();
|
||||||
|
File f = new File(fileName);
|
||||||
|
|
||||||
|
if (fileName.endsWith("/")) {
|
||||||
|
f.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//now create all files
|
||||||
|
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||||
|
JarEntry entry = (JarEntry) enums.nextElement();
|
||||||
|
|
||||||
|
String fileName = destinationDir + File.separator + entry.getName();
|
||||||
|
File f = new File(fileName);
|
||||||
|
|
||||||
|
if (!fileName.endsWith("/")) {
|
||||||
|
InputStream is = jar.getInputStream(entry);
|
||||||
|
FileOutputStream fos = new FileOutputStream(f);
|
||||||
|
|
||||||
|
// write contents of 'is' to 'fos'
|
||||||
|
while (is.available() > 0) {
|
||||||
|
fos.write(is.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
fos.close();
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
jar.close();
|
||||||
|
} catch(Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final String ZIP_FILE_EXTENSION = ".zip";
|
private static final String ZIP_FILE_EXTENSION = ".zip";
|
||||||
private static final FileFilter ZIP_FILE_FILTER = new FileFilter() {
|
private static final FileFilter ZIP_FILE_FILTER = new FileFilter() {
|
||||||
|
|
||||||
|
@ -98,10 +156,10 @@ public final class ZipUtils {
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (zipFile == null) {
|
if (zipFile == null) {
|
||||||
throw new IllegalArgumentException("Cannot unzip a null file!");
|
throw new IllegalArgumentException("Cannot unzip a null file!");
|
||||||
} else if (!ZIP_FILE_FILTER.accept(zipFile)) {
|
} /*else if (!ZIP_FILE_FILTER.accept(zipFile)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Given archive is not a valid Zip file!");
|
"Given archive is not a valid Zip file!");
|
||||||
}
|
}*/
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
throw new IllegalArgumentException("Cannot unzip to a null target!");
|
throw new IllegalArgumentException("Cannot unzip to a null target!");
|
||||||
}
|
}
|
||||||
|
@ -197,4 +255,28 @@ public final class ZipUtils {
|
||||||
|
|
||||||
return new File(file.getAbsolutePath().substring(parentPath.length()));
|
return new File(file.getAbsolutePath().substring(parentPath.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void zipFile(File inputFile, File outputZip) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(outputZip);
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(fos);
|
||||||
|
ZipEntry ze= new ZipEntry(inputFile.getName());
|
||||||
|
zos.putNextEntry(ze);
|
||||||
|
FileInputStream in = new FileInputStream(inputFile);
|
||||||
|
|
||||||
|
int len;
|
||||||
|
while ((len = in.read(buffer)) > 0) {
|
||||||
|
zos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
in.close();
|
||||||
|
zos.closeEntry();
|
||||||
|
|
||||||
|
zos.close();
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,9 @@ package the.bytecode.club.bytecodeviewer.api;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassAdapter;
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldInsnNode;
|
import org.objectweb.asm.tree.FieldInsnNode;
|
||||||
|
@ -13,6 +16,8 @@ import org.objectweb.asm.tree.MethodNode;
|
||||||
import org.objectweb.asm.tree.TypeInsnNode;
|
import org.objectweb.asm.tree.TypeInsnNode;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.CoolClassAdapter;
|
||||||
|
import the.bytecode.club.bytecodeviewer.JarUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to rename/replace methods/classes/fields
|
* Used to rename/replace methods/classes/fields
|
||||||
|
@ -164,16 +169,15 @@ public final class ASMUtil_OLD {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
ClassWriter cw2 = new ClassWriter(0);
|
||||||
* for(ClassNode oldClass : BytecodeViewer.getLoadedClasses()) { try {
|
c.accept(cw2);
|
||||||
* ClassReader cr = new ClassReader(oldClass.name); ClassWriter cw = new
|
ClassReader cr=new ClassReader(cw2.toByteArray());
|
||||||
* ClassWriter(0); cr.accept(new ClassVisitor(0) {
|
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
*
|
ClassAdapter ca=new CoolClassAdapter(cw, oldName, newName);
|
||||||
* @Override
|
cr.accept(ca, 0);
|
||||||
*
|
byte[] newClass = cw.toByteArray();
|
||||||
* }, ClassReader.EXPAND_FRAMES); byte[] b = cw.toByteArray(); }
|
BytecodeViewer.updateNode(c, JarUtils.getNode(newClass));
|
||||||
* catch(Exception e) { new ExceptionUI(e); } }
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -61,6 +61,14 @@ public class BytecodeViewer {
|
||||||
the.bytecode.club.bytecodeviewer.BytecodeViewer.openFiles(files, recentFiles);
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.openFiles(files, recentFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently opened class node, if nothing is opened it'll return null.
|
||||||
|
* @return The opened class node or a null if nothing is opened
|
||||||
|
*/
|
||||||
|
public static ClassNode getCurrentlyOpenedClassNode() {
|
||||||
|
return the.bytecode.club.bytecodeviewer.BytecodeViewer.getCurrentlyOpenedClassNode();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to load a ClassNode.
|
* Used to load a ClassNode.
|
||||||
*
|
*
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class ExceptionUI extends JFrame {
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
e.printStackTrace(new PrintWriter(sw));
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
||||||
txtrBytecodeViewerIs.setText(sw.toString());
|
txtrBytecodeViewerIs.setText("Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString());
|
||||||
this.setLocationRelativeTo(null);
|
this.setLocationRelativeTo(null);
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.java;
|
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -43,9 +43,8 @@ public class CFRDecompiler extends JavaDecompiler {
|
||||||
|
|
||||||
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
||||||
+ "temp";
|
+ "temp";
|
||||||
int fileNumber = getClassNumber(fileStart, ".class");
|
|
||||||
|
|
||||||
final File tempClass = new File(fileStart + fileNumber + ".class");
|
final File tempClass = new File(getUniqueName(fileStart, ".class") + ".class");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final FileOutputStream fos = new FileOutputStream(tempClass);
|
final FileOutputStream fos = new FileOutputStream(tempClass);
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.java;
|
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -61,11 +61,9 @@ public class FernFlowerDecompiler extends JavaDecompiler {
|
||||||
final ClassWriter cw = new ClassWriter(0);
|
final ClassWriter cw = new ClassWriter(0);
|
||||||
cn.accept(cw);
|
cn.accept(cw);
|
||||||
|
|
||||||
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
String start = getUniqueName("", ".class");
|
||||||
+ "temp";
|
|
||||||
int fileNumber = getClassNumber(fileStart, ".class");
|
|
||||||
|
|
||||||
final File tempClass = new File(fileStart + fileNumber + ".class");
|
final File tempClass = new File(start + ".class");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final FileOutputStream fos = new FileOutputStream(tempClass);
|
final FileOutputStream fos = new FileOutputStream(tempClass);
|
||||||
|
@ -82,7 +80,7 @@ public class FernFlowerDecompiler extends JavaDecompiler {
|
||||||
|
|
||||||
tempClass.delete();
|
tempClass.delete();
|
||||||
|
|
||||||
final File outputJava = new File("temp" + fileNumber + ".java");
|
final File outputJava = new File(start + ".java");
|
||||||
if (outputJava.exists()) {
|
if (outputJava.exists()) {
|
||||||
String s;
|
String s;
|
||||||
try {
|
try {
|
|
@ -0,0 +1,51 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.MiscUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Konloch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class JavaDecompiler {
|
||||||
|
|
||||||
|
public abstract String decompileClassNode(ClassNode cn);
|
||||||
|
|
||||||
|
public abstract void decompileToZip(String zipName);
|
||||||
|
|
||||||
|
public abstract void decompileToClass(String className, String classNameSaved);
|
||||||
|
|
||||||
|
public static String getUniqueName(String start, String ext) {
|
||||||
|
String s = null;
|
||||||
|
boolean b = true;
|
||||||
|
File f = null;
|
||||||
|
String m = null;
|
||||||
|
while (b) {
|
||||||
|
m = MiscUtils.randomString(32);
|
||||||
|
f = new File(start + m + ext);
|
||||||
|
if (!f.exists()) {
|
||||||
|
s = start + m;
|
||||||
|
b = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getClassNumber(String start, String ext) {
|
||||||
|
boolean b = true;
|
||||||
|
int i = 0;
|
||||||
|
while (b) {
|
||||||
|
File tempF = new File(start + i + ext);
|
||||||
|
if (!tempF.exists())
|
||||||
|
b = false;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.java;
|
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -96,9 +96,8 @@ public class ProcyonDecompiler extends JavaDecompiler {
|
||||||
|
|
||||||
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
||||||
+ "temp";
|
+ "temp";
|
||||||
int fileNumber = getClassNumber(fileStart, ".class");
|
|
||||||
|
|
||||||
final File tempClass = new File(fileStart + fileNumber + ".class");
|
final File tempClass = new File(getUniqueName(fileStart, ".class") + ".class");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final FileOutputStream fos = new FileOutputStream(tempClass);
|
final FileOutputStream fos = new FileOutputStream(tempClass);
|
131
src/the/bytecode/club/bytecodeviewer/decompilers/Smali.java
Normal file
131
src/the/bytecode/club/bytecodeviewer/decompilers/Smali.java
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.decompilers;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import me.konloch.kontainer.io.DiskReader;
|
||||||
|
import me.konloch.kontainer.io.DiskWriter;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.Dex2Jar;
|
||||||
|
import the.bytecode.club.bytecodeviewer.ZipUtils;
|
||||||
|
|
||||||
|
public class Smali {
|
||||||
|
|
||||||
|
public static String decompileClassNode(ClassNode cn) {
|
||||||
|
final ClassWriter cw = new ClassWriter(0);
|
||||||
|
cn.accept(cw);
|
||||||
|
|
||||||
|
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
||||||
|
+ "temp";
|
||||||
|
|
||||||
|
String start = JavaDecompiler.getUniqueName(fileStart, ".class");
|
||||||
|
|
||||||
|
final File tempClass = new File(start + ".class");
|
||||||
|
final File tempZip = new File(start + ".jar");
|
||||||
|
final File tempDex = new File(start + ".dex");
|
||||||
|
final File tempSmali = new File(start + "-smali"); //output directory
|
||||||
|
|
||||||
|
try {
|
||||||
|
final FileOutputStream fos = new FileOutputStream(tempClass);
|
||||||
|
|
||||||
|
fos.write(cw.toByteArray());
|
||||||
|
|
||||||
|
fos.close();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipUtils.zipFile(tempClass, tempZip);
|
||||||
|
Dex2Jar.saveAsDex(tempZip, tempDex);
|
||||||
|
try {
|
||||||
|
org.jf.baksmali.main.main(new String[]{"-o", tempSmali.getAbsolutePath(), "-x", tempDex.getAbsolutePath()});
|
||||||
|
} catch (Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
File outputSmali = null;
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
File current = tempSmali;
|
||||||
|
while(!found) {
|
||||||
|
File f = current.listFiles()[0];
|
||||||
|
if(f.isDirectory())
|
||||||
|
current = f;
|
||||||
|
else {
|
||||||
|
outputSmali = f;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return DiskReader.loadAsString(outputSmali.getAbsolutePath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] compile(String contents) {
|
||||||
|
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
||||||
|
+ "temp";
|
||||||
|
int fileNumber = JavaDecompiler.getClassNumber(fileStart, ".dex");
|
||||||
|
|
||||||
|
final File tempSmaliFolder = new File(fileStart + fileNumber + "-smalifolder"+BytecodeViewer.fs);
|
||||||
|
tempSmaliFolder.mkdir();
|
||||||
|
|
||||||
|
File tempSmali = new File(tempSmaliFolder.getAbsolutePath() +BytecodeViewer.fs + fileNumber + ".smali");
|
||||||
|
File tempDex = new File(fileStart + fileNumber + ".dex");
|
||||||
|
File tempJar = new File(fileStart + fileNumber + ".jar");
|
||||||
|
File tempJarFolder = new File(fileStart + fileNumber + "-jar"+BytecodeViewer.fs);
|
||||||
|
|
||||||
|
try {
|
||||||
|
DiskWriter.replaceFile(tempSmali.getAbsolutePath(), contents, false);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
org.jf.smali.main.main(new String[]{tempSmaliFolder.getAbsolutePath(), "-o", tempDex.getAbsolutePath()});
|
||||||
|
} catch (Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dex2Jar.dex2Jar(tempDex, tempJar);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipUtils.unzipFilesToPath(tempJar.getAbsolutePath(), tempJarFolder.getAbsolutePath());
|
||||||
|
|
||||||
|
File outputClass = null;
|
||||||
|
boolean found = false;
|
||||||
|
File current = tempJarFolder;
|
||||||
|
try {
|
||||||
|
while(!found) {
|
||||||
|
File f = current.listFiles()[0];
|
||||||
|
if(f.isDirectory())
|
||||||
|
current = f;
|
||||||
|
else {
|
||||||
|
outputClass = f;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return org.apache.commons.io.FileUtils.readFileToByteArray(outputClass);
|
||||||
|
} catch (java.lang.NullPointerException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
package the.bytecode.club.bytecodeviewer.decompilers.java;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Konloch
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public abstract class JavaDecompiler {
|
|
||||||
|
|
||||||
public abstract String decompileClassNode(ClassNode cn);
|
|
||||||
|
|
||||||
public abstract void decompileToZip(String zipName);
|
|
||||||
|
|
||||||
public abstract void decompileToClass(String className, String classNameSaved);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -45,10 +45,11 @@ import org.objectweb.asm.tree.ClassNode;
|
||||||
import com.jhe.hexed.JHexEditor;
|
import com.jhe.hexed.JHexEditor;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.CFRDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.FernFlowerDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.ProcyonDecompiler;
|
||||||
|
import the.bytecode.club.bytecodeviewer.decompilers.Smali;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.CFRDecompiler;
|
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.FernFlowerDecompiler;
|
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.ProcyonDecompiler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents the opened classfile.
|
* This represents the opened classfile.
|
||||||
|
@ -99,7 +100,7 @@ public class ClassViewer extends JPanel {
|
||||||
private static final long serialVersionUID = -8650495368920680024L;
|
private static final long serialVersionUID = -8650495368920680024L;
|
||||||
ArrayList<MethodData> lnData = new ArrayList<MethodData>();
|
ArrayList<MethodData> lnData = new ArrayList<MethodData>();
|
||||||
String name;
|
String name;
|
||||||
ClassNode cn;
|
public ClassNode cn;
|
||||||
JSplitPane sp;
|
JSplitPane sp;
|
||||||
JSplitPane sp2;
|
JSplitPane sp2;
|
||||||
public JPanel panel1Search = new JPanel(new BorderLayout());
|
public JPanel panel1Search = new JPanel(new BorderLayout());
|
||||||
|
@ -114,6 +115,9 @@ public class ClassViewer extends JPanel {
|
||||||
int pane1 = -1;
|
int pane1 = -1;
|
||||||
int pane2 = -1;
|
int pane2 = -1;
|
||||||
int pane3 = -1;
|
int pane3 = -1;
|
||||||
|
public RSyntaxTextArea smali1 = null;
|
||||||
|
public RSyntaxTextArea smali2 = null;
|
||||||
|
public RSyntaxTextArea smali3 = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This was really interesting to write.
|
* This was really interesting to write.
|
||||||
|
@ -455,6 +459,7 @@ public class ClassViewer extends JPanel {
|
||||||
PaneUpdaterThread t;
|
PaneUpdaterThread t;
|
||||||
|
|
||||||
public void startPaneUpdater(final JButton button) {
|
public void startPaneUpdater(final JButton button) {
|
||||||
|
this.cn = BytecodeViewer.getClassNode(cn.name); //update the classnode
|
||||||
if (BytecodeViewer.viewer.panelGroup1
|
if (BytecodeViewer.viewer.panelGroup1
|
||||||
.isSelected(BytecodeViewer.viewer.panel1None.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel1None.getModel()))
|
||||||
pane1 = 0;
|
pane1 = 0;
|
||||||
|
@ -473,6 +478,9 @@ public class ClassViewer extends JPanel {
|
||||||
else if (BytecodeViewer.viewer.panelGroup1
|
else if (BytecodeViewer.viewer.panelGroup1
|
||||||
.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
|
||||||
pane1 = 5;
|
pane1 = 5;
|
||||||
|
else if (BytecodeViewer.viewer.panelGroup1
|
||||||
|
.isSelected(BytecodeViewer.viewer.panel1Smali.getModel()))
|
||||||
|
pane1 = 6;
|
||||||
|
|
||||||
if (BytecodeViewer.viewer.panelGroup2
|
if (BytecodeViewer.viewer.panelGroup2
|
||||||
.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
|
||||||
|
@ -492,6 +500,9 @@ public class ClassViewer extends JPanel {
|
||||||
else if (BytecodeViewer.viewer.panelGroup2
|
else if (BytecodeViewer.viewer.panelGroup2
|
||||||
.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
|
||||||
pane2 = 5;
|
pane2 = 5;
|
||||||
|
else if (BytecodeViewer.viewer.panelGroup2
|
||||||
|
.isSelected(BytecodeViewer.viewer.panel2Smali.getModel()))
|
||||||
|
pane2 = 6;
|
||||||
|
|
||||||
if (BytecodeViewer.viewer.panelGroup3
|
if (BytecodeViewer.viewer.panelGroup3
|
||||||
.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
|
||||||
|
@ -511,6 +522,9 @@ public class ClassViewer extends JPanel {
|
||||||
else if (BytecodeViewer.viewer.panelGroup3
|
else if (BytecodeViewer.viewer.panelGroup3
|
||||||
.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
|
.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
|
||||||
pane3 = 5;
|
pane3 = 5;
|
||||||
|
else if (BytecodeViewer.viewer.panelGroup3
|
||||||
|
.isSelected(BytecodeViewer.viewer.panel3Smali.getModel()))
|
||||||
|
pane3 = 6;
|
||||||
|
|
||||||
t = new PaneUpdaterThread() {
|
t = new PaneUpdaterThread() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -519,6 +533,9 @@ public class ClassViewer extends JPanel {
|
||||||
panel1.removeAll();
|
panel1.removeAll();
|
||||||
panel2.removeAll();
|
panel2.removeAll();
|
||||||
panel3.removeAll();
|
panel3.removeAll();
|
||||||
|
smali1 = null;
|
||||||
|
smali2 = null;
|
||||||
|
smali3 = null;
|
||||||
|
|
||||||
if (pane1 != 0 && pane1 != 5)
|
if (pane1 != 0 && pane1 != 5)
|
||||||
panel1.add(panel1Search, BorderLayout.NORTH);
|
panel1.add(panel1Search, BorderLayout.NORTH);
|
||||||
|
@ -536,6 +553,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(proc_dc.decompileClassNode(cn));
|
panelArea.setText(proc_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel1.add(scrollPane);
|
panel1.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,6 +566,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel1.add(scrollPane);
|
panel1.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,6 +579,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(ff_dc.decompileClassNode(cn));
|
panelArea.setText(ff_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel1.add(scrollPane);
|
panel1.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,6 +593,7 @@ public class ClassViewer extends JPanel {
|
||||||
bytecodeArea);
|
bytecodeArea);
|
||||||
bytecodeArea.setText(ClassNodeDecompiler.decompile(cn));
|
bytecodeArea.setText(ClassNodeDecompiler.decompile(cn));
|
||||||
bytecodeArea.setCaretPosition(0);
|
bytecodeArea.setCaretPosition(0);
|
||||||
|
bytecodeArea.setEditable(false);
|
||||||
panel1.add(bytecodeSPane);
|
panel1.add(bytecodeSPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,6 +604,20 @@ public class ClassViewer extends JPanel {
|
||||||
panel1.add(hex);
|
panel1.add(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pane1 == 6) {// bytecode
|
||||||
|
RSyntaxTextArea bytecodeArea = new RSyntaxTextArea();
|
||||||
|
bytecodeArea
|
||||||
|
.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||||
|
bytecodeArea.setCodeFoldingEnabled(true);
|
||||||
|
bytecodeArea.setAntiAliasingEnabled(true);
|
||||||
|
RTextScrollPane bytecodeSPane = new RTextScrollPane(
|
||||||
|
bytecodeArea);
|
||||||
|
bytecodeArea.setText(Smali.decompileClassNode(cn));
|
||||||
|
bytecodeArea.setCaretPosition(0);
|
||||||
|
smali1 = bytecodeArea;
|
||||||
|
panel1.add(bytecodeSPane);
|
||||||
|
}
|
||||||
|
|
||||||
if (pane2 == 1) {
|
if (pane2 == 1) {
|
||||||
RSyntaxTextArea panelArea = new RSyntaxTextArea();
|
RSyntaxTextArea panelArea = new RSyntaxTextArea();
|
||||||
panelArea
|
panelArea
|
||||||
|
@ -592,6 +627,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(proc_dc.decompileClassNode(cn));
|
panelArea.setText(proc_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel2.add(scrollPane);
|
panel2.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,6 +640,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel2.add(scrollPane);
|
panel2.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,6 +653,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(ff_dc.decompileClassNode(cn));
|
panelArea.setText(ff_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel2.add(scrollPane);
|
panel2.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +665,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
||||||
paneArea.setText(ClassNodeDecompiler.decompile(cn));
|
paneArea.setText(ClassNodeDecompiler.decompile(cn));
|
||||||
paneArea.setCaretPosition(0);
|
paneArea.setCaretPosition(0);
|
||||||
|
paneArea.setEditable(false);
|
||||||
panel2.add(scrollPane);
|
panel2.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +676,18 @@ public class ClassViewer extends JPanel {
|
||||||
panel2.add(hex);
|
panel2.add(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pane2 == 6) {
|
||||||
|
RSyntaxTextArea paneArea = new RSyntaxTextArea();
|
||||||
|
paneArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||||
|
paneArea.setCodeFoldingEnabled(true);
|
||||||
|
paneArea.setAntiAliasingEnabled(true);
|
||||||
|
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
||||||
|
paneArea.setText(Smali.decompileClassNode(cn));
|
||||||
|
paneArea.setCaretPosition(0);
|
||||||
|
smali2 = paneArea;
|
||||||
|
panel2.add(scrollPane);
|
||||||
|
}
|
||||||
|
|
||||||
if (pane3 == 1) {
|
if (pane3 == 1) {
|
||||||
RSyntaxTextArea panelArea = new RSyntaxTextArea();
|
RSyntaxTextArea panelArea = new RSyntaxTextArea();
|
||||||
panelArea
|
panelArea
|
||||||
|
@ -646,6 +697,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(proc_dc.decompileClassNode(cn));
|
panelArea.setText(proc_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel3.add(scrollPane);
|
panel3.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,6 +710,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
panelArea.setText(cfr_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel3.add(scrollPane);
|
panel3.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,6 +723,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
|
||||||
panelArea.setText(ff_dc.decompileClassNode(cn));
|
panelArea.setText(ff_dc.decompileClassNode(cn));
|
||||||
panelArea.setCaretPosition(0);
|
panelArea.setCaretPosition(0);
|
||||||
|
panelArea.setEditable(false);
|
||||||
panel3.add(scrollPane);
|
panel3.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,6 +735,7 @@ public class ClassViewer extends JPanel {
|
||||||
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
||||||
paneArea.setText(ClassNodeDecompiler.decompile(cn));
|
paneArea.setText(ClassNodeDecompiler.decompile(cn));
|
||||||
paneArea.setCaretPosition(0);
|
paneArea.setCaretPosition(0);
|
||||||
|
paneArea.setEditable(false);
|
||||||
panel3.add(scrollPane);
|
panel3.add(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,6 +746,18 @@ public class ClassViewer extends JPanel {
|
||||||
panel3.add(hex);
|
panel3.add(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pane3 == 6) {
|
||||||
|
RSyntaxTextArea paneArea = new RSyntaxTextArea();
|
||||||
|
paneArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||||
|
paneArea.setCodeFoldingEnabled(true);
|
||||||
|
paneArea.setAntiAliasingEnabled(true);
|
||||||
|
RTextScrollPane scrollPane = new RTextScrollPane(paneArea);
|
||||||
|
paneArea.setText(Smali.decompileClassNode(cn));
|
||||||
|
paneArea.setCaretPosition(0);
|
||||||
|
smali3 = paneArea;
|
||||||
|
panel3.add(scrollPane);
|
||||||
|
}
|
||||||
|
|
||||||
resetDivider();
|
resetDivider();
|
||||||
BytecodeViewer.viewer.setIcon(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
@ -705,6 +772,17 @@ public class ClassViewer extends JPanel {
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object[] getSmali() {
|
||||||
|
if(smali1 != null)
|
||||||
|
return new Object[]{cn, smali1.getText()};
|
||||||
|
if(smali2 != null)
|
||||||
|
return new Object[]{cn, smali2.getText()};
|
||||||
|
if(smali3 != null)
|
||||||
|
return new Object[]{cn, smali3.getText()};
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static class MethodData {
|
public static class MethodData {
|
||||||
public String name, desc;
|
public String name, desc;
|
||||||
public int srcLN, bytecodeLN;
|
public int srcLN, bytecodeLN;
|
||||||
|
|
|
@ -41,10 +41,16 @@ public class ExportJar extends JFrame {
|
||||||
|
|
||||||
btnNewButton.addActionListener(new ActionListener() {
|
btnNewButton.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
BytecodeViewer.viewer.setC(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), jarPath,
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), jarPath,
|
||||||
mani.getText());
|
mani.getText());
|
||||||
BytecodeViewer.viewer.setC(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -242,6 +242,7 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTree() {
|
public void updateTree() {
|
||||||
|
try {
|
||||||
treeRoot.removeAllChildren();
|
treeRoot.removeAllChildren();
|
||||||
for (final Entry<String, ClassNode> entry : BytecodeViewer.loadedClasses
|
for (final Entry<String, ClassNode> entry : BytecodeViewer.loadedClasses
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
|
@ -272,6 +273,9 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
treeRoot.sort();
|
treeRoot.sort();
|
||||||
tree.expandPath(new TreePath(tree.getModel().getRoot()));
|
tree.expandPath(new TreePath(tree.getModel().getRoot()));
|
||||||
tree.updateUI();
|
tree.updateUI();
|
||||||
|
} catch(java.util.ConcurrentModificationException e) {
|
||||||
|
//ignore, the last file will reset everything
|
||||||
|
}
|
||||||
// expandAll(tree, true);
|
// expandAll(tree, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +314,7 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(final Graphics g) {
|
public void paint(final Graphics g) {
|
||||||
|
try {
|
||||||
super.paint(g);
|
super.paint(g);
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
m = new StringMetrics((Graphics2D) g);
|
m = new StringMetrics((Graphics2D) g);
|
||||||
|
@ -323,6 +328,9 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
((int) ((getWidth() / 2) - (m.getWidth(s) / 2))),
|
((int) ((getWidth() / 2) - (m.getWidth(s) / 2))),
|
||||||
getHeight() / 2);
|
getHeight() / 2);
|
||||||
}
|
}
|
||||||
|
} catch(java.lang.InternalError | java.lang.NullPointerException e) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ import javax.swing.SwingUtilities;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Frame;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
|
@ -27,17 +30,13 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Dex2Jar;
|
import the.bytecode.club.bytecodeviewer.Dex2Jar;
|
||||||
import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
|
import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
|
||||||
import the.bytecode.club.bytecodeviewer.JarUtils;
|
import the.bytecode.club.bytecodeviewer.JarUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.CFRDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.CFRDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.FernFlowerDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.FernFlowerDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.decompilers.java.ProcyonDecompiler;
|
import the.bytecode.club.bytecodeviewer.decompilers.ProcyonDecompiler;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.RenameClasses;
|
import the.bytecode.club.bytecodeviewer.obfuscators.RenameClasses;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.RenameFields;
|
import the.bytecode.club.bytecodeviewer.obfuscators.RenameFields;
|
||||||
import the.bytecode.club.bytecodeviewer.obfuscators.RenameMethods;
|
import the.bytecode.club.bytecodeviewer.obfuscators.RenameMethods;
|
||||||
import the.bytecode.club.bytecodeviewer.plugins.AllatoriStringDecrypter;
|
import the.bytecode.club.bytecodeviewer.plugins.*;
|
||||||
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.ActionListener;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
@ -45,7 +44,6 @@ import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.swing.JRadioButtonMenuItem;
|
import javax.swing.JRadioButtonMenuItem;
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
|
|
||||||
public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
|
|
||||||
|
@ -297,11 +295,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
public WorkPane workPane = new WorkPane(this);
|
public WorkPane workPane = new WorkPane(this);
|
||||||
private final JMenu mnSettings = new JMenu("Settings");
|
private final JMenu mnSettings = new JMenu("Settings");
|
||||||
private final JSeparator separator_6 = new JSeparator();
|
private final JSeparator separator_6 = new JSeparator();
|
||||||
public final JCheckBox refreshOnChange = new JCheckBox("Refresh On View Change");
|
public final JCheckBoxMenuItem refreshOnChange = new JCheckBoxMenuItem("Refresh On View Change");
|
||||||
|
|
||||||
final MainViewerGUI This = this;
|
public boolean isMaximized = false;
|
||||||
|
|
||||||
public void setC(boolean busy) {
|
public void removed(boolean busy) {
|
||||||
if (busy) {
|
if (busy) {
|
||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
for (Component c : this.getComponents())
|
for (Component c : this.getComponents())
|
||||||
|
@ -342,12 +340,25 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
ImageIcon busy = new ImageIcon(getClass().getResource("/resources/1.gif"));
|
ImageIcon busy = new ImageIcon(getClass().getResource("/resources/1.gif"));
|
||||||
ImageIcon busyB64 = new ImageIcon(BytecodeViewer.b642IMG("R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7"));
|
ImageIcon busyB64 = new ImageIcon(BytecodeViewer.b642IMG("R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7"));
|
||||||
private final JMenuItem mntmSaveAsApk = new JMenuItem("Save As DEX..");
|
private final JMenuItem mntmSaveAsApk = new JMenuItem("Save As DEX..");
|
||||||
|
private final JMenuItem mntmCodeSequenceDiagram = new JMenuItem("Code Sequence Diagram");
|
||||||
|
private final JSeparator separator_7 = new JSeparator();
|
||||||
|
private final JSeparator separator_8 = new JSeparator();
|
||||||
|
private final JSeparator separator_9 = new JSeparator();
|
||||||
|
private final JSeparator separator_10 = new JSeparator();
|
||||||
|
private final JSeparator separator_11 = new JSeparator();
|
||||||
|
private final JSeparator separator_12 = new JSeparator();
|
||||||
|
public final JRadioButtonMenuItem panel1Smali = new JRadioButtonMenuItem("Smali Editable");
|
||||||
|
public final JRadioButtonMenuItem panel2Smali = new JRadioButtonMenuItem("Smali Editable");
|
||||||
|
public final JRadioButtonMenuItem panel3Smali = new JRadioButtonMenuItem("Smali Editable");
|
||||||
|
public final JCheckBoxMenuItem autoCompileSmali = new JCheckBoxMenuItem("Compile Smali On Save");
|
||||||
|
private final JMenuItem mntmNewMenuItem_13 = new JMenuItem("Compile Smali");
|
||||||
|
public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile Smali On Refresh");
|
||||||
public void setIcon(final boolean busy) {
|
public void setIcon(final boolean busy) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (busy) {
|
if (busy) {
|
||||||
try {
|
try {
|
||||||
mntmNewMenuItem_4.setIcon(This.busy);
|
mntmNewMenuItem_4.setIcon(BytecodeViewer.viewer.busy);
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
mntmNewMenuItem_4.setIcon(busyB64);
|
mntmNewMenuItem_4.setIcon(busyB64);
|
||||||
}
|
}
|
||||||
|
@ -359,12 +370,32 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainViewerGUI() {
|
public MainViewerGUI() {
|
||||||
|
mnNewMenu_5.setVisible(false);
|
||||||
|
this.addWindowStateListener(new WindowAdapter() {
|
||||||
|
public void windowStateChanged(WindowEvent evt) {
|
||||||
|
int oldState = evt.getOldState();
|
||||||
|
int newState = evt.getNewState();
|
||||||
|
|
||||||
|
if ((oldState & Frame.ICONIFIED) == 0 && (newState & Frame.ICONIFIED) != 0) {
|
||||||
|
//System.out.println("Frame was iconized");
|
||||||
|
} else if ((oldState & Frame.ICONIFIED) != 0 && (newState & Frame.ICONIFIED) == 0) {
|
||||||
|
//System.out.println("Frame was deiconized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0) {
|
||||||
|
isMaximized = true;
|
||||||
|
} else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0) {
|
||||||
|
isMaximized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
this.setIconImages(BytecodeViewer.iconList);
|
this.setIconImages(BytecodeViewer.iconList);
|
||||||
panelGroup1.add(panel1None);
|
panelGroup1.add(panel1None);
|
||||||
panelGroup1.add(panel1Fern);
|
panelGroup1.add(panel1Fern);
|
||||||
panelGroup1.add(panel1Proc);
|
panelGroup1.add(panel1Proc);
|
||||||
panelGroup1.add(panel1CFR);
|
panelGroup1.add(panel1CFR);
|
||||||
panelGroup1.add(panel1Bytecode);
|
panelGroup1.add(panel1Bytecode);
|
||||||
|
panelGroup1.add(panel1Smali);
|
||||||
panelGroup1.add(panel1Hexcode);
|
panelGroup1.add(panel1Hexcode);
|
||||||
panelGroup1.setSelected(panel1Proc.getModel(), true);//my one true love
|
panelGroup1.setSelected(panel1Proc.getModel(), true);//my one true love
|
||||||
panelGroup2.add(panel2None);
|
panelGroup2.add(panel2None);
|
||||||
|
@ -372,6 +403,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
panelGroup2.add(panel2Proc);
|
panelGroup2.add(panel2Proc);
|
||||||
panelGroup2.add(panel2CFR);
|
panelGroup2.add(panel2CFR);
|
||||||
panelGroup2.add(panel2Bytecode);
|
panelGroup2.add(panel2Bytecode);
|
||||||
|
panelGroup2.add(panel2Smali);
|
||||||
panelGroup2.add(panel2Hexcode);
|
panelGroup2.add(panel2Hexcode);
|
||||||
panelGroup2.setSelected(panel2Bytecode.getModel(), true);
|
panelGroup2.setSelected(panel2Bytecode.getModel(), true);
|
||||||
panelGroup3.add(panel3None);
|
panelGroup3.add(panel3None);
|
||||||
|
@ -379,6 +411,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
panelGroup3.add(panel3Proc);
|
panelGroup3.add(panel3Proc);
|
||||||
panelGroup3.add(panel3CFR);
|
panelGroup3.add(panel3CFR);
|
||||||
panelGroup3.add(panel3Bytecode);
|
panelGroup3.add(panel3Bytecode);
|
||||||
|
panelGroup3.add(panel3Smali);
|
||||||
panelGroup3.add(panel3Hexcode);
|
panelGroup3.add(panel3Hexcode);
|
||||||
panelGroup3.setSelected(panel3None.getModel(), true);
|
panelGroup3.setSelected(panel3None.getModel(), true);
|
||||||
|
|
||||||
|
@ -400,18 +433,21 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
panel1Proc.addActionListener(listener);
|
panel1Proc.addActionListener(listener);
|
||||||
panel1CFR.addActionListener(listener);
|
panel1CFR.addActionListener(listener);
|
||||||
panel1Bytecode.addActionListener(listener);
|
panel1Bytecode.addActionListener(listener);
|
||||||
|
panel1Smali.addActionListener(listener);
|
||||||
panel1Hexcode.addActionListener(listener);
|
panel1Hexcode.addActionListener(listener);
|
||||||
panel2None.addActionListener(listener);
|
panel2None.addActionListener(listener);
|
||||||
panel2Fern.addActionListener(listener);
|
panel2Fern.addActionListener(listener);
|
||||||
panel2Proc.addActionListener(listener);
|
panel2Proc.addActionListener(listener);
|
||||||
panel2CFR.addActionListener(listener);
|
panel2CFR.addActionListener(listener);
|
||||||
panel2Bytecode.addActionListener(listener);
|
panel2Bytecode.addActionListener(listener);
|
||||||
|
panel2Smali.addActionListener(listener);
|
||||||
panel2Hexcode.addActionListener(listener);
|
panel2Hexcode.addActionListener(listener);
|
||||||
panel3None.addActionListener(listener);
|
panel3None.addActionListener(listener);
|
||||||
panel3Fern.addActionListener(listener);
|
panel3Fern.addActionListener(listener);
|
||||||
panel3Proc.addActionListener(listener);
|
panel3Proc.addActionListener(listener);
|
||||||
panel3CFR.addActionListener(listener);
|
panel3CFR.addActionListener(listener);
|
||||||
panel3Bytecode.addActionListener(listener);
|
panel3Bytecode.addActionListener(listener);
|
||||||
|
panel3Smali.addActionListener(listener);
|
||||||
panel3Hexcode.addActionListener(listener);
|
panel3Hexcode.addActionListener(listener);
|
||||||
obfuscatorGroup.add(strongObf);
|
obfuscatorGroup.add(strongObf);
|
||||||
obfuscatorGroup.add(lightObf);
|
obfuscatorGroup.add(lightObf);
|
||||||
|
@ -419,7 +455,6 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
// procyon
|
// procyon
|
||||||
/* none */
|
/* none */
|
||||||
chckbxmntmNewCheckItem_12.setSelected(true);
|
|
||||||
|
|
||||||
setJMenuBar(menuBar);
|
setJMenuBar(menuBar);
|
||||||
|
|
||||||
|
@ -439,14 +474,14 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
fc.setFileFilter(new APKDEXJarZipClassFileFilter());
|
fc.setFileFilter(new APKDEXJarZipClassFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
fc.setAcceptAllFileFilterUsed(false);
|
fc.setAcceptAllFileFilterUsed(false);
|
||||||
int returnVal = fc.showOpenDialog(This);
|
int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
|
||||||
|
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.setC(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
BytecodeViewer.openFiles(new File[] { fc
|
BytecodeViewer.openFiles(new File[] { fc
|
||||||
.getSelectedFile() }, true);
|
.getSelectedFile() }, true);
|
||||||
BytecodeViewer.viewer.setC(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
|
||||||
}
|
}
|
||||||
|
@ -459,6 +494,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
JMenuItem mntmSave = new JMenuItem("Save Files As..");
|
JMenuItem mntmSave = new JMenuItem("Save Files As..");
|
||||||
mntmSave.addActionListener(new ActionListener() {
|
mntmSave.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
if(BytecodeViewer.getLoadedClasses().isEmpty()) {
|
||||||
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(autoCompileSmali.isSelected() && !BytecodeViewer.compileSmali(false))
|
||||||
|
return;
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setFileFilter(new ZipFileFilter());
|
fc.setFileFilter(new ZipFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
|
@ -466,10 +507,42 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
File file = fc.getSelectedFile();
|
File file = fc.getSelectedFile();
|
||||||
BytecodeViewer.viewer.setC(true);
|
if(!file.getAbsolutePath().endsWith(".zip"))
|
||||||
|
file = new File(file.getAbsolutePath()+".zip");
|
||||||
|
|
||||||
|
if(file.exists()) {
|
||||||
|
JOptionPane pane = new JOptionPane(
|
||||||
|
"Are you sure you wish to overwrite this existing file?");
|
||||||
|
Object[] options = new String[] { "Yes", "No" };
|
||||||
|
pane.setOptions(options);
|
||||||
|
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
|
||||||
|
"Bytecode Viewer - Overwrite File");
|
||||||
|
dialog.setVisible(true);
|
||||||
|
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) {
|
||||||
|
file.delete();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final File file2 = file;
|
||||||
|
|
||||||
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(),
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(),
|
||||||
file.getAbsolutePath());
|
file2.getAbsolutePath());
|
||||||
BytecodeViewer.viewer.setC(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -477,6 +550,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
mnNewMenu.add(separator_3);
|
mnNewMenu.add(separator_3);
|
||||||
mntmNewMenuItem_3.addActionListener(new ActionListener() {
|
mntmNewMenuItem_3.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if(BytecodeViewer.getLoadedClasses().isEmpty()) {
|
||||||
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(autoCompileSmali.isSelected() && !BytecodeViewer.compileSmali(false))
|
||||||
|
return;
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setFileFilter(new JarFileFilter());
|
fc.setFileFilter(new JarFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
|
@ -487,14 +566,49 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
String path = file.getAbsolutePath();
|
String path = file.getAbsolutePath();
|
||||||
if (!path.endsWith(".jar"))
|
if (!path.endsWith(".jar"))
|
||||||
path = path + ".jar";
|
path = path + ".jar";
|
||||||
|
|
||||||
|
if(new File(path).exists()) {
|
||||||
|
JOptionPane pane = new JOptionPane(
|
||||||
|
"Are you sure you wish to overwrite this existing file?");
|
||||||
|
Object[] options = new String[] { "Yes", "No" };
|
||||||
|
pane.setOptions(options);
|
||||||
|
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
|
||||||
|
"Bytecode Viewer - Overwrite File");
|
||||||
|
dialog.setVisible(true);
|
||||||
|
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) {
|
||||||
|
file.delete();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
new ExportJar(path).setVisible(true);
|
new ExportJar(path).setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mntmNewMenuItem_13.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
BytecodeViewer.compileSmali(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mnNewMenu.add(mntmNewMenuItem_13);
|
||||||
|
|
||||||
mnNewMenu.add(mntmNewMenuItem_3);
|
mnNewMenu.add(mntmNewMenuItem_3);
|
||||||
mntmSaveAsApk.addActionListener(new ActionListener() {
|
mntmSaveAsApk.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
if(BytecodeViewer.getLoadedClasses().isEmpty()) {
|
||||||
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(autoCompileSmali.isSelected() && !BytecodeViewer.compileSmali(false))
|
||||||
|
return;
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setFileFilter(new DexFileFilter());
|
fc.setFileFilter(new DexFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
|
@ -502,7 +616,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
final File file = fc.getSelectedFile();
|
final File file = fc.getSelectedFile();
|
||||||
if(file.exists()) {
|
String output = file.getAbsolutePath();
|
||||||
|
if (!output.endsWith(".dex"))
|
||||||
|
output = output + ".dex";
|
||||||
|
|
||||||
|
final File file2 = new File(output);
|
||||||
|
|
||||||
|
if(file2.exists()) {
|
||||||
JOptionPane pane = new JOptionPane(
|
JOptionPane pane = new JOptionPane(
|
||||||
"Are you sure you wish to overwrite this existing file?");
|
"Are you sure you wish to overwrite this existing file?");
|
||||||
Object[] options = new String[] { "Yes", "No" };
|
Object[] options = new String[] { "Yes", "No" };
|
||||||
|
@ -527,17 +647,21 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
BytecodeViewer.viewer.setIcon(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
String input = BytecodeViewer.tempDirectory+BytecodeViewer.fs+BytecodeViewer.getRandomizedName()+".jar";
|
final String input = BytecodeViewer.tempDirectory+BytecodeViewer.fs+BytecodeViewer.getRandomizedName()+".jar";
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
|
||||||
String output = file.getAbsolutePath();
|
|
||||||
if (!output.endsWith(".dex"))
|
Thread t = new Thread() {
|
||||||
output = output + ".dex";
|
@Override
|
||||||
Dex2Jar.saveAsDex(new File(input), new File(output));
|
public void run() {
|
||||||
|
Dex2Jar.saveAsDex(new File(input), file2);
|
||||||
BytecodeViewer.viewer.setIcon(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -545,6 +669,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
mnNewMenu.add(mntmSave);
|
mnNewMenu.add(mntmSave);
|
||||||
mntmNewMenuItem.addActionListener(new ActionListener() {
|
mntmNewMenuItem.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
if(BytecodeViewer.getLoadedClasses().isEmpty()) {
|
||||||
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(autoCompileSmali.isSelected() && !BytecodeViewer.compileSmali(false))
|
||||||
|
return;
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setFileFilter(new ZipFileFilter());
|
fc.setFileFilter(new ZipFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
|
@ -552,6 +682,30 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
File file = fc.getSelectedFile();
|
File file = fc.getSelectedFile();
|
||||||
|
if(!file.getAbsolutePath().endsWith(".zip"))
|
||||||
|
file = new File(file.getAbsolutePath()+".zip");
|
||||||
|
|
||||||
|
if(file.exists()) {
|
||||||
|
JOptionPane pane = new JOptionPane(
|
||||||
|
"Are you sure you wish to overwrite this existing file?");
|
||||||
|
Object[] options = new String[] { "Yes", "No" };
|
||||||
|
pane.setOptions(options);
|
||||||
|
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
|
||||||
|
"Bytecode Viewer - Overwrite File");
|
||||||
|
dialog.setVisible(true);
|
||||||
|
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) {
|
||||||
|
file.delete();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BytecodeViewer.viewer.setIcon(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
final String path = appendZip(file);// cheap hax cause
|
final String path = appendZip(file);// cheap hax cause
|
||||||
// string is final
|
// string is final
|
||||||
|
@ -621,9 +775,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
mntmNewMenuItem_12.addActionListener(new ActionListener() {
|
mntmNewMenuItem_12.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
if(workPane.getCurrentClass() == null) {
|
if(workPane.getCurrentClass() == null) {
|
||||||
BytecodeViewer.showMessage("First open a class file.");
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(autoCompileSmali.isSelected() && !BytecodeViewer.compileSmali(false))
|
||||||
|
return;
|
||||||
final String s = workPane.getCurrentClass().name;
|
final String s = workPane.getCurrentClass().name;
|
||||||
|
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
|
@ -633,10 +789,32 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
File file = fc.getSelectedFile();
|
File file = fc.getSelectedFile();
|
||||||
|
|
||||||
BytecodeViewer.viewer.setIcon(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
final String path = appendClass(file);// cheap hax cause
|
final String path = appendJava(file);// cheap hax cause
|
||||||
// string is final
|
// string is final
|
||||||
|
|
||||||
|
if(new File(path).exists()) {
|
||||||
|
JOptionPane pane = new JOptionPane(
|
||||||
|
"Are you sure you wish to overwrite this existing file?");
|
||||||
|
Object[] options = new String[] { "Yes", "No" };
|
||||||
|
pane.setOptions(options);
|
||||||
|
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
|
||||||
|
"Bytecode Viewer - Overwrite File");
|
||||||
|
dialog.setVisible(true);
|
||||||
|
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) {
|
||||||
|
file.delete();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JOptionPane pane = new JOptionPane(
|
JOptionPane pane = new JOptionPane(
|
||||||
"What decompiler will you use?");
|
"What decompiler will you use?");
|
||||||
Object[] options = new String[] { "Procyon", "CFR",
|
Object[] options = new String[] { "Procyon", "CFR",
|
||||||
|
@ -719,8 +897,6 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
|
|
||||||
mnNewMenu.add(mntmAbout);
|
mnNewMenu.add(mntmAbout);
|
||||||
|
|
||||||
mnNewMenu.add(chckbxmntmNewCheckItem_12);
|
|
||||||
|
|
||||||
JMenuItem mntmExit = new JMenuItem("Exit");
|
JMenuItem mntmExit = new JMenuItem("Exit");
|
||||||
mntmExit.addActionListener(new ActionListener() {
|
mntmExit.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
@ -750,46 +926,70 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1None);
|
mnNewMenu_7.add(panel1None);
|
||||||
|
|
||||||
|
mnNewMenu_7.add(separator_7);
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1Proc);
|
mnNewMenu_7.add(panel1Proc);
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1CFR);
|
mnNewMenu_7.add(panel1CFR);
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1Fern);
|
mnNewMenu_7.add(panel1Fern);
|
||||||
|
|
||||||
|
mnNewMenu_7.add(separator_8);
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1Bytecode);
|
mnNewMenu_7.add(panel1Bytecode);
|
||||||
|
|
||||||
|
mnNewMenu_7.add(panel1Smali);
|
||||||
|
|
||||||
mnNewMenu_7.add(panel1Hexcode);
|
mnNewMenu_7.add(panel1Hexcode);
|
||||||
|
|
||||||
mnNewMenu_6.add(mnNewMenu_8);
|
mnNewMenu_6.add(mnNewMenu_8);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2None);
|
mnNewMenu_8.add(panel2None);
|
||||||
|
|
||||||
|
mnNewMenu_8.add(separator_9);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2Proc);
|
mnNewMenu_8.add(panel2Proc);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2CFR);
|
mnNewMenu_8.add(panel2CFR);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2Fern);
|
mnNewMenu_8.add(panel2Fern);
|
||||||
|
|
||||||
|
mnNewMenu_8.add(separator_10);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2Bytecode);
|
mnNewMenu_8.add(panel2Bytecode);
|
||||||
|
|
||||||
|
mnNewMenu_8.add(panel2Smali);
|
||||||
|
|
||||||
mnNewMenu_8.add(panel2Hexcode);
|
mnNewMenu_8.add(panel2Hexcode);
|
||||||
|
|
||||||
mnNewMenu_6.add(mnNewMenu_9);
|
mnNewMenu_6.add(mnNewMenu_9);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3None);
|
mnNewMenu_9.add(panel3None);
|
||||||
|
|
||||||
|
mnNewMenu_9.add(separator_11);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3Proc);
|
mnNewMenu_9.add(panel3Proc);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3CFR);
|
mnNewMenu_9.add(panel3CFR);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3Fern);
|
mnNewMenu_9.add(panel3Fern);
|
||||||
|
|
||||||
|
mnNewMenu_9.add(separator_12);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3Bytecode);
|
mnNewMenu_9.add(panel3Bytecode);
|
||||||
|
|
||||||
|
mnNewMenu_9.add(panel3Smali);
|
||||||
|
|
||||||
mnNewMenu_9.add(panel3Hexcode);
|
mnNewMenu_9.add(panel3Hexcode);
|
||||||
|
|
||||||
menuBar.add(mnSettings);
|
menuBar.add(mnSettings);
|
||||||
|
|
||||||
|
mnSettings.add(autoCompileSmali);
|
||||||
|
|
||||||
|
mnSettings.add(autoCompileOnRefresh);
|
||||||
|
mnSettings.add(chckbxmntmNewCheckItem_12);
|
||||||
|
chckbxmntmNewCheckItem_12.setSelected(true);
|
||||||
|
|
||||||
mnSettings.add(refreshOnChange);
|
mnSettings.add(refreshOnChange);
|
||||||
|
|
||||||
mnSettings.add(separator_6);
|
mnSettings.add(separator_6);
|
||||||
|
@ -1007,8 +1207,6 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
|
|
||||||
mnBytecodeDecompilerSettings.add(chckbxmntmAppendBrackets);
|
mnBytecodeDecompilerSettings.add(chckbxmntmAppendBrackets);
|
||||||
|
|
||||||
mnNewMenu_5.setVisible(false);
|
|
||||||
|
|
||||||
menuBar.add(mnNewMenu_5);
|
menuBar.add(mnNewMenu_5);
|
||||||
mntmNewMenuItem_6.addActionListener(new ActionListener() {
|
mntmNewMenuItem_6.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
@ -1067,6 +1265,20 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
mnNewMenu_1.add(separator_4);
|
mnNewMenu_1.add(separator_4);
|
||||||
mnNewMenu_1.add(mnRecentPlugins);
|
mnNewMenu_1.add(mnRecentPlugins);
|
||||||
mnNewMenu_1.add(separator_5);
|
mnNewMenu_1.add(separator_5);
|
||||||
|
mntmCodeSequenceDiagram.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
if (!BytecodeViewer.loadedClasses.isEmpty())
|
||||||
|
PluginManager.runPlugin(new CodeSequenceDiagram());
|
||||||
|
else {
|
||||||
|
System.out
|
||||||
|
.println("Plugin not ran, put some classes in first.");
|
||||||
|
BytecodeViewer
|
||||||
|
.showMessage("Plugin not ran, put some classes in first.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mnNewMenu_1.add(mntmCodeSequenceDiagram);
|
||||||
mnNewMenu_1.add(mntmNewMenuItem_1);
|
mnNewMenu_1.add(mntmNewMenuItem_1);
|
||||||
mnNewMenu_1.add(mntmShowMainMethods);
|
mnNewMenu_1.add(mntmShowMainMethods);
|
||||||
mnNewMenu_1.add(mntmShowAllStrings);
|
mnNewMenu_1.add(mntmShowAllStrings);
|
||||||
|
@ -1109,13 +1321,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
fc.setFileFilter(new GroovyPythonRubyFileFilter());
|
fc.setFileFilter(new GroovyPythonRubyFileFilter());
|
||||||
fc.setFileHidingEnabled(false);
|
fc.setFileHidingEnabled(false);
|
||||||
fc.setAcceptAllFileFilterUsed(false);
|
fc.setAcceptAllFileFilterUsed(false);
|
||||||
int returnVal = fc.showOpenDialog(This);
|
int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
|
||||||
|
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION)
|
if (returnVal == JFileChooser.APPROVE_OPTION)
|
||||||
try {
|
try {
|
||||||
BytecodeViewer.viewer.setC(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
BytecodeViewer.startPlugin(fc.getSelectedFile());
|
BytecodeViewer.startPlugin(fc.getSelectedFile());
|
||||||
BytecodeViewer.viewer.setC(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
|
||||||
}
|
}
|
||||||
|
@ -1198,6 +1410,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String appendJava(File file) {
|
||||||
|
String path = file.getAbsolutePath();
|
||||||
|
if (!path.endsWith(".java"))
|
||||||
|
path = path + ".java";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openClassFile(final String name, final ClassNode cn) {
|
public void openClassFile(final String name, final ClassNode cn) {
|
||||||
for (final VisibleComponent vc : rfComps) {
|
for (final VisibleComponent vc : rfComps) {
|
||||||
|
|
|
@ -113,16 +113,26 @@ public class WorkPane extends VisibleComponent implements ActionListener {
|
||||||
return (ClassViewer) tabs.getSelectedComponent();
|
return (ClassViewer) tabs.getSelectedComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public java.awt.Component[] getLoadedViewers() {
|
||||||
|
return (java.awt.Component[])tabs.getComponents();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(final ActionEvent arg0) {
|
public void actionPerformed(final ActionEvent arg0) {
|
||||||
|
if(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected())
|
||||||
|
try {
|
||||||
|
BytecodeViewer.compileSmali(false);
|
||||||
|
} catch(java.lang.NullPointerException e) {
|
||||||
|
|
||||||
|
}
|
||||||
final JButton src = (JButton) arg0.getSource();
|
final JButton src = (JButton) arg0.getSource();
|
||||||
if (src == refreshClass) {
|
if (src == refreshClass) {
|
||||||
final Component tabComp = tabs.getSelectedComponent();
|
final Component tabComp = tabs.getSelectedComponent();
|
||||||
if (tabComp != null) {
|
if (tabComp != null) {
|
||||||
src.setEnabled(false);
|
src.setEnabled(false);
|
||||||
BytecodeViewer.viewer.setC(true);
|
BytecodeViewer.viewer.setIcon(true);
|
||||||
((ClassViewer) tabComp).startPaneUpdater(src);
|
((ClassViewer) tabComp).startPaneUpdater(src);
|
||||||
BytecodeViewer.viewer.setC(false);
|
BytecodeViewer.viewer.setIcon(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.plugins;
|
||||||
|
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import com.mxgraph.swing.mxGraphComponent;
|
||||||
|
import com.mxgraph.view.mxGraph;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple code sequence diagram.
|
||||||
|
*
|
||||||
|
* @author Konloch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CodeSequenceDiagram extends Plugin {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void execute(ArrayList<ClassNode> classNodeList) {
|
||||||
|
if(BytecodeViewer.viewer.workPane.getCurrentClass() == null) {
|
||||||
|
BytecodeViewer.showMessage("First open a class file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClassNode c = BytecodeViewer.viewer.workPane.getCurrentClass().cn;
|
||||||
|
JFrame frame = new JFrame("Code Sequence Diagram - " +c.name);
|
||||||
|
frame.setIconImages(BytecodeViewer.iconList);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
frame.setSize(400, 320);
|
||||||
|
mxGraph graph = new mxGraph();
|
||||||
|
graph.setVertexLabelsMovable(false);
|
||||||
|
graph.setGridEnabled(true);
|
||||||
|
graph.setEnabled(false);
|
||||||
|
graph.setCellsEditable(false);
|
||||||
|
graph.setCellsSelectable(false);
|
||||||
|
graph.setCellsMovable(false);
|
||||||
|
graph.setCellsLocked(true);
|
||||||
|
Object parent = graph.getDefaultParent();
|
||||||
|
Font font = UIManager.getDefaults().getFont("TabbedPane.font");
|
||||||
|
AffineTransform affinetransform = new AffineTransform();
|
||||||
|
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);
|
||||||
|
|
||||||
|
graph.getModel().beginUpdate();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
int testX = 10;
|
||||||
|
int testY = 0;
|
||||||
|
double magicNumber = 5.8;
|
||||||
|
|
||||||
|
for(MethodNode m : (ArrayList<MethodNode>)c.methods) {
|
||||||
|
String mIdentifier = c.name+"."+m.name+m.desc;
|
||||||
|
Object node = graph.insertVertex(parent, null, mIdentifier, testX, testY, mIdentifier.length() * magicNumber, 30);
|
||||||
|
Object attach = node;
|
||||||
|
testX += (int) (font.getStringBounds(mIdentifier, frc).getWidth()) + 60;
|
||||||
|
for (AbstractInsnNode i : m.instructions.toArray()) {
|
||||||
|
if (i instanceof MethodInsnNode) {
|
||||||
|
MethodInsnNode mi = (MethodInsnNode) i;
|
||||||
|
String identifier = mi.owner+"."+mi.name+mi.desc;
|
||||||
|
Object node2 = graph.insertVertex(parent, null, identifier, testX, testY, identifier.length() * 5, 30);
|
||||||
|
testX += (int) (font.getStringBounds(identifier, frc).getWidth()) + 60;
|
||||||
|
graph.insertEdge(parent, null, null, attach, node2);
|
||||||
|
attach = node2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testY += 60;
|
||||||
|
testX = 10;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
graph.getModel().endUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
mxGraphComponent graphComponent = new mxGraphComponent(graph);
|
||||||
|
frame.getContentPane().add(graphComponent);
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue