2
2
# This file is part of Quark-Engine - https://github.com/quark-engine/quark-engine
3
3
# See the file 'LICENSE' for copying permission.
4
4
5
- from multiprocessing .pool import Pool
6
5
from multiprocessing import cpu_count
6
+ from multiprocessing .pool import Pool
7
7
8
8
from quark .core .analysis import QuarkAnalysis
9
9
from quark .core .quark import Quark
13
13
14
14
class ParallelQuark (Quark ):
15
15
@staticmethod
16
- def _worker_initializer (apk , core_library ):
16
+ def _worker_initializer (apk , core_library , rizin_path ):
17
+ """
18
+ An initializer that creates multiple Quark object for a subprocess
19
+ pool.
20
+
21
+ :param apk: an APK for Quark to analyze
22
+ :param core_library: a string indicating which analysis library Quark
23
+ should use
24
+ :param rizin_path: a PathLike object to specify a Rizin executable for
25
+ the Rizin-based analysis library
26
+ """
27
+
17
28
global _quark
18
- _quark = Quark (apk , core_library )
29
+ _quark = Quark (apk , core_library , rizin_path )
19
30
20
31
@staticmethod
21
32
def _worker_analysis (rule_obj ):
33
+ """
34
+ A function for the subprocesses in the pool to analyze the target APK
35
+ with the specified rule.
36
+
37
+ :param rule_obj: a Quark rule that the subprocess will analyze
38
+ :return: a tuple of the analysis result, including the reached stage,
39
+ the parent functions, the detected behavior (rule), and the
40
+ corresponding bytecodes.
41
+ """
42
+
22
43
_quark .quark_analysis = QuarkAnalysis ()
23
44
_quark .run (rule_obj )
24
45
@@ -32,7 +53,8 @@ def to_raw_method(methodobject):
32
53
33
54
reached_stage = rule_obj .check_item .count (True )
34
55
level_4_result = tuple (
35
- to_raw_method (method ) for method in _quark .quark_analysis .level_4_result
56
+ to_raw_method (method )
57
+ for method in _quark .quark_analysis .level_4_result
36
58
)
37
59
behavior_list = [
38
60
(
@@ -51,6 +73,13 @@ def to_raw_method(methodobject):
51
73
)
52
74
53
75
def _apply_analysis_result (self , rule_obj ):
76
+ """
77
+ Append the result returned by the subprocesses into the QuarkAnalysis
78
+ object.
79
+
80
+ :param rule_obj: a Quark rule specifying which result this method
81
+ should append
82
+ """
54
83
async_result = self ._result_map [id (rule_obj )]
55
84
result = async_result .get ()
56
85
@@ -112,21 +141,43 @@ def _apply_analysis_result(self, rule_obj):
112
141
]
113
142
)
114
143
115
- def __init__ (self , apk , core_library , num_of_process = 1 ):
144
+ def __init__ (self , apk , core_library , num_of_process = 1 , rizin_path = None ):
145
+ """
146
+ Create a ParallelQuark object to run the Quark analysis parallelly.
147
+
148
+ :param apk: an APK for Quark to analyze
149
+ :param core_library: a string indicating which analysis library Quark
150
+ should use
151
+ :param num_of_process: a value indicating the maximal number of
152
+ available processes for the analysis. Defaults to 1
153
+ :param rizin_path: a PathLike object to specify a Rizin executable for
154
+ the Rizin-based analysis library. Default to None
155
+ """
116
156
self ._result_map = {}
117
157
self ._pool = Pool (
118
- min (num_of_process , cpu_count () - 1 ), self ._worker_initializer ,
119
- (apk , core_library )
158
+ min (num_of_process , cpu_count () - 1 ),
159
+ self ._worker_initializer ,
160
+ (apk , core_library , rizin_path ),
120
161
)
121
162
122
- super ().__init__ (apk , core_library )
163
+ super ().__init__ (apk , core_library , rizin_path = rizin_path )
123
164
124
165
def apply_rules (self , rule_obj_list ):
166
+ """
167
+ Add Quark rules to this pool.
168
+
169
+ :param rule_obj_list: a list of Quark rules
170
+ """
125
171
for rule_obj in rule_obj_list :
126
172
result = self ._pool .apply_async (self ._worker_analysis , (rule_obj ,))
127
173
self ._result_map [id (rule_obj )] = result
128
174
129
175
def run (self , rule_obj ):
176
+ """
177
+ Wait for all rules to be analyzed.
178
+
179
+ :param rule_obj: _description_
180
+ """
130
181
self ._apply_analysis_result (rule_obj )
131
182
132
183
def close (self ):
0 commit comments