Skip to content

Commit

Permalink
Quark-Engine integration
Browse files Browse the repository at this point in the history
  • Loading branch information
pulorsok committed Mar 12, 2021
1 parent 9ef99a2 commit 16309db
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 0 deletions.
17 changes: 17 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -662,6 +663,8 @@ private void nodeClickAction(@Nullable Object obj) {
}
} 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));
}
Expand Down Expand Up @@ -914,6 +917,14 @@ public void actionPerformed(ActionEvent e) {
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);
Expand Down Expand Up @@ -998,6 +1009,8 @@ public void actionPerformed(ActionEvent e) {
toolbar.addSeparator();
toolbar.add(prefsAction);
toolbar.addSeparator();
toolbar.add(quarkAction);
toolbar.addSeparator();
toolbar.add(Box.createHorizontalGlue());
toolbar.add(updateLink);

Expand Down Expand Up @@ -1249,6 +1262,10 @@ public ProgressPanel getProgressPane() {
return progressPane;
}

public JRoot getTreeRoot() {
return treeRoot;
}

private class RecentProjectsMenuListener implements MenuListener {
private final JMenu menu;

Expand Down
232 changes: 232 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/ui/QuarkDialog.java
Original file line number Diff line number Diff line change
@@ -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();
}
}

}
105 changes: 105 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/ui/QuarkReport.java
Original file line number Diff line number Diff line change
@@ -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;
}

}
Loading

0 comments on commit 16309db

Please sign in to comment.