Files
Mobile-Security-Framework-M…/mobsf/MobSF/init.py
T
6e875fb77b Jailbroken iOS Device Support (#2536)
Enables dynamic analysis on real jailbroken iOS devices connected via USB or WiFi SSH, complementing the existing Corellium-based iOS analysis.              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                
  - SSH connectivity — connects to jailbroken devices over USB (via iproxy port forwarding) or WiFi using Paramiko SSH                                         
  - Frida instrumentation — spawns/attaches Frida on-device, with full hook support matching the existing Corellium flow                                       
  - Environment setup — installs AppSync Unified and Frida server on first run; supports both arm and arm64 devices                                            
  - Dynamic analysis — app file extraction, system log streaming (oslog), screenshot capture, process listing, and report generation
  - SSH terminal — execute shell commands on the device over SSH

---------

Co-authored-by: CylentSec <[email protected]>
Co-authored-by: Oz <[email protected]>
2026-03-23 01:46:03 -07:00

215 lines
6.8 KiB
Python

"""Initialize on first run."""
import logging
import os
import random
import subprocess
import sys
import shutil
import threading
from hashlib import sha256
from pathlib import Path
from importlib import (
machinery,
util,
)
from mobsf.MobSF.tools_download import install_jadx
from mobsf.install.windows.setup import windows_config_local
logger = logging.getLogger(__name__)
VERSION = '4.5.0'
BANNER = r"""
__ __ _ ____ _____ _ _ ____
| \/ | ___ | |__/ ___|| ___|_ _| || | | ___|
| |\/| |/ _ \| '_ \___ \| |_ \ \ / / || |_ |___ \
| | | | (_) | |_) |__) | _| \ V /|__ _| ___) |
|_| |_|\___/|_.__/____/|_| \_/ |_|(_)____/
""" # noqa: W291
# ASCII Font: Standard
def first_run(secret_file, base_dir, mobsf_home):
# Based on https://gist.github.com/ndarville/3452907#file-secret-key-gen-py
base_dir = Path(base_dir)
mobsf_home = Path(mobsf_home)
secret_file = Path(secret_file)
if os.getenv('MOBSF_SECRET_KEY'):
secret_key = os.environ['MOBSF_SECRET_KEY']
elif secret_file.exists() and secret_file.is_file():
secret_key = secret_file.read_text().strip()
else:
try:
secret_key = get_random()
secret_file.write_text(secret_key)
except IOError:
raise Exception('Secret file generation failed' % secret_file)
# Run Once
make_migrations(base_dir)
migrate(base_dir)
# Install JADX
thread = threading.Thread(
target=install_jadx,
name='install_jadx',
args=(mobsf_home.as_posix(),))
thread.start()
# Windows Setup
windows_config_local(mobsf_home.as_posix())
return secret_key
def create_user_conf(mobsf_home, base_dir):
try:
config_path = mobsf_home / 'config.py'
if not config_path.exists():
sample_conf = base_dir / 'MobSF' / 'settings.py'
dat = sample_conf.read_text().splitlines()
config = []
add = False
for line in dat:
if '^CONFIG-START^' in line:
add = True
if '^CONFIG-END^' in line:
break
if add:
config.append(line.lstrip())
config.pop(0)
conf_str = '\n'.join(config)
config_path.write_text(conf_str)
except Exception:
logger.exception('Cannot create config file')
def django_operation(cmds, base_dir):
"""Generic Function for Djano operations."""
manage = base_dir.parent / 'manage.py'
if manage.exists() and manage.is_file():
# Bail out for package
return
print(manage)
args = [sys.executable, manage.as_posix()]
args.extend(cmds)
subprocess.call(args)
def make_migrations(base_dir):
"""Create Database Migrations."""
try:
django_operation(['makemigrations'], base_dir)
django_operation(['makemigrations', 'StaticAnalyzer'], base_dir)
except Exception:
logger.exception('Cannot Make Migrations')
def migrate(base_dir):
"""Migrate Database."""
try:
django_operation(['migrate'], base_dir)
django_operation(['migrate', '--run-syncdb'], base_dir)
django_operation(['create_roles'], base_dir)
except Exception:
logger.exception('Cannot Migrate')
def get_random():
choice = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
return ''.join([random.SystemRandom().choice(choice) for i in range(50)])
def get_mobsf_home(use_home, base_dir):
try:
base_dir = Path(base_dir)
mobsf_home = ''
if use_home:
mobsf_home = Path.home() / '.MobSF'
custom_home = os.getenv('MOBSF_HOME_DIR')
if custom_home:
p = Path(custom_home)
if p.exists() and p.is_absolute() and p.is_dir():
mobsf_home = p
# MobSF Home Directory
if not mobsf_home.exists():
mobsf_home.mkdir(parents=True, exist_ok=True)
create_user_conf(mobsf_home, base_dir)
else:
mobsf_home = base_dir
# Download Directory
dwd_dir = mobsf_home / 'downloads'
dwd_dir.mkdir(parents=True, exist_ok=True)
# Screenshot Directory
screen_dir = mobsf_home / 'screen'
screen_dir.mkdir(parents=True, exist_ok=True)
# Upload Directory
upload_dir = mobsf_home / 'uploads'
upload_dir.mkdir(parents=True, exist_ok=True)
# Downloaded tools
downloaded_tools_dir = mobsf_home / 'tools'
downloaded_tools_dir.mkdir(parents=True, exist_ok=True)
# Signatures Directory
sig_dir = mobsf_home / 'signatures'
sig_dir.mkdir(parents=True, exist_ok=True)
if use_home:
src = Path(base_dir) / 'signatures'
try:
shutil.copytree(src, sig_dir, dirs_exist_ok=True)
except Exception:
pass
return mobsf_home.as_posix()
except Exception:
logger.exception('Creating MobSF Home Directory')
def get_mobsf_version():
return BANNER, VERSION, f'v{VERSION}'
def load_source(modname, filename):
loader = machinery.SourceFileLoader(modname, filename)
spec = util.spec_from_file_location(modname, filename, loader=loader)
module = util.module_from_spec(spec)
loader.exec_module(module)
return module
def get_docker_secret_by_file(secret_key):
try:
secret_path = os.environ.get(secret_key)
path = Path(secret_path)
if path.exists() and path.is_file():
return path.read_text().strip()
except Exception:
logger.exception('Cannot read secret from %s', secret_path)
raise Exception('Cannot read secret from file')
def get_secret_from_file_or_env(env_secret_key):
docker_secret_key = f'{env_secret_key}_FILE'
if os.environ.get(docker_secret_key):
return get_docker_secret_by_file(docker_secret_key)
else:
return os.environ[env_secret_key]
def api_key(home_dir):
"""Print REST API Key."""
# Form Docker Secrets
if os.environ.get('MOBSF_API_KEY_FILE'):
logger.info('\nAPI Key read from docker secrets')
try:
return get_docker_secret_by_file('MOBSF_API_KEY_FILE')
except Exception:
logger.exception('Cannot read API Key from docker secrets')
# From Environment Variable
if os.environ.get('MOBSF_API_KEY'):
logger.info('\nAPI Key read from environment variable')
return os.environ['MOBSF_API_KEY']
home_dir = Path(home_dir)
secret_file = home_dir / 'secret'
if secret_file.exists() and secret_file.is_file():
try:
_api_key = secret_file.read_bytes().strip()
return sha256(_api_key).hexdigest()
except Exception:
logger.exception('Cannot Read API Key')
return None