2018-01-31 15:03:53 +00:00
|
|
|
package the.bytecode.club.bytecodeviewer.api;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.net.URLClassLoader;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Enumeration;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.jar.JarEntry;
|
|
|
|
import java.util.jar.JarFile;
|
|
|
|
import org.objectweb.asm.tree.ClassNode;
|
2021-06-26 14:21:23 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.compilers.Compiler;
|
|
|
|
import the.bytecode.club.bytecodeviewer.compilers.InternalCompiler;
|
2021-06-26 01:13:46 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
2018-01-31 15:03:53 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
|
|
|
|
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
|
2021-07-21 15:20:38 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.util.DialogUtils;
|
2021-04-12 20:19:12 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
2021-06-26 01:13:46 +00:00
|
|
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2021-07-01 21:54:10 +00:00
|
|
|
import javax.swing.*;
|
|
|
|
|
2021-06-21 09:45:31 +00:00
|
|
|
import static the.bytecode.club.bytecodeviewer.Constants.*;
|
|
|
|
|
2018-01-31 15:03:53 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
|
|
|
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
|
|
|
|
* *
|
|
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/**
|
2021-07-07 04:36:11 +00:00
|
|
|
* The official API for BCV, this was designed for plugin authors and developers utilizing EZ-Injection.
|
|
|
|
*
|
|
|
|
* The BCV Class is meant to to help aid in dynamic analysis and plugin utility.
|
2018-01-31 15:41:24 +00:00
|
|
|
*
|
2018-01-31 15:03:53 +00:00
|
|
|
* @author Konloch
|
|
|
|
*/
|
2021-07-07 04:36:11 +00:00
|
|
|
public class BCV
|
2021-07-07 04:21:06 +00:00
|
|
|
{
|
2021-07-19 17:46:35 +00:00
|
|
|
private static ClassNodeLoader loader = new ClassNodeLoader();
|
2018-01-31 15:41:24 +00:00
|
|
|
private static URLClassLoader cl;
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Grab the loader instance
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public static ClassNodeLoader getClassNodeLoader() {
|
2021-07-07 04:21:06 +00:00
|
|
|
return loader;
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the URLClassLoader instance
|
|
|
|
*
|
|
|
|
* @return the URLClassLoader instance
|
|
|
|
*/
|
|
|
|
public static URLClassLoader getClassLoaderInstance() {
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Re-instances the URLClassLoader and loads a jar to it.
|
|
|
|
*
|
|
|
|
* @return The loaded classes into the new URLClassLoader instance
|
|
|
|
* @author Cafebabe
|
|
|
|
*/
|
2021-06-28 04:13:55 +00:00
|
|
|
public static Class<?> loadClassIntoClassLoader(ClassNode cn)
|
|
|
|
{
|
2021-07-23 22:34:26 +00:00
|
|
|
if(cn == null)
|
|
|
|
return null;
|
|
|
|
|
2021-06-28 04:13:55 +00:00
|
|
|
getClassNodeLoader().addClass(cn);
|
|
|
|
|
2021-07-23 22:34:26 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
//TODO this should be rebuilding the class loader each time a new resource has been added or removed
|
|
|
|
if(cl == null)
|
|
|
|
loadClassesIntoClassLoader();
|
|
|
|
|
2021-06-28 04:13:55 +00:00
|
|
|
return cl.loadClass(cn.name);
|
|
|
|
} catch (Exception classLoadException) {
|
2021-07-07 02:51:10 +00:00
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.handleException(classLoadException);
|
2021-06-28 04:13:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-06-28 00:03:43 +00:00
|
|
|
public static List<Class<?>> loadClassesIntoClassLoader()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2021-06-26 01:13:46 +00:00
|
|
|
File f = new File(tempDirectory + fs + MiscUtils.randomString(12) + "loaded_temp.jar");
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2021-07-07 04:36:11 +00:00
|
|
|
JarUtils.saveAsJar(BCV.getLoadedClasses(), f.getAbsolutePath());
|
2018-01-31 15:41:24 +00:00
|
|
|
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
Enumeration<JarEntry> e = jarFile.entries();
|
|
|
|
URL[] urls = {new URL("jar:file:" + "" + f.getAbsolutePath() + "!/")};
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
cl = URLClassLoader.newInstance(urls);
|
2021-04-12 22:31:22 +00:00
|
|
|
List<Class<?>> ret = new ArrayList<>();
|
2018-01-31 15:41:24 +00:00
|
|
|
|
2021-06-28 00:03:43 +00:00
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
2021-04-12 20:19:12 +00:00
|
|
|
JarEntry je = e.nextElement();
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
if (je.isDirectory() || !je.getName().endsWith(".class"))
|
|
|
|
continue;
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
String className = je.getName().replace("/", ".").replace(".class", "");
|
|
|
|
className = className.replace('/', '.');
|
2021-06-28 00:03:43 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
try {
|
|
|
|
ret.add(cl.loadClass(className));
|
2021-06-28 00:03:43 +00:00
|
|
|
} catch (Exception classLoadException) {
|
2021-07-07 02:51:10 +00:00
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.handleException(classLoadException);
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
}
|
2021-06-28 04:13:55 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
jarFile.close();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
} catch (Exception e) {
|
2021-07-07 02:51:10 +00:00
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.handleException(e);
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new instance of the ClassNode loader.
|
|
|
|
*/
|
|
|
|
public static void createNewClassNodeLoaderInstance() {
|
2021-07-07 04:21:06 +00:00
|
|
|
loader.clear();
|
|
|
|
loader = new ClassNodeLoader();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to start a plugin from file.
|
|
|
|
*
|
|
|
|
* @param plugin the file of the plugin
|
|
|
|
*/
|
|
|
|
public static void startPlugin(File plugin) {
|
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.startPlugin(plugin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to load classes/jars into BCV.
|
|
|
|
*
|
|
|
|
* @param files an array of the files you want loaded.
|
|
|
|
* @param recentFiles if it should save to the recent files menu.
|
|
|
|
*/
|
|
|
|
public static void openFiles(File[] files, boolean 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.
|
|
|
|
*
|
|
|
|
* @param name the full name of the ClassNode
|
|
|
|
* @return the ClassNode
|
|
|
|
*/
|
|
|
|
public static ClassNode getClassNode(String name) {
|
|
|
|
return the.bytecode.club.bytecodeviewer.BytecodeViewer
|
2021-07-10 16:05:08 +00:00
|
|
|
.blindlySearchForClassNode(name);
|
2018-01-31 15:03:53 +00:00
|
|
|
}
|
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Used to grab the loaded ClassNodes.
|
|
|
|
*
|
|
|
|
* @return the loaded classes
|
|
|
|
*/
|
|
|
|
public static ArrayList<ClassNode> getLoadedClasses() {
|
|
|
|
return the.bytecode.club.bytecodeviewer.BytecodeViewer
|
|
|
|
.getLoadedClasses();
|
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Used to insert a Bytecode Hook using EZ-Injection.
|
|
|
|
*
|
|
|
|
* @param hook
|
|
|
|
*/
|
|
|
|
public static void insertHook(BytecodeHook hook) {
|
|
|
|
EZInjection.hookArray.add(hook);
|
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* This will ask the user if they really want to reset the workspace, then
|
|
|
|
* it'll reset the work space.
|
|
|
|
*
|
|
|
|
* @param ask if it should ask the user about resetting the workspace
|
|
|
|
*/
|
|
|
|
public static void resetWorkSpace(boolean ask) {
|
2021-07-06 22:57:42 +00:00
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.resetWorkspace(ask);
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* If true, it will display the busy icon, if false it will remove it if
|
|
|
|
* it's displayed.
|
|
|
|
*
|
|
|
|
* @param busy if it should display the busy icon or not
|
|
|
|
*/
|
|
|
|
public static void setBusy(boolean busy) {
|
2021-07-06 22:57:42 +00:00
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.updateBusyStatus(busy);
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Sends a small window popup with the defined message.
|
|
|
|
*
|
|
|
|
* @param message the message you want to display
|
|
|
|
*/
|
|
|
|
public static void showMessage(String message) {
|
|
|
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.showMessage(message);
|
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2021-07-01 21:54:10 +00:00
|
|
|
/**
|
|
|
|
* Asks if the user would like to overwrite the file
|
|
|
|
*/
|
|
|
|
public static boolean canOverwriteFile(File file) {
|
2021-07-21 15:20:38 +00:00
|
|
|
return DialogUtils.canOverwriteFile(file);
|
2021-07-01 21:54:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void hideFrame(JFrame frame, long milliseconds)
|
|
|
|
{
|
|
|
|
new Thread(()->{
|
|
|
|
long started = System.currentTimeMillis();
|
|
|
|
while(System.currentTimeMillis()-started <= milliseconds)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Thread.sleep(100);
|
|
|
|
} catch (InterruptedException e) { }
|
|
|
|
}
|
|
|
|
|
|
|
|
frame.setVisible(false);
|
|
|
|
}, "Timed Swing Hide").start();
|
|
|
|
}
|
2021-07-21 15:20:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Log to System.out
|
|
|
|
*/
|
|
|
|
public static void log(String s)
|
|
|
|
{
|
|
|
|
log(false, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Log to System.out
|
|
|
|
*/
|
|
|
|
public static void log(boolean devModeOnly, String s)
|
|
|
|
{
|
|
|
|
if(!devModeOnly || DEV_MODE)
|
|
|
|
System.out.println(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Log to System.err
|
|
|
|
*/
|
|
|
|
public static void logE(String s)
|
|
|
|
{
|
|
|
|
logE(false, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Log to System.err
|
|
|
|
*/
|
|
|
|
public static void logE(boolean devModeOnly, String s)
|
|
|
|
{
|
|
|
|
if(!devModeOnly || DEV_MODE)
|
|
|
|
System.err.println(s);
|
|
|
|
}
|
2021-07-01 21:54:10 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped Krakatau Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Krakatau Decompiler instance
|
|
|
|
*/
|
2021-06-26 01:13:46 +00:00
|
|
|
public static InternalDecompiler getKrakatauDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.KRAKATAU_DECOMPILER.getDecompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped Procyon Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Procyon Decompiler instance
|
|
|
|
*/
|
2021-06-26 01:13:46 +00:00
|
|
|
public static InternalDecompiler getProcyonDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.PROCYON_DECOMPILER.getDecompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped CFR Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped CFR Decompiler instance
|
|
|
|
*/
|
2021-06-26 01:13:46 +00:00
|
|
|
public static InternalDecompiler getCFRDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.CFR_DECOMPILER.getDecompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped FernFlower Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped FernFlower Decompiler instance
|
|
|
|
*/
|
2021-06-26 01:13:46 +00:00
|
|
|
public static InternalDecompiler getFernFlowerDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.FERNFLOWER_DECOMPILER.getDecompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the wrapped Krakatau Disassembler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Krakatau Disassembler instance
|
|
|
|
*/
|
2021-06-26 01:13:46 +00:00
|
|
|
public static InternalDecompiler getKrakatauDisassembler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.KRAKATAU_DISASSEMBLER.getDecompiler();
|
2021-06-26 01:13:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the wrapped JD-GUI Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped JD-GUI Decompiler instance
|
|
|
|
*/
|
|
|
|
public static InternalDecompiler getDJGUIDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.JD_DECOMPILER.getDecompiler();
|
2021-06-26 01:13:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the wrapped JADX Decompiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped JADX Decompiler instance
|
|
|
|
*/
|
|
|
|
public static InternalDecompiler getJADXDecompiler() {
|
2021-07-04 05:59:42 +00:00
|
|
|
return Decompiler.JADX_DECOMPILER.getDecompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
2021-06-26 14:37:41 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped Java Compiler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Java Compiler instance
|
|
|
|
*/
|
|
|
|
public static InternalCompiler getJavaCompiler() {
|
|
|
|
return Compiler.JAVA_COMPILER.getCompiler();
|
|
|
|
}
|
|
|
|
|
2018-01-31 15:41:24 +00:00
|
|
|
/**
|
|
|
|
* Returns the wrapped Krakatau Assembler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Krakatau Assembler instance
|
|
|
|
*/
|
2021-06-26 14:21:23 +00:00
|
|
|
public static InternalCompiler getKrakatauCompiler() {
|
|
|
|
return Compiler.KRAKATAU_ASSEMBLER.getCompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the wrapped Smali Assembler instance.
|
|
|
|
*
|
|
|
|
* @return The wrapped Smali Assembler instance
|
|
|
|
*/
|
2021-06-26 14:21:23 +00:00
|
|
|
public static InternalCompiler getSmaliCompiler() {
|
|
|
|
return Compiler.SMALI_ASSEMBLER.getCompiler();
|
2018-01-31 15:41:24 +00:00
|
|
|
}
|
2018-01-31 15:03:53 +00:00
|
|
|
}
|