@@ -143,6 +143,7 @@ public class MainWindow extends JFrame {
|
||||
private static final ImageIcon ICON_COMMENT_SEARCH = UiUtils.openIcon("table_edit");
|
||||
private static final ImageIcon ICON_BACK = UiUtils.openIcon("icon_back");
|
||||
private static final ImageIcon ICON_FORWARD = UiUtils.openIcon("icon_forward");
|
||||
private static final ImageIcon ICON_QUARK = UiUtils.openIcon("icon_quark");
|
||||
private static final ImageIcon ICON_PREF = UiUtils.openIcon("wrench");
|
||||
private static final ImageIcon ICON_DEOBF = UiUtils.openIcon("lock_edit");
|
||||
private static final ImageIcon ICON_LOG = UiUtils.openIcon("report");
|
||||
@@ -662,6 +663,8 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
} else if (obj instanceof ApkSignature) {
|
||||
tabbedPane.showSimpleNode((JNode) obj);
|
||||
} else if (obj instanceof QuarkReport) {
|
||||
tabbedPane.showSimpleNode((JNode) obj);
|
||||
} else if (obj instanceof JNode) {
|
||||
tabbedPane.codeJump(new JumpPosition((JNode) obj));
|
||||
}
|
||||
@@ -914,6 +917,14 @@ public class MainWindow extends JFrame {
|
||||
forwardAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("nav.forward"));
|
||||
forwardAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.ALT_DOWN_MASK));
|
||||
|
||||
Action quarkAction = new AbstractAction("Quark Engine", ICON_QUARK) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new QuarkDialog(MainWindow.this).setVisible(true);
|
||||
}
|
||||
};
|
||||
quarkAction.putValue(Action.SHORT_DESCRIPTION, "Quark Engine");
|
||||
|
||||
JMenu file = new JMenu(NLS.str("menu.file"));
|
||||
file.setMnemonic(KeyEvent.VK_F);
|
||||
file.add(openAction);
|
||||
@@ -998,6 +1009,8 @@ public class MainWindow extends JFrame {
|
||||
toolbar.addSeparator();
|
||||
toolbar.add(prefsAction);
|
||||
toolbar.addSeparator();
|
||||
toolbar.add(quarkAction);
|
||||
toolbar.addSeparator();
|
||||
toolbar.add(Box.createHorizontalGlue());
|
||||
toolbar.add(updateLink);
|
||||
|
||||
@@ -1249,6 +1262,10 @@ public class MainWindow extends JFrame {
|
||||
return progressPane;
|
||||
}
|
||||
|
||||
public JRoot getTreeRoot() {
|
||||
return treeRoot;
|
||||
}
|
||||
|
||||
private class RecentProjectsMenuListener implements MenuListener {
|
||||
private final JMenu menu;
|
||||
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.treemodel.JRoot;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.logs.LogCollector;
|
||||
|
||||
class QuarkDialog extends JDialog {
|
||||
|
||||
private static final long serialVersionUID = 4855753773520368215L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QuarkDialog.class);
|
||||
|
||||
private File quarkReportFile;
|
||||
|
||||
private final transient JadxSettings settings;
|
||||
private final transient MainWindow mainWindow;
|
||||
private JProgressBar progressBar;
|
||||
private JPanel progressPane;
|
||||
|
||||
private JComboBox<String> selectFile;
|
||||
|
||||
private final List<Path> files;
|
||||
private ArrayList<Path> analyzeFile = new ArrayList<Path>();
|
||||
|
||||
public QuarkDialog(MainWindow mainWindow) {
|
||||
|
||||
this.mainWindow = mainWindow;
|
||||
this.settings = mainWindow.getSettings();
|
||||
this.files = mainWindow.getWrapper().getOpenPaths();
|
||||
|
||||
if (!prepareAnalysis()) {
|
||||
// The files are unable to analysis by Quark
|
||||
return;
|
||||
}
|
||||
initUI();
|
||||
settings.loadWindowPos(this);
|
||||
}
|
||||
|
||||
private boolean prepareAnalysis() {
|
||||
|
||||
String[] exts = new String[] { "apk", "dex" };
|
||||
|
||||
if (this.files.size() != 1) {
|
||||
for (Path filePath : this.files) {
|
||||
String fileName = filePath.toString();
|
||||
int dotIndex = fileName.lastIndexOf('.');
|
||||
String extension = (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
|
||||
|
||||
if (!Arrays.stream(exts).anyMatch(extension::equals)) {
|
||||
LOG.warn("Quark: Current file can't be analysis ", fileName);
|
||||
continue;
|
||||
}
|
||||
analyzeFile.add(filePath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
String fileName = this.files.get(0).toString();
|
||||
int dotIndex = fileName.lastIndexOf('.');
|
||||
String extension = (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
|
||||
if (!Arrays.stream(exts).anyMatch(extension::equals)) {
|
||||
LOG.warn("Quark: Current file can't be analysis ", fileName);
|
||||
return false;
|
||||
}
|
||||
analyzeFile.add(this.files.get(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
private String[] filesToStringArr() {
|
||||
String[] arr = new String[files.size()];
|
||||
int index = 0;
|
||||
for (Path file : analyzeFile) {
|
||||
arr[index] = file.getFileName().toString();
|
||||
index++;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
public final void initUI() {
|
||||
|
||||
JLabel description = new JLabel("Analyzing apk using Quark-Engine");
|
||||
JLabel selectApkText = new JLabel("Select Apk/Dex");
|
||||
description.setAlignmentX(0.5f);
|
||||
|
||||
selectFile = new JComboBox<String>(filesToStringArr());
|
||||
|
||||
JPanel textPane = new JPanel();
|
||||
|
||||
textPane.add(description);
|
||||
|
||||
JPanel selectApkPanel = new JPanel();
|
||||
selectApkPanel.add(selectApkText);
|
||||
selectApkPanel.add(selectFile);
|
||||
|
||||
progressPane = new JPanel();
|
||||
progressPane.setVisible(false);
|
||||
progressPane.setSize(150, 10);
|
||||
|
||||
progressBar = new JProgressBar(0, 100);
|
||||
progressBar.setSize(150, 10);
|
||||
progressBar.setIndeterminate(true);
|
||||
progressBar.setStringPainted(false);
|
||||
progressPane.add(progressBar);
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
JButton start = new JButton("Start");
|
||||
JButton close = new JButton(NLS.str("tabs.close"));
|
||||
close.addActionListener(event -> close());
|
||||
start.addActionListener(event -> analyzeAPK());
|
||||
buttonPane.add(start);
|
||||
buttonPane.add(close);
|
||||
getRootPane().setDefaultButton(close);
|
||||
|
||||
JPanel centerPane = new JPanel();
|
||||
centerPane.add(selectApkPanel);
|
||||
centerPane.add(progressPane);
|
||||
Container contentPane = getContentPane();
|
||||
|
||||
contentPane.add(textPane, BorderLayout.PAGE_START);
|
||||
contentPane.add(centerPane);
|
||||
contentPane.add(buttonPane, BorderLayout.PAGE_END);
|
||||
|
||||
setTitle("Quark Engine");
|
||||
pack();
|
||||
setSize(200, 125);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
setModalityType(ModalityType.MODELESS);
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
private void analyzeAPK() {
|
||||
LoadTask task = new LoadTask();
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private void loadReportFile() {
|
||||
try {
|
||||
JsonObject quarkReport = (JsonObject) JsonParser.parseReader(new FileReader(quarkReportFile.getAbsolutePath().toString()));
|
||||
|
||||
JRoot root = mainWindow.getCacheObject().getJRoot();
|
||||
|
||||
QuarkReport quarkNode = QuarkReport.analysisAPK(quarkReport);
|
||||
|
||||
root.update();
|
||||
root.add(quarkNode);
|
||||
|
||||
mainWindow.reloadTree();
|
||||
|
||||
} catch (JsonIOException | JsonSyntaxException | FileNotFoundException e) {
|
||||
LOG.error("Quark: Load report failed: ", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void close() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
LogCollector.getInstance().resetListener();
|
||||
settings.saveWindowPos(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private class LoadTask extends SwingWorker<Void, Void> {
|
||||
public LoadTask() {
|
||||
progressPane.setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void doInBackground() {
|
||||
try {
|
||||
|
||||
quarkReportFile = File.createTempFile("QuarkReport-", ".json");
|
||||
|
||||
String outputPath = quarkReportFile.getAbsolutePath().toString();
|
||||
String apkName = selectFile.getSelectedItem().toString();
|
||||
String apkPath = null;
|
||||
for (Path path : files) {
|
||||
if (path.getFileName().toString().equals(apkName)) {
|
||||
apkPath = path.toString();
|
||||
}
|
||||
}
|
||||
String cmd = "quark -a " + apkPath + " -s -o " + outputPath;
|
||||
Runtime run = Runtime.getRuntime();
|
||||
Process process = run.exec(cmd);
|
||||
|
||||
BufferedReader buf = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String output = "";
|
||||
LOG.debug("Quark analyzing...");
|
||||
while ((output = buf.readLine()) != null) {
|
||||
LOG.debug(output);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
LOG.error("Quark failed: ", e);
|
||||
dispose();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
loadReportFile();
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
public class QuarkReport extends JNode {
|
||||
|
||||
private static final long serialVersionUID = -766800957202637021L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QuarkReport.class);
|
||||
|
||||
private static final ImageIcon REPORT_ICON = UiUtils.openIcon("report");
|
||||
|
||||
private String content;
|
||||
private String apkFileName;
|
||||
|
||||
private JsonObject reportData;
|
||||
|
||||
public static QuarkReport analysisAPK(JsonObject data) {
|
||||
return new QuarkReport(data);
|
||||
}
|
||||
|
||||
public QuarkReport(JsonObject data) {
|
||||
this.reportData = data;
|
||||
this.apkFileName = data.get("apk_filename").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return REPORT_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return "Quark analysis report";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
if (content != null) {
|
||||
return this.content;
|
||||
}
|
||||
try {
|
||||
|
||||
JsonArray crimes = (JsonArray) this.reportData.get("crimes");
|
||||
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
|
||||
builder.append("<h1>Quark Analysis Report</h1>");
|
||||
builder.append("<h3>");
|
||||
builder.append("File name: ");
|
||||
builder.append(apkFileName);
|
||||
builder.append("</h3>");
|
||||
builder.append("<table><thead><tr>");
|
||||
builder.append("<th>Potential Malicious Activities</th>");
|
||||
builder.append("<th>Confidence</th>");
|
||||
builder.append("</tr></thead><tbody>");
|
||||
|
||||
for (Object obj : crimes) {
|
||||
JsonObject crime = (JsonObject) obj;
|
||||
String crimeDes = crime.get("crime").getAsString();
|
||||
String confidence = crime.get("confidence").getAsString();
|
||||
|
||||
builder.append("<tr><td>");
|
||||
builder.append(crimeDes);
|
||||
builder.append("</td><td>");
|
||||
builder.append(confidence);
|
||||
builder.append("</td></tr>");
|
||||
}
|
||||
|
||||
builder.append("</tbody></table>");
|
||||
this.content = builder.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>");
|
||||
builder.escape("Quark analysis failed!");
|
||||
builder.append("</h1><pre>");
|
||||
builder.escape(ExceptionUtils.getStackTrace(e));
|
||||
builder.append("</pre>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
return this.content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -305,6 +305,9 @@ public class TabbedPane extends JTabbedPane {
|
||||
if (node instanceof ApkSignature) {
|
||||
return new HtmlPanel(this, node);
|
||||
}
|
||||
if (node instanceof QuarkReport) {
|
||||
return new HtmlPanel(this, node);
|
||||
}
|
||||
return new ClassCodeContentPanel(this, node);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user