Skip to content

Latest commit

 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

instrumented android session orchestrator.

AVD/physical device management, UI automation via uiautomator2, Frida instrumentation, mitmproxy traffic interception, static analysis, evidence collection. daemon mode with JSON-RPC API and MCP server for agent-driven automation.

demo

Architecture

architecture

Install

git clone https://github.com/AbuCTF/Golem.git
cd Golem
./setup.sh

handles everything: system deps, Java, Android SDK, system image, KVM, Python package, static analysis tools. works on arch, debian/ubuntu, fedora, opensuse, void, alpine.

flags: --no-system, --no-sdk, --no-static, --verify.

The current release is v0.7.1. See CHANGELOG.md for the release notes.

The Python package and CLI also use host-native Android SDK paths on Linux, macOS, and Windows. setup.sh is the Linux bootstrap; on other hosts install the Android SDK/tooling normally and use pip install -e '.[all,dev]'.

Quick start

Prepare the latest Play build for the default x86_64 emulator:

golem doctor
golem target com.example.app --workspace ./targets/com.example.app

This resolves the current Play version, downloads and validates its base/split APK set with gplaydl, decompiles every DEX with JADX, decodes every base/split manifest and Smali tree with apktool, and writes target.json, analysis.json, and a source-linked review.md queue. To install and launch in the same command:

golem target com.example.app \
  --workspace ./targets/com.example.app \
  --session example-test \
  --headed

Use --arch arm64 for an arm64 physical device. Golem checks the APK/device ABI intersection before installation and returns a specific recovery hint for missing splits, signing conflicts, version downgrades, and storage failures.

CLI

golem create test-phone --headed
golem create headless-a
golem list
golem status test-phone
golem observe test-phone
golem tap test-phone "Settings"
golem type test-phone "search query"
golem fill test-phone "Search" "hello world"
golem press test-phone back
golem swipe test-phone up
golem screenshot test-phone evidence.png
golem screen test-phone
golem diff test-phone
golem health test-phone
golem shell test-phone "pm list packages -3"
golem install test-phone target.apk
golem launch test-phone com.target.app
golem app-info test-phone com.target.app
golem logcat test-phone --package com.target.app --clear
golem deeplink test-phone 'example://open/item'
golem cert-install test-phone
golem proxy-on test-phone --port 8082
golem proxy-off test-phone
golem frida-scripts
golem instrument test-phone com.target.app network_monitor intent_intercept --duration 15
golem frida-messages test-phone --script network_monitor --json
golem checkpoint test-phone save before-login
golem persona "hunt-seed-001"
golem evidence test-phone list
golem evidence test-phone capture --desc "login screen"
golem analyze target.apk
golem analyze base.apk config.x86_64.apk config.xxhdpi.apk
golem doctor --profile dynamic --json
golem pull com.example.app --arch x86_64
golem target com.example.app --session test-phone --headed
golem experiment test-phone start "exported service" "an untrusted caller can write a private marker"
golem close test-phone
golem destroy test-phone

# start the daemon
golem daemon

# start the MCP server (stdio)
golem mcp

Direct Client

from golem import Pool

async with Pool() as pool:
    s = await pool.create("test-phone", headless=True)

    # observe interactive elements (indexed for tap targets)
    elements = await s.observe()
    for el in elements:
        print(f"[{el.idx}] {el.cls}{el.text}")

    # tap by index, text, or resource ID
    await s.tap(0)
    await s.tap("Settings")
    await s.tap("id:com.android.settings:id/search_bar")

    # type and fill
    await s.fill("Search", "wifi")
    await s.type_text("hello", clear=True)

    # screen state after every action
    state = await s.screen_state()

    # screen diffing — what changed since last observe
    diff = await s.observe_diff()
    print(diff.summary())

    # screenshots
    png = await s.screenshot("evidence.png")

    # shell commands
    output = await s.shell("dumpsys activity top")

    # app lifecycle
    await s.app_install("target.apk")
    await s.app_start("com.target.app")
    apps = await s.app_list()

    # atomic early instrumentation: spawn paused, load hooks, resume
    await s.frida_instrument("com.target.app", "network_monitor", "crypto_monitor")
    messages = await s.frida_messages("crypto_monitor")
    await s.frida_detach()

    # bounded runtime diagnostics and reproducible reset points
    await s.logcat(clear=True)
    await s.open_uri("example://open/item")
    logs = await s.logcat(package="com.target.app", lines=500)
    await s.checkpoint("save", "before-login")

    # proxy + cert
    await s.proxy_install_cert()
    await s.proxy_configure(port=8082)

    # evidence collection
    eid = await s.capture_screenshot_evidence("login bypass")
    items = s.evidence.list()

    # health monitoring
    status = await s.health_check()

    await s.close()

    # reopen later — device still running
    s = await pool.get("test-phone", launch=True)

Multi-session / cross-account

from golem import Pool, SessionGroup

async with Pool() as pool:
    group = SessionGroup(pool, "idor-test")
    await group.add("account-a")
    await group.add("account-b")

    await group.install_all("target.apk")
    await group.launch_all("com.target.app")

    # observe all sessions in parallel
    results = await group.observe_all()

    # run arbitrary action across all sessions
    results = await group.run_all(lambda s: s.tap("Profile"))

BBP Harness Integration

from golem.bbp_bridge import GolemHuntSession

async with GolemHuntSession("hunt-opensea-001", persona_seed="opensea-a") as hunt:
    await hunt.prepare("com.opensea.app", workspace="./targets/com.opensea.app")
    await hunt.instrument(["network_monitor", "crypto_monitor", "intent_intercept"])

    elements = await hunt.observe()
    await hunt.tap("Sign in")
    eid = await hunt.capture("login screen reached")

    messages = await hunt.frida_messages("crypto_monitor")
    hunt.add_finding(
        title="hardcoded API key in crypto init",
        category="info-disclosure",
        severity="medium",
        description="AES key derived from static seed",
        evidence_ids=[eid],
    )

    print(hunt.findings_summary())

Features

Feature Description
Device management AVD create/boot/shutdown/checkpoints + USB/network ADB devices with runtime ABI discovery
Session isolation Separate profile dir, u2 connection, Frida bridge, proxy per session
UI automation observe, tap, type, fill, press, swipe, scroll_to, wait_element
Screen diffing What changed between observations (activity, elements, count)
Context tracking Ring buffer of screen states (50) and actions (200)
Frida instrumentation Atomic spawn/load/resume, attach retries, process discovery, detach diagnostics, and eight reusable scripts
Runtime diagnostics Bounded package-aware logcat, installed/runtime metadata, deep-link launches, and clean state checkpoints
Traffic interception mitmproxy with tmpfs CA cert install for Android 11+
Play acquisition Latest/version-pinned gplaydl downloads, split validation, hashes, ABI inventory, versioned workspaces
Static analysis Whole split-set JADX plus apktool Smali, APKiD, redacted secret locations, endpoints, manifest security context, source-linked review queue
Device personas 6 real device profiles, 6 carriers, seeded PRNG for consistent fingerprints
Evidence store Screenshot, traffic, Frida, shell, observe capture with index
Health monitoring Battery, memory, disk, u2 responsiveness, periodic checks
Multi-session Parallel observe/screenshot/action, SessionGroup, cross-account testing
Experiment ledger Persistent hypotheses, preconditions, actions, observations, evidence links, and explicit outcomes
MCP server 43 acquisition, analysis, experiment, job, UI, runtime, Frida, proxy, health, and evidence tools over stdio; long jobs can be polled or cancelled and large reports default to bounded summaries
JSON-RPC daemon Local Unix socket server (loopback TCP fallback on Windows) for persistent session management
BBP bridge GolemHuntSession for bug-bounty harness integration

Frida scripts

Script What it hooks
ssl_bypass TrustManager, OkHttp CertificatePinner, Conscrypt, WebViewClient SSL errors, NetworkSecurityConfig
root_bypass su paths, Runtime.exec, PackageManager (root packages), Build.TAGS, RootBeer
emulator_bypass Build.*, TelephonyManager, SystemProperties, sensors, emulator files
crypto_monitor Cipher.doFinal, SecretKeySpec, MessageDigest, Mac, IvParameterSpec
webview_dump addJavascriptInterface, loadUrl, evaluateJavascript, shouldOverrideUrlLoading
intent_intercept startActivity, sendBroadcast, startService, ContentResolver.query, deep links
sharedprefs_monitor getString/putString reads and writes with interesting-key filtering
network_monitor passive URL, Android/OkHttp connection, response, error, and cleartext-policy diagnostics with query redaction

Device personas

Profile Model
Pixel 7 Google Tensor
Pixel 6 Pro Google Tensor
Galaxy S23 Ultra Samsung Exynos
Galaxy A54 Samsung Exynos
Redmi Note 12 Xiaomi Snapdragon
OPPO A58 OPPO MediaTek

each persona bundles matching IMEI, Android ID, build props, SIM info, carrier. same seed = same identity.

See Agent workflow for the artifact contract, recovery rules, and a complete acquisition-to-report sequence.

License

MIT

About

Android Session Orchestrator

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages