mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-24 18:30:55 +02:00
Merge branch 'main' into docs/recommend-pymobiledevice3
This commit is contained in:
@@ -34,6 +34,7 @@ jobs:
|
|||||||
publish:
|
publish:
|
||||||
if: github.ref_type == 'tag'
|
if: github.ref_type == 'tag'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
environment: pypi # only tag refs may deploy; the PyPI trusted publisher requires it
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # PyPI trusted publishing
|
id-token: write # PyPI trusted publishing
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
prune tests
|
||||||
|
prune docs
|
||||||
|
prune .github
|
||||||
|
exclude uv.lock Dockerfile* mkdocs.yml .readthedocs.yaml .safety-policy.yml .python-version .gitignore Makefile
|
||||||
+1
-3
@@ -24,10 +24,8 @@ dependencies = [
|
|||||||
"simplejson==4.1.1",
|
"simplejson==4.1.1",
|
||||||
"packaging==26.3",
|
"packaging==26.3",
|
||||||
"appdirs==1.4.4",
|
"appdirs==1.4.4",
|
||||||
"iphone_backup_decrypt==0.9.0",
|
"iphone_backup_decrypt==0.10.0",
|
||||||
"pycryptodome>=3.20.0",
|
"pycryptodome>=3.20.0",
|
||||||
"adb-shell[usb]==0.4.4",
|
|
||||||
"libusb1==3.4.0",
|
|
||||||
"cryptography==50.0.0",
|
"cryptography==50.0.0",
|
||||||
"PyYAML>=6.0.2",
|
"PyYAML>=6.0.2",
|
||||||
"pyahocorasick==2.3.1",
|
"pyahocorasick==2.3.1",
|
||||||
|
|||||||
@@ -136,6 +136,10 @@ class Mounts(AndroidArtifact):
|
|||||||
mount_options = fields[5].split(",")
|
mount_options = fields[5].split(",")
|
||||||
super_options = fields[separator + 3].split(",")
|
super_options = fields[separator + 3].split(",")
|
||||||
options = list(dict.fromkeys(mount_options + super_options))
|
options = list(dict.fromkeys(mount_options + super_options))
|
||||||
|
# fields[5] are the per-mount (VFS) flags, the field after the
|
||||||
|
# separator the superblock's; a mount is writable only if both
|
||||||
|
# allow it. The merged list made every read-only overlay a HIGH.
|
||||||
|
is_read_write = "rw" in mount_options and "rw" in super_options
|
||||||
mount_point = fields[4].replace("\\040", " ")
|
mount_point = fields[4].replace("\\040", " ")
|
||||||
device = fields[separator + 2].replace("\\040", " ")
|
device = fields[separator + 2].replace("\\040", " ")
|
||||||
filesystem_type = fields[separator + 1]
|
filesystem_type = fields[separator + 1]
|
||||||
@@ -156,7 +160,7 @@ class Mounts(AndroidArtifact):
|
|||||||
"options_list": options,
|
"options_list": options,
|
||||||
"optional_fields": fields[6:separator],
|
"optional_fields": fields[6:separator],
|
||||||
"is_system_partition": is_system,
|
"is_system_partition": is_system,
|
||||||
"is_read_write": "rw" in options,
|
"is_read_write": is_read_write,
|
||||||
"process_ids": [process_id],
|
"process_ids": [process_id],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -191,7 +195,14 @@ class Mounts(AndroidArtifact):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Check for other suspicious mount options
|
# Check for other suspicious mount options
|
||||||
suspicious_opts = [opt for opt in options if opt in SUSPICIOUS_OPTIONS]
|
# `rw` sitting in the merged option list is not evidence of
|
||||||
|
# writability (see is_read_write in parse_mountinfo); every other
|
||||||
|
# suspicious option is meaningful in either list.
|
||||||
|
suspicious_opts = [
|
||||||
|
opt
|
||||||
|
for opt in options
|
||||||
|
if opt in SUSPICIOUS_OPTIONS and (opt != "rw" or mount["is_read_write"])
|
||||||
|
]
|
||||||
if suspicious_opts and mount["is_system_partition"]:
|
if suspicious_opts and mount["is_system_partition"]:
|
||||||
if (
|
if (
|
||||||
"noatime" in mount["mount_options"]
|
"noatime" in mount["mount_options"]
|
||||||
|
|||||||
@@ -1275,5 +1275,9 @@
|
|||||||
{
|
{
|
||||||
"version": "26.6.2",
|
"version": "26.6.2",
|
||||||
"build": "23G90"
|
"build": "23G90"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "27.0",
|
||||||
|
"build": "24A437"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -52,7 +52,7 @@ class MVTEncryptedBackup(EncryptedBackup):
|
|||||||
|
|
||||||
NOTE: This subclass relies on internal APIs of iphone_backup_decrypt
|
NOTE: This subclass relies on internal APIs of iphone_backup_decrypt
|
||||||
(specifically _read_and_unlock_keybag, _keybag, and the Keybag class
|
(specifically _read_and_unlock_keybag, _keybag, and the Keybag class
|
||||||
internals). Pinned to iphone_backup_decrypt==0.9.0.
|
internals). Pinned to iphone_backup_decrypt==0.10.0.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *, backup_directory, passphrase=None, derived_key=None):
|
def __init__(self, *, backup_directory, passphrase=None, derived_key=None):
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2026 The MVT Authors.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
"""A mount is writable only if both mountinfo option layers allow it."""
|
||||||
|
|
||||||
|
from mvt.android.artifacts.mounts import Mounts
|
||||||
|
from mvt.common.alerts import AlertLevel
|
||||||
|
|
||||||
|
# fields[5] is the per-mount (VFS) layer, the field after "-" the superblock.
|
||||||
|
RO_OVERLAY = (
|
||||||
|
"304 166 0:130 / /product/usr rw,relatime shared:63 - overlay overlay "
|
||||||
|
"ro,seclabel,lowerdir=/mnt/vendor/ext/product/usr:/product/usr"
|
||||||
|
)
|
||||||
|
RW_SYSTEM = (
|
||||||
|
"305 166 0:131 / /system rw,relatime shared:64 - ext4 /dev/block/dm-1 "
|
||||||
|
"rw,seclabel,errors=panic"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(line):
|
||||||
|
mounts = Mounts()
|
||||||
|
mounts.results = Mounts.parse_mountinfo(line, 1)
|
||||||
|
mounts.check_indicators()
|
||||||
|
return mounts
|
||||||
|
|
||||||
|
|
||||||
|
class TestMountsReadWriteLayers:
|
||||||
|
def test_rw_vfs_over_ro_superblock_is_not_writable(self):
|
||||||
|
mounts = _run(RO_OVERLAY)
|
||||||
|
assert mounts.results[0]["is_read_write"] is False
|
||||||
|
assert mounts.alertstore.count(AlertLevel.HIGH) == 0
|
||||||
|
assert mounts.alertstore.count(AlertLevel.MEDIUM) == 0
|
||||||
|
|
||||||
|
def test_rw_in_both_layers_still_alerts(self):
|
||||||
|
mounts = _run(RW_SYSTEM)
|
||||||
|
assert mounts.results[0]["is_read_write"] is True
|
||||||
|
assert mounts.alertstore.count(AlertLevel.HIGH) == 1
|
||||||
|
|
||||||
|
def test_both_option_layers_are_still_reported(self):
|
||||||
|
mounts = _run(RO_OVERLAY)
|
||||||
|
options = mounts.results[0]["options_list"]
|
||||||
|
assert "rw" in options and "ro" in options
|
||||||
@@ -6,22 +6,6 @@ resolution-markers = [
|
|||||||
"python_full_version < '3.15'",
|
"python_full_version < '3.15'",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adb-shell"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "cryptography" },
|
|
||||||
{ name = "pyasn1" },
|
|
||||||
{ name = "rsa" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/8f/73/d246034db6f3e374dad9a35ee3f61345a6b239d4febd2a41ab69df9936fe/adb_shell-0.4.4.tar.gz", hash = "sha256:04c305f30a2ca25d5c54b3cd6ce9bb64c36e5f07967b23b3fb6aaecc851b90b6", size = 61822, upload-time = "2023-09-01T03:48:40.348Z" }
|
|
||||||
|
|
||||||
[package.optional-dependencies]
|
|
||||||
usb = [
|
|
||||||
{ name = "libusb1" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -625,14 +609,14 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iphone-backup-decrypt"
|
name = "iphone-backup-decrypt"
|
||||||
version = "0.9.0"
|
version = "0.10.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pycryptodome" },
|
{ name = "pycryptodome" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/e7/bcdacdec21d628122ba240e7f742ab2175149e58672be63af55ff37a0f28/iphone_backup_decrypt-0.9.0.tar.gz", hash = "sha256:13b18fef3c8e3af627914f8c1a429bbc5555dfb0505239ba49efe99984cc0c96", size = 16125, upload-time = "2024-09-18T15:50:12.179Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/01/b8/a2ec2b10d792403d36bb6661fea6357179c31ece1ed3285c442e636d6335/iphone_backup_decrypt-0.10.0.tar.gz", hash = "sha256:5f2799e58f908cce28d7929dd82231abc8acd57c25b37bce6a2d6a82e018d343", size = 20000, upload-time = "2026-09-17T21:46:44Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/94/64a31be93f72e0a254bde68e4cf7d24aef37a0a985754a197fa1b028a665/iphone_backup_decrypt-0.9.0-py3-none-any.whl", hash = "sha256:55b5adfafac757f58aa6444b83a4cc2c20cdd699c6ff1d2f4b549936a5dad92c", size = 15767, upload-time = "2024-09-18T15:50:10.537Z" },
|
{ url = "https://files.pythonhosted.org/packages/89/10/349b2a720e012921d1457e1d1c2b921b16300a5f3570c4c64d0d3787539f/iphone_backup_decrypt-0.10.0-py3-none-any.whl", hash = "sha256:1ac4345a07b104a3eacab20932b8621cd1e0164e0f03d913e66eed6ea5ee173e", size = 17400, upload-time = "2026-09-17T21:46:42Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -777,17 +761,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/38/a6/800800bfed7b1fb10fc3f3d557785c3854e80d3f7a9800d784b176a1fc2d/librt-0.15.0-cp315-cp315t-win_arm64.whl", hash = "sha256:84d244b00604d17df3fc7736c327892d6bba66181254aa4087be807b6c342bdc", size = 110700, upload-time = "2026-08-07T10:49:15.499Z" },
|
{ url = "https://files.pythonhosted.org/packages/38/a6/800800bfed7b1fb10fc3f3d557785c3854e80d3f7a9800d784b176a1fc2d/librt-0.15.0-cp315-cp315t-win_arm64.whl", hash = "sha256:84d244b00604d17df3fc7736c327892d6bba66181254aa4087be807b6c342bdc", size = 110700, upload-time = "2026-08-07T10:49:15.499Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libusb1"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/89/35/f9d2a990d092d647b47540cd229e1d68432c0f51183484ca189612a4824c/libusb1-3.4.0.tar.gz", hash = "sha256:9cf5638506d54f21bf36550d97ea63189111a23c4d8078f630103a2052135f45", size = 91206, upload-time = "2026-05-16T20:59:19.315Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/64/d4b59444e4d3b6979aa5eb58840634465a24b41a9ab03dcf8434c9b89551/libusb1-3.4.0-py3-none-any.whl", hash = "sha256:e83d034e44c3efe1c4599c6281d34bca50a38c12cab3b7b6217d583161a01ffd", size = 67373, upload-time = "2026-05-16T20:59:13.142Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/55/a838a4278fac4ee49bf670ddc59d621999a1cb2a3188fb13a23609ea4f06/libusb1-3.4.0-py3-none-win32.whl", hash = "sha256:0a1aa1416034690eb9dc9a895eda0fef44d853bca1053eb1de50a5906684846d", size = 129704, upload-time = "2026-05-16T20:59:15.243Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/08/02aecf6dad627534a5835244ece14d7f187ef430354d9b8551199934d059/libusb1-3.4.0-py3-none-win_amd64.whl", hash = "sha256:b7dcc1f324a895af6aac708bc5513a17373f97349cc2ab8a277519c788bd18ca", size = 141212, upload-time = "2026-05-16T20:59:17.286Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown"
|
name = "markdown"
|
||||||
version = "3.10.3"
|
version = "3.10.3"
|
||||||
@@ -1016,13 +989,11 @@ wheels = [
|
|||||||
name = "mvt"
|
name = "mvt"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "adb-shell", extra = ["usb"] },
|
|
||||||
{ name = "appdirs" },
|
{ name = "appdirs" },
|
||||||
{ name = "betterproto2" },
|
{ name = "betterproto2" },
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
{ name = "cryptography" },
|
{ name = "cryptography" },
|
||||||
{ name = "iphone-backup-decrypt" },
|
{ name = "iphone-backup-decrypt" },
|
||||||
{ name = "libusb1" },
|
|
||||||
{ name = "nskeyedunarchiver" },
|
{ name = "nskeyedunarchiver" },
|
||||||
{ name = "packaging" },
|
{ name = "packaging" },
|
||||||
{ name = "pyahocorasick" },
|
{ name = "pyahocorasick" },
|
||||||
@@ -1063,13 +1034,11 @@ docs = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "adb-shell", extras = ["usb"], specifier = "==0.4.4" },
|
|
||||||
{ name = "appdirs", specifier = "==1.4.4" },
|
{ name = "appdirs", specifier = "==1.4.4" },
|
||||||
{ name = "betterproto2", specifier = "==0.10.0" },
|
{ name = "betterproto2", specifier = "==0.10.0" },
|
||||||
{ name = "click", specifier = "==8.4.2" },
|
{ name = "click", specifier = "==8.4.2" },
|
||||||
{ name = "cryptography", specifier = "==50.0.0" },
|
{ name = "cryptography", specifier = "==50.0.0" },
|
||||||
{ name = "iphone-backup-decrypt", specifier = "==0.9.0" },
|
{ name = "iphone-backup-decrypt", specifier = "==0.10.0" },
|
||||||
{ name = "libusb1", specifier = "==3.4.0" },
|
|
||||||
{ name = "nskeyedunarchiver", specifier = "==1.5.2" },
|
{ name = "nskeyedunarchiver", specifier = "==1.5.2" },
|
||||||
{ name = "packaging", specifier = "==26.3" },
|
{ name = "packaging", specifier = "==26.3" },
|
||||||
{ name = "pyahocorasick", specifier = "==2.3.1" },
|
{ name = "pyahocorasick", specifier = "==2.3.1" },
|
||||||
@@ -1274,15 +1243,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c5/96/37c50ac951bb0260ec38d8d12e5b51587ef1ef4035c279088f2771544b28/pyahocorasick-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:4acb11a0a2ff10519465749d22ad70789e9fe7f81dc8fe9957a8868e499e18ab", size = 35987, upload-time = "2026-04-27T16:32:07.08Z" },
|
{ url = "https://files.pythonhosted.org/packages/c5/96/37c50ac951bb0260ec38d8d12e5b51587ef1ef4035c279088f2771544b28/pyahocorasick-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:4acb11a0a2ff10519465749d22ad70789e9fe7f81dc8fe9957a8868e499e18ab", size = 35987, upload-time = "2026-04-27T16:32:07.08Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyasn1"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a4/9a/23310166d960def5897e91fe20e5b724601b02a22e84ba1f94232c0b7f67/pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81", size = 151262, upload-time = "2026-07-09T01:12:33.988Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b", size = 84410, upload-time = "2026-07-09T01:12:32.92Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pycparser"
|
name = "pycparser"
|
||||||
version = "3.0"
|
version = "3.0"
|
||||||
@@ -1684,18 +1644,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rsa"
|
|
||||||
version = "4.9.1"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "pyasn1" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.16.2"
|
version = "0.16.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user