Skip to content

Commit d155da6

Browse files
committed
Update public API to use this feature
1 parent 817bfe2 commit d155da6

File tree

2 files changed

+99
-10
lines changed

2 files changed

+99
-10
lines changed

quark/report.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,54 @@
66

77
from quark.core.quark import Quark
88
from quark.core.struct.ruleobject import RuleObject
9+
from quark.utils.tools import find_rizin_instance
910

1011

1112
class Report:
1213
"""
1314
This module is for users who want to use quark as a Python module.
1415
"""
1516

16-
def __init__(self):
17-
self.quark = None
17+
def __init__(self, rizin_path=None, disable_rizin_installation=False):
18+
"""
19+
Create a Report object.
1820
19-
def analysis(self, apk, rule, core_library="androguard"):
21+
:param rizin_path: a PathLike object to specify a Rizin executable for
22+
the Rizin-based analysis library. Defaults to None
23+
:param disable_rizin_installation: a flag to disable the automatic
24+
installation of Rizin. Defaults to False. Defaults to False
2025
"""
21-
The main function of Quark-Engine analysis, the analysis is based on the provided APK file.
26+
self.quark = None
27+
self.rizin_path = rizin_path
28+
self.disable_rizin_installation = disable_rizin_installation
2229

23-
:param core_library: the library to analysis binary
24-
:param apk: the APK file
25-
:param rule: the rule to be checked, it could be a directory or a single json rule
30+
def analysis(self, apk, rule, core_library="androguard", rizin_path=None):
31+
"""
32+
The main function of Quark-Engine analysis, the analysis is based on
33+
the provided APK file.
34+
35+
:param apk: an APK for Quark to analyze
36+
:param rule: a Quark rule that will be used in the analysis. It could
37+
be a directory or a Quark rule
38+
:param core_library: a string indicating which analysis library Quark
39+
should use. Defaults to "androguard"
40+
:param rizin_path: a PathLike object to specify a Rizin executable for
41+
the Rizin-based analysis library. Defaults to None
2642
:return: None
2743
"""
2844

29-
self.quark = Quark(apk, core_library)
45+
if core_library.lower() == "rizin":
46+
if rizin_path:
47+
self.rizin_path = rizin_path
48+
elif not self.rizin_path:
49+
self.rizin_path = find_rizin_instance(
50+
disable_rizin_installation=self.disable_rizin_installation
51+
)
52+
53+
if not self.rizin_path:
54+
raise ValueError("Cannot found a valid Rizin executable.")
55+
56+
self.quark = Quark(apk, core_library, self.rizin_path)
3057

3158
if os.path.isdir(rule):
3259

tests/test_report.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import os
22
import os.path
3+
import shutil
34
import zipfile
45
from unittest.mock import patch
56

67
import pytest
78
import requests
8-
99
from quark.report import Report
1010

1111

@@ -19,7 +19,8 @@ def invalid_file(tempfile):
1919
@pytest.fixture(scope="module")
2020
def sample_apk_file():
2121
APK_SOURCE = (
22-
"https://github.com/quark-engine/" "apk-malware-samples/raw/master/Ahmyth.apk"
22+
"https://github.com/quark-engine/"
23+
"apk-malware-samples/raw/master/Ahmyth.apk"
2324
)
2425
APK_NAME = "Ahmyth.apk"
2526

@@ -130,6 +131,67 @@ def test_analysis_with_rule_directory(
130131
assert mock_run.call_count == num_of_rules
131132
assert mock_generate_report.call_count == num_of_rules
132133

134+
def test_analysis_without_specified_rizin_path(
135+
self, sample_apk_file, sample_rule_directory
136+
):
137+
expected_path = shutil.which("rizin")
138+
139+
with patch("quark.core.quark.Quark.run") as mock_run:
140+
with patch(
141+
"quark.core.quark.Quark.generate_json_report"
142+
) as mock_generate_report:
143+
sample_report = Report()
144+
sample_report.analysis(
145+
sample_apk_file,
146+
sample_rule_directory,
147+
core_library="rizin",
148+
)
149+
150+
assert sample_report.rizin_path == expected_path
151+
152+
mock_run.assert_called_once()
153+
mock_generate_report.assert_called_once()
154+
155+
def test_analysis_with_specified_rizin_path(
156+
self, sample_apk_file, sample_rule_directory
157+
):
158+
rizin_path = shutil.which("rizin")
159+
160+
with patch("quark.core.quark.Quark.run") as mock_run:
161+
with patch(
162+
"quark.core.quark.Quark.generate_json_report"
163+
) as mock_generate_report:
164+
with patch(
165+
"quark.utils.tools.find_rizin_instance"
166+
) as mock_find_rizin:
167+
168+
sample_report = Report()
169+
sample_report.analysis(
170+
sample_apk_file,
171+
sample_rule_directory,
172+
core_library="rizin",
173+
rizin_path=rizin_path,
174+
)
175+
176+
assert sample_report.rizin_path == rizin_path
177+
178+
mock_find_rizin.assert_not_called()
179+
mock_run.assert_called_once()
180+
mock_generate_report.assert_called_once()
181+
182+
def test_analysis_with_invalid_rizin_path(
183+
self, sample_report, sample_apk_file, sample_rule_directory
184+
):
185+
invalid_path = "INVALID_PATH"
186+
187+
with pytest.raises(ValueError):
188+
sample_report.analysis(
189+
sample_apk_file,
190+
sample_rule_directory,
191+
core_library="rizin",
192+
rizin_path=invalid_path,
193+
)
194+
133195
def test_get_report_with_invalid_type(self, sample_report):
134196
with pytest.raises(ValueError):
135197
sample_report.get_report(None)

0 commit comments

Comments
 (0)