/* SAAF: A static analyzer for APK files. * Copyright (C) 2013 syssec.rub.de * * 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/>. */ package de.rub.syssec.saaf.gui; import java.awt.Color; import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.util.Vector; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu.Separator; import javax.swing.KeyStroke; import javax.swing.UIManager; import org.apache.log4j.Logger; import de.rub.syssec.saaf.Main; import de.rub.syssec.saaf.analysis.Analysis; import de.rub.syssec.saaf.gui.actions.AboutAction; import de.rub.syssec.saaf.gui.actions.CloseAnalysisAction; import de.rub.syssec.saaf.gui.actions.DecompileToJavaAction; import de.rub.syssec.saaf.gui.actions.DetectObfuscationAction; import de.rub.syssec.saaf.gui.actions.DoAnalysisAction; import de.rub.syssec.saaf.gui.actions.FoundAPICallsAction; import de.rub.syssec.saaf.gui.actions.GenerateCFGsAction; import de.rub.syssec.saaf.gui.actions.OpenAPKAction; import de.rub.syssec.saaf.gui.actions.QuitAction; import de.rub.syssec.saaf.gui.actions.SearchBytecodeAction; import de.rub.syssec.saaf.gui.actions.SearchStringsAction; import de.rub.syssec.saaf.gui.actions.ShowLogAction; import de.rub.syssec.saaf.gui.actions.ShowReportAction; import de.rub.syssec.saaf.misc.config.Config; import de.rub.syssec.saaf.misc.config.ConfigKeys; import de.rub.syssec.saaf.model.analysis.AnalysisInterface; public class MainWindow extends JFrame implements ActionListener { private static final long serialVersionUID = -7146327106175691998L; public static final Logger logger = Logger.getLogger(MainWindow.class); // private static final Logger LOGGER = Config.getLogger(); private static MainWindow self; public ROA roaList = new ROA(); /** * The desktop pane is used to add frames to it */ private final JDesktopPane desktopPane; private final OpenAppsMgr openAppsMgr; public MainWindow() { super(Main.title + ": Static Android Analysis Framework"); self = this; openAppsMgr = new OpenAppsMgr(); Config.getInstance().setBooleanConfigValue(ConfigKeys.ANALYSIS_GENERATE_REPORT, true); try { // Load recently used application, will be used in the menu roaList.loadList(); } catch (IOException e) { logger.error("Could not load recently used apk list: " + e.getMessage()); } // Make the big window be indented 35 pixels from each edge // of the screen. int inset = 35; GraphicsEnvironment ge = GraphicsEnvironment .getLocalGraphicsEnvironment(); setBounds(inset, inset, ge.getDefaultScreenDevice().getDisplayMode() .getWidth() - (inset * 2), ge.getDefaultScreenDevice().getDisplayMode() .getHeight() - (inset * 2)); // Set up the GUI. // TODO: Add some smart internal frame placement code: // http://www.java2s.com/Code/Java/Swing-JFC/InterestingthingsusingJInternalFramesJDesktopPaneandDesktopManager2.htm desktopPane = new JDesktopPane(); // a specialized layered pane // createFrame(); //create first "window" setContentPane(desktopPane); setJMenuBar(createMenuBar()); desktopPane.setBackground(Color.gray); // Make dragging a little faster but perhaps uglier: will only move the // borders of the frame // desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); } private static final String CMD_SHOW_LOGS = "de.rub.syssec.saaf.cmd.check.show.logs"; private static final String CMD_CLEAR_ROA = "de.rub.syssec.saaf.cmd.clear.recently.openend.apks"; protected JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); menuBar.add(fileMenu); JMenuItem menuItem = new JMenuItem(new OpenAPKAction("Open APK", openAppsMgr, this, true)); menuItem.setMnemonic(KeyEvent.VK_O); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_OPEN); // menuItem.addActionListener(this); fileMenu.add(menuItem); JMenu roa = new JMenu("Recently opened APKs"); // menuItem.setMnemonic(KeyEvent.VK_R); // menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, // ActionEvent.ALT_MASK)); fileMenu.add(roa); boolean isListEmtpy = true; for (String apk : roaList.getRoaList()) { menuItem = new JMenuItem(new OpenAPKAction(apk, openAppsMgr, this, false)); roa.add(menuItem); // menuItem.setActionCommand(CMD_ROA_APK+apk); // menuItem.addActionListener(this); isListEmtpy = false; } if (isListEmtpy) { menuItem = new JMenuItem("Emtpy"); menuItem.setEnabled(false); roa.add(menuItem); } roa.addSeparator(); menuItem = new JMenuItem("Clear"); menuItem.setActionCommand(CMD_CLEAR_ROA); menuItem.addActionListener(this); if (isListEmtpy) menuItem.setEnabled(false); roa.add(menuItem); Separator sep1 = new Separator(); fileMenu.add(sep1); menuItem = new JMenuItem(new CloseAnalysisAction("Close APK", openAppsMgr, this)); menuItem.setMnemonic(KeyEvent.VK_C); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_CLOSE_APP); // menuItem.addActionListener(this); fileMenu.add(menuItem); Separator sep2 = new Separator(); fileMenu.add(sep2); menuItem = new JMenuItem(new ShowLogAction("Show Logs",this)); menuItem.setMnemonic(KeyEvent.VK_L); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_SHOW_LOGS); // menuItem.addActionListener(this); fileMenu.add(menuItem); Separator sep3 = new Separator(); fileMenu.add(sep3); menuItem = new JMenuItem(new QuitAction("Exit", this)); menuItem.setMnemonic(KeyEvent.VK_X); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_EXIT); // menuItem.addActionListener(this); fileMenu.add(menuItem); // JMenu analysisMenu = new JMenu("Analysis"); analysisMenu.setMnemonic(KeyEvent.VK_A); menuBar.add(analysisMenu); menuItem = new JMenuItem(new DoAnalysisAction( "Perform Analysis", this)); menuItem.setMnemonic(KeyEvent.VK_P); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_PROGRAM_SLICING); // menuItem.addActionListener(this); analysisMenu.add(menuItem); Separator sep4 = new Separator(); analysisMenu.add(sep4); menuItem = new JMenuItem(new ShowReportAction("Show Report", this)); menuItem.setMnemonic(KeyEvent.VK_R); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_SHOW_REPORT); // menuItem.addActionListener(this); analysisMenu.add(menuItem); JMenu miscMenu = new JMenu("Misc"); miscMenu.setMnemonic(KeyEvent.VK_M); menuBar.add(miscMenu); menuItem = new JMenuItem(new SearchBytecodeAction("Search Bytecode...", openAppsMgr, this)); menuItem.setMnemonic(KeyEvent.VK_B); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_SEARCH_BYTECODE); // menuItem.addActionListener(this); miscMenu.add(menuItem); menuItem = new JMenuItem(new SearchStringsAction("Show Strings...", openAppsMgr, this)); menuItem.setMnemonic(KeyEvent.VK_S); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_FIND_STRINGS); // menuItem.addActionListener(this); miscMenu.add(menuItem); menuItem = new JMenuItem(new FoundAPICallsAction("Show APIcalls...", openAppsMgr, this)); // menuItem.setMnemonic(KeyEvent.VK_S); // menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, // ActionEvent.ALT_MASK)); miscMenu.add(menuItem); menuItem = new JMenuItem(new DetectObfuscationAction("Check for obfuscation",this,openAppsMgr)); miscMenu.add(menuItem); Separator sep5 = new Separator(); miscMenu.add(sep5); menuItem = new JMenuItem(new GenerateCFGsAction("Generate all CFGs", this)); // menuItem.setMnemonic(KeyEvent.VK_C); // menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, // ActionEvent.ALT_MASK)); // menuItem.setActionCommand(CMD_GENERATE_CFGS); // menuItem.addActionListener(this); miscMenu.add(menuItem); menuItem = new JMenuItem(new DecompileToJavaAction("Decompile to Java",this, openAppsMgr)); miscMenu.add(menuItem); Separator sep6 = new Separator(); miscMenu.add(sep6); menuItem = new JMenuItem(new AboutAction("About")); miscMenu.add(menuItem); return menuBar; } // React to menu selections. public void actionPerformed(ActionEvent e) { if (CMD_CLEAR_ROA.equals(e.getActionCommand())) { roaList.clear(); setJMenuBar(createMenuBar()); getRootPane().updateUI(); } else { logger.error("Unknown cmd found. This should not happen. Cmd=" + e.getActionCommand()); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ public void createAndShowGUI() { // Set up Look and Feel, possible: null (use the default), "Metal", // "System", "Motif", and "GTK" boolean useDefaultLaF = false; String laf = null; try { String os = System.getProperty("os.name").toLowerCase(); // linux or unix if (os.indexOf("linux") >= 0) { // Set GTK L&F, it is somehow not used on my system, but instead // the Metal L&F // is the default one. laf = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; } else { laf = UIManager.getSystemLookAndFeelClassName(); } UIManager.setLookAndFeel(laf); } catch (Exception e) { useDefaultLaF = true; laf = "Metal"; // default and cross platform logger.error("Problem setting look-and-feel"); } // fallback if (useDefaultLaF) { try { UIManager.setLookAndFeel(laf); } catch (Exception e) { /* ignore */ } } // System.out.println("Using L&F "+laf); // debug // Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); // Create and set up the window. final MainWindow frame = new MainWindow(); // Do nothing by default when 'X' is pressed and set our own handle for // this event frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent we) { new QuitAction("Exit", frame).actionPerformed(null); } }); // Display the window. frame.setVisible(true); } /** * Display an Info Dialog in the GUI. THIS METHOD SHOULD ONLY BE CALLED FROM * THE LOGGER COMPONENT. * * @param msg * the message to display * @param title * the title of the dialog */ public static void showInfoDialog(String msg, String title) { JOptionPane.showMessageDialog(self, msg, title, JOptionPane.INFORMATION_MESSAGE); } /** * Display an Error Dialog in the GUI. THIS METHOD SHOULD ONLY BE CALLED * FROM THE LOGGER COMPONENT. * * @param msg * the message to display * @param title * the title of the dialog */ public static void showErrorDialog(String msg, String title) { JOptionPane.showMessageDialog(self, msg, title, JOptionPane.ERROR_MESSAGE); } /** * If multiple applications are opened, the user is asked to select one. * This has to be done for several operations which require a * "target application". If only one application is opened, this application * is returned w/o required user interaction. * * @return the selected application, the only application, or null if none * is opened */ public Analysis getUserselectedAnalysisIfMultipleAreOpened() { if (openAppsMgr.getOpenedAnalysisCnt() == 0) return null; // nothing opened else if (openAppsMgr.getOpenedAnalysisCnt() == 1) { return openAppsMgr.getAllOpenedAnalysis().firstElement() .getAnalysis(); } else { // > 1 Vector<OpenAnalysis> v = openAppsMgr.getAllOpenedAnalysis(); Vector<Analysis> av = new Vector<Analysis>(v.size()); for (OpenAnalysis ao : v) { av.add(ao.getAnalysis()); } AnalysisInterface[] apps = (AnalysisInterface[]) av.toArray(new Analysis[av.size()]); Analysis selectedAnalysis = (Analysis) JOptionPane.showInputDialog( null, "Chose an application for this operation.", "Multiple Opened Applications", JOptionPane.QUESTION_MESSAGE, null, apps, apps[0]); return selectedAnalysis; } } /** * * @return the desktop pane to add frames etc */ public static JDesktopPane getDesktopPane() { return self.desktopPane; } }