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 ctypes import Union
5
6
import functools
6
7
import json
7
8
import re
17
18
from frida .core import Device
18
19
from frida .core import Session as FridaSession
19
20
21
+ MethodCallEvent = Dict [str , Union [List [str ], str ]]
22
+
20
23
21
24
class MethodCallEventDispatcher :
22
25
def __init__ (self , frida : FridaSession ) -> None :
@@ -29,20 +32,20 @@ def _getMethodIdentifier(targetMethod: str, paramType: str):
29
32
30
33
def startWatchingMethodCall (
31
34
self , targetMethod : str , methodParamTypes : str
32
- ) -> List ["Behavior" ]:
35
+ ) -> List [MethodCallEvent ]:
33
36
"""Start tracking calls to the target method.
34
37
35
38
:param targetMethod: the target API
36
39
:param methodParamTypes: the parameter types of the target API
37
40
:return: python list that holds calls to the target method
38
41
"""
39
- messageBuffer = []
42
+ eventBuffer = []
40
43
methodId = self ._getMethodIdentifier (targetMethod , methodParamTypes )
41
44
42
- self .watchedMethods [methodId ] = messageBuffer
45
+ self .watchedMethods [methodId ] = eventBuffer
43
46
self .script .exports .watch_method_call (targetMethod , methodParamTypes )
44
47
45
- return messageBuffer
48
+ return eventBuffer
46
49
47
50
def stopWatchingMethodCall (
48
51
self , targetMethod : str , methodParamTypes : str
@@ -80,9 +83,17 @@ def receiveMessage(self, messageFromFridaAgent: dict, _) -> None:
80
83
81
84
82
85
@functools .lru_cache
83
- def _setupFrida (
86
+ def _spawnApp (
84
87
appPackageName : str , protocol = "usb" , ** kwargs : Any
85
88
) -> Tuple [Device , FridaSession , int ]:
89
+ """Spawn the target APP with Frida
90
+
91
+ :param appPackageName: the package name of the target APP
92
+ :param protocol: string that holds the protocol to communicate with the
93
+ Frida server, defaults to "usb"
94
+ :return: tuple containing the device ID, the Frida instance and the process
95
+ ID of the APP.
96
+ """
86
97
device = None
87
98
if protocol == "usb" :
88
99
device = frida .get_usb_device (** kwargs )
@@ -99,6 +110,12 @@ def _setupFrida(
99
110
100
111
@functools .lru_cache
101
112
def _injectAgent (frida : FridaSession ) -> MethodCallEventDispatcher :
113
+ """Inject a Frida agent to help track method calls.
114
+
115
+ :param frida: Frida instance to be injected
116
+ :return: dispatcher that stores the captured calls to the appropriate
117
+ buffers
118
+ """
102
119
dispatcher = MethodCallEventDispatcher (frida )
103
120
104
121
pathToFridaAgentSource = pkg_resources .resource_filename (
@@ -116,7 +133,7 @@ def _injectAgent(frida: FridaSession) -> MethodCallEventDispatcher:
116
133
117
134
@dataclass
118
135
class Behavior :
119
- _message : Dict [ str , str ]
136
+ _callEvent : MethodCallEvent
120
137
121
138
def hasString (self , pattern : str , regex : bool = False ) -> List [str ]:
122
139
"""Check if the behavior contains strings
@@ -153,12 +170,12 @@ def getParamValues(self) -> List[str]:
153
170
154
171
:return: python list containing parameter values
155
172
"""
156
- return self ._message ["paramValues" ]
173
+ return self ._callEvent ["paramValues" ]
157
174
158
175
159
176
@dataclass
160
177
class FridaResult :
161
- _messageBuffer : List [str ]
178
+ _eventBuffer : List [MethodCallEvent ]
162
179
163
180
@property
164
181
def behaviorOccurList (self ) -> List [Behavior ]:
@@ -167,7 +184,7 @@ def behaviorOccurList(self) -> List[Behavior]:
167
184
168
185
:return: detected behavior instance
169
186
"""
170
- return [Behavior (message ) for message in self ._messageBuffer ]
187
+ return [Behavior (message ) for message in self ._eventBuffer ]
171
188
172
189
173
190
def runFridaHook (
@@ -178,20 +195,22 @@ def runFridaHook(
178
195
) -> FridaResult :
179
196
"""Track calls to the specified method for given seconds.
180
197
181
- :param apkPackageName: the target APK
198
+ :param apkPackageName: the package name of the target APP
182
199
:param targetMethod: the target API
183
200
:param methodParamTypes: string that holds the parameters used by the
184
201
target API
185
- :param secondToWait: seconds to wait for method calls
202
+ :param secondToWait: seconds to wait for method calls, defaults to 10
186
203
:return: FridaResult instance
187
204
"""
188
- device , frida , appProcess = _setupFrida (apkPackageName )
205
+ device , frida , appProcess = _spawnApp (apkPackageName )
189
206
dispatcher = _injectAgent (frida )
190
207
191
- buffer = dispatcher .startWatchingMethodCall (targetMethod , methodParamTypes )
208
+ eventBuffer = dispatcher .startWatchingMethodCall (
209
+ targetMethod , methodParamTypes
210
+ )
192
211
device .resume (appProcess )
193
212
194
213
sleep (secondToWait )
195
214
dispatcher .stopWatchingMethodCall (targetMethod , methodParamTypes )
196
215
197
- return FridaResult (buffer )
216
+ return FridaResult (eventBuffer )
0 commit comments