Resource Viewing Improvements

All of the components that update resources should now function as normal again

The decompiler gui API has been improved to use less boilerplate when adding a new decompiler
This commit is contained in:
Konloch 2021-07-11 01:44:37 -07:00
parent 4ebdd2bdbc
commit 2ef221f6e1
35 changed files with 457 additions and 471 deletions

View file

@ -122,7 +122,7 @@ public class BytecodeViewer
public static MainViewerGUI viewer; public static MainViewerGUI viewer;
//All of the opened resources (Files/Classes/Etc) //All of the opened resources (Files/Classes/Etc)
public static List<FileContainer> files = new ArrayList<>(); public static List<ResourceContainer> files = new ArrayList<>();
//All of the created processes (Decompilers/etc) //All of the created processes (Decompilers/etc)
public static List<Process> createdProcesses = new ArrayList<>(); public static List<Process> createdProcesses = new ArrayList<>();
@ -178,6 +178,7 @@ public class BytecodeViewer
//load settings and set swing components state //load settings and set swing components state
SettingsSerializer.loadSettings(); SettingsSerializer.loadSettings();
Configuration.bootState = Configuration.BootState.SETTINGS_LOADED;
//set translation language //set translation language
if(!Settings.hasSetLanguageAsSystemLanguage) if(!Settings.hasSetLanguageAsSystemLanguage)
@ -188,20 +189,21 @@ public class BytecodeViewer
if (CLI == CommandLineInput.STOP) if (CLI == CommandLineInput.STOP)
return; return;
if (!FAT_JAR) //load with shaded libraries
{ if (FAT_JAR)
bootCheck.start();
Boot.boot(args, CLI != CommandLineInput.GUI);
}
else
{ {
installFatJar.start(); installFatJar.start();
} }
else //load through bootloader
{
bootCheck.start();
Boot.boot(args, CLI != CommandLineInput.GUI);
}
if (CLI == CommandLineInput.GUI) if (CLI == CommandLineInput.GUI)
{ {
BytecodeViewer.boot(false); BytecodeViewer.boot(false);
Configuration.bootState = Configuration.BootState.GUI_SHOWING;
} }
else else
{ {
@ -357,7 +359,7 @@ public class BytecodeViewer
@Deprecated @Deprecated
public static ClassNode blindlySearchForClassNode(String name) public static ClassNode blindlySearchForClassNode(String name)
{ {
for (FileContainer container : files) for (ResourceContainer container : files)
{ {
ClassNode node = container.getClassNode(name); ClassNode node = container.getClassNode(name);
if(node != null) if(node != null)
@ -370,9 +372,9 @@ public class BytecodeViewer
/** /**
* Returns the File Container by the specific name * Returns the File Container by the specific name
*/ */
public static FileContainer getFileContainer(String name) public static ResourceContainer getFileContainer(String name)
{ {
for (FileContainer container : files) for (ResourceContainer container : files)
if (container.name.equals(name)) if (container.name.equals(name))
return container; return container;
@ -382,7 +384,7 @@ public class BytecodeViewer
/** /**
* Returns all of the loaded File Containers * Returns all of the loaded File Containers
*/ */
public static List<FileContainer> getFiles() { public static List<ResourceContainer> getFiles() {
return files; return files;
} }
@ -394,7 +396,7 @@ public class BytecodeViewer
*/ */
public static byte[] getFileContents(String name) public static byte[] getFileContents(String name)
{ {
for (FileContainer container : files) for (ResourceContainer container : files)
if (container.resourceFiles.containsKey(name)) if (container.resourceFiles.containsKey(name))
return container.resourceFiles.get(name); return container.resourceFiles.get(name);
@ -409,24 +411,6 @@ public class BytecodeViewer
return ClassFileUtils.getClassFileBytes(clazz); return ClassFileUtils.getClassFileBytes(clazz);
} }
/**
* Replaces an old node with a new instance
*
* @param oldNode the old instance
* @param newNode the new instance
*/
public static void updateNode(ClassNode oldNode, ClassNode newNode)
{
for (FileContainer container : files)
{
if (container.resourceClasses.containsKey(oldNode.name))
{
container.resourceClasses.remove(oldNode.name);
container.resourceClasses.put(newNode.name, newNode);
}
}
}
/** /**
* Gets all of the loaded classes as an array list * Gets all of the loaded classes as an array list
* *
@ -436,7 +420,7 @@ public class BytecodeViewer
{ {
ArrayList<ClassNode> a = new ArrayList<>(); ArrayList<ClassNode> a = new ArrayList<>();
for (FileContainer container : files) for (ResourceContainer container : files)
for (ClassNode c : container.resourceClasses.values()) for (ClassNode c : container.resourceClasses.values())
if (!a.contains(c)) if (!a.contains(c))
a.add(c); a.add(c);

View file

@ -24,6 +24,7 @@ public class Configuration
public static File krakatauTempJar; public static File krakatauTempJar;
public static boolean displayParentInTab = false; //also change in the main GUI public static boolean displayParentInTab = false; //also change in the main GUI
public static boolean simplifiedTabNames = false; public static boolean simplifiedTabNames = false;
public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI
public static boolean currentlyDumping = false; public static boolean currentlyDumping = false;
public static boolean needsReDump = true; public static boolean needsReDump = true;
public static boolean warnForEditing = false; public static boolean warnForEditing = false;
@ -39,12 +40,11 @@ public class Configuration
public static final int maxRecentFiles = 25; //eventually may be a setting public static final int maxRecentFiles = 25; //eventually may be a setting
public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting public static boolean verifyCorruptedStateOnBoot = false; //eventually may be a setting
public static long lastHotKeyExecuted = 0; public static BootState bootState = BootState.START_UP;
public static Language language = Language.ENGLISH; public static Language language = Language.ENGLISH;
public static LAFTheme lafTheme = LAFTheme.SYSTEM; //lightmode by default since it uses the system theme public static LAFTheme lafTheme = LAFTheme.SYSTEM; //lightmode by default since it uses the system theme
public static RSTATheme rstaTheme = lafTheme.getRSTATheme(); public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
public static long lastHotKeyExecuted = 0;
public static File getLastDirectory() public static File getLastDirectory()
{ {
@ -54,4 +54,11 @@ public class Configuration
return new File("."); return new File(".");
} }
public enum BootState
{
START_UP,
SETTINGS_LOADED,
GUI_SHOWING,
}
} }

View file

@ -1,12 +1,6 @@
package the.bytecode.club.bytecodeviewer.decompilers; package the.bytecode.club.bytecodeviewer.decompilers;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.impl.*; import the.bytecode.club.bytecodeviewer.decompilers.impl.*;
import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent;
import javax.swing.*;
import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentTypes.*;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -33,46 +27,28 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/ */
public enum Decompiler public enum Decompiler
{ {
NONE("None", null, (JRadioButtonMenuItem) null), //TODO WARNING: do not change the decompiler order, when adding a new decompiler just add it to the end
PROCYON_DECOMPILER("Procyon Decompiler", new ProcyonDecompiler(), new DecompilerViewComponent("Procyon", JAVA)), // enum ordinal is used for settings serialization instead of the enum name
CFR_DECOMPILER("CFR Decompiler", new CFRDecompiler(), new DecompilerViewComponent("CFR", JAVA)), NONE("None", null),
FERNFLOWER_DECOMPILER("FernFlower Decompiler", new FernFlowerDecompiler(), new DecompilerViewComponent("FernFlower", JAVA)), PROCYON_DECOMPILER("Procyon Decompiler", new ProcyonDecompiler()),
BYTECODE_DISASSEMBLER("Bytecode Disassembler", new BytecodeDisassembler(), new JRadioButtonMenuItem("Bytecode")), CFR_DECOMPILER("CFR Decompiler", new CFRDecompiler()),
HEXCODE_VIEWER("Hexcode Viewer", null, new JRadioButtonMenuItem("Hexcode")), FERNFLOWER_DECOMPILER("FernFlower Decompiler", new FernFlowerDecompiler()),
SMALI_DISASSEMBLER("Smali Disassembler", new SmaliDisassembler(), new DecompilerViewComponent("Smali", BYTECODE)), BYTECODE_DISASSEMBLER("Bytecode Disassembler", new BytecodeDisassembler()),
KRAKATAU_DECOMPILER("Krakatau Decompiler", new KrakatauDecompiler(), DecompilerViewComponent.KRAKATAU), HEXCODE_VIEWER("Hexcode Viewer", null),
KRAKATAU_DISASSEMBLER("Krakatau Disassembler", new KrakatauDisassembler(), DecompilerViewComponent.KRAKATAU), SMALI_DISASSEMBLER("Smali Disassembler", new SmaliDisassembler()),
JD_DECOMPILER("JD-GUI Decompiler", new JDGUIDecompiler(), new DecompilerViewComponent("JD-GUI", JAVA)), KRAKATAU_DECOMPILER("Krakatau Decompiler", new KrakatauDecompiler()),
JADX_DECOMPILER("JADX Decompiler", new JADXDecompiler(), new DecompilerViewComponent("JADX", JAVA)), KRAKATAU_DISASSEMBLER("Krakatau Disassembler", new KrakatauDisassembler()),
ASM_TEXTIFY_DISASSEMBLER("ASM Disassembler", new ASMTextifierDecompiler(), new DecompilerViewComponent("ASM Textify", BYTECODE)), JD_DECOMPILER("JD-GUI Decompiler", new JDGUIDecompiler()),
JADX_DECOMPILER("JADX Decompiler", new JADXDecompiler()),
ASM_TEXTIFY_DISASSEMBLER("ASM Disassembler", new ASMTextifierDecompiler()),
; ;
private final String decompilerName; private final String decompilerName;
private final InternalDecompiler decompiler; private final InternalDecompiler decompiler;
private final DecompilerViewComponent decompilerSelectComponent;
private final JRadioButtonMenuItem basicSelectComponent;
Decompiler(String decompilerName, InternalDecompiler decompiler, DecompilerViewComponent decompilerSelectComponent) { Decompiler(String decompilerName, InternalDecompiler decompiler) {
this.decompilerName = decompilerName; this.decompilerName = decompilerName;
this.decompiler = decompiler; this.decompiler = decompiler;
this.decompilerSelectComponent = decompilerSelectComponent;
this.basicSelectComponent = null;
}
Decompiler(String decompilerName, InternalDecompiler decompiler, JRadioButtonMenuItem basicSelectComponent)
{
this.decompilerName = decompilerName;
this.decompiler = decompiler;
this.decompilerSelectComponent = null;
this.basicSelectComponent = basicSelectComponent;
}
public void addDecompilerToGroup(ButtonGroup group)
{
if(decompilerSelectComponent != null)
decompilerSelectComponent.addToGroup(group);
else if(basicSelectComponent != null)
group.add(basicSelectComponent);
} }
public String getDecompilerName() public String getDecompilerName()
@ -84,17 +60,4 @@ public enum Decompiler
{ {
return decompiler; return decompiler;
} }
public DecompilerViewComponent getDecompilerSelectComponent()
{
return decompilerSelectComponent;
}
public JMenuItem getMenu()
{
if(decompilerSelectComponent != null)
return decompilerSelectComponent.getMenu();
return basicSelectComponent;
}
} }

View file

@ -14,7 +14,6 @@ import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler; import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.util.Dex2Jar; import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import static the.bytecode.club.bytecodeviewer.Constants.*; import static the.bytecode.club.bytecodeviewer.Constants.*;

View file

@ -292,9 +292,9 @@ public class MainViewerGUI extends JFrame
uiComponents.add(searchBoxPane); uiComponents.add(searchBoxPane);
uiComponents.add(workPane); uiComponents.add(workPane);
viewPane1.getGroup().setSelected(viewPane1.getFern().getJava().getModel(), true); viewPane1.setDefault();
viewPane2.getGroup().setSelected(viewPane1.getBytecode().getModel(), true); viewPane2.setDefault();
viewPane3.getGroup().setSelected(viewPane1.getNone().getModel(), true); viewPane3.setDefault();
this.setLocationRelativeTo(null); this.setLocationRelativeTo(null);
} }
@ -349,9 +349,9 @@ public class MainViewerGUI extends JFrame
{ {
rootMenu.add(viewMainMenu); rootMenu.add(viewMainMenu);
viewMainMenu.add(visualSettings); viewMainMenu.add(visualSettings);
viewMainMenu.add(viewPane1.menu); viewMainMenu.add(viewPane1.getMenu());
viewMainMenu.add(viewPane2.menu); viewMainMenu.add(viewPane2.getMenu());
viewMainMenu.add(viewPane3.menu); viewMainMenu.add(viewPane3.getMenu());
} }
public void buildSettingsMenu() public void buildSettingsMenu()
@ -769,11 +769,11 @@ public class MainViewerGUI extends JFrame
}); });
} }
public void openClassFile(final FileContainer container, final String name, final ClassNode cn) { public void openClassFile(final ResourceContainer container, final String name, final ClassNode cn) {
workPane.addClassResource(container, name, cn); workPane.addClassResource(container, name, cn);
} }
public void openFile(final FileContainer container, final String name, byte[] content) { public void openFile(final ResourceContainer container, final String name, byte[] content) {
workPane.addFileResource(container, name, content); workPane.addFileResource(container, name, content);
} }
@ -811,7 +811,7 @@ public class MainViewerGUI extends JFrame
LazyNameUtil.reset(); LazyNameUtil.reset();
ArrayList<File> reopen = new ArrayList<>(); ArrayList<File> reopen = new ArrayList<>();
for (FileContainer container : BytecodeViewer.files) { for (ResourceContainer container : BytecodeViewer.files) {
File newFile = new File(container.file.getParent() + fs + container.name); File newFile = new File(container.file.getParent() + fs + container.name);
if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) && if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) &&
(container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed (container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed

View file

@ -1,5 +1,6 @@
package the.bytecode.club.bytecodeviewer.gui.components; package the.bytecode.club.bytecodeviewer.gui.components;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBoxMenuItem; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBoxMenuItem;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioButtonMenuItem; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioButtonMenuItem;
@ -7,7 +8,7 @@ import the.bytecode.club.bytecodeviewer.util.RefreshWorkPane;
import javax.swing.*; import javax.swing.*;
import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentTypes.JAVA_AND_BYTECODE; import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentType.JAVA_AND_BYTECODE;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -33,41 +34,49 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/ */
public class DecompilerViewComponent public class DecompilerViewComponent
{ {
public static final DecompilerViewComponent KRAKATAU = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE);
private final String name; private final String name;
private final JMenu menu; private final JMenu menu;
private final DecompilerComponentTypes types; private final DecompilerComponentType type;
private final JRadioButtonMenuItem java = new TranslatedJRadioButtonMenuItem("Java", Translation.JAVA); private final Decompiler[] decompilers;
private final JRadioButtonMenuItem bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", Translation.BYTECODE); private final JRadioButtonMenuItem java;
private final JCheckBoxMenuItem editable = new TranslatedJCheckBoxMenuItem("Editable", Translation.EDITABLE); private final JRadioButtonMenuItem bytecode;
private final JCheckBoxMenuItem editable;
public DecompilerViewComponent(String name, DecompilerComponentTypes types) public DecompilerViewComponent(String name, DecompilerComponentType type, Decompiler... decompilers)
{ {
this.name = name; this.name = name;
this.menu = new JMenu(name); this.menu = new JMenu(name);
this.types = types; this.type = type;
this.decompilers = decompilers;
this.java = new TranslatedJRadioButtonMenuItem("Java", Translation.JAVA);
this.bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", Translation.BYTECODE);
this.editable = new TranslatedJCheckBoxMenuItem( "Editable", Translation.EDITABLE);
createMenu(); createMenu();
} }
private void createMenu() private void createMenu()
{ {
if(types == DecompilerComponentTypes.JAVA || types == DecompilerComponentTypes.JAVA_AND_BYTECODE) if(type == DecompilerComponentType.JAVA || type == DecompilerComponentType.JAVA_AND_BYTECODE)
menu.add(java); menu.add(java);
if(types == DecompilerComponentTypes.BYTECODE || types == DecompilerComponentTypes.JAVA_AND_BYTECODE) if(type == DecompilerComponentType.BYTECODE || type == DecompilerComponentType.JAVA_AND_BYTECODE
|| type == DecompilerComponentType.BYTECODE_NON_EDITABLE)
menu.add(bytecode); menu.add(bytecode);
menu.add(new JSeparator()); if(type != DecompilerComponentType.BYTECODE_NON_EDITABLE)
menu.add(editable); {
menu.add(new JSeparator());
menu.add(editable);
}
java.addActionListener(new RefreshWorkPane()); java.addActionListener(new RefreshWorkPane());
} }
public void addToGroup(ButtonGroup group) public void addToGroup(ButtonGroup group)
{ {
if(types == DecompilerComponentTypes.JAVA || types == DecompilerComponentTypes.JAVA_AND_BYTECODE) if(type == DecompilerComponentType.JAVA || type == DecompilerComponentType.JAVA_AND_BYTECODE)
group.add(java); group.add(java);
if(types == DecompilerComponentTypes.BYTECODE || types == DecompilerComponentTypes.JAVA_AND_BYTECODE) if(type == DecompilerComponentType.BYTECODE || type == DecompilerComponentType.JAVA_AND_BYTECODE)
group.add(bytecode); group.add(bytecode);
} }
@ -91,10 +100,21 @@ public class DecompilerViewComponent
return editable; return editable;
} }
public enum DecompilerComponentTypes public DecompilerComponentType getType()
{
return type;
}
public Decompiler[] getDecompilers()
{
return decompilers;
}
public enum DecompilerComponentType
{ {
JAVA, JAVA,
BYTECODE, BYTECODE,
BYTECODE_NON_EDITABLE,
JAVA_AND_BYTECODE JAVA_AND_BYTECODE
} }
} }

View file

@ -34,7 +34,7 @@ import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJTextField; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJTextField;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.FileDrop; import the.bytecode.club.bytecodeviewer.util.FileDrop;
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil; import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
@ -109,10 +109,10 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
} }
//used to remove resources from the resource list //used to remove resources from the resource list
public void removeFile(FileContainer fileContainer) public void removeFile(ResourceContainer resourceContainer)
{ {
BytecodeViewer.files.remove(fileContainer); BytecodeViewer.files.remove(resourceContainer);
LazyNameUtil.removeName(fileContainer.name); LazyNameUtil.removeName(resourceContainer.name);
} }
public ResourceListPane() public ResourceListPane()
@ -160,7 +160,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
try try
{ {
treeRoot.removeAllChildren(); treeRoot.removeAllChildren();
for (FileContainer container : BytecodeViewer.files) for (ResourceContainer container : BytecodeViewer.files)
{ {
ResourceTreeNode root = new ResourceTreeNode(container.name); ResourceTreeNode root = new ResourceTreeNode(container.name);
treeRoot.add(root); treeRoot.add(root);
@ -299,9 +299,9 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
} }
String cheapHax = path.getPathComponent(1).toString(); String cheapHax = path.getPathComponent(1).toString();
FileContainer container = null; ResourceContainer container = null;
for (FileContainer c : BytecodeViewer.files) for (ResourceContainer c : BytecodeViewer.files)
{ {
if (c.name.equals(cheapHax)) if (c.name.equals(cheapHax))
container = c; container = c;

View file

@ -1,7 +1,7 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist; package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import javax.swing.*; import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
@ -44,11 +44,11 @@ public class ResourceListRightClickRemove extends AbstractAction
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot(); DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
root.remove(node); root.remove(node);
for (FileContainer fileContainer : BytecodeViewer.files) for (ResourceContainer resourceContainer : BytecodeViewer.files)
{ {
if (fileContainer.name.equals(selectNode.toString())) if (resourceContainer.name.equals(selectNode.toString()))
{ {
resourceListPane.removeFile(fileContainer); resourceListPane.removeFile(resourceContainer);
break; break;
} }
} }

View file

@ -8,7 +8,7 @@ import the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder;
import the.bytecode.club.bytecodeviewer.searching.impl.RegexSearch; import the.bytecode.club.bytecodeviewer.searching.impl.RegexSearch;
import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import javax.swing.tree.TreePath; import javax.swing.tree.TreePath;
import java.util.Objects; import java.util.Objects;
@ -42,7 +42,7 @@ class PerformSearch extends BackgroundSearchThread
BytecodeViewer.showMessage("You have an error in your regex syntax."); BytecodeViewer.showMessage("You have an error in your regex syntax.");
} }
for (FileContainer container : BytecodeViewer.files) for (ResourceContainer container : BytecodeViewer.files)
for (ClassNode c : container.resourceClasses.values()) for (ClassNode c : container.resourceClasses.values())
searchBoxPane.searchType.details.search(container, c, srn, searchBoxPane.exact.isSelected()); searchBoxPane.searchType.details.search(container, c, srn, searchBoxPane.exact.isSelected());

View file

@ -3,13 +3,11 @@ package the.bytecode.club.bytecodeviewer.gui.resourcesearch;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.beans.PropertyVetoException;
import java.util.Objects; import java.util.Objects;
import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTree; import javax.swing.JTree;
@ -18,14 +16,13 @@ import javax.swing.tree.DefaultTreeModel;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread; import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread;
import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.*; import the.bytecode.club.bytecodeviewer.translation.components.*;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -147,7 +144,7 @@ public class SearchBoxPane extends TranslatedVisibleComponent
String containerName = path.split(">", 2)[0]; String containerName = path.split(">", 2)[0];
String className = path.split(">", 2)[1].split("\\.")[0]; String className = path.split(">", 2)[1].split("\\.")[0];
FileContainer container = BytecodeViewer.getFileContainer(containerName); ResourceContainer container = BytecodeViewer.getFileContainer(containerName);
final ClassNode fN = Objects.requireNonNull(container).getClassNode(className); final ClassNode fN = Objects.requireNonNull(container).getClassNode(className);

View file

@ -1,5 +1,7 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer; package the.bytecode.club.bytecodeviewer.gui.resourceviewer;
import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.SettingsSerializer;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent; import the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
@ -8,7 +10,12 @@ import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioB
import javax.swing.*; import javax.swing.*;
import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentTypes.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComponent.DecompilerComponentType.*;
/** /**
* @author Konloch * @author Konloch
@ -16,20 +23,25 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/ */
public class DecompilerSelectionPane public class DecompilerSelectionPane
{ {
public final int paneID; private final int paneID;
public final JMenu menu; private final JMenu menu;
public final ButtonGroup group = new ButtonGroup(); private final ButtonGroup group = new ButtonGroup();
public final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", Translation.NONE); private final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", Translation.NONE);
public final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA); private final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", Translation.HEXCODE);
public final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA); private final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
public final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA); private final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
public final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA); private final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
public final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA); private final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
public final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE); private final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
public final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE); private final DecompilerViewComponent krakatau = new DecompilerViewComponent( "Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_DISASSEMBLER);
public final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", Translation.HEXCODE); private final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE, Decompiler.SMALI_DISASSEMBLER);
public final JRadioButtonMenuItem bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", Translation.BYTECODE); private final DecompilerViewComponent bytecode = new DecompilerViewComponent("Bytecode", BYTECODE_NON_EDITABLE, Decompiler.BYTECODE_DISASSEMBLER);
public final JRadioButtonMenuItem asmTextify = new TranslatedJRadioButtonMenuItem("ASM Textify", Translation.ASM_TEXTIFY); private final DecompilerViewComponent asmTextify = new DecompilerViewComponent("ASM Textify", BYTECODE_NON_EDITABLE, Decompiler.ASM_TEXTIFY_DISASSEMBLER);
//TODO when adding new decompilers insert the DecompilerViewComponent object into here
// also in the group, then finally the build menu
public List<DecompilerViewComponent> components = new ArrayList<>(Arrays.asList(
procyon, CFR, JADX, JD, fern, krakatau, smali, bytecode, asmTextify));
public DecompilerSelectionPane(int paneID) public DecompilerSelectionPane(int paneID)
{ {
@ -44,8 +56,31 @@ public class DecompilerSelectionPane
buildMenu(); buildMenu();
} }
/**
* Sets the default decompilers for each pane
*/
public void setDefault()
{
switch(paneID)
{
case 1:
group.setSelected(fern.getJava().getModel(), true);
break;
case 2:
group.setSelected(bytecode.getBytecode().getModel(), true);
break;
case 3:
group.setSelected(none.getModel(), true);
break;
}
}
/**
* Builds the Decompiler View menu
*/
public void buildMenu() public void buildMenu()
{ {
//build the radiobutton group
group.add(none); group.add(none);
procyon.addToGroup(group); procyon.addToGroup(group);
CFR.addToGroup(group); CFR.addToGroup(group);
@ -54,10 +89,42 @@ public class DecompilerSelectionPane
fern.addToGroup(group); fern.addToGroup(group);
krakatau.addToGroup(group); krakatau.addToGroup(group);
smali.addToGroup(group); smali.addToGroup(group);
group.add(bytecode); bytecode.addToGroup(group);
asmTextify.addToGroup(group);
group.add(hexcode); group.add(hexcode);
group.add(asmTextify);
//build the action commands
none.setActionCommand(Decompiler.NONE.name());
hexcode.setActionCommand(Decompiler.HEXCODE_VIEWER.name());
for(DecompilerViewComponent component : components)
{
for(Decompiler decompiler : component.getDecompilers())
{
String cmd = decompiler.name();
//TODO this is pretty janky and will break if a decompiler doesn't end with _DECOMPILER suffix
if(cmd.endsWith("DECOMPILER"))
component.getJava().setActionCommand(cmd);
else// if(cmd.endsWith("DISASSEMBLER"))
component.getBytecode().setActionCommand(cmd);
}
}
//auto-save on decompiler change
Enumeration<AbstractButton> it = group.getElements();
while(it.hasMoreElements())
{
AbstractButton button = it.nextElement();
button.addActionListener((event)->
{
if(Configuration.bootState != Configuration.BootState.GUI_SHOWING)
return;
SettingsSerializer.saveSettingsAsync();
});
}
//build the menu
menu.add(none); menu.add(none);
menu.add(new JSeparator()); menu.add(new JSeparator());
menu.add(procyon.getMenu()); menu.add(procyon.getMenu());
@ -69,164 +136,58 @@ public class DecompilerSelectionPane
menu.add(new JSeparator()); menu.add(new JSeparator());
menu.add(smali.getMenu()); menu.add(smali.getMenu());
menu.add(new JSeparator()); menu.add(new JSeparator());
menu.add(bytecode.getMenu());
menu.add(asmTextify.getMenu());
menu.add(new JSeparator());
menu.add(hexcode); menu.add(hexcode);
menu.add(bytecode);
menu.add(asmTextify);
} }
public Decompiler getSelectedDecompiler() public Decompiler getSelectedDecompiler()
{ {
if (group.isSelected(none.getModel())) return Decompiler.valueOf(group.getSelection().getActionCommand());
return Decompiler.NONE;
else if (group.isSelected(procyon.getJava().getModel()))
return Decompiler.PROCYON_DECOMPILER;
else if (group.isSelected(CFR.getJava().getModel()))
return Decompiler.CFR_DECOMPILER;
else if (group.isSelected(fern.getJava().getModel()))
return Decompiler.FERNFLOWER_DECOMPILER;
else if (group.isSelected(bytecode.getModel()))
return Decompiler.BYTECODE_DISASSEMBLER;
else if (group.isSelected(hexcode.getModel()))
return Decompiler.HEXCODE_VIEWER;
else if (group.isSelected(smali.getBytecode().getModel()))
return Decompiler.SMALI_DISASSEMBLER;
else if (group.isSelected(krakatau.getJava().getModel()))
return Decompiler.KRAKATAU_DECOMPILER;
else if (group.isSelected(krakatau.getBytecode().getModel()))
return Decompiler.KRAKATAU_DISASSEMBLER;
else if (group.isSelected(JD.getJava().getModel()))
return Decompiler.JD_DECOMPILER;
else if (group.isSelected(JADX.getJava().getModel()))
return Decompiler.JADX_DECOMPILER;
else if (group.isSelected(asmTextify.getModel()))
return Decompiler.ASM_TEXTIFY_DISASSEMBLER;
System.out.println("DEFAULTING TO NULL");
//default to none
return Decompiler.NONE;
} }
public void setSelectedDecompiler(Decompiler decompiler) public void setSelectedDecompiler(Decompiler decompiler)
{ {
switch (decompiler) Enumeration<AbstractButton> it = group.getElements();
while(it.hasMoreElements())
{ {
case NONE: AbstractButton button = it.nextElement();
group.setSelected(none.getModel(), true); if(button.getActionCommand().equals(decompiler.name()))
break; {
case PROCYON_DECOMPILER: group.setSelected(button.getModel(), true);
group.setSelected(procyon.getJava().getModel(), true);
break;
case CFR_DECOMPILER:
group.setSelected(CFR.getJava().getModel(), true);
break;
case FERNFLOWER_DECOMPILER:
group.setSelected(fern.getJava().getModel(), true);
break;
case BYTECODE_DISASSEMBLER:
group.setSelected(bytecode.getModel(), true);
break;
case HEXCODE_VIEWER:
group.setSelected(hexcode.getModel(), true);
break;
case SMALI_DISASSEMBLER:
group.setSelected(smali.getBytecode().getModel(), true);
break;
case KRAKATAU_DECOMPILER:
group.setSelected(krakatau.getJava().getModel(), true);
break;
case KRAKATAU_DISASSEMBLER:
group.setSelected(krakatau.getBytecode().getModel(), true);
break;
case JD_DECOMPILER:
group.setSelected(JD.getJava().getModel(), true);
break;
case JADX_DECOMPILER:
group.setSelected(JADX.getJava().getModel(), true);
break;
case ASM_TEXTIFY_DISASSEMBLER:
group.setSelected(asmTextify.getModel(), true);
break; break;
}
} }
} }
public boolean isPaneEditable() public boolean isPaneEditable()
{ {
if(group.isSelected(procyon.getJava().getModel()) && procyon.getEditable().isSelected()) String cmd = group.getSelection().getActionCommand();
return true;
if(group.isSelected(CFR.getJava().getModel()) && CFR.getEditable().isSelected()) for(DecompilerViewComponent component : components)
return true; for (Decompiler decompiler : component.getDecompilers())
if(group.isSelected(JADX.getJava().getModel()) && JADX.getEditable().isSelected()) if(decompiler.name().equalsIgnoreCase(cmd))
return true; return component.getEditable().isSelected();
if(group.isSelected(JD.getJava().getModel()) && JD.getEditable().isSelected())
return true;
if(group.isSelected(fern.getJava().getModel()) && fern.getEditable().isSelected())
return true;
if((group.isSelected(krakatau.getJava().getModel()) || group.isSelected(krakatau.getBytecode().getModel())) && krakatau.getEditable().isSelected())
return true;
if(group.isSelected(smali.getBytecode().getModel()) && smali.getEditable().isSelected())
return true;
return false; return false;
} }
public ButtonGroup getGroup() public void setPaneEditable(boolean value)
{ {
return group; String cmd = group.getSelection().getActionCommand();
for(DecompilerViewComponent component : components)
for (Decompiler decompiler : component.getDecompilers())
if(decompiler.name().equalsIgnoreCase(cmd))
{
component.getEditable().setSelected(value);
return;
}
} }
public JRadioButtonMenuItem getNone() public JMenu getMenu()
{ {
return none; return menu;
}
public DecompilerViewComponent getProcyon()
{
return procyon;
}
public DecompilerViewComponent getCFR()
{
return CFR;
}
public DecompilerViewComponent getJADX()
{
return JADX;
}
public DecompilerViewComponent getJD()
{
return JD;
}
public DecompilerViewComponent getFern()
{
return fern;
}
public DecompilerViewComponent getKrakatau()
{
return krakatau;
}
public DecompilerViewComponent getSmali()
{
return smali;
}
public JRadioButtonMenuItem getHexcode()
{
return hexcode;
}
public JRadioButtonMenuItem getBytecode()
{
return bytecode;
}
public JRadioButtonMenuItem getAsmTextify()
{
return asmTextify;
} }
} }

View file

@ -89,7 +89,7 @@ public class ResourceViewPanel
if (compiledClass != null) if (compiledClass != null)
{ {
ClassNode newNode = JarUtils.getNode(compiledClass); ClassNode newNode = JarUtils.getNode(compiledClass);
BytecodeViewer.updateNode(viewer.cn, newNode); viewer.container.updateNode(viewer.cn, newNode);
errConsole.finished(); errConsole.finished();
return true; return true;
} }

View file

@ -14,14 +14,13 @@ import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.components.VisibleComponent;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.FileViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.FileViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJButton; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJButton;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedVisibleComponent;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU; import static the.bytecode.club.bytecodeviewer.Constants.BLOCK_TAB_MENU;
@ -162,13 +161,13 @@ public class WorkPaneMainComponent extends TranslatedVisibleComponent
} }
//load class resources //load class resources
public void addClassResource(final FileContainer container, final String name, final ClassNode cn) public void addClassResource(final ResourceContainer container, final String name, final ClassNode cn)
{ {
addResource(container, name, new ClassViewer(container, name, cn)); addResource(container, name, new ClassViewer(container, name, cn));
} }
//Load file resources //Load file resources
public void addFileResource(final FileContainer container, final String name, byte[] contents) public void addFileResource(final ResourceContainer container, final String name, byte[] contents)
{ {
if (contents == null) //a directory if (contents == null) //a directory
return; return;
@ -176,9 +175,9 @@ public class WorkPaneMainComponent extends TranslatedVisibleComponent
addResource(container, name, new FileViewer(container, name, contents)); addResource(container, name, new FileViewer(container, name, contents));
} }
private void addResource(final FileContainer container, final String name, final ResourceViewer resourceView) private void addResource(final ResourceContainer container, final String name, final ResourceViewer resourceView)
{ {
final String workingName = container.generateWorkName(name); final String workingName = container.getWorkingName(name);
//create a new tab if the resource isn't opened currently //create a new tab if the resource isn't opened currently
if (!openedTabs.contains(workingName)) if (!openedTabs.contains(workingName))

View file

@ -3,16 +3,14 @@ package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
import the.bytecode.club.bytecodeviewer.api.ASMUtil; import the.bytecode.club.bytecodeviewer.api.ASMUtil;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point; import java.awt.Point;
import java.awt.event.ComponentAdapter; import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent; import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener; import java.awt.event.HierarchyListener;
import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.swing.JButton; import javax.swing.JButton;
@ -22,13 +20,11 @@ import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.SettingsSerializer; import the.bytecode.club.bytecodeviewer.SettingsSerializer;
import the.bytecode.club.bytecodeviewer.util.BCVResourceUtils; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.MethodParser; import the.bytecode.club.bytecodeviewer.util.MethodParser;
import static the.bytecode.club.bytecodeviewer.util.MethodParser.Method; import static the.bytecode.club.bytecodeviewer.util.MethodParser.Method;
@ -70,9 +66,9 @@ public class ClassViewer extends ResourceViewer
public List<MethodParser> methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser()); public List<MethodParser> methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser());
public final String workingName; public final String workingName;
public ClassViewer(final FileContainer container, final String name, final ClassNode cn) public ClassViewer(final ResourceContainer container, final String name, final ClassNode cn)
{ {
this.workingName = container.generateWorkName(name); this.workingName = container.getWorkingName(name);
this.container = container; this.container = container;
this.name = name; this.name = name;
@ -103,12 +99,19 @@ public class ClassViewer extends ResourceViewer
resourceViewPanel2.createPane(this); resourceViewPanel2.createPane(this);
resourceViewPanel3.createPane(this); resourceViewPanel3.createPane(this);
byte[] classBytes = getBytes(); byte[] classBytes = getResourceBytes();
//TODO remove this once all of the importers have been properly updated to use a FileContainerImporter //TODO remove this once all of the importers have been properly updated to use a FileContainerImporter
if(classBytes == null || classBytes.length == 0) if(classBytes == null || classBytes.length == 0 || Configuration.forceResourceUpdateFromClassNode)
{ {
System.err.println("WARNING: Imported using the old importer!"); //TODO remove this error message when all of the importers have been updated
// only APK and DEX are left
if(!Configuration.forceResourceUpdateFromClassNode)
{
System.err.println("WARNING: Class Resource imported using the old importer!");
System.err.println("TODO: Update it to use the FileContainerImporter");
}
classBytes = ASMUtil.nodeToBytes(cn); classBytes = ASMUtil.nodeToBytes(cn);
} }
@ -159,13 +162,6 @@ public class ClassViewer extends ResourceViewer
} }
} }
@Override
public void refreshTitle()
{
if(tabbedPane != null)
tabbedPane.label.setText(getTabName());
}
public void setPanes() { public void setPanes() {
resourceViewPanel1.decompiler = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler(); resourceViewPanel1.decompiler = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler();
resourceViewPanel2.decompiler = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler(); resourceViewPanel2.decompiler = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler();

View file

@ -1,27 +1,19 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer; package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.imgscalr.Scalr; import org.imgscalr.Scalr;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.Resources;
import the.bytecode.club.bytecodeviewer.gui.components.ImageJLabel; import the.bytecode.club.bytecodeviewer.gui.components.ImageJLabel;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener;
import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor; import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage; import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage;
@ -61,11 +53,11 @@ public class FileViewer extends ResourceViewer
public BufferedImage image; public BufferedImage image;
public boolean canRefresh; public boolean canRefresh;
public FileViewer(final FileContainer container, final String name, final byte[] contents) public FileViewer(final ResourceContainer container, final String name, final byte[] contents)
{ {
this.name = name; this.name = name;
this.contents = contents; this.contents = contents;
this.workingName = container.generateWorkName(name); this.workingName = container.getWorkingName(name);
this.container = container; this.container = container;
this.setName(name); this.setName(name);
this.setLayout(new BorderLayout()); this.setLayout(new BorderLayout());
@ -130,13 +122,6 @@ public class FileViewer extends ResourceViewer
mainPanel.add(textArea.getScrollPane()); mainPanel.add(textArea.getScrollPane());
} }
@Override
public void refreshTitle()
{
if(tabbedPane != null)
tabbedPane.label.setText(getTabName());
}
public void refresh(JButton src) public void refresh(JButton src)
{ {
refreshTitle(); refreshTitle();

View file

@ -4,7 +4,7 @@ import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.TabbedPane;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/*************************************************************************** /***************************************************************************
@ -36,11 +36,12 @@ public abstract class ResourceViewer extends JPanel
public ClassNode cn; public ClassNode cn;
public String name; public String name;
public String workingName; public String workingName;
public FileContainer container; public ResourceContainer container;
public TabbedPane tabbedPane; public TabbedPane tabbedPane;
public abstract void refreshTitle(); /**
* Returns the tab name
*/
public String getTabName() public String getTabName()
{ {
String tabName = name; String tabName = name;
@ -53,12 +54,21 @@ public abstract class ResourceViewer extends JPanel
return tabName; return tabName;
} }
public byte[] getBytes() /**
* Returns the resource bytes from the resource container
*/
public byte[] getResourceBytes()
{ {
if(container.resourceClassBytes.containsKey(name)) return container.getBytes(name);
return container.resourceClassBytes.get(name); }
else
return container.resourceFiles.get(name); /**
* Updates the tab's title
*/
public void refreshTitle()
{
if(tabbedPane != null)
tabbedPane.label.setText(getTabName());
} }
private static final long serialVersionUID = -2965538493489119191L; private static final long serialVersionUID = -2965538493489119191L;

View file

@ -27,17 +27,17 @@ public class APKExport implements Exporter
if (BytecodeViewer.promptIfNoLoadedClasses()) if (BytecodeViewer.promptIfNoLoadedClasses())
return; return;
List<FileContainer> containers = BytecodeViewer.getFiles(); List<ResourceContainer> containers = BytecodeViewer.getFiles();
List<FileContainer> validContainers = new ArrayList<>(); List<ResourceContainer> validContainers = new ArrayList<>();
List<String> validContainersNames = new ArrayList<>(); List<String> validContainersNames = new ArrayList<>();
FileContainer container; ResourceContainer container;
for (FileContainer fileContainer : containers) for (ResourceContainer resourceContainer : containers)
{ {
if (fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists()) if (resourceContainer.APKToolContents != null && resourceContainer.APKToolContents.exists())
{ {
validContainersNames.add(fileContainer.name); validContainersNames.add(resourceContainer.name);
validContainers.add(fileContainer); validContainers.add(resourceContainer);
} }
} }
@ -60,7 +60,7 @@ public class APKExport implements Exporter
return; return;
} }
final FileContainer finalContainer = container; final ResourceContainer finalContainer = container;
Thread exportThread = new Thread(() -> Thread exportThread = new Thread(() ->
{ {

View file

@ -7,7 +7,6 @@ import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.*; import the.bytecode.club.bytecodeviewer.util.*;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import static the.bytecode.club.bytecodeviewer.Constants.fs; import static the.bytecode.club.bytecodeviewer.Constants.fs;
@ -28,7 +27,7 @@ public class APKResourceImporter implements Importer
FileUtils.copyFile(file, tempCopy); FileUtils.copyFile(file, tempCopy);
FileContainer container = new FileContainer(tempCopy, file.getName()); ResourceContainer container = new ResourceContainer(tempCopy, file.getName());
if (BytecodeViewer.viewer.decodeAPKResources.isSelected()) { if (BytecodeViewer.viewer.decodeAPKResources.isSelected()) {
File decodedResources = File decodedResources =
@ -48,10 +47,9 @@ public class APKResourceImporter implements Importer
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
Enjarify.apk2Jar(tempCopy, output); Enjarify.apk2Jar(tempCopy, output);
//TODO update to FileContainerImporter //create a new resource importer and copy the contents from it
ArrayList<ClassNode> nodeList = JarUtils.loadClasses(output); container.clear().copy(new ResourceContainerImporter(
for(ClassNode cn : nodeList) new ResourceContainer(output)).importAsZip().getContainer());
container.resourceClasses.put(cn.name, cn);
BytecodeViewer.updateBusyStatus(false); BytecodeViewer.updateBusyStatus(false);
BytecodeViewer.files.add(container); BytecodeViewer.files.add(container);

View file

@ -4,7 +4,7 @@ import org.apache.commons.io.FilenameUtils;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
@ -22,7 +22,7 @@ public class ClassResourceImporter implements Importer
{ {
final String name = file.getName(); final String name = file.getName();
byte[] bytes = MiscUtils.getBytes(new FileInputStream(file)); byte[] bytes = MiscUtils.getBytes(new FileInputStream(file));
FileContainer container = new FileContainer(file); ResourceContainer container = new ResourceContainer(file);
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
{ {

View file

@ -27,7 +27,7 @@ public class DEXResourceImporter implements Importer
FileUtils.copyFile(file, tempCopy); //copy and rename to prevent unicode filenames FileUtils.copyFile(file, tempCopy); //copy and rename to prevent unicode filenames
FileContainer container = new FileContainer(tempCopy, file.getName()); ResourceContainer container = new ResourceContainer(tempCopy, file.getName());
String name = MiscUtils.getRandomizedName() + ".jar"; String name = MiscUtils.getRandomizedName() + ".jar";
File output = new File(tempDirectory + fs + name); File output = new File(tempDirectory + fs + name);
@ -37,10 +37,9 @@ public class DEXResourceImporter implements Importer
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
Enjarify.apk2Jar(tempCopy, output); Enjarify.apk2Jar(tempCopy, output);
//TODO update to FileContainerImporter //create a new resource importer and copy the contents from it
ArrayList<ClassNode> nodeList = JarUtils.loadClasses(output); container.clear().copy(new ResourceContainerImporter(
for(ClassNode cn : nodeList) new ResourceContainer(output)).importAsZip().getContainer());
container.resourceClasses.put(cn.name, cn);
BytecodeViewer.updateBusyStatus(false); BytecodeViewer.updateBusyStatus(false);
BytecodeViewer.files.add(container); BytecodeViewer.files.add(container);

View file

@ -5,7 +5,7 @@ import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.importing.Import; import the.bytecode.club.bytecodeviewer.resources.importing.Import;
import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
@ -25,7 +25,7 @@ public class DirectoryResourceImporter implements Importer
@Override @Override
public void open(File file) throws Exception public void open(File file) throws Exception
{ {
FileContainer container = new FileContainer(file); ResourceContainer container = new ResourceContainer(file);
HashMap<String, byte[]> allDirectoryFiles = new HashMap<>(); HashMap<String, byte[]> allDirectoryFiles = new HashMap<>();
HashMap<String, ClassNode> allDirectoryClasses = new HashMap<>(); HashMap<String, ClassNode> allDirectoryClasses = new HashMap<>();

View file

@ -2,14 +2,10 @@ package the.bytecode.club.bytecodeviewer.resources.importing.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainerImporter; import the.bytecode.club.bytecodeviewer.util.ResourceContainerImporter;
import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
/** /**
* @author Konloch * @author Konloch
@ -21,9 +17,9 @@ public class FileResourceImporter implements Importer
public void open(File file) throws Exception public void open(File file) throws Exception
{ {
//create the new file container //create the new file container
FileContainer container = new FileContainer(file); ResourceContainer container = new ResourceContainer(file);
//create the new file importer //create the new file importer
FileContainerImporter importer = new FileContainerImporter(container); ResourceContainerImporter importer = new ResourceContainerImporter(container);
//import the file into the file container //import the file into the file container
importer.importAsFile(); importer.importAsFile();
//add the file container to BCV's total loaded files //add the file container to BCV's total loaded files

View file

@ -6,7 +6,7 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.resources.importing.Import; import the.bytecode.club.bytecodeviewer.resources.importing.Import;
import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import java.io.*; import java.io.*;
@ -29,7 +29,7 @@ public class XAPKResourceImporter implements Importer
@Override @Override
public void open(File file) throws Exception public void open(File file) throws Exception
{ {
FileContainer container = new FileContainer(file); ResourceContainer container = new ResourceContainer(file);
HashMap<String, byte[]> allDirectoryFiles = new HashMap<>(); HashMap<String, byte[]> allDirectoryFiles = new HashMap<>();
Configuration.silenceExceptionGUI++; //turn exceptions off Configuration.silenceExceptionGUI++; //turn exceptions off

View file

@ -1,14 +1,11 @@
package the.bytecode.club.bytecodeviewer.resources.importing.impl; package the.bytecode.club.bytecodeviewer.resources.importing.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
import the.bytecode.club.bytecodeviewer.resources.importing.Importer; import the.bytecode.club.bytecodeviewer.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainerImporter; import the.bytecode.club.bytecodeviewer.util.ResourceContainerImporter;
import the.bytecode.club.bytecodeviewer.util.JarUtils;
import java.io.File; import java.io.File;
import java.io.IOException;
/** /**
* @author Konloch * @author Konloch
@ -20,9 +17,9 @@ public class ZipResourceImporter implements Importer
public void open(File file) throws Exception public void open(File file) throws Exception
{ {
//create the new file container //create the new file container
FileContainer container = new FileContainer(file); ResourceContainer container = new ResourceContainer(file);
//create the new file importer //create the new file importer
FileContainerImporter importer = new FileContainerImporter(container); ResourceContainerImporter importer = new ResourceContainerImporter(container);
//import the file as zip into the file container //import the file as zip into the file container
importer.importAsZip(); importer.importAsZip();
//add the file container to BCV's total loaded files //add the file container to BCV's total loaded files

View file

@ -2,7 +2,7 @@ package the.bytecode.club.bytecodeviewer.searching;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -34,5 +34,5 @@ public interface SearchTypeDetails
{ {
JPanel getPanel(); JPanel getPanel();
void search(FileContainer container, ClassNode node, SearchResultNotifier srn, boolean exact); void search(ResourceContainer container, ClassNode node, SearchResultNotifier srn, boolean exact);
} }

View file

@ -8,7 +8,7 @@ import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.MethodNode;
import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -38,7 +38,7 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer;
public class FieldCallSearch extends MethodCallSearch public class FieldCallSearch extends MethodCallSearch
{ {
@Override @Override
public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, public void search(final ResourceContainer container, final ClassNode node, final SearchResultNotifier srn,
boolean exact) boolean exact)
{ {
final Iterator<MethodNode> methods = node.methods.iterator(); final Iterator<MethodNode> methods = node.methods.iterator();

View file

@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.searching.impl;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.util.Iterator; import java.util.Iterator;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@ -17,7 +16,7 @@ import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails; import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -70,7 +69,7 @@ public class LDCSearch implements SearchTypeDetails
} }
@Override @Override
public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, public void search(final ResourceContainer container, final ClassNode node, final SearchResultNotifier srn,
boolean exact) boolean exact)
{ {
final Iterator<MethodNode> methods = node.methods.iterator(); final Iterator<MethodNode> methods = node.methods.iterator();

View file

@ -4,7 +4,6 @@ import eu.bibl.banalysis.asm.desc.OpcodeInfo;
import java.awt.*; import java.awt.*;
import java.util.Iterator; import java.util.Iterator;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@ -18,7 +17,7 @@ import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails; import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -81,7 +80,7 @@ public class MethodCallSearch implements SearchTypeDetails
} }
@Override @Override
public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, public void search(final ResourceContainer container, final ClassNode node, final SearchResultNotifier srn,
boolean exact) boolean exact)
{ {
final Iterator<MethodNode> methods = node.methods.iterator(); final Iterator<MethodNode> methods = node.methods.iterator();
@ -137,7 +136,7 @@ public class MethodCallSearch implements SearchTypeDetails
} }
} }
public void found(final FileContainer container, final ClassNode node, final MethodNode method, final AbstractInsnNode insnNode, final SearchResultNotifier srn) public void found(final ResourceContainer container, final ClassNode node, final MethodNode method, final AbstractInsnNode insnNode, final SearchResultNotifier srn)
{ {
String desc = method.desc; String desc = method.desc;
try try

View file

@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.searching.impl;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.util.Iterator; import java.util.Iterator;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@ -15,7 +14,7 @@ import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails; import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails;
import the.bytecode.club.bytecodeviewer.translation.Translation; import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel; import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel;
import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import static the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder.processRegex; import static the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder.processRegex;
@ -70,7 +69,7 @@ public class RegexSearch implements SearchTypeDetails
} }
@Override @Override
public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, public void search(final ResourceContainer container, final ClassNode node, final SearchResultNotifier srn,
boolean exact) boolean exact)
{ {
final Iterator<MethodNode> methods = node.methods.iterator(); final Iterator<MethodNode> methods = node.methods.iterator();

View file

@ -29,7 +29,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
*/ */
public class APKTool { public class APKTool {
public static synchronized void decodeResources(File input, File output, FileContainer container) { public static synchronized void decodeResources(File input, File output, ResourceContainer container) {
try { try {
File dir = new File(tempDirectory + fs + MiscUtils.randomString(32) + fs + "Decoded Resources"); File dir = new File(tempDirectory + fs + MiscUtils.randomString(32) + fs + "Decoded Resources");
dir.mkdirs(); dir.mkdirs();
@ -52,7 +52,7 @@ public class APKTool {
} }
} }
public static synchronized void buildAPK(File input, File output, FileContainer container) { public static synchronized void buildAPK(File input, File output, ResourceContainer container) {
String temp = tempDirectory + fs; String temp = tempDirectory + fs;
File tempDir = new File(temp + fs + MiscUtils.getRandomizedName() + fs); File tempDir = new File(temp + fs + MiscUtils.getRandomizedName() + fs);
tempDir.mkdirs(); tempDir.mkdirs();

View file

@ -1,61 +0,0 @@
package the.bytecode.club.bytecodeviewer.util;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import org.objectweb.asm.tree.ClassNode;
/***************************************************************************
* 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/>. *
***************************************************************************/
/**
* Represents a file container
*
* @author Konloch
*/
public class FileContainer {
public FileContainer(File f) {
this.file = f;
this.name = LazyNameUtil.applyNameChanges(f.getName());
}
public FileContainer(File f, String name) {
this.file = f;
this.name = LazyNameUtil.applyNameChanges(name);
}
public File file;
public String name;
public File APKToolContents = null;
public HashMap<String, byte[]> resourceFiles = new HashMap<>();
public HashMap<String, byte[]> resourceClassBytes = new HashMap<>();
public HashMap<String, ClassNode> resourceClasses = new HashMap<>();
public ClassNode getClassNode(String name)
{
return resourceClasses.get(name);
}
public String generateWorkName(String name)
{
return file.getAbsolutePath() + ">" + name;
}
}

View file

@ -1,6 +1,5 @@
package the.bytecode.club.bytecodeviewer.util; package the.bytecode.club.bytecodeviewer.util;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -67,7 +66,7 @@ public class JarUtils
*/ */
public static void importArchiveA(final File jarFile) throws IOException public static void importArchiveA(final File jarFile) throws IOException
{ {
FileContainer container = new FileContainer(jarFile); ResourceContainer container = new ResourceContainer(jarFile);
HashMap<String, byte[]> files = new HashMap<>(); HashMap<String, byte[]> files = new HashMap<>();
ZipInputStream jis = new ZipInputStream(new FileInputStream(jarFile)); ZipInputStream jis = new ZipInputStream(new FileInputStream(jarFile));
@ -121,7 +120,7 @@ public class JarUtils
//if this ever fails, worst case import Sun's jarsigner code from JDK 7 re-sign the jar to rebuild the CRC, //if this ever fails, worst case import Sun's jarsigner code from JDK 7 re-sign the jar to rebuild the CRC,
// should also rebuild the archive byte offsets // should also rebuild the archive byte offsets
FileContainer container = new FileContainer(jarFile); ResourceContainer container = new ResourceContainer(jarFile);
HashMap<String, byte[]> files = new HashMap<>(); HashMap<String, byte[]> files = new HashMap<>();
try (ZipFile zipFile = new ZipFile(jarFile)) { try (ZipFile zipFile = new ZipFile(jarFile)) {
@ -231,7 +230,9 @@ public class JarUtils
* @param bytez the class file's byte[] * @param bytez the class file's byte[]
* @return the ClassNode instance * @return the ClassNode instance
*/ */
public static ClassNode getNode(final byte[] bytez) { public static ClassNode getNode(final byte[] bytez)
{
//TODO figure out why is this synchronized and if it's actually needed (probably not)
synchronized (LOCK) synchronized (LOCK)
{ {
return ASMUtil.bytesToNode(bytez); return ASMUtil.bytesToNode(bytez);
@ -263,7 +264,7 @@ public class JarUtils
out.write((manifest.trim() + "\r\n\r\n").getBytes()); out.write((manifest.trim() + "\r\n\r\n").getBytes());
out.closeEntry(); out.closeEntry();
for (FileContainer container : BytecodeViewer.files) for (ResourceContainer container : BytecodeViewer.files)
for (Entry<String, byte[]> entry : container.resourceFiles.entrySet()) { for (Entry<String, byte[]> entry : container.resourceFiles.entrySet()) {
String filename = entry.getKey(); String filename = entry.getKey();
if (!filename.startsWith("META-INF")) { if (!filename.startsWith("META-INF")) {
@ -287,6 +288,7 @@ public class JarUtils
*/ */
public static void saveAsJarClassesOnly(Collection<ClassNode> nodeList, String path) public static void saveAsJarClassesOnly(Collection<ClassNode> nodeList, String path)
{ {
//TODO figure out why is this synchronized and if it's actually needed (probably not)
synchronized (LOCK) synchronized (LOCK)
{ {
try try
@ -366,7 +368,7 @@ public class JarUtils
} }
} }
for (FileContainer container : BytecodeViewer.files) for (ResourceContainer container : BytecodeViewer.files)
for (Entry<String, byte[]> entry : container.resourceFiles.entrySet()) { for (Entry<String, byte[]> entry : container.resourceFiles.entrySet()) {
String filename = entry.getKey(); String filename = entry.getKey();
if (!filename.startsWith("META-INF")) { if (!filename.startsWith("META-INF")) {

View file

@ -176,9 +176,9 @@ public class MiscUtils
return path; return path;
} }
public static int fileContainersHash(ArrayList<FileContainer> fileContainers) { public static int fileContainersHash(ArrayList<ResourceContainer> resourceContainers) {
StringBuilder block = new StringBuilder(); StringBuilder block = new StringBuilder();
for (FileContainer container : fileContainers) { for (ResourceContainer container : resourceContainers) {
block.append(container.name); block.append(container.name);
for (ClassNode node : container.resourceClasses.values()) { for (ClassNode node : container.resourceClasses.values()) {
block.append(node.name); block.append(node.name);

View file

@ -0,0 +1,123 @@
package the.bytecode.club.bytecodeviewer.util;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.commons.io.FilenameUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.api.ASMUtil;
/***************************************************************************
* 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/>. *
***************************************************************************/
/**
* Represents a file container
*
* @author Konloch
*/
public class ResourceContainer
{
public File file;
public String name;
public File APKToolContents = null;
public HashMap<String, byte[]> resourceFiles = new HashMap<>();
public HashMap<String, byte[]> resourceClassBytes = new HashMap<>();
public HashMap<String, ClassNode> resourceClasses = new HashMap<>();
public ResourceContainer(File f)
{
this(f, LazyNameUtil.applyNameChanges(f.getName()));
}
public ResourceContainer(File f, String name)
{
this.file = f;
this.name = LazyNameUtil.applyNameChanges(name);
}
/**
* Returns the ClassNode resource for the specified resource key (full name path)
*/
public ClassNode getClassNode(String resourceName)
{
return resourceClasses.get(resourceName);
}
/**
* Returns the unique 'working' name for container + resource look up.
* This is used to look up a specific resource inside of this specific
* container when you need to iterate through all opened containers
*/
public String getWorkingName(String resourceName)
{
return file.getAbsolutePath() + ">" + resourceName;
}
/**
* Returns the resource bytes for the specified resource key (full name path)
*/
public byte[] getBytes(String resourceName)
{
if(resourceClassBytes.containsKey(resourceName))
return resourceClassBytes.get(resourceName);
else
return resourceFiles.get(resourceName);
}
/**
* Updates the ClassNode reference on the resourceClass list and resourceClassBytes list
*/
public ResourceContainer updateNode(ClassNode oldNode, ClassNode newNode)
{
//update all classnode references for ASM
if (resourceClasses.containsKey(oldNode.name))
{
resourceClasses.remove(oldNode.name);
resourceClasses.put(newNode.name, newNode);
}
//update the resource bytes
String oldResourceKey = oldNode.name + ".class";
String newResourceKey = newNode.name + ".class";
if(resourceClassBytes.containsKey(oldResourceKey))
{
resourceClassBytes.remove(oldResourceKey);
resourceClassBytes.put(newResourceKey, ASMUtil.nodeToBytes(newNode));
}
return this;
}
public ResourceContainer clear()
{
resourceFiles.clear();
resourceClassBytes.clear();
resourceClasses.clear();
return this;
}
public ResourceContainer copy(ResourceContainer copyFrom)
{
resourceFiles.putAll(copyFrom.resourceFiles);
resourceClassBytes.putAll(copyFrom.resourceClassBytes);
resourceClasses.putAll(copyFrom.resourceClasses);
return this;
}
}

View file

@ -15,21 +15,26 @@ import java.util.zip.ZipInputStream;
* @author Konloch * @author Konloch
* @since 7/10/2021 * @since 7/10/2021
*/ */
public class FileContainerImporter public class ResourceContainerImporter
{ {
private final FileContainer container; private final ResourceContainer container;
public FileContainerImporter(FileContainer container) public ResourceContainerImporter(ResourceContainer container)
{ {
this.container = container; this.container = container;
} }
public void importAsFile() throws IOException public ResourceContainer getContainer()
{ {
addUnknownFile(container.file.getName(), new FileInputStream(container.file), false); return container;
} }
public void importAsZip() throws IOException public ResourceContainerImporter importAsFile() throws IOException
{
return addUnknownFile(container.file.getName(), new FileInputStream(container.file), false);
}
public ResourceContainerImporter importAsZip() throws IOException
{ {
container.resourceClasses.clear(); container.resourceClasses.clear();
container.resourceClassBytes.clear(); container.resourceClassBytes.clear();
@ -47,19 +52,22 @@ public class FileContainerImporter
//fallback to apache commons ZipFile //fallback to apache commons ZipFile
importApacheZipFile(false); importApacheZipFile(false);
} }
return this;
} }
//sorts the file type from classes or resources //sorts the file type from classes or resources
public void addUnknownFile(String name, InputStream stream, boolean classesOnly) throws IOException public ResourceContainerImporter addUnknownFile(String name, InputStream stream, boolean classesOnly) throws IOException
{ {
//TODO remove this .class check and just look for cafebabe //TODO remove this .class check and just look for cafebabe
if (name.endsWith(".class")) if (name.endsWith(".class"))
addClassResource(name, stream); addClassResource(name, stream);
else if(!classesOnly) else if(!classesOnly)
addResource(name, stream); addResource(name, stream);
return this;
} }
public void addClassResource(String name, InputStream stream) throws IOException public ResourceContainerImporter addClassResource(String name, InputStream stream) throws IOException
{ {
byte[] bytes = MiscUtils.getBytes(stream); byte[] bytes = MiscUtils.getBytes(stream);
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe")) if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
@ -87,15 +95,18 @@ public class FileContainerImporter
} else { } else {
System.err.println(container.file + ">" + name + ": Header does not start with CAFEBABE, ignoring."); System.err.println(container.file + ">" + name + ": Header does not start with CAFEBABE, ignoring.");
} }
return this;
} }
public void addResource(String name, InputStream stream) throws IOException public ResourceContainerImporter addResource(String name, InputStream stream) throws IOException
{ {
byte[] bytes = MiscUtils.getBytes(stream); byte[] bytes = MiscUtils.getBytes(stream);
container.resourceFiles.put(name, bytes); container.resourceFiles.put(name, bytes);
return this;
} }
public void importZipInputStream(boolean classesOnly) throws IOException public ResourceContainerImporter importZipInputStream(boolean classesOnly) throws IOException
{ {
ZipInputStream jis = new ZipInputStream(new FileInputStream(container.file)); ZipInputStream jis = new ZipInputStream(new FileInputStream(container.file));
ZipEntry entry; ZipEntry entry;
@ -111,11 +122,12 @@ public class FileContainerImporter
jis.closeEntry(); jis.closeEntry();
} }
jis.close(); jis.close();
return this;
} }
//TODO if this ever fails: import Sun's jarsigner code from JDK 7, re-sign the jar to rebuild the CRC, //TODO if this ever fails: import Sun's jarsigner code from JDK 7, re-sign the jar to rebuild the CRC,
// should also rebuild the archive byte offsets // should also rebuild the archive byte offsets
public void importApacheZipFile(boolean classesOnly) throws IOException public ResourceContainerImporter importApacheZipFile(boolean classesOnly) throws IOException
{ {
try (ZipFile zipFile = new ZipFile(container.file)) try (ZipFile zipFile = new ZipFile(container.file))
{ {
@ -134,5 +146,7 @@ public class FileContainerImporter
} }
} }
} }
return this;
} }
} }