diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index 18f710aa..8227f120 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -122,7 +122,7 @@ public class BytecodeViewer public static MainViewerGUI viewer; //All of the opened resources (Files/Classes/Etc) - public static List files = new ArrayList<>(); + public static List files = new ArrayList<>(); //All of the created processes (Decompilers/etc) public static List 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 getFiles() { + public static List 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 a = new ArrayList<>(); - for (FileContainer container : files) + for (ResourceContainer container : files) for (ClassNode c : container.resourceClasses.values()) if (!a.contains(c)) a.add(c); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java b/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java index e2b6736c..df6faeef 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Configuration.java @@ -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, + } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java index dd0350e8..5d8de838 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java @@ -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; - } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/SmaliDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/SmaliDisassembler.java index 38490d75..50eadb71 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/SmaliDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/SmaliDisassembler.java @@ -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.*; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java index 84495e29..4da2facf 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java @@ -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 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 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java index 3243184a..85edc636 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/DecompilerViewComponent.java @@ -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 } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java index 43fd9008..5c11ae81 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java @@ -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; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListRightClickRemove.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListRightClickRemove.java index b702864a..39489388 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListRightClickRemove.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListRightClickRemove.java @@ -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; } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java index 5f96cb0f..74549d00 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/PerformSearch.java @@ -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()); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java index e24b60aa..23d0c36a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchBoxPane.java @@ -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); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java index c69d8230..9d32aee1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/DecompilerSelectionPane.java @@ -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 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 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 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; } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java index fa41bb8a..f52a5ed6 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/ResourceViewPanel.java @@ -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; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java index 9d1384c2..5d1e4ee6 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/WorkPaneMainComponent.java @@ -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)) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java index 555e3087..92d0d541 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ClassViewer.java @@ -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 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(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java index 645bcf8a..f2adeb98 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/FileViewer.java @@ -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(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java index c1e367cc..7abc7e46 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourceviewer/viewer/ResourceViewer.java @@ -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; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java index cd014119..44ee9c1c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/exporting/impl/APKExport.java @@ -27,17 +27,17 @@ public class APKExport implements Exporter if (BytecodeViewer.promptIfNoLoadedClasses()) return; - List containers = BytecodeViewer.getFiles(); - List validContainers = new ArrayList<>(); + List containers = BytecodeViewer.getFiles(); + List validContainers = new ArrayList<>(); List 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(() -> { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java index e0ba2772..fcbf7941 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/APKResourceImporter.java @@ -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 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); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java index c6d57746..66854f63 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ClassResourceImporter.java @@ -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")) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java index 2dfbb159..934014e5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DEXResourceImporter.java @@ -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 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); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java index 82776824..c5185a12 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/DirectoryResourceImporter.java @@ -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 allDirectoryFiles = new HashMap<>(); HashMap allDirectoryClasses = new HashMap<>(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java index 80f9df36..84c2f081 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/FileResourceImporter.java @@ -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 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java index f1eb2945..5d65b8a6 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/XAPKResourceImporter.java @@ -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 allDirectoryFiles = new HashMap<>(); Configuration.silenceExceptionGUI++; //turn exceptions off diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java index 4826a89f..92f39728 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/importing/impl/ZipResourceImporter.java @@ -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 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java index 3070aeba..35a3aba5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java @@ -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); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/FieldCallSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/FieldCallSearch.java index 8fc0a803..5392892c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/FieldCallSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/FieldCallSearch.java @@ -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 methods = node.methods.iterator(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/LDCSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/LDCSearch.java index f61136d0..43575d48 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/LDCSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/LDCSearch.java @@ -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 methods = node.methods.iterator(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MethodCallSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MethodCallSearch.java index 24d03e51..f13e9a92 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MethodCallSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MethodCallSearch.java @@ -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 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 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/RegexSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/RegexSearch.java index 31716c80..8fb88bc1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/RegexSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/RegexSearch.java @@ -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 methods = node.methods.iterator(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java index 35cd4872..46bde02e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java @@ -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(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java deleted file mode 100644 index 0d96872d..00000000 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java +++ /dev/null @@ -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 . * - ***************************************************************************/ - -/** - * 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 resourceFiles = new HashMap<>(); - public HashMap resourceClassBytes = new HashMap<>(); - public HashMap resourceClasses = new HashMap<>(); - - public ClassNode getClassNode(String name) - { - return resourceClasses.get(name); - } - - public String generateWorkName(String name) - { - return file.getAbsolutePath() + ">" + name; - } -} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java index 1be9dccc..a306effe 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java @@ -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 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 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 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 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 entry : container.resourceFiles.entrySet()) { String filename = entry.getKey(); if (!filename.startsWith("META-INF")) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java index 575fdf90..5877105c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java @@ -176,9 +176,9 @@ public class MiscUtils return path; } - public static int fileContainersHash(ArrayList fileContainers) { + public static int fileContainersHash(ArrayList 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); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainer.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainer.java new file mode 100644 index 00000000..ff1137b2 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainer.java @@ -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 . * + ***************************************************************************/ + +/** + * Represents a file container + * + * @author Konloch + */ + +public class ResourceContainer +{ + public File file; + public String name; + public File APKToolContents = null; + + public HashMap resourceFiles = new HashMap<>(); + public HashMap resourceClassBytes = new HashMap<>(); + public HashMap 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; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainerImporter.java similarity index 74% rename from src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java rename to src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainerImporter.java index 5bfb06b9..f2a08510 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainerImporter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/ResourceContainerImporter.java @@ -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; } }