Refactor SMS ADB code to use backup functions

This commit is contained in:
Donncha Ó Cearbhaill 2022-03-04 17:06:10 +01:00
parent b44c67e699
commit be511dcb51
3 changed files with 31 additions and 30 deletions

View File

@ -19,6 +19,7 @@ from adb_shell.exceptions import (AdbCommandFailureException, DeviceAuthError,
from usb1 import USBErrorAccess, USBErrorBusy from usb1 import USBErrorAccess, USBErrorBusy
from mvt.common.module import InsufficientPrivileges, MVTModule from mvt.common.module import InsufficientPrivileges, MVTModule
from mvt.android.parsers.backup import parse_ab_header, parse_backup_file
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -243,6 +244,33 @@ class AndroidExtraction(MVTModule):
# Disconnect from the device. # Disconnect from the device.
self._adb_disconnect() self._adb_disconnect()
def _generate_backup(package_name):
# Run ADB command to create a backup of SMS app
self.log.warning("Please check phone and accept Android backup prompt. You may need to set a backup password. \a")
# Run ADB command to create a backup of SMS app
# TODO: Base64 encoding as temporary fix to avoid byte-mangling over the shell transport...
backup_output_b64 = self._adb_command("/system/bin/bu backup -nocompress '{}' | base64".format(package_name))
backup_output = base64.b64decode(backup_output_b64)
header = parse_ab_header(backup_output)
if not header["backup"]:
self.log.error("Extracting SMS via Android backup failed. No valid backup data found.")
return
if header["encryption"] == "none":
return parse_backup_file(backup_output, password=None)
# Backup encrypted. Request password from user.
while password_retry in range(0, 3):
backup_password = getpass.getpass(prompt="Backup Password: ", stream=None)
try:
decrypted_backup_tar = parse_backup_file(backup_output, backup_password)
return decrypted_backup_tar
except InvalidBackupPassword:
self.log.info("Invalid backup password")
self.log.warn("All attempts to decrypt backup with password failed!")
def run(self): def run(self):
"""Run the main procedure.""" """Run the main procedure."""
raise NotImplementedError raise NotImplementedError

View File

@ -10,7 +10,7 @@ import base64
import getpass import getpass
from mvt.common.utils import check_for_links, convert_timestamp_to_iso from mvt.common.utils import check_for_links, convert_timestamp_to_iso
from mvt.android.parsers.backup import parse_ab_header, parse_sms_backup, InvalidBackupPassword, AndroidBackupParsingError from mvt.android.parsers.backup import parse_tar_for_sms, AndroidBackupParsingError
from mvt.common.module import InsufficientPrivileges from mvt.common.module import InsufficientPrivileges
from .base import AndroidExtraction from .base import AndroidExtraction
@ -116,28 +116,9 @@ class SMS(AndroidExtraction):
It is crucial to use the under-documented "-nocompress" flag to disable the non-standard Java compression It is crucial to use the under-documented "-nocompress" flag to disable the non-standard Java compression
algorithim. This module only supports an unencrypted ADB backup. algorithim. This module only supports an unencrypted ADB backup.
""" """
# Run ADB command to create a backup of SMS app backup_tar = self._generate_backup("com.android.providers.telephony")
self.log.warning("Please check phone and accept Android backup prompt. Do not set an encryption password. \a")
# Run ADB command to create a backup of SMS app
# TODO: Base64 encoding as temporary fix to avoid byte-mangling over the shell transport...
backup_output_b64 = self._adb_command("/system/bin/bu backup -nocompress com.android.providers.telephony | base64")
backup_output = base64.b64decode(backup_output_b64)
header = parse_ab_header(backup_output)
if not header["backup"]:
self.log.error("Extracting SMS via Android backup failed. No valid backup data found.")
return
pwd = None
if header["encryption"] != "none":
pwd = getpass.getpass(prompt="Backup Password: ", stream=None)
try: try:
self.results = parse_sms_backup(backup_output, password=pwd) self.results = parse_tar_for_sms(backup_tar)
except InvalidBackupPassword:
self.log.info("Invalid backup password")
return
except AndroidBackupParsingError: except AndroidBackupParsingError:
self.log.info("Impossible to read SMS from the Android Backup, please extract the SMS and try extracting it with Android Backup Extractor") self.log.info("Impossible to read SMS from the Android Backup, please extract the SMS and try extracting it with Android Backup Extractor")
return return

View File

@ -42,14 +42,6 @@ def to_utf8_bytes(input_bytes):
return bytes(output) return bytes(output)
def parse_sms_backup(data, password=None):
"""
Parse a backup file and returns SMS in it
"""
tardata = parse_backup_file(data, password=password)
return parse_tar_for_sms(tardata)
def parse_ab_header(data): def parse_ab_header(data):
""" """
Parse the header of an Android Backup file Parse the header of an Android Backup file