# analyzing-ios-app-security-with-objection

Runtime iOS app security testing with Objection (Frida): inspect keychain and filesystem data, explore app internals at runtime, and validate/bypass client-side protections during authorized mobile assessments.

- **Kind:** skill
- **Source:** https://github.com/mukul975/Anthropic-Cybersecurity-Skills
- **Page:** https://forefy.com/skills/322c09de-d283-4e20-bfd5-7302a15e0669
- **API (JSON + files):** https://forefy.com/api/asr/322c09de-d283-4e20-bfd5-7302a15e0669

---

## LICENSE

```

```

## SKILL.md

---
name: analyzing-ios-app-security-with-objection
description: >-
  Runtime iOS app security testing with Objection (Frida): inspect keychain and
  filesystem data, explore app internals at runtime, and validate/bypass
  client-side protections during authorized mobile assessments.
domain: cybersecurity
subdomain: mobile-security
author: mahipal
tags:
- mobile-security
- ios
- objection
- frida
- owasp-mobile
- penetration-testing
version: 1.0.0
license: Apache-2.0
atlas_techniques:
- AML.T0054
nist_ai_rmf:
- MEASURE-2.7
- MANAGE-2.4
- GOVERN-6.2
- MAP-5.1
nist_csf:
- PR.PS-01
- PR.AA-05
- ID.RA-01
- DE.CM-09
mitre_attack:
- T1635
- T1414
- T1417.001
- T1409
---
# Analyzing iOS App Security with Objection

## When to Use

Use this skill when:
- Performing runtime security assessment of iOS applications during authorized penetration tests
- Inspecting iOS keychain, filesystem, and memory for sensitive data exposure
- Bypassing client-side security controls (SSL pinning, jailbreak detection) during security testing
- Evaluating iOS app behavior at runtime without access to source code

**Do not use** this skill on production devices without explicit authorization -- Objection modifies app runtime behavior and may trigger security monitoring.

## Prerequisites

- Python 3.10+ with pip
- Objection installed: `pip install objection`
- Frida installed: `pip install frida-tools`
- Target iOS device (jailbroken with Frida server, or non-jailbroken with repackaged IPA)
- For non-jailbroken: `objection patchipa` to inject Frida gadget into IPA
- macOS recommended for iOS testing (Xcode, ideviceinstaller)
- USB connection to target device or network Frida server

## Workflow

### Step 1: Prepare the Testing Environment

**For jailbroken devices:**
```bash
# Install Frida server on device via Cydia/Sileo
# SSH to device and start Frida server
ssh root@<device_ip> "/usr/sbin/frida-server -D"

# Verify Frida connectivity
frida-ps -U  # List processes on USB-connected device
```

**For non-jailbroken devices (authorized testing):**
```bash
# Patch IPA with Frida gadget
objection patchipa --source target.ipa --codesign-signature "Apple Development: test@example.com"

# Install patched IPA
ideviceinstaller -i target-patched.ipa
```

### Step 2: Attach Objection to Target App

```bash
# Attach to running app by bundle ID
objection --gadget "com.target.app" explore

# Or spawn the app fresh
objection --gadget "com.target.app" explore --startup-command "ios hooking list classes"
```

Once attached, Objection provides an interactive REPL for runtime exploration.

### Step 3: Assess Data Storage Security (MASVS-STORAGE)

```bash
# Dump iOS Keychain items accessible to the app
ios keychain dump

# List files in app sandbox
ios plist cat Info.plist
env  # Show app environment paths

# Inspect NSUserDefaults for sensitive data
ios nsuserdefaults get

# List SQLite databases
sqlite connect app_data.db
sqlite execute query "SELECT * FROM credentials"

# Check for sensitive data in pasteboard
ios pasteboard monitor
```

### Step 4: Evaluate Network Security (MASVS-NETWORK)

```bash
# Disable SSL/TLS certificate pinning
ios sslpinning disable

# Verify pinning is bypassed by observing traffic in Burp Suite proxy
# Monitor network-related class method calls
ios hooking watch class NSURLSession
ios hooking watch class NSURLConnection
```

### Step 5: Inspect Authentication and Authorization (MASVS-AUTH)

```bash
# List all Objective-C classes
ios hooking list classes

# Search for authentication-related classes
ios hooking search classes Auth
ios hooking search classes Login
ios hooking search classes Token

# Hook authentication methods to observe parameters
ios hooking watch method "+[AuthManager validateToken:]" --dump-args --dump-return

# Monitor biometric authentication calls
ios hooking watch class LAContext
```

### Step 6: Assess Binary Protections (MASVS-RESILIENCE)

```bash
# Check jailbreak detection implementation
ios jailbreak disable

# Simulate jailbreak detection bypass
ios jailbreak simulate

# List loaded frameworks and libraries
memory list modules

# Search memory for sensitive strings
memory search "password" --string
memory search "api_key" --string
memory search "Bearer" --string

# Dump specific memory regions
memory dump all dump_output/
```

### Step 7: Review Platform Interaction (MASVS-PLATFORM)

```bash
# List URL schemes registered by the app
ios info binary
ios bundles list_frameworks

# Hook URL scheme handlers
ios hooking watch method "-[AppDelegate application:openURL:options:]" --dump-args

# Monitor clipboard access
ios pasteboard monitor

# Check for custom keyboard restrictions
ios hooking search classes UITextField
```

## Key Concepts

| Term | Definition |
|------|-----------|
| **Objection** | Runtime mobile exploration toolkit built on Frida that provides pre-built scripts for common security testing tasks |
| **Frida Gadget** | Shared library injected into app process to enable Frida instrumentation without jailbreak |
| **Keychain** | iOS secure credential storage system; Objection can dump items accessible to the target app's keychain access group |
| **SSL Pinning Bypass** | Runtime modification of certificate validation logic to allow proxy interception of HTTPS traffic |
| **Method Hooking** | Intercepting Objective-C/Swift method calls at runtime to observe arguments, return values, and modify behavior |

## Tools & Systems

- **Objection**: High-level Frida-powered mobile security exploration toolkit with pre-built commands
- **Frida**: Dynamic instrumentation framework providing JavaScript injection into native app processes
- **Frida-tools**: CLI utilities for Frida including frida-ps, frida-trace, and frida-discover
- **ideviceinstaller**: Cross-platform tool for installing/managing iOS apps via USB
- **Burp Suite**: HTTP proxy for intercepting traffic after SSL pinning bypass

## Common Pitfalls

- **App crashes on attach**: Some apps implement Frida detection. Use `--startup-command` to hook anti-Frida checks early in the app lifecycle.
- **Keychain access scope**: Objection can only dump keychain items within the app's access group. System keychain items require separate jailbreak-level tools.
- **Swift name mangling**: Swift method names are mangled in the runtime. Use `ios hooking list classes` with grep to find demangled names.
- **Non-persistent changes**: All Objection modifications are runtime-only and reset on app restart. Document findings immediately.

## assets

```

```

## assets/template.md

# iOS Objection Security Assessment Report

## Engagement Information

| Field | Value |
|-------|-------|
| Application | [APP_NAME] |
| Bundle ID | [BUNDLE_ID] |
| iOS Version | [IOS_VERSION] |
| Device | [DEVICE_MODEL] |
| Device State | [Jailbroken/Non-Jailbroken] |
| Assessment Date | [DATE] |
| Analyst | [ANALYST] |
| Objection Version | [VERSION] |

## Executive Summary

[Brief narrative of findings from Objection runtime analysis]

## Keychain Analysis

| Service | Account | Data Type | Protection Class | Risk |
|---------|---------|-----------|-----------------|------|
| [SERVICE] | [ACCOUNT] | [TYPE] | [CLASS] | [RISK] |

**Findings**: [Description of sensitive data found in keychain]

## Data Storage Assessment

### NSUserDefaults
| Key | Contains Sensitive Data | Risk |
|-----|----------------------|------|
| [KEY] | [YES/NO] | [RISK] |

### SQLite Databases
| Database | Encrypted | Sensitive Tables | Risk |
|----------|-----------|-----------------|------|
| [DB_NAME] | [YES/NO] | [TABLES] | [RISK] |

### Filesystem
| Path | Contents | Protection | Risk |
|------|----------|-----------|------|
| [PATH] | [DESCRIPTION] | [ATTRIBUTE] | [RISK] |

## Network Security

| Check | Result | Details |
|-------|--------|---------|
| SSL Pinning Present | [YES/NO] | [IMPLEMENTATION_DETAILS] |
| SSL Pinning Bypass | [SUCCESS/FAIL] | [METHOD_USED] |
| ATS Configuration | [STRICT/RELAXED] | [EXCEPTIONS] |

## Binary Protection Assessment

| Protection | Status | Details |
|-----------|--------|---------|
| Jailbreak Detection | [Present/Absent] | [BYPASS_DIFFICULTY] |
| Frida Detection | [Present/Absent] | [DETAILS] |
| Debug Detection | [Present/Absent] | [DETAILS] |
| Code Obfuscation | [Yes/No] | [DETAILS] |

## Memory Analysis

| Search Pattern | Found | Risk | Details |
|---------------|-------|------|---------|
| Passwords | [YES/NO] | [RISK] | [DETAILS] |
| Auth Tokens | [YES/NO] | [RISK] | [DETAILS] |
| API Keys | [YES/NO] | [RISK] | [DETAILS] |
| JWTs | [YES/NO] | [RISK] | [DETAILS] |

## Recommendations

### Critical
1. [RECOMMENDATION]

### High
1. [RECOMMENDATION]

### Medium
1. [RECOMMENDATION]

## references

```

```

## references/api-reference.md

# API Reference: iOS App Security with Objection

## Objection CLI

### Launch
```bash
objection -g com.example.app explore          # Attach to running app
objection -g com.example.app explore -s "command"  # Run startup command
objection patchipa --source app.ipa           # Patch IPA with Frida gadget
```

### Keychain & Data Storage
```bash
ios keychain dump                    # Dump keychain items
ios keychain dump --json             # JSON output
ios cookies get                      # List HTTP cookies
ios nsuserdefaults get               # Read NSUserDefaults
ios plist cat Info.plist             # Read plist file
```

### SSL Pinning
```bash
ios sslpinning disable               # Bypass SSL pinning
ios sslpinning disable --quiet        # Quiet mode
```

### Jailbreak Detection
```bash
ios jailbreak disable                 # Bypass jailbreak detection
ios jailbreak simulate                # Simulate jailbroken device
```

### Hooking
```bash
ios hooking list classes                        # List all classes
ios hooking list classes --include Auth          # Filter classes
ios hooking list class_methods ClassName         # List methods
ios hooking watch method "-[Class method]"       # Watch method calls
ios hooking set return_value "-[Class isJB]" false  # Override return
```

### Filesystem
```bash
ls /                                  # List app sandbox root
ls /Documents                         # List Documents directory
file download /path/to/file local.out  # Download file
file upload local.file /remote/path    # Upload file
```

### Memory
```bash
memory dump all dump.bin              # Dump all memory
memory search "password"              # Search memory for string
memory list modules                   # List loaded modules
memory list exports libModule.dylib   # List module exports
```

## Frida CLI

### Syntax
```bash
frida -U -n AppName                   # Attach by name
frida -U -f com.app.id                # Spawn and attach
frida -U -n AppName -l script.js      # Load script
frida-ps -U                           # List running processes
frida-ls-devices                      # List connected devices
```

### Common Frida Scripts
```javascript
// Hook method and log arguments
ObjC.choose(ObjC.classes.ClassName, {
    onMatch: function(instance) {
        Interceptor.attach(instance['- methodName:'].implementation, {
            onEnter: function(args) {
                console.log('arg1:', ObjC.Object(args[2]));
            }
        });
    }, onComplete: function() {}
});
```

## OWASP Mobile Top 10 (2024)

| ID | Category | Objection Check |
|----|----------|-----------------|
| M1 | Improper Credential Usage | `ios keychain dump` |
| M2 | Inadequate Supply Chain Security | Binary analysis |
| M3 | Insecure Authentication | Hook auth classes |
| M4 | Insufficient Input/Output Validation | Hook input methods |
| M5 | Insecure Communication | `ios sslpinning disable` |
| M6 | Inadequate Privacy Controls | `ios nsuserdefaults get` |
| M7 | Insufficient Binary Protections | Check PIE, ARC, stack canary |
| M8 | Security Misconfiguration | `ios plist cat Info.plist` |
| M9 | Insecure Data Storage | Filesystem + keychain review |
| M10 | Insufficient Cryptography | Hook crypto classes |

## iOS App Sandbox Paths
| Path | Contents |
|------|----------|
| `/Documents` | User-generated data |
| `/Library/Caches` | Cached data |
| `/Library/Preferences` | Plist settings |
| `/tmp` | Temporary files |
| `/Library/Cookies` | Cookie storage |

## references/standards.md

# Standards Reference: iOS App Security with Objection

## OWASP Mobile Top 10 2024 Mapping

| OWASP ID | Risk | Objection Testing Coverage |
|----------|------|---------------------------|
| M1 | Improper Credential Usage | Keychain dumping, memory string search for hardcoded credentials |
| M3 | Insecure Authentication/Authorization | Hook authentication methods, bypass biometric checks |
| M5 | Insecure Communication | SSL pinning bypass, network class hooking |
| M7 | Insufficient Binary Protections | Jailbreak detection bypass, Frida detection assessment |
| M8 | Security Misconfiguration | Info.plist review, URL scheme analysis, ATS configuration |
| M9 | Insecure Data Storage | NSUserDefaults inspection, SQLite database access, file system review |

## OWASP MASVS v2.0 Control Mapping

| MASVS Category | Objection Commands | Assessment Area |
|----------------|-------------------|-----------------|
| MASVS-STORAGE | `ios keychain dump`, `ios nsuserdefaults get`, `sqlite connect` | Sensitive data in keychain, NSUserDefaults, databases |
| MASVS-CRYPTO | `memory search`, hook crypto framework calls | Key storage, algorithm selection |
| MASVS-AUTH | Hook LAContext, authentication classes | Biometric bypass, session management |
| MASVS-NETWORK | `ios sslpinning disable`, hook NSURLSession | Certificate pinning, cleartext traffic |
| MASVS-PLATFORM | Hook URL scheme handlers, pasteboard monitor | Deep link security, clipboard exposure |
| MASVS-CODE | `memory list modules`, binary inspection | Debugging symbols, framework analysis |
| MASVS-RESILIENCE | `ios jailbreak disable`, Frida detection hooks | Anti-tampering, anti-debugging |

## OWASP MASTG Test Cases

| Test ID | Description | Objection Approach |
|---------|-------------|-------------------|
| MASTG-TEST-0053 | Testing Local Storage for Sensitive Data | `ios keychain dump`, filesystem inspection |
| MASTG-TEST-0057 | Testing Backups for Sensitive Data | Check backup exclusion attributes |
| MASTG-TEST-0060 | Testing Custom URL Schemes | Hook `application:openURL:options:` |
| MASTG-TEST-0063 | Testing for Sensitive Data in Logs | Monitor NSLog calls via hooking |
| MASTG-TEST-0066 | Testing Enforced App Transport Security | Inspect Info.plist ATS configuration |

## Apple Platform Security Requirements

| Requirement | Assessment Method |
|-------------|-------------------|
| Keychain Access Control | Verify kSecAttrAccessible values via keychain dump |
| App Transport Security | Check Info.plist for NSAllowsArbitraryLoads exceptions |
| Data Protection API | Verify file protection attributes on sensitive files |
| Secure Enclave Usage | Hook SecKey operations for biometric-protected keys |

## references/workflows.md

# Workflows: iOS App Security with Objection

## Workflow 1: iOS Runtime Security Assessment

```
[Setup Environment] --> [Prepare Device] --> [Attach Objection] --> [Runtime Analysis]
       |                      |                     |                      |
       v                      v                     v                      v
[Install Frida]      [Jailbroken: Start    [Connect via USB]    [Data Storage Check]
[Install Objection]   frida-server]        [Spawn target app]   [Network Security]
                     [Non-JB: Patch IPA]                        [Auth Mechanism Review]
                                                                [Binary Protection Test]
                                                                         |
                                                                         v
                                                                [Document Findings]
                                                                [Generate Report]
```

## Workflow 2: SSL Pinning Bypass for Traffic Interception

```
[Configure Burp Proxy] --> [Set device proxy] --> [Attach Objection]
                                                        |
                                                        v
                                              [ios sslpinning disable]
                                                        |
                                                        v
                                              [Navigate app in browser/UI]
                                                        |
                                                        v
                                              [Capture HTTPS traffic in Burp]
                                              [Analyze API endpoints]
                                              [Test authentication flows]
                                              [Check for sensitive data in transit]
```

## Workflow 3: Keychain and Data Storage Assessment

```
[Attach Objection] --> [ios keychain dump] --> [Analyze keychain items]
                              |                        |
                              v                        v
                    [ios nsuserdefaults get]   [Check protection classes]
                              |               [Identify sensitive tokens]
                              v               [Verify encryption at rest]
                    [List app sandbox files]
                              |
                              v
                    [sqlite connect *.db]
                    [Query sensitive tables]
                              |
                              v
                    [memory search "password"]
                    [memory search "token"]
                    [memory search "secret"]
```

## Workflow 4: Jailbreak Detection Assessment

```
[Attach Objection] --> [ios jailbreak disable] --> [Navigate app]
                              |                          |
                              v                   [App functions normally?]
                    [Hook detection methods]        /           \
                    [Monitor file checks]       [Yes]          [No]
                    [Monitor Cydia URL scheme]    |              |
                              |               [Detection       [Additional detection
                              v                bypassed]        methods exist]
                    [Document detection                          |
                     methods found]                    [Hook deeper: search
                    [Assess bypass                      for custom checks]
                     difficulty]                       [Frida script for
                                                       targeted bypass]
```

## Decision Matrix: Testing Approach

| Device State | IPA Access | Approach |
|-------------|-----------|----------|
| Jailbroken | Not needed | Direct Frida server + Objection attach |
| Non-jailbroken | Available | Patch IPA with `objection patchipa` |
| Non-jailbroken | Not available | Request IPA from client or use device management |
| Emulator | N/A | Limited: Frida on Corellium or similar platform |

## scripts

```

```

## scripts/agent.py

```python
#!/usr/bin/env python3
"""iOS app security analysis agent using Objection/Frida concepts.

Performs runtime security assessment of iOS apps including SSL pinning bypass,
keychain dumping, filesystem inspection, and jailbreak detection bypass.
"""

import subprocess
import json
import sys


def run_objection(command, app_id=None, timeout=30):
    """Execute an Objection command against a target app."""
    cmd = ["objection"]
    if app_id:
        cmd.extend(["-g", app_id])
    cmd.extend(["explore", "-c", command])
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        return result.stdout, result.returncode
    except FileNotFoundError:
        return "objection not installed (pip install objection)", 1
    except subprocess.TimeoutExpired:
        return "Command timed out", 1


def run_frida(script_code, app_id, timeout=30):
    """Execute a Frida script against target app."""
    cmd = ["frida", "-U", "-n", app_id, "-e", script_code]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        return result.stdout, result.returncode
    except FileNotFoundError:
        return "frida not installed (pip install frida-tools)", 1
    except subprocess.TimeoutExpired:
        return "Command timed out", 1


def dump_keychain(app_id):
    """Dump keychain items accessible by the application."""
    return run_objection("ios keychain dump", app_id)


def dump_cookies(app_id):
    """Dump HTTP cookies stored by the application."""
    return run_objection("ios cookies get", app_id)


def list_classes(app_id, filter_str=None):
    """List Objective-C classes loaded in the app."""
    cmd = "ios hooking list classes"
    if filter_str:
        cmd += f" --include {filter_str}"
    return run_objection(cmd, app_id)


def check_ssl_pinning(app_id):
    """Check and bypass SSL certificate pinning."""
    return run_objection("ios sslpinning disable", app_id)


def check_jailbreak_detection(app_id):
    """Check for and bypass jailbreak detection."""
    return run_objection("ios jailbreak disable", app_id)


def inspect_filesystem(app_id, path="/"):
    """Inspect the application's filesystem sandbox."""
    return run_objection(f"ls {path}", app_id)


def dump_plist(app_id):
    """Dump application plist configuration files."""
    return run_objection("ios plist cat Info.plist", app_id)


def check_pasteboard(app_id):
    """Check pasteboard/clipboard for sensitive data."""
    return run_objection("ios pasteboard monitor", app_id)


def search_binary_strings(app_id, pattern):
    """Search for strings in the app binary."""
    return run_objection(f"memory search '{pattern}'", app_id)


OWASP_MOBILE_CHECKS = {
    "M1_Improper_Platform_Usage": {
        "checks": ["ios keychain dump", "ios plist cat Info.plist"],
        "description": "Check for misuse of platform security features",
    },
    "M2_Insecure_Data_Storage": {
        "checks": ["ios keychain dump", "ios cookies get", "ios nsuserdefaults get"],
        "description": "Check for sensitive data in insecure storage",
    },
    "M3_Insecure_Communication": {
        "checks": ["ios sslpinning disable"],
        "description": "Test SSL/TLS implementation and certificate pinning",
    },
    "M4_Insecure_Authentication": {
        "checks": ["ios hooking list classes --include Auth",
                    "ios hooking list classes --include Login"],
        "description": "Analyze authentication mechanisms",
    },
    "M5_Insufficient_Cryptography": {
        "checks": ["ios hooking list classes --include Crypto",
                    "ios hooking list classes --include AES"],
        "description": "Review cryptographic implementations",
    },
    "M8_Code_Tampering": {
        "checks": ["ios jailbreak disable"],
        "description": "Test runtime integrity and jailbreak detection",
    },
    "M9_Reverse_Engineering": {
        "checks": ["ios hooking list classes"],
        "description": "Assess reverse engineering protections",
    },
}


def run_owasp_assessment(app_id):
    """Run OWASP Mobile Top 10 security checks."""
    results = {}
    for category, config in OWASP_MOBILE_CHECKS.items():
        category_results = {"description": config["description"], "findings": []}
        for check in config["checks"]:
            output, rc = run_objection(check, app_id)
            category_results["findings"].append({
                "command": check,
                "status": "success" if rc == 0 else "failed",
                "output_preview": output[:200] if output else "",
            })
        results[category] = category_results
    return results


FRIDA_SCRIPTS = {
    "ssl_pinning_bypass": """
ObjC.choose(ObjC.classes.NSURLSessionConfiguration, {
    onMatch: function(instance) {
        instance['- setTLSMinimumSupportedProtocol:'](0);
    }, onComplete: function() {}
});
""",
    "jailbreak_bypass": """
var paths = ['/Applications/Cydia.app', '/usr/sbin/sshd', '/etc/apt'];
Interceptor.attach(ObjC.classes.NSFileManager['- fileExistsAtPath:'].implementation, {
    onEnter: function(args) { this.path = ObjC.Object(args[2]).toString(); },
    onLeave: function(retval) {
        if (paths.some(p => this.path.includes(p))) retval.replace(0);
    }
});
""",
    "keychain_dump": """
var kSecClass = ObjC.classes.__NSDictionary.dictionaryWithObject_forKey_(
    ObjC.classes.__NSCFConstantString.alloc().initWithUTF8String_('genp'),
    ObjC.classes.__NSCFConstantString.alloc().initWithUTF8String_('class')
);
console.log('Keychain query prepared');
""",
}


def generate_report(app_id, assessment_results):
    """Generate iOS security assessment report."""
    findings_count = sum(
        len(cat["findings"]) for cat in assessment_results.values()
    )
    return {
        "app_identifier": app_id,
        "assessment_framework": "OWASP Mobile Top 10",
        "categories_tested": len(assessment_results),
        "total_checks": findings_count,
        "results": assessment_results,
    }


if __name__ == "__main__":
    print("=" * 60)
    print("iOS App Security Analysis Agent (Objection/Frida)")
    print("Runtime analysis, SSL bypass, keychain dump, OWASP checks")
    print("=" * 60)

    app_id = sys.argv[1] if len(sys.argv) > 1 else None

    if not app_id:
        print("\n[DEMO] Usage: python agent.py <app_bundle_id>")
        print("  e.g. python agent.py com.example.app")
        print("\nAvailable checks:")
        for category, config in OWASP_MOBILE_CHECKS.items():
            print(f"  {category}: {config['description']}")
        print("\nFrida scripts available:")
        for name in FRIDA_SCRIPTS:
            print(f"  {name}")
        sys.exit(0)

    print(f"\n[*] Target: {app_id}")
    print("[*] Running OWASP Mobile Top 10 assessment...")

    results = run_owasp_assessment(app_id)
    report = generate_report(app_id, results)

    for category, data in results.items():
        status_counts = {"success": 0, "failed": 0}
        for f in data["findings"]:
            status_counts[f["status"]] += 1
        print(f"\n  [{category}] {data['description']}")
        print(f"    Checks: {status_counts['success']} passed, {status_counts['failed']} failed")

    print(f"\n{json.dumps(report, indent=2, default=str)}")
```

## scripts/process.py

```python
#!/usr/bin/env python3
"""
Objection iOS Security Assessment Automation

Automates common Objection commands for iOS app security testing.
Runs keychain dump, storage inspection, SSL pinning check, and jailbreak detection analysis.

Usage:
    python process.py --bundle-id com.target.app [--device-id UDID] [--output report.json]
"""

import argparse
import json
import subprocess
import sys
import re
from datetime import datetime
from pathlib import Path


class ObjectionAssessor:
    """Automates Objection-based iOS security assessment tasks."""

    def __init__(self, bundle_id: str, device_id: str = None):
        self.bundle_id = bundle_id
        self.device_id = device_id
        self.findings = []

    def _run_objection_command(self, command: str, timeout: int = 30) -> str:
        """Execute an Objection command and return output."""
        cmd = ["objection", "--gadget", self.bundle_id, "run", command]
        if self.device_id:
            cmd.insert(1, "--serial")
            cmd.insert(2, self.device_id)

        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=timeout,
            )
            return result.stdout + result.stderr
        except subprocess.TimeoutExpired:
            return f"TIMEOUT: Command '{command}' exceeded {timeout}s"
        except FileNotFoundError:
            return "ERROR: Objection not found. Install with: pip install objection"

    def _run_frida_command(self, script: str, timeout: int = 15) -> str:
        """Execute a Frida script snippet."""
        cmd = ["frida", "-U", "-n", self.bundle_id, "-e", script]
        if self.device_id:
            cmd.extend(["-D", self.device_id])

        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=timeout,
            )
            return result.stdout
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return ""

    def check_frida_connectivity(self) -> dict:
        """Verify Frida can connect to the device."""
        cmd = ["frida-ps", "-U"]
        if self.device_id:
            cmd.extend(["-D", self.device_id])

        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            connected = result.returncode == 0
            processes = len(result.stdout.strip().split("\n")) - 1 if connected else 0
            return {
                "connected": connected,
                "process_count": processes,
                "target_running": self.bundle_id in result.stdout,
            }
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return {"connected": False, "process_count": 0, "target_running": False}

    def dump_keychain(self) -> dict:
        """Dump keychain items accessible to the app."""
        output = self._run_objection_command("ios keychain dump")
        items = []
        current_item = {}

        for line in output.split("\n"):
            line = line.strip()
            if "Service" in line and ":" in line:
                if current_item:
                    items.append(current_item)
                current_item = {"service": line.split(":", 1)[-1].strip()}
            elif "Account" in line and ":" in line:
                current_item["account"] = line.split(":", 1)[-1].strip()
            elif "Data" in line and ":" in line:
                data = line.split(":", 1)[-1].strip()
                current_item["data_preview"] = data[:50] + "..." if len(data) > 50 else data
                current_item["data_length"] = len(data)

        if current_item:
            items.append(current_item)

        finding = {
            "check": "keychain_dump",
            "category": "MASVS-STORAGE",
            "owasp_mobile": "M9",
            "items_found": len(items),
            "items": items[:20],
            "severity": "HIGH" if items else "INFO",
            "description": f"Found {len(items)} keychain items accessible to the application",
        }
        self.findings.append(finding)
        return finding

    def check_nsuserdefaults(self) -> dict:
        """Inspect NSUserDefaults for sensitive data."""
        output = self._run_objection_command("ios nsuserdefaults get")
        sensitive_patterns = [
            "password", "token", "secret", "key", "auth",
            "session", "credential", "api_key", "apikey",
        ]

        sensitive_entries = []
        for line in output.split("\n"):
            line_lower = line.lower()
            for pattern in sensitive_patterns:
                if pattern in line_lower:
                    sensitive_entries.append(line.strip())
                    break

        finding = {
            "check": "nsuserdefaults",
            "category": "MASVS-STORAGE",
            "owasp_mobile": "M9",
            "sensitive_entries": len(sensitive_entries),
            "entries": sensitive_entries[:10],
            "severity": "HIGH" if sensitive_entries else "PASS",
            "description": f"Found {len(sensitive_entries)} potentially sensitive NSUserDefaults entries",
        }
        self.findings.append(finding)
        return finding

    def check_ssl_pinning(self) -> dict:
        """Assess SSL pinning implementation."""
        output = self._run_objection_command("ios sslpinning disable")
        pinning_detected = "pinning" in output.lower() or "hook" in output.lower()

        finding = {
            "check": "ssl_pinning",
            "category": "MASVS-NETWORK",
            "owasp_mobile": "M5",
            "pinning_detected": pinning_detected,
            "bypass_output": output[:500],
            "severity": "MEDIUM" if not pinning_detected else "INFO",
            "description": "SSL pinning " + ("detected and bypassed" if pinning_detected else "not detected"),
        }
        self.findings.append(finding)
        return finding

    def check_jailbreak_detection(self) -> dict:
        """Assess jailbreak detection implementation."""
        output = self._run_objection_command("ios jailbreak disable")
        detection_found = "hook" in output.lower() or "bypass" in output.lower()

        finding = {
            "check": "jailbreak_detection",
            "category": "MASVS-RESILIENCE",
            "owasp_mobile": "M7",
            "detection_implemented": detection_found,
            "bypass_output": output[:500],
            "severity": "MEDIUM" if not detection_found else "INFO",
            "description": "Jailbreak detection " + ("found" if detection_found else "not found or not implemented"),
        }
        self.findings.append(finding)
        return finding

    def search_sensitive_memory(self) -> dict:
        """Search app memory for sensitive strings."""
        patterns = ["password", "Bearer ", "eyJ", "api_key", "secret"]
        memory_findings = []

        for pattern in patterns:
            output = self._run_objection_command(f'memory search "{pattern}" --string')
            matches = output.count("Found")
            if matches > 0:
                memory_findings.append({
                    "pattern": pattern,
                    "matches": matches,
                })

        finding = {
            "check": "memory_search",
            "category": "MASVS-STORAGE",
            "owasp_mobile": "M9",
            "patterns_with_matches": len(memory_findings),
            "details": memory_findings,
            "severity": "HIGH" if memory_findings else "PASS",
            "description": f"Found sensitive patterns in memory for {len(memory_findings)} search terms",
        }
        self.findings.append(finding)
        return finding

    def get_app_info(self) -> dict:
        """Gather basic app information."""
        output = self._run_objection_command("ios info binary")
        env_output = self._run_objection_command("env")

        return {
            "bundle_id": self.bundle_id,
            "binary_info": output[:1000],
            "environment": env_output[:1000],
        }

    def generate_report(self) -> dict:
        """Generate consolidated assessment report."""
        severity_counts = {"HIGH": 0, "MEDIUM": 0, "LOW": 0, "INFO": 0, "PASS": 0}
        for f in self.findings:
            sev = f.get("severity", "INFO")
            severity_counts[sev] = severity_counts.get(sev, 0) + 1

        return {
            "assessment": {
                "target": self.bundle_id,
                "date": datetime.now().isoformat(),
                "tool": "Objection (Frida-powered)",
                "type": "iOS Runtime Security Assessment",
            },
            "summary": {
                "total_checks": len(self.findings),
                "severity_breakdown": severity_counts,
                "critical_findings": [
                    f for f in self.findings if f.get("severity") in ("HIGH", "CRITICAL")
                ],
            },
            "findings": self.findings,
        }


def main():
    parser = argparse.ArgumentParser(
        description="Objection iOS Security Assessment Automation"
    )
    parser.add_argument("--bundle-id", required=True, help="iOS app bundle identifier")
    parser.add_argument("--device-id", help="Device UDID for targeting specific device")
    parser.add_argument("--output", default="objection_report.json", help="Output report path")
    parser.add_argument("--checks", nargs="+",
                        default=["keychain", "nsuserdefaults", "ssl", "jailbreak", "memory"],
                        help="Checks to run")
    args = parser.parse_args()

    assessor = ObjectionAssessor(args.bundle_id, args.device_id)

    # Verify connectivity
    connectivity = assessor.check_frida_connectivity()
    if not connectivity["connected"]:
        print("[-] ERROR: Cannot connect to device via Frida")
        print("    Ensure Frida server is running on device or IPA is patched")
        sys.exit(1)

    print(f"[+] Connected to device. Target running: {connectivity['target_running']}")

    # Run selected checks
    check_map = {
        "keychain": assessor.dump_keychain,
        "nsuserdefaults": assessor.check_nsuserdefaults,
        "ssl": assessor.check_ssl_pinning,
        "jailbreak": assessor.check_jailbreak_detection,
        "memory": assessor.search_sensitive_memory,
    }

    for check in args.checks:
        if check in check_map:
            print(f"[*] Running check: {check}")
            result = check_map[check]()
            print(f"    Severity: {result['severity']} - {result['description']}")

    # Generate report
    report = assessor.generate_report()

    with open(args.output, "w") as f:
        json.dump(report, f, indent=2)
    print(f"\n[+] Report saved: {args.output}")

    # Summary
    high_count = report["summary"]["severity_breakdown"].get("HIGH", 0)
    if high_count > 0:
        print(f"[!] {high_count} HIGH severity findings require attention")


if __name__ == "__main__":
    main()
```

