未验证 提交 ab02e6e7 编写于 作者: S Shaun Dang 提交者: GitHub

feat(gui): add Quark-Engine integration (#1119) (PR #1135)

上级 9ef99a2b
......@@ -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;
......
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();
}
}
}
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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册