moabile 1.1.1__tar.gz

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.
moabile-1.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Francesco Berti
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
moabile-1.1.1/PKG-INFO ADDED
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.4
2
+ Name: moabile
3
+ Version: 1.1.1
4
+ Summary: Mother of All Mobile — TUI for Android and iOS mobile app security assessment
5
+ Author-email: Francesco Berti <berti.francesco@proton.me>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/bertifrancesco/MOABile
8
+ Project-URL: Documentation, https://github.com/bertifrancesco/MOABile#readme
9
+ Project-URL: Repository, https://github.com/bertifrancesco/MOABile
10
+ Project-URL: Issues, https://github.com/bertifrancesco/MOABile/issues
11
+ Keywords: frida,android,ios,mobile-security,pentesting,tui,terminal,textual
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: textual>=6.2
27
+ Requires-Dist: pyte
28
+ Dynamic: license-file
29
+
30
+ # MOABile — mother of all mobile
31
+
32
+ [![PyPI](https://img.shields.io/pypi/v/moabile.svg)](https://pypi.org/project/moabile/)
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
34
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
35
+ [![Platform](https://img.shields.io/badge/platform-Android%20%7C%20iOS-brightgreen.svg)](#)
36
+ [![Tested on: Kali Linux](https://img.shields.io/badge/tested%20on-Kali%20Linux-557C94.svg?logo=kalilinux&logoColor=white)](#)
37
+ [![Coverage](https://img.shields.io/badge/coverage-97%25-success.svg)](#)
38
+
39
+ A multi-device terminal UI for mobile app testing.
40
+ Android over `adb`, jailbroken iOS over usbmux and ssh, both at the same time,
41
+ each attached device in its own panel.
42
+
43
+ ![MOABile Multi-Device Interface](assets/screenshot_devices.svg)
44
+
45
+ <p align="center">
46
+ <img src="assets/screenshot_splash.svg" width="49%" alt="MOABile Splashscreen" />
47
+ <img src="assets/screenshot_filemanager.svg" width="49%" alt="Dual-Pane File Manager" />
48
+ </p>
49
+
50
+ It does not reimplement the toolchain: it drives `adb`, `scrcpy`,
51
+ libimobiledevice, `iproxy`, `ioscpy`, `frida`, `objection`, `curl` and `xz`,
52
+ which have to be on `PATH` already. The startup screen reports what is missing
53
+ and which of the two device families that leaves usable — an Android-only
54
+ machine never needs libimobiledevice installed to get past it.
55
+
56
+ An iPhone is reached with libimobiledevice for everything that needs no
57
+ cooperation from the phone (device info, syslog, installing an ipa) and with ssh
58
+ down an `iproxy` tunnel for a shell, the filesystem and frida-server. The ssh
59
+ password is asked for once and kept in memory. No key is ever installed on the
60
+ phone: that would be a file of ours left behind on someone else's device.
61
+
62
+ Nothing is assumed to be installed on the phone either. Jailbreaks ship
63
+ different halves of a userland, so where a tool the panel asks for is not there
64
+ it says so once and falls back — the address row reads `usb` for a phone on the
65
+ end of a cable with nothing on the network, because that is what there is to
66
+ say: usbmux carries no address, and lockdownd hands out the wifi MAC and never
67
+ the lease. What the phone *does* have is found, though: every command carries
68
+ the `PATH` a non-interactive ssh leaves out — `/usr/sbin`, and everything a
69
+ rootless jailbreak keeps under `/var/jb` — inside `sudo` as well as outside it,
70
+ so `grep` and `open` are not reported missing on a phone that has them.
71
+
72
+ ## Installation & Run
73
+
74
+ ### Recommended: `pipx` (Isolated CLI)
75
+
76
+ The easiest and cleanest way to run MOABile without dependency conflicts or `externally-managed-environment` errors:
77
+
78
+ ```bash
79
+ # Install globally in an isolated environment
80
+ pipx install moabile
81
+
82
+ # Run
83
+ moabile
84
+ ```
85
+
86
+ Or run it directly on the fly without permanent installation:
87
+
88
+ ```bash
89
+ pipx run moabile
90
+ ```
91
+
92
+ ### Via `pip`
93
+
94
+ ```bash
95
+ pip install moabile
96
+ moabile
97
+ ```
98
+
99
+ ### From Source
100
+
101
+ Clone the repository and install requirements:
102
+
103
+ ```bash
104
+ pip install -r requirements.txt
105
+ python3 moabile.py
106
+ ```
107
+
108
+ On distributions that manage their own Python (`error: externally-managed-environment`), use a virtualenv:
109
+
110
+ ```bash
111
+ python3 -m venv .venv && . .venv/bin/activate
112
+ pip install -r requirements.txt
113
+ python3 moabile.py
114
+ ```
115
+
116
+ Python 3.10 or newer, and Textual 6.2 or newer — the floor `requirements.txt`
117
+ names, and the oldest release the suite passes on. Linux and macOS: it needs a
118
+ real pty, so it does not run on Windows outside WSL.
119
+
120
+ Tested and fully verified on **Kali Linux** (`x86_64`).
121
+
122
+ No arguments and no options — `--help` says as much as there is to say, and
123
+ everything else is a key inside.
124
+
125
+ ## Tools it drives
126
+
127
+ The startup screen checks for these and reports each one's version. Nothing here
128
+ is installed for you — which package manager your machine has, and what it calls
129
+ a package, is your business.
130
+
131
+ | Tool | For | Family | From |
132
+ |---|---|---|---|
133
+ | `frida` | instrumentation, and its version | both | frida-tools |
134
+ | `objection` | exploration REPL | both | |
135
+ | `curl` | fetch frida-server and codeshare | both | |
136
+ | `xz` | unpack frida-server | both | XZ Utils |
137
+ | `adb` | device control | android | android platform-tools |
138
+ | `scrcpy` | screen mirroring | android | |
139
+ | `idevice_id` | device discovery, info and syslog | ios | libimobiledevice |
140
+ | `ideviceinstaller` | ipa install and app list | ios | |
141
+ | `iproxy` | ssh tunnel over usb | ios | libusbmuxd |
142
+ | `ssh` | shell, filesystem and frida-server | ios | OpenSSH |
143
+ | `ioscpy` | screen mirroring | ios | [lautarovculic/ioscpy](https://github.com/lautarovculic/ioscpy) |
144
+
145
+ Either family works on its own. Both missing, or a core tool missing, and the
146
+ gate does not let you through — there would be nothing past it to do.
147
+
148
+ ## Keys
149
+
150
+ | | | | |
151
+ |---|---|---|---|
152
+ | `r` | **r**escan for devices | `i` | device **i**nfo dump |
153
+ | `b` | the side**b**ar, on and off | `u` | ssh **u**ser for this device |
154
+ | `f` | **f**rida-server, on and off | `p` | **p**urge frida-server off the device |
155
+ | `s` | **s**pawn the app under frida, or attach | `k` | clear this panel's log |
156
+ | `o` | explore the app with **o**bjection | `/` | filter log stream by keyword |
157
+ | `w` | mirror the screen in a **w**indow | `c` | **c**opy log / text viewer modal |
158
+ | `t` | **t**erminal on the device | `v` | save an s**v**g of the interface |
159
+ | `l` | stream the device **l**og | `m` | dark/light **m**ode |
160
+ | `d` | files: browse host ↔ device | `h` | **h**elp: keys and widgets |
161
+ | `a` | **a**dd an app: install an apk or ipa | `alt+c` | **c**opy terminal session / viewer |
162
+ | `e` | **e**xport the app's apk/ipa | `f8` | return focus from tool pane |
163
+ | `q`, `ctrl+q` | **q**uit | | |
164
+
165
+ `s` spawns the app under frida, which is what a script that has to be in
166
+ place before the app starts needs. Where the app is already running it offers
167
+ to attach to it instead — the app keeps whatever state it is in, and a script
168
+ on the running process sees what the device log does not carry: the unified
169
+ log's debug and info entries never reach `idevicesyslog`. Enter and escape keep
170
+ the spawn. `f` toggles frida-server, offering to match the host client, keep
171
+ what is installed, or install a specific custom version.
172
+
173
+ An app that is off screen is suspended on iOS, and attaching to a suspended
174
+ process is a prompt that never arrives — so `s` and `o` bring the app to the
175
+ front first, with `open` on the phone. A jailbreak that has no `open` is asked
176
+ to do it by hand rather than left looking stuck, and `o` says so at once
177
+ instead of watching a process table that is not going to change. Android needs
178
+ none of this: a process there runs whether it is on screen or not.
179
+
180
+ The device log, `l`, is pinned to the app's pid rather than its name: `logcat`
181
+ is asked for `--pid`, and on iOS `idevicesyslog` has no pid filter at all — its
182
+ `-p` matches process *names*, and a process merely named something similar
183
+ comes with it — so the pid is applied here, on the bracket every syslog line
184
+ carries after the process name. Which is why the whole-device-or-one-app
185
+ question comes up only while the app is running: with no pid there is no
186
+ filter to be had, so the stream is the whole device and the panel says why.
187
+ `/` filters the active stream in real time by keyword, and `c` opens the
188
+ accumulated log in a selectable viewer modal with native clipboard copy.
189
+
190
+ Inside the file browser (`d`): `p` push host → device, `l` pull device → host, `a`
191
+ jumps to the app's own data directory and `h` back to where the device side
192
+ opened (`/sdcard` or `/var/mobile`), `n` rename, `d` delete, `←`/`→` switch
193
+ side, `backspace` up, `r` reload, `esc` close, and `enter` opens a directory or
194
+ transfers the file under the cursor.
195
+
196
+ Every panel keeps its own selected app and frida arguments, so multiple devices
197
+ can be worked in parallel without crossing over. The sidebar highlights the active
198
+ device at the top, and lists its installed packages at the bottom.
199
+
200
+ ## Nothing is left behind
201
+
202
+ Not a design goal that happened to fall out — the point. Nothing is written to
203
+ disk between runs: no config, no history, no selected app, no ssh account.
204
+ What you were looking at is a record of the work, and this is a tool for leaving
205
+ none of that. The single exception is the frida-server download, cached one
206
+ version deep where caches go.
207
+
208
+ While an iOS panel is open, ssh's multiplexing socket lives in the temporary
209
+ directory — an empty file holding no data of yours, unlinked when the panel
210
+ closes. A crash leaves it there, and the next run clears the one it finds.
211
+
212
+ ## Tests
213
+
214
+ Headless, driven by fake tools on `PATH`, no device required:
215
+
216
+ ```bash
217
+ python3 test_moabile.py
218
+ ```
219
+
220
+ It prints a `PASS` line per check and `all good` at the end. Run it as a script,
221
+ not under pytest: the module executes the suite on import. One copy at a time —
222
+ it opens real local ports for the usb tunnel, so two runs at once collide.
223
+
224
+ Lint:
225
+
226
+ ```bash
227
+ ruff check .
228
+ ```
229
+
230
+ ## Scope
231
+
232
+ A testing tool for devices you own or are authorised to test. It talks to
233
+ whatever is plugged in over the phone's own debug interfaces — that is the job,
234
+ and it is yours to have permission for.
235
+
236
+ ## License
237
+
238
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,209 @@
1
+ # MOABile — mother of all mobile
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/moabile.svg)](https://pypi.org/project/moabile/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
6
+ [![Platform](https://img.shields.io/badge/platform-Android%20%7C%20iOS-brightgreen.svg)](#)
7
+ [![Tested on: Kali Linux](https://img.shields.io/badge/tested%20on-Kali%20Linux-557C94.svg?logo=kalilinux&logoColor=white)](#)
8
+ [![Coverage](https://img.shields.io/badge/coverage-97%25-success.svg)](#)
9
+
10
+ A multi-device terminal UI for mobile app testing.
11
+ Android over `adb`, jailbroken iOS over usbmux and ssh, both at the same time,
12
+ each attached device in its own panel.
13
+
14
+ ![MOABile Multi-Device Interface](assets/screenshot_devices.svg)
15
+
16
+ <p align="center">
17
+ <img src="assets/screenshot_splash.svg" width="49%" alt="MOABile Splashscreen" />
18
+ <img src="assets/screenshot_filemanager.svg" width="49%" alt="Dual-Pane File Manager" />
19
+ </p>
20
+
21
+ It does not reimplement the toolchain: it drives `adb`, `scrcpy`,
22
+ libimobiledevice, `iproxy`, `ioscpy`, `frida`, `objection`, `curl` and `xz`,
23
+ which have to be on `PATH` already. The startup screen reports what is missing
24
+ and which of the two device families that leaves usable — an Android-only
25
+ machine never needs libimobiledevice installed to get past it.
26
+
27
+ An iPhone is reached with libimobiledevice for everything that needs no
28
+ cooperation from the phone (device info, syslog, installing an ipa) and with ssh
29
+ down an `iproxy` tunnel for a shell, the filesystem and frida-server. The ssh
30
+ password is asked for once and kept in memory. No key is ever installed on the
31
+ phone: that would be a file of ours left behind on someone else's device.
32
+
33
+ Nothing is assumed to be installed on the phone either. Jailbreaks ship
34
+ different halves of a userland, so where a tool the panel asks for is not there
35
+ it says so once and falls back — the address row reads `usb` for a phone on the
36
+ end of a cable with nothing on the network, because that is what there is to
37
+ say: usbmux carries no address, and lockdownd hands out the wifi MAC and never
38
+ the lease. What the phone *does* have is found, though: every command carries
39
+ the `PATH` a non-interactive ssh leaves out — `/usr/sbin`, and everything a
40
+ rootless jailbreak keeps under `/var/jb` — inside `sudo` as well as outside it,
41
+ so `grep` and `open` are not reported missing on a phone that has them.
42
+
43
+ ## Installation & Run
44
+
45
+ ### Recommended: `pipx` (Isolated CLI)
46
+
47
+ The easiest and cleanest way to run MOABile without dependency conflicts or `externally-managed-environment` errors:
48
+
49
+ ```bash
50
+ # Install globally in an isolated environment
51
+ pipx install moabile
52
+
53
+ # Run
54
+ moabile
55
+ ```
56
+
57
+ Or run it directly on the fly without permanent installation:
58
+
59
+ ```bash
60
+ pipx run moabile
61
+ ```
62
+
63
+ ### Via `pip`
64
+
65
+ ```bash
66
+ pip install moabile
67
+ moabile
68
+ ```
69
+
70
+ ### From Source
71
+
72
+ Clone the repository and install requirements:
73
+
74
+ ```bash
75
+ pip install -r requirements.txt
76
+ python3 moabile.py
77
+ ```
78
+
79
+ On distributions that manage their own Python (`error: externally-managed-environment`), use a virtualenv:
80
+
81
+ ```bash
82
+ python3 -m venv .venv && . .venv/bin/activate
83
+ pip install -r requirements.txt
84
+ python3 moabile.py
85
+ ```
86
+
87
+ Python 3.10 or newer, and Textual 6.2 or newer — the floor `requirements.txt`
88
+ names, and the oldest release the suite passes on. Linux and macOS: it needs a
89
+ real pty, so it does not run on Windows outside WSL.
90
+
91
+ Tested and fully verified on **Kali Linux** (`x86_64`).
92
+
93
+ No arguments and no options — `--help` says as much as there is to say, and
94
+ everything else is a key inside.
95
+
96
+ ## Tools it drives
97
+
98
+ The startup screen checks for these and reports each one's version. Nothing here
99
+ is installed for you — which package manager your machine has, and what it calls
100
+ a package, is your business.
101
+
102
+ | Tool | For | Family | From |
103
+ |---|---|---|---|
104
+ | `frida` | instrumentation, and its version | both | frida-tools |
105
+ | `objection` | exploration REPL | both | |
106
+ | `curl` | fetch frida-server and codeshare | both | |
107
+ | `xz` | unpack frida-server | both | XZ Utils |
108
+ | `adb` | device control | android | android platform-tools |
109
+ | `scrcpy` | screen mirroring | android | |
110
+ | `idevice_id` | device discovery, info and syslog | ios | libimobiledevice |
111
+ | `ideviceinstaller` | ipa install and app list | ios | |
112
+ | `iproxy` | ssh tunnel over usb | ios | libusbmuxd |
113
+ | `ssh` | shell, filesystem and frida-server | ios | OpenSSH |
114
+ | `ioscpy` | screen mirroring | ios | [lautarovculic/ioscpy](https://github.com/lautarovculic/ioscpy) |
115
+
116
+ Either family works on its own. Both missing, or a core tool missing, and the
117
+ gate does not let you through — there would be nothing past it to do.
118
+
119
+ ## Keys
120
+
121
+ | | | | |
122
+ |---|---|---|---|
123
+ | `r` | **r**escan for devices | `i` | device **i**nfo dump |
124
+ | `b` | the side**b**ar, on and off | `u` | ssh **u**ser for this device |
125
+ | `f` | **f**rida-server, on and off | `p` | **p**urge frida-server off the device |
126
+ | `s` | **s**pawn the app under frida, or attach | `k` | clear this panel's log |
127
+ | `o` | explore the app with **o**bjection | `/` | filter log stream by keyword |
128
+ | `w` | mirror the screen in a **w**indow | `c` | **c**opy log / text viewer modal |
129
+ | `t` | **t**erminal on the device | `v` | save an s**v**g of the interface |
130
+ | `l` | stream the device **l**og | `m` | dark/light **m**ode |
131
+ | `d` | files: browse host ↔ device | `h` | **h**elp: keys and widgets |
132
+ | `a` | **a**dd an app: install an apk or ipa | `alt+c` | **c**opy terminal session / viewer |
133
+ | `e` | **e**xport the app's apk/ipa | `f8` | return focus from tool pane |
134
+ | `q`, `ctrl+q` | **q**uit | | |
135
+
136
+ `s` spawns the app under frida, which is what a script that has to be in
137
+ place before the app starts needs. Where the app is already running it offers
138
+ to attach to it instead — the app keeps whatever state it is in, and a script
139
+ on the running process sees what the device log does not carry: the unified
140
+ log's debug and info entries never reach `idevicesyslog`. Enter and escape keep
141
+ the spawn. `f` toggles frida-server, offering to match the host client, keep
142
+ what is installed, or install a specific custom version.
143
+
144
+ An app that is off screen is suspended on iOS, and attaching to a suspended
145
+ process is a prompt that never arrives — so `s` and `o` bring the app to the
146
+ front first, with `open` on the phone. A jailbreak that has no `open` is asked
147
+ to do it by hand rather than left looking stuck, and `o` says so at once
148
+ instead of watching a process table that is not going to change. Android needs
149
+ none of this: a process there runs whether it is on screen or not.
150
+
151
+ The device log, `l`, is pinned to the app's pid rather than its name: `logcat`
152
+ is asked for `--pid`, and on iOS `idevicesyslog` has no pid filter at all — its
153
+ `-p` matches process *names*, and a process merely named something similar
154
+ comes with it — so the pid is applied here, on the bracket every syslog line
155
+ carries after the process name. Which is why the whole-device-or-one-app
156
+ question comes up only while the app is running: with no pid there is no
157
+ filter to be had, so the stream is the whole device and the panel says why.
158
+ `/` filters the active stream in real time by keyword, and `c` opens the
159
+ accumulated log in a selectable viewer modal with native clipboard copy.
160
+
161
+ Inside the file browser (`d`): `p` push host → device, `l` pull device → host, `a`
162
+ jumps to the app's own data directory and `h` back to where the device side
163
+ opened (`/sdcard` or `/var/mobile`), `n` rename, `d` delete, `←`/`→` switch
164
+ side, `backspace` up, `r` reload, `esc` close, and `enter` opens a directory or
165
+ transfers the file under the cursor.
166
+
167
+ Every panel keeps its own selected app and frida arguments, so multiple devices
168
+ can be worked in parallel without crossing over. The sidebar highlights the active
169
+ device at the top, and lists its installed packages at the bottom.
170
+
171
+ ## Nothing is left behind
172
+
173
+ Not a design goal that happened to fall out — the point. Nothing is written to
174
+ disk between runs: no config, no history, no selected app, no ssh account.
175
+ What you were looking at is a record of the work, and this is a tool for leaving
176
+ none of that. The single exception is the frida-server download, cached one
177
+ version deep where caches go.
178
+
179
+ While an iOS panel is open, ssh's multiplexing socket lives in the temporary
180
+ directory — an empty file holding no data of yours, unlinked when the panel
181
+ closes. A crash leaves it there, and the next run clears the one it finds.
182
+
183
+ ## Tests
184
+
185
+ Headless, driven by fake tools on `PATH`, no device required:
186
+
187
+ ```bash
188
+ python3 test_moabile.py
189
+ ```
190
+
191
+ It prints a `PASS` line per check and `all good` at the end. Run it as a script,
192
+ not under pytest: the module executes the suite on import. One copy at a time —
193
+ it opens real local ports for the usb tunnel, so two runs at once collide.
194
+
195
+ Lint:
196
+
197
+ ```bash
198
+ ruff check .
199
+ ```
200
+
201
+ ## Scope
202
+
203
+ A testing tool for devices you own or are authorised to test. It talks to
204
+ whatever is plugged in over the phone's own debug interfaces — that is the job,
205
+ and it is yours to have permission for.
206
+
207
+ ## License
208
+
209
+ MIT — see [LICENSE](LICENSE).