Compare commits

...

16 Commits

Author SHA1 Message Date
Rory Flynn
06f65dbbcf Autofix for ruff 2025-01-14 11:50:24 +01:00
Nimrod Adam
1c78874b82 Add command completion docs (#410) 2025-01-13 14:48:47 +01:00
Donncha Ó Cearbhaill
0c73e3e8fa Merge pull request #587 from mvt-project/feature/uninstalled-apps
Add a module to parse uninstalled apps from dumpsys data
2024-12-16 00:03:23 +01:00
Donncha Ó Cearbhaill
9b5f2d89d5 Merge branch 'main' into feature/uninstalled-apps 2024-12-16 00:00:12 +01:00
Donncha Ó Cearbhaill
3da61c8da8 Fix ruff checks 2024-12-15 23:22:36 +01:00
Tek
5b2fe3baec Reorganize code in iOS app module (#586) 2024-12-14 10:04:47 +01:00
Donncha Ó Cearbhaill
a3a7789547 Merge pull request #584 from mvt-project/enhance-community-guidelines
Update MVT contributor guidelines
2024-12-13 23:01:58 +01:00
Donncha Ó Cearbhaill
d3fcc686ff Update contribution guidelines 2024-12-13 22:45:41 +01:00
github-actions[bot]
4bcc0e5f27 Add new iOS versions and build numbers (#583)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2024-12-12 14:43:59 +01:00
tes
9d81b5bfa8 Add a module to parse uninstalled apps from dumpsys data, for both bugreport and AndroidQF output, and match them against package name IoCs. 2024-12-11 16:47:19 -03:00
github-actions[bot]
22fce280af Add new iOS versions and build numbers (#572)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2024-11-20 11:02:09 +01:00
Donncha Ó Cearbhaill
4739d8853e Merge pull request #570 from mvt-project/fix/files-detection-bug
Fix error to due extra equal character in Files detection
2024-10-31 20:04:33 +01:00
Donncha Ó Cearbhaill
ace01ff7fb Merge branch 'main' into fix/files-detection-bug 2024-10-31 19:59:53 +01:00
Donncha Ó Cearbhaill
7e4f0aec4d Fix error to due extra equal character in Files detection 2024-10-31 19:59:29 +01:00
github-actions[bot]
57647583cc Add new iOS versions and build numbers (#569)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2024-10-29 04:17:03 +01:00
Donncha Ó Cearbhaill
cd99b293ed Merge pull request #563 from mvt-project/feature/add-package-detections
Add additional detections for suspicious packages
2024-10-24 17:37:30 +02:00
30 changed files with 384 additions and 40 deletions

View File

@@ -1,19 +1,65 @@
# Contributing # Contributing to Mobile Verification Toolkit (MVT)
Thank you for your interest in contributing to Mobile Verification Toolkit (MVT)! Your help is very much appreciated. We greatly appreciate contributions to MVT!
Your involvement, whether through identifying issues, improving functionality, or enhancing documentation, is very much appreciated. To ensure smooth collaboration and a welcoming environment, we've outlined some key guidelines for contributing below.
## Getting started
Contributing to an open-source project like MVT might seem overwhelming at first, but we're here to support you!
Whether you're a technologist, a frontline human rights defender, a field researcher, or someone new to consensual spyware forensics, there are many ways to make meaningful contributions.
Here's how you can get started:
1. **Explore the codebase:**
- Browse the repository to get familar with MVT. Many MVT modules are simple in functionality and easy to understand.
- Look for `TODO:` or `FIXME:` comments in the code for areas that need attention.
2. **Check Github issues:**
- Look for issues tagged with ["help wanted"](https://github.com/mvt-project/mvt/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) or ["good first issue"](https://github.com/mvt-project/mvt/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to find tasks that are beginner-friendly or where input from the community would be helpful.
3. **Ask for guidance:**
- If you're unsure where to start, feel free to open a [discussion](https://github.com/mvt-project/mvt/discussions) or comment on an issue.
## How to contribute:
1. **Report issues:**
- Found a bug? Please check existing issues to see if it's already reported. If not, open a new issue. Mobile operating systems and databases are constantly evolving, an new errors may appear spontaniously in new app versions.
**Please provide as much information as possible about the prodblem including: any error messages, steps to reproduce the problem, and any logs or screenshots that can help.**
## Where to start 2. **Suggest features:**
- If you have an idea for new functionality, create a feature request issue and describe your proposal.
Starting to contribute to a somewhat complex project like MVT might seem intimidating. Unless you have specific ideas of new functionality you would like to submit, some good starting points are searching for `TODO:` and `FIXME:` comments throughout the code. Alternatively you can check if any GitHub issues existed marked with the ["help wanted"](https://github.com/mvt-project/mvt/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) tag. 3. **Submit code:**
- Fork the repository and create a new branch for your changes.
- Ensure your changes align with the code style guidelines (see below).
- Open a pull request (PR) with a clear description of your changes and link it to any relevant issues.
4. **Documentation contributions:**
- Improving documentation is just as valuable as contributing code! If you notice gaps or inaccuracies in the documentation, feel free to submit changes or suggest updates.
## Code style ## Code style
Please follow these code style guidelines for consistency and readability:
When contributing code to - **Indentation**: use 4 spaces per tab.
- **Quotes**: Use double quotes (`"`) by default. Use single quotes (`'`) for nested strings instead of escaping (`\"`), or when using f-formatting.
- **Maximum line length**:
- Aim for lines no longer than 80 characters.
- Exceptions are allowed for long log lines or strings, which may extend up to 100 characters.
- Wrap lines that exceed 100 characters.
- **Indentation**: we use 4-spaces tabs. Follow [PEP 8 guidelines](https://peps.python.org/pep-0008/) for indentation and overall Python code style. All MVT code is automatically linted with [Ruff](https://github.com/astral-sh/ruff) before merging.
- **Quotes**: we use double quotes (`"`) as a default. Single quotes (`'`) can be favored with nested strings instead of escaping (`\"`), or when using f-formatting. Please check your code before opening a pull request by running `make ruff`
- **Maximum line length**: we strongly encourage to respect a 80 characters long lines and to follow [PEP8 indentation guidelines](https://peps.python.org/pep-0008/#indentation) when having to wrap. However, if breaking at 80 is not possible or is detrimental to the readability of the code, exceptions are tolerated. For example, long log lines, or long strings can be extended to 100 characters long. Please hard wrap anything beyond 100 characters.
## Community and support
We aim to create a supportive and collaborative environment for all contributors. If you run into any challenges, feel free to reach out through the discussions or issues section of the repository.
Your contributions, big or small, help improve MVT and are always appreciated.

View File

@@ -0,0 +1,37 @@
# Command Completion
MVT utilizes the [Click](https://click.palletsprojects.com/en/stable/) library for creating its command line interface.
Click provides tab completion support for Bash (version 4.4 and up), Zsh, and Fish.
To enable it, you need to manually register a special function with your shell, which varies depending on the shell you are using.
The following describes how to generate the command completion scripts and add them to your shell configuration.
`You will need to start a new shell for the changes to take effect.`
### For Bash
```bash
# Generates bash completion scripts
echo "$(_MVT_IOS_COMPLETE=bash_source mvt-ios)" > ~/.mvt-ios-complete.bash &&
echo "$(_MVT_ANDROID_COMPLETE=bash_source mvt-android)" > ~/.mvt-android-complete.bash
# Sources the scripts in ~/.bashrc.
. ~/.mvt-ios-complete.bash && . ~/.mvt-android-complete.bash
```
### For Zsh
```bash
# Generates zsh completion scripts
echo "$(_MVT_IOS_COMPLETE=zsh_source mvt-ios)" > ~/.mvt-ios-complete.zsh &&
echo "$(_MVT_ANDROID_COMPLETE=zsh_source mvt-android)" > ~/.mvt-android-complete.zsh
# Sources the scripts in ~/.zshrc.
. ~/.mvt-ios-complete.zsh && . ~/.mvt-android-complete.zsh
```
For more information, visit the official [Click Docs](https://click.palletsprojects.com/en/stable/shell-completion/#enabling-completion).

View File

@@ -51,7 +51,7 @@ class DumpsysAppopsArtifact(AndroidArtifact):
and perm["access"] == "allow" and perm["access"] == "allow"
): ):
self.log.info( self.log.info(
"Package %s with REQUEST_INSTALL_PACKAGES " "permission", "Package %s with REQUEST_INSTALL_PACKAGES permission",
result["package_name"], result["package_name"],
) )

View File

@@ -16,8 +16,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
for result in self.results: for result in self.results:
if result["package_name"] in ROOT_PACKAGES: if result["package_name"] in ROOT_PACKAGES:
self.log.warning( self.log.warning(
"Found an installed package related to " 'Found an installed package related to rooting/jailbreaking: "%s"',
'rooting/jailbreaking: "%s"',
result["package_name"], result["package_name"],
) )
self.detected.append(result) self.detected.append(result)

View File

@@ -0,0 +1,42 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 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/
from .artifact import AndroidArtifact
class DumpsysPlatformCompatArtifact(AndroidArtifact):
"""
Parser for uninstalled apps listed in platform_compat section.
"""
def check_indicators(self) -> None:
if not self.indicators:
return
for result in self.results:
ioc = self.indicators.check_app_id(result["package_name"])
if ioc:
result["matched_indicator"] = ioc
self.detected.append(result)
continue
def parse(self, data: str) -> None:
for line in data.splitlines():
if not line.startswith("ChangeId(168419799; name=DOWNSCALED;"):
continue
if line.strip() == "":
break
# Look for rawOverrides field
if "rawOverrides={" in line:
# Extract the content inside the braces for rawOverrides
overrides_field = line.split("rawOverrides={", 1)[1].split("};", 1)[0]
for entry in overrides_field.split(", "):
# Extract app name
uninstall_app = entry.split("=")[0].strip()
self.results.append({"package_name": uninstall_app})

View File

@@ -326,8 +326,7 @@ class AndroidExtraction(MVTModule):
if not header["backup"]: if not header["backup"]:
self.log.error( self.log.error(
"Extracting SMS via Android backup failed. " "Extracting SMS via Android backup failed. No valid backup data found."
"No valid backup data found."
) )
return None return None

View File

@@ -75,8 +75,7 @@ class Packages(AndroidExtraction):
for result in self.results: for result in self.results:
if result["package_name"] in ROOT_PACKAGES: if result["package_name"] in ROOT_PACKAGES:
self.log.warning( self.log.warning(
"Found an installed package related to " 'Found an installed package related to rooting/jailbreaking: "%s"',
'rooting/jailbreaking: "%s"',
result["package_name"], result["package_name"],
) )
self.detected.append(result) self.detected.append(result)

View File

@@ -70,7 +70,7 @@ class SMS(AndroidExtraction):
"timestamp": record["isodate"], "timestamp": record["isodate"],
"module": self.__class__.__name__, "module": self.__class__.__name__,
"event": f"sms_{record['direction']}", "event": f"sms_{record['direction']}",
"data": f"{record.get('address', 'unknown source')}: \"{body}\"", "data": f'{record.get("address", "unknown source")}: "{body}"',
} }
def check_indicators(self) -> None: def check_indicators(self) -> None:

View File

@@ -14,6 +14,7 @@ from .dumpsys_receivers import DumpsysReceivers
from .dumpsys_adb import DumpsysADBState from .dumpsys_adb import DumpsysADBState
from .getprop import Getprop from .getprop import Getprop
from .packages import Packages from .packages import Packages
from .dumpsys_platform_compat import DumpsysPlatformCompat
from .processes import Processes from .processes import Processes
from .settings import Settings from .settings import Settings
from .sms import SMS from .sms import SMS
@@ -29,6 +30,7 @@ ANDROIDQF_MODULES = [
DumpsysBatteryHistory, DumpsysBatteryHistory,
DumpsysADBState, DumpsysADBState,
Packages, Packages,
DumpsysPlatformCompat,
Processes, Processes,
Getprop, Getprop,
Settings, Settings,

View File

@@ -0,0 +1,44 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 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/
import logging
from typing import Optional
from mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
from .base import AndroidQFModule
class DumpsysPlatformCompat(DumpsysPlatformCompatArtifact, AndroidQFModule):
"""This module extracts details on uninstalled apps."""
def __init__(
self,
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
super().__init__(
file_path=file_path,
target_path=target_path,
results_path=results_path,
module_options=module_options,
log=log,
results=results,
)
def run(self) -> None:
dumpsys_file = self._get_files_by_pattern("*/dumpsys.txt")
if not dumpsys_file:
return
data = self._get_file_content(dumpsys_file[0]).decode("utf-8", errors="replace")
content = self.extract_dumpsys_section(data, "DUMP OF SERVICE platform_compat:")
self.parse(content)
self.log.info("Found %d uninstalled apps", len(self.results))

View File

@@ -74,7 +74,7 @@ class Files(AndroidQFModule):
for result in self.results: for result in self.results:
ioc = self.indicators.check_file_path(result["path"]) ioc = self.indicators.check_file_path(result["path"])
if ioc: if ioc:
result["matched_indicator"] == ioc result["matched_indicator"] = ioc
self.detected.append(result) self.detected.append(result)
continue continue

View File

@@ -44,8 +44,7 @@ class Packages(AndroidQFModule):
for result in self.results: for result in self.results:
if result["name"] in ROOT_PACKAGES: if result["name"] in ROOT_PACKAGES:
self.log.warning( self.log.warning(
"Found an installed package related to " 'Found an installed package related to rooting/jailbreaking: "%s"',
'rooting/jailbreaking: "%s"',
result["name"], result["name"],
) )
self.detected.append(result) self.detected.append(result)

View File

@@ -11,6 +11,7 @@ from .battery_history import BatteryHistory
from .dbinfo import DBInfo from .dbinfo import DBInfo
from .getprop import Getprop from .getprop import Getprop
from .packages import Packages from .packages import Packages
from .platform_compat import PlatformCompat
from .receivers import Receivers from .receivers import Receivers
from .adb_state import DumpsysADBState from .adb_state import DumpsysADBState
@@ -23,6 +24,7 @@ BUGREPORT_MODULES = [
DBInfo, DBInfo,
Getprop, Getprop,
Packages, Packages,
PlatformCompat,
Receivers, Receivers,
DumpsysADBState, DumpsysADBState,
] ]

View File

@@ -0,0 +1,48 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 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/
import logging
from typing import Optional
from mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
from mvt.android.modules.bugreport.base import BugReportModule
class PlatformCompat(DumpsysPlatformCompatArtifact, BugReportModule):
"""This module extracts details on uninstalled apps."""
def __init__(
self,
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
super().__init__(
file_path=file_path,
target_path=target_path,
results_path=results_path,
module_options=module_options,
log=log,
results=results,
)
def run(self) -> None:
data = self._get_dumpstate_file()
if not data:
self.log.error(
"Unable to find dumpstate file. "
"Did you provide a valid bug report archive?"
)
return
data = data.decode("utf-8", errors="replace")
content = self.extract_dumpsys_section(data, "DUMP OF SERVICE platform_compat:")
self.parse(content)
self.log.info("Found %d uninstalled apps", len(self.results))

View File

@@ -81,7 +81,7 @@ class Command:
os.path.join(self.results_path, "command.log") os.path.join(self.results_path, "command.log")
) )
formatter = logging.Formatter( formatter = logging.Formatter(
"%(asctime)s - %(name)s - " "%(levelname)s - %(message)s" "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
) )
file_handler.setLevel(logging.DEBUG) file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter) file_handler.setFormatter(formatter)

View File

@@ -383,8 +383,7 @@ class Indicators:
for ioc in self.get_iocs("urls"): for ioc in self.get_iocs("urls"):
if ioc["value"] == url: if ioc["value"] == url:
self.log.warning( self.log.warning(
"Found a known suspicious URL %s " 'Found a known suspicious URL %s matching indicator "%s" from "%s"',
'matching indicator "%s" from "%s"',
url, url,
ioc["value"], ioc["value"],
ioc["name"], ioc["name"],

View File

@@ -100,7 +100,7 @@ def decrypt_backup(ctx, destination, password, key_file, hashes, backup_path):
if key_file: if key_file:
if MVT_IOS_BACKUP_PASSWORD in os.environ: if MVT_IOS_BACKUP_PASSWORD in os.environ:
log.info( log.info(
"Ignoring %s environment variable, using --key-file" "'%s' instead", "Ignoring %s environment variable, using --key-file'%s' instead",
MVT_IOS_BACKUP_PASSWORD, MVT_IOS_BACKUP_PASSWORD,
key_file, key_file,
) )
@@ -114,7 +114,7 @@ def decrypt_backup(ctx, destination, password, key_file, hashes, backup_path):
if MVT_IOS_BACKUP_PASSWORD in os.environ: if MVT_IOS_BACKUP_PASSWORD in os.environ:
log.info( log.info(
"Ignoring %s environment variable, using --password" "argument instead", "Ignoring %s environment variable, using --passwordargument instead",
MVT_IOS_BACKUP_PASSWORD, MVT_IOS_BACKUP_PASSWORD,
) )
@@ -168,8 +168,7 @@ def extract_key(password, key_file, backup_path):
if MVT_IOS_BACKUP_PASSWORD in os.environ: if MVT_IOS_BACKUP_PASSWORD in os.environ:
log.info( log.info(
"Ignoring %s environment variable, using --password " "Ignoring %s environment variable, using --password argument instead",
"argument instead",
MVT_IOS_BACKUP_PASSWORD, MVT_IOS_BACKUP_PASSWORD,
) )
elif MVT_IOS_BACKUP_PASSWORD in os.environ: elif MVT_IOS_BACKUP_PASSWORD in os.environ:

View File

@@ -1083,5 +1083,17 @@
{ {
"version": "18.0.1", "version": "18.0.1",
"build": "22A3370" "build": "22A3370"
},
{
"version": "18.1",
"build": "22B83"
},
{
"version": "18.1.1",
"build": "22B91"
},
{
"version": "18.2",
"build": "22C152"
} }
] ]

View File

@@ -41,7 +41,7 @@ class BackupInfo(IOSExtraction):
info_path = os.path.join(self.target_path, "Info.plist") info_path = os.path.join(self.target_path, "Info.plist")
if not os.path.exists(info_path): if not os.path.exists(info_path):
raise DatabaseNotFoundError( raise DatabaseNotFoundError(
"No Info.plist at backup path, unable to extract device " "information" "No Info.plist at backup path, unable to extract device information"
) )
with open(info_path, "rb") as handle: with open(info_path, "rb") as handle:

View File

@@ -110,8 +110,7 @@ class Manifest(IOSExtraction):
ioc = self.indicators.check_url(part) ioc = self.indicators.check_url(part)
if ioc: if ioc:
self.log.warning( self.log.warning(
'Found mention of domain "%s" in a backup file with ' 'Found mention of domain "%s" in a backup file with path: %s',
"path: %s",
ioc["value"], ioc["value"],
rel_path, rel_path,
) )

View File

@@ -74,7 +74,7 @@ class IOSExtraction(MVTModule):
if not shutil.which("sqlite3"): if not shutil.which("sqlite3"):
raise DatabaseCorruptedError( raise DatabaseCorruptedError(
"failed to recover without sqlite3 binary: please install " "sqlite3!" "failed to recover without sqlite3 binary: please install sqlite3!"
) )
if '"' in file_path: if '"' in file_path:
raise DatabaseCorruptedError( raise DatabaseCorruptedError(

View File

@@ -17,6 +17,12 @@ from mvt.ios.modules.base import IOSExtraction
APPLICATIONS_DB_PATH = [ APPLICATIONS_DB_PATH = [
"private/var/containers/Bundle/Application/*/iTunesMetadata.plist" "private/var/containers/Bundle/Application/*/iTunesMetadata.plist"
] ]
KNOWN_APP_INSTALLERS = [
"com.apple.AppStore",
"com.apple.AppStore.ProductPageExtension",
"com.apple.dmd",
"dmd",
]
class Applications(IOSExtraction): class Applications(IOSExtraction):
@@ -80,12 +86,10 @@ class Applications(IOSExtraction):
self.detected.append(result) self.detected.append(result)
continue continue
# Some apps installed from apple store with sourceApp "com.apple.AppStore.ProductPageExtension" # Some apps installed from apple store with sourceApp "com.apple.AppStore.ProductPageExtension"
if result.get("sourceApp", "com.apple.AppStore") not in [ if (
"com.apple.AppStore", result.get("sourceApp", "com.apple.AppStore")
"com.apple.AppStore.ProductPageExtension", not in KNOWN_APP_INSTALLERS
"com.apple.dmd", ):
"dmd",
]:
self.log.warning( self.log.warning(
"Suspicious app not installed from the App Store or MDM: %s", "Suspicious app not installed from the App Store or MDM: %s",
result["softwareVersionBundleId"], result["softwareVersionBundleId"],

View File

@@ -43,7 +43,7 @@ class SMS(IOSExtraction):
def serialize(self, record: dict) -> Union[dict, list]: def serialize(self, record: dict) -> Union[dict, list]:
text = record["text"].replace("\n", "\\n") text = record["text"].replace("\n", "\\n")
sms_data = f"{record['service']}: {record['guid']} \"{text}\" from {record['phone_number']} ({record['account']})" sms_data = f'{record["service"]}: {record["guid"]} "{text}" from {record["phone_number"]} ({record["account"]})'
records = [ records = [
{ {
"timestamp": record["isodate"], "timestamp": record["isodate"],

View File

@@ -100,7 +100,7 @@ class WebkitSessionResourceLog(IOSExtraction):
redirect_path += ", ".join(source_domains) redirect_path += ", ".join(source_domains)
redirect_path += " -> " redirect_path += " -> "
redirect_path += f"ORIGIN: \"{entry['origin']}\"" redirect_path += f'ORIGIN: "{entry["origin"]}"'
if len(destination_domains) > 0: if len(destination_domains) > 0:
redirect_path += " -> " redirect_path += " -> "

View File

@@ -0,0 +1,40 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 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/
import logging
from mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
from mvt.common.indicators import Indicators
from ..utils import get_artifact
class TestDumpsysPlatformCompatArtifact:
def test_parsing(self):
dbi = DumpsysPlatformCompatArtifact()
file = get_artifact("android_data/dumpsys_platform_compat.txt")
with open(file) as f:
data = f.read()
assert len(dbi.results) == 0
dbi.parse(data)
assert len(dbi.results) == 2
assert dbi.results[0]["package_name"] == "org.torproject.torbrowser"
assert dbi.results[1]["package_name"] == "org.article19.circulo.next"
def test_ioc_check(self, indicator_file):
dbi = DumpsysPlatformCompatArtifact()
file = get_artifact("android_data/dumpsys_platform_compat.txt")
with open(file) as f:
data = f.read()
dbi.parse(data)
ind = Indicators(log=logging.getLogger())
ind.parse_stix2(indicator_file)
ind.ioc_collections[0]["app_ids"].append("org.torproject.torbrowser")
ind.ioc_collections[0]["app_ids"].append("org.article19.circulo.next")
dbi.indicators = ind
assert len(dbi.detected) == 0
dbi.check_indicators()
assert len(dbi.detected) == 2

View File

@@ -0,0 +1,23 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 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/
from pathlib import Path
from mvt.android.modules.androidqf.dumpsys_platform_compat import DumpsysPlatformCompat
from mvt.common.module import run_module
from ..utils import get_android_androidqf, list_files
class TestDumpsysPlatformCompatModule:
def test_parsing(self):
data_path = get_android_androidqf()
m = DumpsysPlatformCompat(target_path=data_path)
files = list_files(data_path)
parent_path = Path(data_path).absolute().parent.as_posix()
m.from_folder(parent_path, files)
run_module(m)
assert len(m.results) == 2
assert len(m.detected) == 0

View File

@@ -246,6 +246,23 @@ Packages:
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivity com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivity
com.instagram.share.handleractivity.ClipsShareHandlerActivity com.instagram.share.handleractivity.ClipsShareHandlerActivity
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivityInterop com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivityInterop
--------- 0.053s was the duration of dumpsys appops, ending at: 2022-03-29 23:14:27
-------------------------------------------------------------------------------
DUMP OF SERVICE platform_compat:
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)

View File

@@ -0,0 +1,16 @@
DUMP OF SERVICE platform_compat:
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)

View File

@@ -379,4 +379,22 @@ Daily stats:
Update com.google.android.projection.gearhead vers=99632623 Update com.google.android.projection.gearhead vers=99632623
Update com.google.android.projection.gearhead vers=99632623 Update com.google.android.projection.gearhead vers=99632623
Update com.google.android.projection.gearhead vers=99632623 Update com.google.android.projection.gearhead vers=99632623
--------- 0.053s was the duration of dumpsys batterystats, ending at: 2024-03-21 11:07:22
-------------------------------------------------------------------------------
DUMP OF SERVICE platform_compat:
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)

View File

@@ -75,7 +75,7 @@ class TestHashes:
# This needs to be updated when we add or edit files in AndroidQF folder # This needs to be updated when we add or edit files in AndroidQF folder
assert ( assert (
hashes[1]["sha256"] hashes[1]["sha256"]
== "1bd255f656a7f9d5647a730f0f0cc47053115576f11532d41bf28c16635b193d" == "9fb6396b64cfff30e2a459a64496d3c1386926d09edd68be2d878de45fa7b3a9"
) )