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;
//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)
public static List<Process> createdProcesses = new ArrayList<>();
@ -178,6 +178,7 @@ public class BytecodeViewer
//load settings and set swing components state
SettingsSerializer.loadSettings();
Configuration.bootState = Configuration.BootState.SETTINGS_LOADED;
//set translation language
if(!Settings.hasSetLanguageAsSystemLanguage)
@ -188,20 +189,21 @@ public class BytecodeViewer
if (CLI == CommandLineInput.STOP)
return;
if (!FAT_JAR)
{
bootCheck.start();
Boot.boot(args, CLI != CommandLineInput.GUI);
}
else
//load with shaded libraries
if (FAT_JAR)
{
installFatJar.start();
}
else //load through bootloader
{
bootCheck.start();
Boot.boot(args, CLI != CommandLineInput.GUI);
}
if (CLI == CommandLineInput.GUI)
{
BytecodeViewer.boot(false);
Configuration.bootState = Configuration.BootState.GUI_SHOWING;
}
else
{
@ -357,7 +359,7 @@ public class BytecodeViewer
@Deprecated
public static ClassNode blindlySearchForClassNode(String name)
{
for (FileContainer container : files)
for (ResourceContainer container : files)
{
ClassNode node = container.getClassNode(name);
if(node != null)
@ -370,9 +372,9 @@ public class BytecodeViewer
/**
* 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))
return container;
@ -382,7 +384,7 @@ public class BytecodeViewer
/**
* Returns all of the loaded File Containers
*/
public static List<FileContainer> getFiles() {
public static List<ResourceContainer> getFiles() {
return files;
}
@ -394,7 +396,7 @@ public class BytecodeViewer
*/
public static byte[] getFileContents(String name)
{
for (FileContainer container : files)
for (ResourceContainer container : files)
if (container.resourceFiles.containsKey(name))
return container.resourceFiles.get(name);
@ -409,24 +411,6 @@ public class BytecodeViewer
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
*
@ -436,7 +420,7 @@ public class BytecodeViewer
{
ArrayList<ClassNode> a = new ArrayList<>();
for (FileContainer container : files)
for (ResourceContainer container : files)
for (ClassNode c : container.resourceClasses.values())
if (!a.contains(c))
a.add(c);

View file

@ -24,6 +24,7 @@ public class Configuration
public static File krakatauTempJar;
public static boolean displayParentInTab = false; //also change in the main GUI
public static boolean simplifiedTabNames = false;
public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI
public static boolean currentlyDumping = false;
public static boolean needsReDump = true;
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 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 LAFTheme lafTheme = LAFTheme.SYSTEM; //lightmode by default since it uses the system theme
public static RSTATheme rstaTheme = lafTheme.getRSTATheme();
public static long lastHotKeyExecuted = 0;
public static File getLastDirectory()
{
@ -54,4 +54,11 @@ public class Configuration
return new File(".");
}
public enum BootState
{
START_UP,
SETTINGS_LOADED,
GUI_SHOWING,
}
}

View file

@ -1,12 +1,6 @@
package the.bytecode.club.bytecodeviewer.decompilers;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
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 *
@ -33,46 +27,28 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/
public enum Decompiler
{
NONE("None", null, (JRadioButtonMenuItem) null),
PROCYON_DECOMPILER("Procyon Decompiler", new ProcyonDecompiler(), new DecompilerViewComponent("Procyon", JAVA)),
CFR_DECOMPILER("CFR Decompiler", new CFRDecompiler(), new DecompilerViewComponent("CFR", JAVA)),
FERNFLOWER_DECOMPILER("FernFlower Decompiler", new FernFlowerDecompiler(), new DecompilerViewComponent("FernFlower", JAVA)),
BYTECODE_DISASSEMBLER("Bytecode Disassembler", new BytecodeDisassembler(), new JRadioButtonMenuItem("Bytecode")),
HEXCODE_VIEWER("Hexcode Viewer", null, new JRadioButtonMenuItem("Hexcode")),
SMALI_DISASSEMBLER("Smali Disassembler", new SmaliDisassembler(), new DecompilerViewComponent("Smali", BYTECODE)),
KRAKATAU_DECOMPILER("Krakatau Decompiler", new KrakatauDecompiler(), DecompilerViewComponent.KRAKATAU),
KRAKATAU_DISASSEMBLER("Krakatau Disassembler", new KrakatauDisassembler(), DecompilerViewComponent.KRAKATAU),
JD_DECOMPILER("JD-GUI Decompiler", new JDGUIDecompiler(), new DecompilerViewComponent("JD-GUI", JAVA)),
JADX_DECOMPILER("JADX Decompiler", new JADXDecompiler(), new DecompilerViewComponent("JADX", JAVA)),
ASM_TEXTIFY_DISASSEMBLER("ASM Disassembler", new ASMTextifierDecompiler(), new DecompilerViewComponent("ASM Textify", BYTECODE)),
//TODO WARNING: do not change the decompiler order, when adding a new decompiler just add it to the end
// enum ordinal is used for settings serialization instead of the enum name
NONE("None", null),
PROCYON_DECOMPILER("Procyon Decompiler", new ProcyonDecompiler()),
CFR_DECOMPILER("CFR Decompiler", new CFRDecompiler()),
FERNFLOWER_DECOMPILER("FernFlower Decompiler", new FernFlowerDecompiler()),
BYTECODE_DISASSEMBLER("Bytecode Disassembler", new BytecodeDisassembler()),
HEXCODE_VIEWER("Hexcode Viewer", null),
SMALI_DISASSEMBLER("Smali Disassembler", new SmaliDisassembler()),
KRAKATAU_DECOMPILER("Krakatau Decompiler", new KrakatauDecompiler()),
KRAKATAU_DISASSEMBLER("Krakatau Disassembler", new KrakatauDisassembler()),
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 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.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()
@ -84,17 +60,4 @@ public enum 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.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import static the.bytecode.club.bytecodeviewer.Constants.*;

View file

@ -292,9 +292,9 @@ public class MainViewerGUI extends JFrame
uiComponents.add(searchBoxPane);
uiComponents.add(workPane);
viewPane1.getGroup().setSelected(viewPane1.getFern().getJava().getModel(), true);
viewPane2.getGroup().setSelected(viewPane1.getBytecode().getModel(), true);
viewPane3.getGroup().setSelected(viewPane1.getNone().getModel(), true);
viewPane1.setDefault();
viewPane2.setDefault();
viewPane3.setDefault();
this.setLocationRelativeTo(null);
}
@ -349,9 +349,9 @@ public class MainViewerGUI extends JFrame
{
rootMenu.add(viewMainMenu);
viewMainMenu.add(visualSettings);
viewMainMenu.add(viewPane1.menu);
viewMainMenu.add(viewPane2.menu);
viewMainMenu.add(viewPane3.menu);
viewMainMenu.add(viewPane1.getMenu());
viewMainMenu.add(viewPane2.getMenu());
viewMainMenu.add(viewPane3.getMenu());
}
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);
}
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);
}
@ -811,7 +811,7 @@ public class MainViewerGUI extends JFrame
LazyNameUtil.reset();
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);
if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) &&
(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;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBoxMenuItem;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioButtonMenuItem;
@ -7,7 +8,7 @@ import the.bytecode.club.bytecodeviewer.util.RefreshWorkPane;
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 *
@ -33,41 +34,49 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/
public class DecompilerViewComponent
{
public static final DecompilerViewComponent KRAKATAU = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE);
private final String name;
private final JMenu menu;
private final DecompilerComponentTypes types;
private final JRadioButtonMenuItem java = new TranslatedJRadioButtonMenuItem("Java", Translation.JAVA);
private final JRadioButtonMenuItem bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", Translation.BYTECODE);
private final JCheckBoxMenuItem editable = new TranslatedJCheckBoxMenuItem("Editable", Translation.EDITABLE);
private final DecompilerComponentType type;
private final Decompiler[] decompilers;
private final JRadioButtonMenuItem java;
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.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();
}
private void createMenu()
{
if(types == DecompilerComponentTypes.JAVA || types == DecompilerComponentTypes.JAVA_AND_BYTECODE)
if(type == DecompilerComponentType.JAVA || type == DecompilerComponentType.JAVA_AND_BYTECODE)
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(new JSeparator());
menu.add(editable);
if(type != DecompilerComponentType.BYTECODE_NON_EDITABLE)
{
menu.add(new JSeparator());
menu.add(editable);
}
java.addActionListener(new RefreshWorkPane());
}
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);
if(types == DecompilerComponentTypes.BYTECODE || types == DecompilerComponentTypes.JAVA_AND_BYTECODE)
if(type == DecompilerComponentType.BYTECODE || type == DecompilerComponentType.JAVA_AND_BYTECODE)
group.add(bytecode);
}
@ -91,10 +100,21 @@ public class DecompilerViewComponent
return editable;
}
public enum DecompilerComponentTypes
public DecompilerComponentType getType()
{
return type;
}
public Decompiler[] getDecompilers()
{
return decompilers;
}
public enum DecompilerComponentType
{
JAVA,
BYTECODE,
BYTECODE_NON_EDITABLE,
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.TranslatedJTextField;
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.LazyNameUtil;
@ -109,10 +109,10 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
}
//used to remove resources from the resource list
public void removeFile(FileContainer fileContainer)
public void removeFile(ResourceContainer resourceContainer)
{
BytecodeViewer.files.remove(fileContainer);
LazyNameUtil.removeName(fileContainer.name);
BytecodeViewer.files.remove(resourceContainer);
LazyNameUtil.removeName(resourceContainer.name);
}
public ResourceListPane()
@ -160,7 +160,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
try
{
treeRoot.removeAllChildren();
for (FileContainer container : BytecodeViewer.files)
for (ResourceContainer container : BytecodeViewer.files)
{
ResourceTreeNode root = new ResourceTreeNode(container.name);
treeRoot.add(root);
@ -299,9 +299,9 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
}
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))
container = c;

View file

@ -1,7 +1,7 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
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.tree.DefaultMutableTreeNode;
@ -44,11 +44,11 @@ public class ResourceListRightClickRemove extends AbstractAction
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
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;
}
}

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.SearchResultNotifier;
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 java.util.Objects;
@ -42,7 +42,7 @@ class PerformSearch extends BackgroundSearchThread
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())
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.GridLayout;
import java.awt.event.ItemListener;
import java.beans.PropertyVetoException;
import java.util.Objects;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
@ -18,14 +16,13 @@ import javax.swing.tree.DefaultTreeModel;
import org.objectweb.asm.tree.ClassNode;
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.searching.BackgroundSearchThread;
import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.translation.Translation;
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 *
@ -147,7 +144,7 @@ public class SearchBoxPane extends TranslatedVisibleComponent
String containerName = path.split(">", 2)[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);

View file

@ -1,5 +1,7 @@
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.gui.components.DecompilerViewComponent;
import the.bytecode.club.bytecodeviewer.translation.Translation;
@ -8,7 +10,12 @@ import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJRadioB
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
@ -16,20 +23,25 @@ import static the.bytecode.club.bytecodeviewer.gui.components.DecompilerViewComp
*/
public class DecompilerSelectionPane
{
public final int paneID;
public final JMenu menu;
public final ButtonGroup group = new ButtonGroup();
public final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", Translation.NONE);
public final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA);
public final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA);
public final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA);
public final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA);
public final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA);
public final DecompilerViewComponent krakatau = new DecompilerViewComponent("Krakatau", JAVA_AND_BYTECODE);
public final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE);
public final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", Translation.HEXCODE);
public final JRadioButtonMenuItem bytecode = new TranslatedJRadioButtonMenuItem("Bytecode", Translation.BYTECODE);
public final JRadioButtonMenuItem asmTextify = new TranslatedJRadioButtonMenuItem("ASM Textify", Translation.ASM_TEXTIFY);
private final int paneID;
private final JMenu menu;
private final ButtonGroup group = new ButtonGroup();
private final JRadioButtonMenuItem none = new TranslatedJRadioButtonMenuItem("None", Translation.NONE);
private final JRadioButtonMenuItem hexcode = new TranslatedJRadioButtonMenuItem("Hexcode", Translation.HEXCODE);
private final DecompilerViewComponent procyon = new DecompilerViewComponent("Procyon", JAVA, Decompiler.PROCYON_DECOMPILER);
private final DecompilerViewComponent CFR = new DecompilerViewComponent("CFR", JAVA, Decompiler.CFR_DECOMPILER);
private final DecompilerViewComponent JADX = new DecompilerViewComponent("JADX", JAVA, Decompiler.JADX_DECOMPILER);
private final DecompilerViewComponent JD = new DecompilerViewComponent("JD-GUI", JAVA, Decompiler.JD_DECOMPILER);
private final DecompilerViewComponent fern = new DecompilerViewComponent("FernFlower", JAVA, Decompiler.FERNFLOWER_DECOMPILER);
private final DecompilerViewComponent krakatau = new DecompilerViewComponent( "Krakatau", JAVA_AND_BYTECODE, Decompiler.KRAKATAU_DECOMPILER, Decompiler.KRAKATAU_DISASSEMBLER);
private final DecompilerViewComponent smali = new DecompilerViewComponent("Smali", BYTECODE, Decompiler.SMALI_DISASSEMBLER);
private final DecompilerViewComponent bytecode = new DecompilerViewComponent("Bytecode", BYTECODE_NON_EDITABLE, Decompiler.BYTECODE_DISASSEMBLER);
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)
{
@ -44,8 +56,31 @@ public class DecompilerSelectionPane
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()
{
//build the radiobutton group
group.add(none);
procyon.addToGroup(group);
CFR.addToGroup(group);
@ -54,10 +89,42 @@ public class DecompilerSelectionPane
fern.addToGroup(group);
krakatau.addToGroup(group);
smali.addToGroup(group);
group.add(bytecode);
bytecode.addToGroup(group);
asmTextify.addToGroup(group);
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(new JSeparator());
menu.add(procyon.getMenu());
@ -69,164 +136,58 @@ public class DecompilerSelectionPane
menu.add(new JSeparator());
menu.add(smali.getMenu());
menu.add(new JSeparator());
menu.add(bytecode.getMenu());
menu.add(asmTextify.getMenu());
menu.add(new JSeparator());
menu.add(hexcode);
menu.add(bytecode);
menu.add(asmTextify);
}
public Decompiler getSelectedDecompiler()
{
if (group.isSelected(none.getModel()))
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;
return Decompiler.valueOf(group.getSelection().getActionCommand());
}
public void setSelectedDecompiler(Decompiler decompiler)
{
switch (decompiler)
Enumeration<AbstractButton> it = group.getElements();
while(it.hasMoreElements())
{
case NONE:
group.setSelected(none.getModel(), true);
break;
case PROCYON_DECOMPILER:
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);
AbstractButton button = it.nextElement();
if(button.getActionCommand().equals(decompiler.name()))
{
group.setSelected(button.getModel(), true);
break;
}
}
}
public boolean isPaneEditable()
{
if(group.isSelected(procyon.getJava().getModel()) && procyon.getEditable().isSelected())
return true;
if(group.isSelected(CFR.getJava().getModel()) && CFR.getEditable().isSelected())
return true;
if(group.isSelected(JADX.getJava().getModel()) && JADX.getEditable().isSelected())
return true;
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;
String cmd = group.getSelection().getActionCommand();
for(DecompilerViewComponent component : components)
for (Decompiler decompiler : component.getDecompilers())
if(decompiler.name().equalsIgnoreCase(cmd))
return component.getEditable().isSelected();
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;
}
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;
return menu;
}
}

View file

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

View file

@ -14,14 +14,13 @@ import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import org.objectweb.asm.tree.ClassNode;
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.FileViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
import the.bytecode.club.bytecodeviewer.translation.Translation;
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJButton;
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;
@ -162,13 +161,13 @@ public class WorkPaneMainComponent extends TranslatedVisibleComponent
}
//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));
}
//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
return;
@ -176,9 +175,9 @@ public class WorkPaneMainComponent extends TranslatedVisibleComponent
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
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.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.ResourceViewPanel;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
@ -22,13 +20,11 @@ import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.SettingsSerializer;
import the.bytecode.club.bytecodeviewer.util.BCVResourceUtils;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.MethodParser;
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 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.name = name;
@ -103,12 +99,19 @@ public class ClassViewer extends ResourceViewer
resourceViewPanel2.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
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);
}
@ -159,13 +162,6 @@ public class ClassViewer extends ResourceViewer
}
}
@Override
public void refreshTitle()
{
if(tabbedPane != null)
tabbedPane.label.setText(getTabName());
}
public void setPanes() {
resourceViewPanel1.decompiler = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler();
resourceViewPanel2.decompiler = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler();

View file

@ -1,27 +1,19 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.imgscalr.Scalr;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
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.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.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.SyntaxLanguage;
@ -61,11 +53,11 @@ public class FileViewer extends ResourceViewer
public BufferedImage image;
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.contents = contents;
this.workingName = container.generateWorkName(name);
this.workingName = container.getWorkingName(name);
this.container = container;
this.setName(name);
this.setLayout(new BorderLayout());
@ -130,13 +122,6 @@ public class FileViewer extends ResourceViewer
mainPanel.add(textArea.getScrollPane());
}
@Override
public void refreshTitle()
{
if(tabbedPane != null)
tabbedPane.label.setText(getTabName());
}
public void refresh(JButton src)
{
refreshTitle();

View file

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

View file

@ -27,17 +27,17 @@ public class APKExport implements Exporter
if (BytecodeViewer.promptIfNoLoadedClasses())
return;
List<FileContainer> containers = BytecodeViewer.getFiles();
List<FileContainer> validContainers = new ArrayList<>();
List<ResourceContainer> containers = BytecodeViewer.getFiles();
List<ResourceContainer> validContainers = 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);
validContainers.add(fileContainer);
validContainersNames.add(resourceContainer.name);
validContainers.add(resourceContainer);
}
}
@ -60,7 +60,7 @@ public class APKExport implements Exporter
return;
}
final FileContainer finalContainer = container;
final ResourceContainer finalContainer = container;
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 java.io.File;
import java.util.ArrayList;
import java.util.Objects;
import static the.bytecode.club.bytecodeviewer.Constants.fs;
@ -28,7 +27,7 @@ public class APKResourceImporter implements Importer
FileUtils.copyFile(file, tempCopy);
FileContainer container = new FileContainer(tempCopy, file.getName());
ResourceContainer container = new ResourceContainer(tempCopy, file.getName());
if (BytecodeViewer.viewer.decodeAPKResources.isSelected()) {
File decodedResources =
@ -48,10 +47,9 @@ public class APKResourceImporter implements Importer
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
Enjarify.apk2Jar(tempCopy, output);
//TODO update to FileContainerImporter
ArrayList<ClassNode> nodeList = JarUtils.loadClasses(output);
for(ClassNode cn : nodeList)
container.resourceClasses.put(cn.name, cn);
//create a new resource importer and copy the contents from it
container.clear().copy(new ResourceContainerImporter(
new ResourceContainer(output)).importAsZip().getContainer());
BytecodeViewer.updateBusyStatus(false);
BytecodeViewer.files.add(container);

View file

@ -4,7 +4,7 @@ import org.apache.commons.io.FilenameUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
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.MiscUtils;
@ -22,7 +22,7 @@ public class ClassResourceImporter implements Importer
{
final String name = file.getName();
byte[] bytes = MiscUtils.getBytes(new FileInputStream(file));
FileContainer container = new FileContainer(file);
ResourceContainer container = new ResourceContainer(file);
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
FileContainer container = new FileContainer(tempCopy, file.getName());
ResourceContainer container = new ResourceContainer(tempCopy, file.getName());
String name = MiscUtils.getRandomizedName() + ".jar";
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()))
Enjarify.apk2Jar(tempCopy, output);
//TODO update to FileContainerImporter
ArrayList<ClassNode> nodeList = JarUtils.loadClasses(output);
for(ClassNode cn : nodeList)
container.resourceClasses.put(cn.name, cn);
//create a new resource importer and copy the contents from it
container.clear().copy(new ResourceContainerImporter(
new ResourceContainer(output)).importAsZip().getContainer());
BytecodeViewer.updateBusyStatus(false);
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.resources.importing.Import;
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.MiscUtils;
@ -25,7 +25,7 @@ public class DirectoryResourceImporter implements Importer
@Override
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, 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.resources.importing.Importer;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainerImporter;
import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.ResourceContainerImporter;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
/**
* @author Konloch
@ -21,9 +17,9 @@ public class FileResourceImporter implements Importer
public void open(File file) throws Exception
{
//create the new file container
FileContainer container = new FileContainer(file);
ResourceContainer container = new ResourceContainer(file);
//create the new file importer
FileContainerImporter importer = new FileContainerImporter(container);
ResourceContainerImporter importer = new ResourceContainerImporter(container);
//import the file into the file container
importer.importAsFile();
//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.resources.importing.Import;
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 java.io.*;
@ -29,7 +29,7 @@ public class XAPKResourceImporter implements Importer
@Override
public void open(File file) throws Exception
{
FileContainer container = new FileContainer(file);
ResourceContainer container = new ResourceContainer(file);
HashMap<String, byte[]> allDirectoryFiles = new HashMap<>();
Configuration.silenceExceptionGUI++; //turn exceptions off

View file

@ -1,14 +1,11 @@
package the.bytecode.club.bytecodeviewer.resources.importing.impl;
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.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.FileContainerImporter;
import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.util.ResourceContainer;
import the.bytecode.club.bytecodeviewer.util.ResourceContainerImporter;
import java.io.File;
import java.io.IOException;
/**
* @author Konloch
@ -20,9 +17,9 @@ public class ZipResourceImporter implements Importer
public void open(File file) throws Exception
{
//create the new file container
FileContainer container = new FileContainer(file);
ResourceContainer container = new ResourceContainer(file);
//create the new file importer
FileContainerImporter importer = new FileContainerImporter(container);
ResourceContainerImporter importer = new ResourceContainerImporter(container);
//import the file as zip into the file container
importer.importAsZip();
//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 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 *
@ -34,5 +34,5 @@ public interface SearchTypeDetails
{
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.MethodNode;
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 *
@ -38,7 +38,7 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer;
public class FieldCallSearch extends MethodCallSearch
{
@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)
{
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.util.Iterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
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.translation.Translation;
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 *
@ -70,7 +69,7 @@ public class LDCSearch implements SearchTypeDetails
}
@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)
{
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.util.Iterator;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
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.translation.Translation;
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 *
@ -81,7 +80,7 @@ public class MethodCallSearch implements SearchTypeDetails
}
@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)
{
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;
try

View file

@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.searching.impl;
import java.awt.GridLayout;
import java.util.Iterator;
import java.util.regex.Pattern;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
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.translation.Translation;
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;
@ -70,7 +69,7 @@ public class RegexSearch implements SearchTypeDetails
}
@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)
{
final Iterator<MethodNode> methods = node.methods.iterator();

View file

@ -29,7 +29,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.*;
*/
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 {
File dir = new File(tempDirectory + fs + MiscUtils.randomString(32) + fs + "Decoded Resources");
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;
File tempDir = new File(temp + fs + MiscUtils.getRandomizedName() + fs);
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;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -67,7 +66,7 @@ public class JarUtils
*/
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<>();
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,
// should also rebuild the archive byte offsets
FileContainer container = new FileContainer(jarFile);
ResourceContainer container = new ResourceContainer(jarFile);
HashMap<String, byte[]> files = new HashMap<>();
try (ZipFile zipFile = new ZipFile(jarFile)) {
@ -231,7 +230,9 @@ public class JarUtils
* @param bytez the class file's byte[]
* @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)
{
return ASMUtil.bytesToNode(bytez);
@ -263,7 +264,7 @@ public class JarUtils
out.write((manifest.trim() + "\r\n\r\n").getBytes());
out.closeEntry();
for (FileContainer container : BytecodeViewer.files)
for (ResourceContainer container : BytecodeViewer.files)
for (Entry<String, byte[]> entry : container.resourceFiles.entrySet()) {
String filename = entry.getKey();
if (!filename.startsWith("META-INF")) {
@ -287,6 +288,7 @@ public class JarUtils
*/
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)
{
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()) {
String filename = entry.getKey();
if (!filename.startsWith("META-INF")) {

View file

@ -176,9 +176,9 @@ public class MiscUtils
return path;
}
public static int fileContainersHash(ArrayList<FileContainer> fileContainers) {
public static int fileContainersHash(ArrayList<ResourceContainer> resourceContainers) {
StringBuilder block = new StringBuilder();
for (FileContainer container : fileContainers) {
for (ResourceContainer container : resourceContainers) {
block.append(container.name);
for (ClassNode node : container.resourceClasses.values()) {
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
* @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;
}
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.resourceClassBytes.clear();
@ -47,19 +52,22 @@ public class FileContainerImporter
//fallback to apache commons ZipFile
importApacheZipFile(false);
}
return this;
}
//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
if (name.endsWith(".class"))
addClassResource(name, stream);
else if(!classesOnly)
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);
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
@ -87,15 +95,18 @@ public class FileContainerImporter
} else {
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);
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));
ZipEntry entry;
@ -111,11 +122,12 @@ public class FileContainerImporter
jis.closeEntry();
}
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,
// 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))
{
@ -134,5 +146,7 @@ public class FileContainerImporter
}
}
}
return this;
}
}