AndroidFridaManager 1.9.5__py3-none-any.whl → 1.9.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- AndroidFridaManager/about.py +1 -1
- AndroidFridaManager/job.py +96 -18
- {androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/METADATA +2 -2
- androidfridamanager-1.9.6.dist-info/RECORD +11 -0
- androidfridamanager-1.9.5.dist-info/RECORD +0 -11
- {androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/WHEEL +0 -0
- {androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/entry_points.txt +0 -0
- {androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/licenses/LICENSE +0 -0
- {androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/top_level.txt +0 -0
AndroidFridaManager/about.py
CHANGED
AndroidFridaManager/job.py
CHANGED
|
@@ -32,7 +32,7 @@ class Job:
|
|
|
32
32
|
display_name: Human-readable name for UI display.
|
|
33
33
|
hooks_registry: List of methods/functions this job hooks (for conflict detection).
|
|
34
34
|
priority: Job priority (lower = higher priority, default 50).
|
|
35
|
-
state: Current state ("initialized", "running", "stopping").
|
|
35
|
+
state: Current state ("initialized", "running", "stopping", "error", "stopped").
|
|
36
36
|
started_at: Timestamp when job was started (None if not started).
|
|
37
37
|
"""
|
|
38
38
|
|
|
@@ -75,6 +75,50 @@ class Job:
|
|
|
75
75
|
self.priority = priority
|
|
76
76
|
self.started_at: Optional[datetime.datetime] = None
|
|
77
77
|
|
|
78
|
+
# State propagation for callers to wait on job readiness
|
|
79
|
+
self._ready_event = threading.Event()
|
|
80
|
+
self._error_message: Optional[str] = None
|
|
81
|
+
|
|
82
|
+
def _set_state(self, new_state: str, error_msg: Optional[str] = None) -> None:
|
|
83
|
+
"""Set state and signal ready event if terminal state reached.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
new_state: New state value ("initialized", "running", "error", "stopping", "stopped").
|
|
87
|
+
error_msg: Optional error message when transitioning to "error" state.
|
|
88
|
+
"""
|
|
89
|
+
self.state = new_state
|
|
90
|
+
if error_msg:
|
|
91
|
+
self._error_message = error_msg
|
|
92
|
+
# Signal ready event when job reaches a terminal state (running, error, stopped)
|
|
93
|
+
if new_state in ("running", "error", "stopped"):
|
|
94
|
+
self._ready_event.set()
|
|
95
|
+
|
|
96
|
+
def wait_until_ready(self, timeout: float = 10.0) -> bool:
|
|
97
|
+
"""Wait for job to reach running or error state.
|
|
98
|
+
|
|
99
|
+
Blocks until the job thread signals that hooks have been loaded
|
|
100
|
+
successfully (state="running") or an error occurred (state="error").
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
timeout: Maximum seconds to wait (default: 10.0).
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
True if job is running successfully, False if error or timeout.
|
|
107
|
+
"""
|
|
108
|
+
if self._ready_event.wait(timeout=timeout):
|
|
109
|
+
return self.state == "running"
|
|
110
|
+
# Timeout occurred
|
|
111
|
+
self._error_message = f"Timeout waiting for job to start after {timeout}s"
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
def get_error(self) -> Optional[str]:
|
|
115
|
+
"""Get error message if job failed.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Error message string if job is in error state, None otherwise.
|
|
119
|
+
"""
|
|
120
|
+
return self._error_message
|
|
121
|
+
|
|
78
122
|
|
|
79
123
|
def create_job_script(self):
|
|
80
124
|
self.instrument(self.process_session)
|
|
@@ -93,18 +137,39 @@ class Job:
|
|
|
93
137
|
|
|
94
138
|
|
|
95
139
|
def invoke_handle_hooking(self):
|
|
96
|
-
|
|
97
|
-
self.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.stop_event.
|
|
140
|
+
try:
|
|
141
|
+
if self.is_script_created == False:
|
|
142
|
+
self.instrument(self.process_session)
|
|
143
|
+
self.is_script_created = True
|
|
144
|
+
self.script.on("message", self.wrap_custom_hooking_handler_with_job_id(self.custom_hooking_handler))
|
|
145
|
+
self.script.load()
|
|
146
|
+
self._set_state("running")
|
|
147
|
+
self.logger.info("[+] hooks successfully loaded")
|
|
148
|
+
|
|
149
|
+
#if self.is_running_as_thread:
|
|
150
|
+
# Keep the thread alive to handle messages until stop_event is set
|
|
151
|
+
while not self.stop_event.is_set():
|
|
152
|
+
self.stop_event.wait(1) # Sleep for 1 second and check again
|
|
153
|
+
except frida.TransportError as e:
|
|
154
|
+
error_msg = f"TransportError during script load: {e} - target app may have crashed or restarted"
|
|
155
|
+
self._set_state("error", error_msg)
|
|
156
|
+
self.logger.error(f"[-] {error_msg}")
|
|
157
|
+
except frida.InvalidOperationError as e:
|
|
158
|
+
error_msg = f"InvalidOperationError during script load: {e}"
|
|
159
|
+
self._set_state("error", error_msg)
|
|
160
|
+
self.logger.error(f"[-] {error_msg}")
|
|
161
|
+
except frida.ProcessNotFoundError as e:
|
|
162
|
+
error_msg = f"ProcessNotFoundError: Target process no longer exists: {e}"
|
|
163
|
+
self._set_state("error", error_msg)
|
|
164
|
+
self.logger.error(f"[-] {error_msg}")
|
|
165
|
+
except frida.ProtocolError as e:
|
|
166
|
+
error_msg = f"ProtocolError: Connection issue with target: {e}"
|
|
167
|
+
self._set_state("error", error_msg)
|
|
168
|
+
self.logger.error(f"[-] {error_msg}")
|
|
169
|
+
except Exception as e:
|
|
170
|
+
error_msg = f"Unexpected error in hook thread: {type(e).__name__}: {e}"
|
|
171
|
+
self._set_state("error", error_msg)
|
|
172
|
+
self.logger.error(f"[-] {error_msg}")
|
|
108
173
|
|
|
109
174
|
|
|
110
175
|
def wrap_custom_hooking_handler_with_job_id(self, handler):
|
|
@@ -137,6 +202,12 @@ class Job:
|
|
|
137
202
|
def close_job(self, timeout: float = 5.0) -> bool:
|
|
138
203
|
"""Stop the job and cleanup resources.
|
|
139
204
|
|
|
205
|
+
Uses a staged shutdown approach:
|
|
206
|
+
1. Set stop_event FIRST to signal thread to exit wait loop
|
|
207
|
+
2. Wait briefly for thread to notice stop_event
|
|
208
|
+
3. Try to unload script (may hang if connection broken)
|
|
209
|
+
4. Set final stopped state
|
|
210
|
+
|
|
140
211
|
Args:
|
|
141
212
|
timeout: Maximum seconds to wait for thread to stop.
|
|
142
213
|
Default 5.0 seconds. Use 0 for no wait.
|
|
@@ -144,24 +215,31 @@ class Job:
|
|
|
144
215
|
Returns:
|
|
145
216
|
True if job stopped cleanly, False if timed out.
|
|
146
217
|
"""
|
|
147
|
-
self.
|
|
218
|
+
self._set_state("stopping")
|
|
219
|
+
|
|
220
|
+
# Step 1: Signal thread to exit wait loop FIRST
|
|
148
221
|
self.stop_event.set()
|
|
149
222
|
|
|
223
|
+
# Step 2: Wait for thread to notice stop_event (short timeout)
|
|
224
|
+
thread_timeout = min(1.0, timeout) if timeout > 0 else 1.0
|
|
150
225
|
timed_out = False
|
|
151
226
|
if self.thread and self.thread.is_alive():
|
|
152
|
-
self.thread.join(timeout=
|
|
227
|
+
self.thread.join(timeout=thread_timeout)
|
|
153
228
|
if self.thread.is_alive():
|
|
154
229
|
self.logger.warning(
|
|
155
|
-
f"Job {self.job_id} thread did not stop within {
|
|
230
|
+
f"Job {self.job_id} thread did not stop within {thread_timeout}s"
|
|
156
231
|
)
|
|
157
232
|
timed_out = True
|
|
158
233
|
|
|
159
|
-
# Try to unload script
|
|
234
|
+
# Step 3: Try to unload script (may hang if connection broken)
|
|
160
235
|
if self.script:
|
|
161
236
|
try:
|
|
162
237
|
self.script.unload()
|
|
163
238
|
except Exception as e:
|
|
164
|
-
self.logger.warning(f"
|
|
239
|
+
self.logger.warning(f"Script unload failed (connection may be broken): {e}")
|
|
240
|
+
|
|
241
|
+
# Step 4: Set final state
|
|
242
|
+
self._set_state("stopped")
|
|
165
243
|
|
|
166
244
|
status = "timed out" if timed_out else "stopped"
|
|
167
245
|
self.logger.info(f"Job {self.job_id} {status}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AndroidFridaManager
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.6
|
|
4
4
|
Summary: A python API in order to install and run the frida-server on an Android device.
|
|
5
5
|
Home-page: https://github.com/fkie-cad/AndroidFridaManager
|
|
6
6
|
Author: Daniel Baier
|
|
@@ -33,7 +33,7 @@ Dynamic: requires-dist
|
|
|
33
33
|
Dynamic: requires-python
|
|
34
34
|
Dynamic: summary
|
|
35
35
|
|
|
36
|
-
 [](https://badge.fury.io/py/AndroidFridaManager) [](https://github.com/fkie-cad/AndroidFridaManager/actions/workflows/publish-to-pypi.yml)
|
|
37
37
|
|
|
38
38
|
# AndroidFridaManager
|
|
39
39
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
AndroidFridaManager/FridaManager.py,sha256=pTcis4oLPBN5U7CdBqdUufwuG6QQDWTPBleTC7rtTbI,32145
|
|
2
|
+
AndroidFridaManager/__init__.py,sha256=T6AKtrGSLQ9M5bJoWDQcsRTJbSEbksdgrx3AAAdozRI,171
|
|
3
|
+
AndroidFridaManager/about.py,sha256=tytVSs7JHtb8wVUCXH89lg4vd5mn04MrHfzmOgihOUQ,98
|
|
4
|
+
AndroidFridaManager/job.py,sha256=jDDaqiG_ri-vAwwk045X80mzftd8INxh7UIv9YOELDU,10525
|
|
5
|
+
AndroidFridaManager/job_manager.py,sha256=Ce2lHLezRVKuj7r_RodH6Q8l43zL_cL5ZGhE1zGB-E8,27336
|
|
6
|
+
androidfridamanager-1.9.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
7
|
+
androidfridamanager-1.9.6.dist-info/METADATA,sha256=Dmw-7QAphEDeTviAvvTbHllZzksDSnO7lSfdgAF-3Xw,5141
|
|
8
|
+
androidfridamanager-1.9.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
+
androidfridamanager-1.9.6.dist-info/entry_points.txt,sha256=GmNngu2fDNCxUcquFRegBa7GWknPKG1jsM4lvWeyKnY,64
|
|
10
|
+
androidfridamanager-1.9.6.dist-info/top_level.txt,sha256=oH2lVMSRlghmt-_tVrOEUqvY462P9hd5Ktgp5-1qF3o,20
|
|
11
|
+
androidfridamanager-1.9.6.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
AndroidFridaManager/FridaManager.py,sha256=pTcis4oLPBN5U7CdBqdUufwuG6QQDWTPBleTC7rtTbI,32145
|
|
2
|
-
AndroidFridaManager/__init__.py,sha256=T6AKtrGSLQ9M5bJoWDQcsRTJbSEbksdgrx3AAAdozRI,171
|
|
3
|
-
AndroidFridaManager/about.py,sha256=wGo_88YOuzXo2vF1EyCEmIO4uxM7wOJLC-FrGLp__Mw,98
|
|
4
|
-
AndroidFridaManager/job.py,sha256=Yzir0XkkpFj5cFIcMRGJlLnIcIuDVZ9jBLFMqwQKTFA,7041
|
|
5
|
-
AndroidFridaManager/job_manager.py,sha256=Ce2lHLezRVKuj7r_RodH6Q8l43zL_cL5ZGhE1zGB-E8,27336
|
|
6
|
-
androidfridamanager-1.9.5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
7
|
-
androidfridamanager-1.9.5.dist-info/METADATA,sha256=pjOCtO1KPNhyybRz8O5a56LXfeTqnKRcm0P0Kii5kpA,5141
|
|
8
|
-
androidfridamanager-1.9.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
-
androidfridamanager-1.9.5.dist-info/entry_points.txt,sha256=GmNngu2fDNCxUcquFRegBa7GWknPKG1jsM4lvWeyKnY,64
|
|
10
|
-
androidfridamanager-1.9.5.dist-info/top_level.txt,sha256=oH2lVMSRlghmt-_tVrOEUqvY462P9hd5Ktgp5-1qF3o,20
|
|
11
|
-
androidfridamanager-1.9.5.dist-info/RECORD,,
|
|
File without changes
|
{androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{androidfridamanager-1.9.5.dist-info → androidfridamanager-1.9.6.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|