mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-04 17:06:35 +02:00
Merge branch 'main' into fix/alert-timestamps
This commit is contained in:
@@ -32,3 +32,17 @@ docker run -it mvt
|
|||||||
```
|
```
|
||||||
|
|
||||||
If a prompt is spawned successfully, you can close it with `exit`.
|
If a prompt is spawned successfully, you can close it with `exit`.
|
||||||
|
|
||||||
|
## Access an iOS device from Docker
|
||||||
|
|
||||||
|
On the Linux host, install and start [usbmuxd](https://github.com/libimobiledevice/usbmuxd), then connect and unlock the iOS device. The daemon exposes the device through the `/var/run/usbmuxd` socket.
|
||||||
|
|
||||||
|
Bind that socket into the container to let MVT communicate with the device:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it \
|
||||||
|
--mount type=bind,source=/var/run/usbmuxd,target=/var/run/usbmuxd \
|
||||||
|
ghcr.io/mvt-project/mvt
|
||||||
|
```
|
||||||
|
|
||||||
|
If you built the image from source, replace `ghcr.io/mvt-project/mvt` with `mvt`.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# https://license.mvt.re/1.1/
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from mvt.android.utils import ROOT_PACKAGES
|
from mvt.android.utils import ROOT_PACKAGES
|
||||||
from mvt.common.module_types import ModuleAtomicResult, ModuleSerializedResult
|
from mvt.common.module_types import ModuleAtomicResult, ModuleSerializedResult
|
||||||
@@ -74,6 +74,8 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
|||||||
"timestamp": "",
|
"timestamp": "",
|
||||||
"first_install_time": "",
|
"first_install_time": "",
|
||||||
"last_update_time": "",
|
"last_update_time": "",
|
||||||
|
"installer": "",
|
||||||
|
"system": False,
|
||||||
"permissions": list(),
|
"permissions": list(),
|
||||||
"requested_permissions": list(),
|
"requested_permissions": list(),
|
||||||
}
|
}
|
||||||
@@ -81,7 +83,14 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
|||||||
in_runtime_permissions = False
|
in_runtime_permissions = False
|
||||||
in_declared_permissions = False
|
in_declared_permissions = False
|
||||||
in_requested_permissions = True
|
in_requested_permissions = True
|
||||||
|
current_user: Optional[int] = None
|
||||||
|
first_install_times: Dict[Optional[int], str] = {}
|
||||||
|
runtime_permissions: Dict[Optional[int], List[Dict[str, Any]]] = {}
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
|
user_match = re.match(r"User (\d+):", line.strip())
|
||||||
|
if user_match:
|
||||||
|
current_user = int(user_match.group(1))
|
||||||
|
|
||||||
if in_install_permissions:
|
if in_install_permissions:
|
||||||
if line.startswith(" " * 4) and not line.startswith(" " * 6):
|
if line.startswith(" " * 4) and not line.startswith(" " * 6):
|
||||||
in_install_permissions = False
|
in_install_permissions = False
|
||||||
@@ -105,7 +114,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
|||||||
if "granted=" in lineinfo[1]:
|
if "granted=" in lineinfo[1]:
|
||||||
granted = "granted=true" in lineinfo[1]
|
granted = "granted=true" in lineinfo[1]
|
||||||
|
|
||||||
details["permissions"].append(
|
runtime_permissions.setdefault(current_user, []).append(
|
||||||
{"name": permission, "granted": granted, "type": "runtime"}
|
{"name": permission, "granted": granted, "type": "runtime"}
|
||||||
)
|
)
|
||||||
if in_declared_permissions:
|
if in_declared_permissions:
|
||||||
@@ -129,8 +138,12 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
|||||||
details["version_code"] = line.split("=", 1)[1].strip()
|
details["version_code"] = line.split("=", 1)[1].strip()
|
||||||
elif line.strip().startswith("timeStamp="):
|
elif line.strip().startswith("timeStamp="):
|
||||||
details["timestamp"] = line.split("=")[1].strip()
|
details["timestamp"] = line.split("=")[1].strip()
|
||||||
|
elif line.strip().startswith("installerPackageName="):
|
||||||
|
details["installer"] = line.split("=", 1)[1].strip()
|
||||||
|
elif line.strip().startswith("pkgFlags="):
|
||||||
|
details["system"] = "SYSTEM" in line.split("=", 1)[1].split()
|
||||||
elif line.strip().startswith("firstInstallTime="):
|
elif line.strip().startswith("firstInstallTime="):
|
||||||
details["first_install_time"] = line.split("=")[1].strip()
|
first_install_times[current_user] = line.split("=", 1)[1].strip()
|
||||||
elif line.strip().startswith("lastUpdateTime="):
|
elif line.strip().startswith("lastUpdateTime="):
|
||||||
details["last_update_time"] = line.split("=")[1].strip()
|
details["last_update_time"] = line.split("=")[1].strip()
|
||||||
elif line.strip() == "install permissions:":
|
elif line.strip() == "install permissions:":
|
||||||
@@ -142,6 +155,19 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
|||||||
elif line.strip() == "requested permissions:":
|
elif line.strip() == "requested permissions:":
|
||||||
in_requested_permissions = True
|
in_requested_permissions = True
|
||||||
|
|
||||||
|
if 0 in first_install_times:
|
||||||
|
details["first_install_time"] = first_install_times[0]
|
||||||
|
elif None in first_install_times:
|
||||||
|
details["first_install_time"] = first_install_times[None]
|
||||||
|
elif first_install_times:
|
||||||
|
details["first_install_time"] = next(iter(first_install_times.values()))
|
||||||
|
|
||||||
|
if 0 in runtime_permissions:
|
||||||
|
details["permissions"].extend(runtime_permissions[0])
|
||||||
|
elif None in runtime_permissions:
|
||||||
|
details["permissions"].extend(runtime_permissions[None])
|
||||||
|
elif runtime_permissions:
|
||||||
|
details["permissions"].extend(next(iter(runtime_permissions.values())))
|
||||||
return details
|
return details
|
||||||
|
|
||||||
def parse_dumpsys_packages(self, output: str) -> List[Dict[str, Any]]:
|
def parse_dumpsys_packages(self, output: str) -> List[Dict[str, Any]]:
|
||||||
|
|||||||
@@ -25,6 +25,25 @@ class TestDumpsysPackagesArtifact:
|
|||||||
== "com.samsung.android.provider.filterprovider"
|
== "com.samsung.android.provider.filterprovider"
|
||||||
)
|
)
|
||||||
assert dpa.results[0]["version_name"] == "5.0.07"
|
assert dpa.results[0]["version_name"] == "5.0.07"
|
||||||
|
assert dpa.results[0]["first_install_time"] == "2008-12-31 16:00:00"
|
||||||
|
assert dpa.results[0]["system"] is True
|
||||||
|
|
||||||
|
def test_parsing_system_flag(self):
|
||||||
|
system_details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
|
||||||
|
" pkgFlags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ]"
|
||||||
|
)
|
||||||
|
third_party_details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
|
||||||
|
" pkgFlags=[ HAS_CODE ALLOW_BACKUP ]"
|
||||||
|
)
|
||||||
|
missing_flag_details = (
|
||||||
|
DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
|
||||||
|
" versionName=1.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert system_details["system"] is True
|
||||||
|
assert third_party_details["system"] is False
|
||||||
|
assert missing_flag_details["system"] is False
|
||||||
|
|
||||||
def test_ioc_check(self, indicator_file):
|
def test_ioc_check(self, indicator_file):
|
||||||
dpa = DumpsysPackagesArtifact()
|
dpa = DumpsysPackagesArtifact()
|
||||||
@@ -40,3 +59,43 @@ class TestDumpsysPackagesArtifact:
|
|||||||
assert len(dpa.alertstore.alerts) == 0
|
assert len(dpa.alertstore.alerts) == 0
|
||||||
dpa.check_indicators()
|
dpa.check_indicators()
|
||||||
assert len(dpa.alertstore.alerts) == 1
|
assert len(dpa.alertstore.alerts) == 1
|
||||||
|
|
||||||
|
def test_per_user_fields_use_primary_user(self):
|
||||||
|
details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
|
||||||
|
""" User 0: installed=true
|
||||||
|
firstInstallTime=2024-01-10 09:19:39
|
||||||
|
runtime permissions:
|
||||||
|
android.permission.CAMERA: granted=true
|
||||||
|
User 95: installed=false
|
||||||
|
firstInstallTime=1970-01-01 01:00:00
|
||||||
|
runtime permissions:
|
||||||
|
android.permission.CAMERA: granted=false
|
||||||
|
android.permission.RECORD_AUDIO: granted=false
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert details["first_install_time"] == "2024-01-10 09:19:39"
|
||||||
|
runtime_permissions = [
|
||||||
|
permission
|
||||||
|
for permission in details["permissions"]
|
||||||
|
if permission["type"] == "runtime"
|
||||||
|
]
|
||||||
|
assert runtime_permissions == [
|
||||||
|
{
|
||||||
|
"name": "android.permission.CAMERA",
|
||||||
|
"granted": True,
|
||||||
|
"type": "runtime",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_per_user_fields_fall_back_when_user_zero_is_missing(self):
|
||||||
|
details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
|
||||||
|
""" User 10: installed=true
|
||||||
|
firstInstallTime=2024-02-10 09:19:39
|
||||||
|
runtime permissions:
|
||||||
|
android.permission.CAMERA: granted=true
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert details["first_install_time"] == "2024-02-10 09:19:39"
|
||||||
|
assert details["permissions"][-1]["name"] == "android.permission.CAMERA"
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ class TestBugreportAnalysis:
|
|||||||
== "com.samsung.android.provider.filterprovider"
|
== "com.samsung.android.provider.filterprovider"
|
||||||
)
|
)
|
||||||
assert m.results[1]["package_name"] == "com.instagram.android"
|
assert m.results[1]["package_name"] == "com.instagram.android"
|
||||||
|
assert m.results[0]["installer"] == ""
|
||||||
|
assert m.results[1]["installer"] == "com.android.vending"
|
||||||
assert len(m.results[0]["permissions"]) == 4
|
assert len(m.results[0]["permissions"]) == 4
|
||||||
assert len(m.results[1]["permissions"]) == 32
|
assert len(m.results[1]["permissions"]) == 32
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user