Skip to content

Scaling Operations

You have patched a target, deployed it, pushed payloads, verified injection, captured evidence, and written a report. One app. One engagement. Fifteen to twenty minutes if you worked manually, five to seven with automation. The methodology works. The toolkit works. The question now is what happens when you need to do it again.

Not once. Ten times. Twenty. Fifty different applications across a financial services portfolio. A re-test of every target after a toolkit update changes the HookEngine. Continuous validation runs against a catalog of apps that ship new versions every two weeks. A device farm running parallel assessments against the same target on different Android versions, screen sizes, and API levels.

One target at a time does not scale. And the problem is not just speed — it is consistency. The third time you manually patch an APK, you will forget a permission grant. The seventh time, you will push the wrong payload directory. The fifteenth time, you will lose track of which target used which sensor profile, and your report will have a gap you cannot fill because the engagement was three days ago and the logs are gone.

This chapter teaches you to build the infrastructure that turns ad-hoc engagements into a repeatable, scalable operation. A payload library that serves any engagement. A target catalog that preserves everything you learn. Batch scripts that patch, deploy, and verify dozens of targets in a single run. Configuration management that makes every engagement reproducible by anyone on the team.

This is the last chapter in Part III. It is not about new techniques — it is about operationalizing the techniques you already have. Parts IV and V go deeper into smali internals, custom hooks, anti-tamper evasion, automation pipelines, and defense architecture.

Ethics Note: Scaling capability means scaling responsibility. Every target in a batch run needs the same authorization and scope as a single engagement. Automation does not create permission. A script that patches fifty apps still requires fifty authorized scope entries. If anything, the speed of automated operations makes the rules of engagement from Chapter 2 more important, not less — because mistakes propagate faster when they are automated.


Here is a realistic breakdown of a single manual engagement:

StepTime
Decode the APK with apktool2 min
Reconnaissance (camera API, location API, sensors, defenses)3 min
Patch with patch-tool3 min
Install, grant permissions, push payloads3 min
Launch and verify injection via logcat3 min
Capture evidence and write notes3 min
Total~17 min

With scripted automation, the same steps collapse to five to seven minutes — most of that is waiting for adb install and the app to launch. The human effort drops to choosing payloads and reviewing logs.

That difference is negligible for a single target. For ten targets, it is the difference between three hours and one hour. For a re-test run of fifty targets after a toolkit update, it is the difference between two full days and a single afternoon. And the automated version produces consistent, machine-parseable output that feeds directly into reports.

The investment in infrastructure pays for itself on the second engagement. By the fifth, it is indispensable.


Payloads — face frames, location configs, sensor profiles — are the raw materials of every engagement. You will reuse the same payloads across dozens of targets. The key is organizing them so that selecting the right combination for any engagement is fast, obvious, and error-free.

~/payloads/
faces/
male_caucasian_30s/
neutral/ 30 frames, forward-facing, slight natural movement
tilt_left/ 20 frames, head tilting left sequence
tilt_right/ 20 frames, head tilting right sequence
nod/ 25 frames, nodding sequence
blink/ 15 frames, blink sequence
female_asian_20s/
neutral/
tilt_left/
tilt_right/
nod/
blink/
male_african_40s/
neutral/
tilt_left/
...
documents/
id_front.png Sample ID card front
id_back.png Sample ID card back
passport.png Sample passport page
barcodes/
qr_test.png Generic test QR code
locations/
us_east/
nyc_midtown.json
nyc_walking_route.json
boston_downtown.json
us_west/
sf_downtown.json
la_westside.json
eu/
london_city.json
berlin_mitte.json
paris_centre.json
apac/
tokyo_shibuya.json
singapore_cbd.json
sensors/
holding.json For selfie/face scans (slight tremor)
still.json Phone on table (zero motion)
walking.json Step-like pattern
tilt-left.json Matches face tilt_left frames
tilt-right.json Matches face tilt_right frames
nod.json Matches face nod frames

The top-level split is by data type: faces, locations, sensors. Within faces, the split is by demographic profile, then by action sequence. Within locations, the split is by region, then by specific location. Sensors are flat because the set of motion types is small and universal.

Liveness SDKs are trained on diverse face datasets, but their performance is not uniform across all face types. Some SDKs have measurably different acceptance thresholds for different skin tones, facial structures, and age groups. This is not a hypothetical — it is a documented characteristic of machine learning models trained on imbalanced datasets.

Organizing your payload library by demographic serves two purposes. First, it lets you test whether a target SDK exhibits differential performance — a finding that belongs in your report regardless of whether the bypass succeeds. Second, it lets you quickly match a payload to a scenario. If the engagement involves a specific enrolled identity with known characteristics, you select the payload set that most closely matches. The goal is not to exploit demographic bias — it is to test for it and to ensure your payloads are realistic for the scenario.

Over time, you will build payload sets across multiple demographics. A well-stocked library has at least three to four demographic profiles, each with the full set of action sequences. The broader your library, the more scenarios you can cover without recording new material.

This is the single most important concept in payload management. Frame sequences and sensor configs must tell the same physical story. If your frames show a head tilting left, your sensor config must report the corresponding device rotation. If the frames show a stationary face, your sensor config must report the subtle tremor of a hand-held device, not perfect stillness.

The reason is straightforward: advanced liveness SDKs cross-validate camera and sensor data. The camera says the visual scene is rotating. The gyroscope should confirm rotation. The accelerometer should show the corresponding tilt. If there is a mismatch — visual motion without physical motion, or physical motion without visual change — the SDK flags it as injection.

Think of it like dubbing a film. If the lips move but the audio does not match, the audience knows something is wrong. Your camera frames are the video. Your sensor config is the audio. They must be synchronized.

Build and deploy payloads as matched pairs:

Camera SequenceSensor ConfigUse Case
neutral/holding.jsonStatic face scan, passive liveness
tilt_left/tilt-left.json”Tilt left” active liveness challenge
tilt_right/tilt-right.json”Tilt right” active liveness challenge
nod/nod.json”Nod” active liveness challenge
blink/holding.json”Blink” challenge (facial only, no device motion)

Notice that blink/ pairs with holding.json, not a dedicated blink sensor config. Blinking does not move the phone. The person holds still and blinks. The sensor config for that scenario is the same gentle hand tremor as a static face scan. Getting this right requires thinking about what the physical scenario actually looks like, not just what the camera sees.

When you need a new payload set — a new demographic, a new action, a new resolution — record a short video and extract frames with ffmpeg:

Terminal window
# Record 3-5 seconds at selfie camera resolution
# Then extract at 15fps:
ffmpeg -i recording.mp4 -vf "fps=15,scale=640:480" frames/%03d.png

The 15fps extraction rate matches the typical processing rate of liveness SDKs. Faster rates waste storage without benefit — most SDKs process at 10-20fps regardless of input rate. Slower rates risk temporal gaps that sophisticated SDKs can detect.

Quality checklist for new frame sequences:

  • Resolution: 640x480 or 1280x720 (match the target’s camera preview resolution)
  • Lighting: even, no harsh shadows across the face
  • Background: neutral, solid color preferred
  • Face centered and filling at least 30% of the frame area
  • Movement smooth and continuous for action sequences (no jerky cuts)
  • 15-30 frames per sequence (1-2 seconds at 15fps)
  • No visible artifacts, compression blocks, or moire patterns
  • For action sequences, movement should start from a neutral position and return to it

Test new sequences against at least one target before adding them to the library. A sequence that looks good to your eye may fail face detection if the lighting is uneven or the face is too small in frame.

Location configs are simpler than face payloads — each is a single JSON file specifying coordinates, altitude, accuracy, and speed. Organize by region and city. Include both static configs (device at a fixed location) and route configs (device moving along a path) for targets that check for realistic movement patterns.

A well-stocked location library covers the regions where your targets operate. Financial apps often geofence by country. Ride-sharing and delivery apps geofence by city. Know your target’s requirements and stock the corresponding configs.

The sensor library is the smallest collection but arguably the most critical for consistency. Each profile defines accelerometer, gyroscope, and magnetometer base values plus the motion pattern applied over time. The toolkit computes all derived sensors (gravity, linear acceleration, rotation vector, and others) automatically from these base values.

Keep sensor profiles minimal and well-documented. A holding.json that has been validated against ten targets is worth more than five experimental profiles that have never been tested. Label each profile with its intended use case and the camera sequences it pairs with.


After every engagement, you know things about the target that took time and effort to discover. Which camera API it uses. Which liveness SDK it embeds. Whether it checks certificate pinning. What challenges its active liveness presents. Which evasion techniques you applied. What payloads worked.

If you do not write this down in a structured format, you will re-discover it all next time. The target catalog is the solution: a collection of structured intelligence records, one per target, that capture everything operationally relevant about each application you have tested.

Each target gets a YAML file named after its package:

target_catalog/com.bank.app.yaml
package: com.bank.app
version_tested: "3.2.1"
last_tested: "2026-03-15"
# API surfaces
camera_api: camerax
location_api: fused
sensors: accel + gyro
# Liveness configuration
liveness_type: active
active_challenges:
- tilt_left
- tilt_right
- nod
# Defense layers
anti_tamper:
signature_check: "SecurityManager.verifySignature()"
dex_integrity: none
cert_pinning: "OkHttp CertificatePinner on api.bank.com"
installer_check: none
# What we applied
hooks_applied:
- "analyze(): com/bank/app/FaceAnalyzer.smali"
- "toBitmap(): 1 file"
- "onLocationResult(): com/bank/app/LocationVerifier.smali"
- "onSensorChanged(): com/bank/app/MotionChecker.smali"
evasion_applied:
- "signature: forced isValid() to return true"
- "pinning: added user CAs to network_security_config.xml"
# Payloads that worked
payloads_used:
frames: "male_caucasian_30s/neutral + tilt_left + nod"
location: "times-square.json"
sensors: "holding.json + tilt-left.json + nod.json"
# Outcome
result: FULL_BYPASS
notes: |
SDK processes frames synchronously in analyze().
15fps frame rate sufficient. No frame hash verification.
Location check is one-shot on step 2 -- no continuous monitoring.
Active liveness challenges appear in random order.
Challenge order: random each run, but always exactly three.
Frame injection latency under 8ms -- well within SDK timeout.

liveness_type records whether the SDK uses passive (single frame analysis) or active (user performs actions) liveness detection. This determines which payload pairs you need.

active_challenges lists the specific actions the SDK requests. This directly maps to your matched pair table — each challenge needs a corresponding frame sequence and sensor config.

anti_tamper documents the defense layers you encountered. This is your evasion checklist for re-engagement. If the app checks signature integrity, you know you need the signature bypass patch. If it pins certificates, you know to modify the network security config.

evasion_applied is the complement to anti_tamper — it records exactly what you did to defeat each defense. This is the most valuable field for re-engagement because it eliminates the trial-and-error of figuring out which evasion technique works against which defense.

payloads_used links the engagement to specific items in your payload library. When you re-engage, you know exactly which payloads to push.

result uses a simple taxonomy: FULL_BYPASS (all checks passed), PARTIAL_BYPASS (some checks passed), FAILED (injection detected or blocked), BLOCKED (could not patch or deploy). This enables summary reporting across the catalog.

When a target releases version 3.3.0 and the client asks for a re-test, you open the catalog entry. You already know the camera API, the liveness type, the defense layers, the payloads that worked. The only question is: did anything change?

The workflow becomes: patch the new version, deploy with the same payloads, verify injection, diff the behavior against the catalog entry. If everything matches, the re-engagement takes five minutes. If something changed — a new defense layer, a different liveness challenge, an API migration — you update the catalog entry with the new information and adjust accordingly.

This is institutional knowledge. It is not in anyone’s head. It is not in a Slack thread or an email chain. It is in a structured, version-controlled file that anyone on the team can read and act on.

The catalog’s value compounds over time. After fifty engagements, you have a dataset that answers questions no single engagement could:

  • Which liveness SDKs are most common in your target vertical?
  • Which anti-tamper measures appear most frequently?
  • What is your bypass success rate against active vs. passive liveness?
  • Which payload demographics have the highest acceptance rates?
  • Are there defense patterns that consistently block injection?

These are the questions that inform strategy — which capabilities to invest in, which defenses to prioritize research against, where the toolkit has gaps. The catalog makes them answerable.


The scripts in this section automate the three phases of a multi-target engagement: patching, deployment, and reporting. Each script is designed to be run independently or chained together in a pipeline.

Place all target APKs in a directory and patch them in a single pass. The materials kit includes starter scripts at materials/scripts/batch-patch.sh and materials/scripts/batch-deploy.sh — adapt them for your engagements or use the expanded versions below:

#!/bin/bash
# patch-all.sh -- Patch every APK in a target directory
set -euo pipefail
PATCH_TOOL="patch-tool.jar"
TARGETS_DIR="./targets"
OUTPUT_DIR="./patched"
WORK_DIR="./work"
REPORTS_DIR="./reports"
mkdir -p "$OUTPUT_DIR" "$WORK_DIR" "$REPORTS_DIR"
success=0
failed=0
for apk in "$TARGETS_DIR"/*.apk; do
[ -f "$apk" ] || continue
name=$(basename "$apk" .apk)
echo "=== Patching: $name ==="
if java -jar "$PATCH_TOOL" "$apk" \
--out "$OUTPUT_DIR/${name}-patched.apk" \
--work-dir "$WORK_DIR/$name" 2>&1 | tee "$REPORTS_DIR/${name}_patch.log"; then
echo "[+] $name patched successfully"
((success++))
else
echo "[-] $name FAILED"
((failed++))
fi
echo ""
done
echo "=== Patch Summary: $success succeeded, $failed failed ==="

The set -euo pipefail at the top catches common shell scripting errors: unset variables, pipe failures, and unexpected exits. The [ -f "$apk" ] || continue guard handles the case where the glob matches nothing (an empty directory). These are small details, but in batch operations, small details prevent cascading failures.

This script installs each patched APK, grants permissions, pushes payloads, launches the app, and checks logcat for evidence of active injection:

#!/bin/bash
# deploy-all.sh -- Deploy patched APKs and verify injection
set -uo pipefail
PATCHED_DIR="./patched"
REPORTS_DIR="./reports"
PAYLOAD_FRAMES="$HOME/payloads/faces/male_caucasian_30s/neutral"
PAYLOAD_LOCATION="$HOME/payloads/locations/times-square.json"
PAYLOAD_SENSOR="$HOME/payloads/sensors/holding.json"
mkdir -p "$REPORTS_DIR"
for apk in "$PATCHED_DIR"/*-patched.apk; do
[ -f "$apk" ] || continue
name=$(basename "$apk" -patched.apk)
# Extract package name from the APK
pkg=$(aapt2 dump badging "$apk" 2>/dev/null | \
grep "package:" | sed "s/.*name='\([^']*\)'.*/\1/")
if [ -z "$pkg" ]; then
echo "[-] $name: could not extract package name, skipping"
continue
fi
echo "=== Deploying: $name ($pkg) ==="
# Clean install
adb uninstall "$pkg" 2>/dev/null || true
if ! adb install -r "$apk"; then
echo "[-] $name: install failed, skipping"
continue
fi
# Grant permissions
adb shell pm grant "$pkg" android.permission.CAMERA 2>/dev/null || true
adb shell pm grant "$pkg" android.permission.ACCESS_FINE_LOCATION 2>/dev/null || true
adb shell pm grant "$pkg" android.permission.READ_EXTERNAL_STORAGE 2>/dev/null || true
adb shell pm grant "$pkg" android.permission.WRITE_EXTERNAL_STORAGE 2>/dev/null || true
adb shell appops set "$pkg" MANAGE_EXTERNAL_STORAGE allow 2>/dev/null || true
# Push payloads
adb shell rm -rf /sdcard/poc_frames/ /sdcard/poc_location/ /sdcard/poc_sensor/
adb shell mkdir -p /sdcard/poc_frames/ /sdcard/poc_location/ /sdcard/poc_sensor/
adb push "$PAYLOAD_FRAMES"/. /sdcard/poc_frames/
adb push "$PAYLOAD_LOCATION" /sdcard/poc_location/config.json
adb push "$PAYLOAD_SENSOR" /sdcard/poc_sensor/config.json
# Clear logcat and launch
adb logcat -c
launcher=$(adb shell cmd package resolve-activity --brief "$pkg" 2>/dev/null | tail -1)
adb shell am start -n "$launcher" 2>/dev/null || \
adb shell monkey -p "$pkg" -c android.intent.category.LAUNCHER 1
# Wait for app to initialize and hooks to fire
sleep 5
# Capture injection logs
adb logcat -d -s FrameInterceptor,LocationInterceptor,SensorInterceptor,HookEngine \
> "$REPORTS_DIR/${name}_delivery.log"
if grep -q "DELIVERED\|Auto-enabled\|injection active" "$REPORTS_DIR/${name}_delivery.log"; then
echo "[+] $name: injection ACTIVE"
else
echo "[-] $name: injection NOT detected"
fi
# Stop the app before moving to next target
adb shell am force-stop "$pkg"
echo ""
done

Notice the cleanup at the top of each iteration: the script removes existing payload directories before pushing new ones. This prevents stale payloads from a previous run from contaminating the current engagement. It also clears logcat before launch so that the captured log contains only output from this specific run.

The fallback from resolve-activity to monkey handles targets where the launcher activity cannot be resolved programmatically — a common issue with apps that use activity aliases or non-standard launch configurations.

After all deployments complete, generate a summary table:

#!/bin/bash
# summary.sh -- Generate engagement summary from delivery logs
REPORTS_DIR="./reports"
echo "=== Engagement Summary ==="
echo ""
printf "%-35s %8s %8s %8s %s\n" "TARGET" "FRAMES" "LOCS" "SENSORS" "STATUS"
printf "%-35s %8s %8s %8s %s\n" "------" "------" "----" "-------" "------"
total=0
active=0
for log in "$REPORTS_DIR"/*_delivery.log; do
[ -f "$log" ] || continue
name=$(basename "$log" _delivery.log)
frames=$(grep -c "FRAME_DELIVERED" "$log" 2>/dev/null || echo 0)
locations=$(grep -c "LOCATION_DELIVERED" "$log" 2>/dev/null || echo 0)
sensors=$(grep -c "SENSOR_DELIVERED" "$log" 2>/dev/null || echo 0)
if [ "$frames" -gt 0 ] || [ "$locations" -gt 0 ] || [ "$sensors" -gt 0 ]; then
status="ACTIVE"
((active++))
else
status="FAILED"
fi
((total++))
printf "%-35s %8s %8s %8s %s\n" "$name" "$frames" "$locations" "$sensors" "$status"
done
echo ""
echo "=== $active / $total targets with active injection ==="

This produces output you can paste directly into an engagement report or pipe to a file for archival. The counts tell you not just whether injection was active, but how many frames, location updates, and sensor events were delivered — a proxy for how thoroughly the injection exercised the target’s verification pipeline.

Batch operations fail. APKs that will not decode. Targets that crash on launch. Permission grants that the OS rejects. Device storage that fills up mid-push. The key principle is: a failure in one target must not abort the entire run.

Use || true or || continue after commands that may fail for a specific target but should not stop the batch. Log every failure with the target name so you can investigate after the run completes. Never use set -e in a deploy script where individual target failures are expected — use it in the patch script where a failure is more likely to indicate a systemic problem.

After a batch run, review the summary report first, then investigate individual failure logs only for targets that did not show active injection.


The toolkit’s injection system was designed for headless operation from the start. All three subsystems — frame injection, location spoofing, sensor injection — auto-enable when they detect payload files in the expected directories on device storage. No overlay interaction is needed. No human taps a button. Push the files, launch the app, and injection activates.

This design makes the toolkit compatible with any deployment mechanism that can install an APK, push files, and launch an activity.

The auto-enable conditions are simple:

SubsystemAuto-Enable Condition
Frame Injection/sdcard/poc_frames/ contains at least one PNG file
Location Spoofing/sdcard/poc_location/config.json exists
Sensor Injection/sdcard/poc_sensor/config.json exists

Push payloads before launching the target app. The Application.onCreate() hook checks for payload files during initialization. If they are present, the corresponding interceptor arms itself and begins delivering synthetic data as soon as the app’s callbacks register. No timing dependency, no race condition — the check happens before any camera, location, or sensor code runs.

When you have multiple devices connected via ADB — physical devices, emulators, or a combination — you can deploy to all of them in parallel:

#!/bin/bash
# deploy-multi-device.sh -- Deploy to all connected devices in parallel
APK="./patched/target-patched.apk"
PKG="com.target.app"
PAYLOAD_DIR="$HOME/payloads"
REPORTS_DIR="./reports/devices"
mkdir -p "$REPORTS_DIR"
deploy_to_device() {
local device="$1"
echo "[$device] Starting deployment..."
adb -s "$device" install -r "$APK" || { echo "[$device] Install failed"; return 1; }
adb -s "$device" shell pm grant "$PKG" android.permission.CAMERA 2>/dev/null
adb -s "$device" shell pm grant "$PKG" android.permission.ACCESS_FINE_LOCATION 2>/dev/null
adb -s "$device" shell appops set "$PKG" MANAGE_EXTERNAL_STORAGE allow 2>/dev/null
adb -s "$device" push "$PAYLOAD_DIR/faces/male_caucasian_30s/neutral"/. /sdcard/poc_frames/
adb -s "$device" push "$PAYLOAD_DIR/locations/times-square.json" /sdcard/poc_location/config.json
adb -s "$device" push "$PAYLOAD_DIR/sensors/holding.json" /sdcard/poc_sensor/config.json
adb -s "$device" logcat -c
adb -s "$device" shell monkey -p "$PKG" -c android.intent.category.LAUNCHER 1
sleep 5
adb -s "$device" logcat -d -s FrameInterceptor,LocationInterceptor,SensorInterceptor \
> "$REPORTS_DIR/${device}_delivery.log"
if grep -q "DELIVERED\|Auto-enabled" "$REPORTS_DIR/${device}_delivery.log"; then
echo "[$device] Injection ACTIVE"
else
echo "[$device] Injection NOT detected"
fi
}
# Deploy to all connected devices in parallel
for device in $(adb devices | grep -w 'device' | awk '{print $1}'); do
deploy_to_device "$device" &
done
wait
echo "=== All devices complete ==="

Each device gets its own background process, its own log file, and its own status report. The wait at the end blocks until all deployments complete. The per-device log files (emulator-5554_delivery.log, R5CR1234567_delivery.log) let you investigate individual device results without log interleaving.

For extended runs — where you need logs from the entire engagement, not just the first five seconds — use a persistent logcat process per device:

Terminal window
# Start persistent log capture for each device
for device in $(adb devices | grep -w 'device' | awk '{print $1}'); do
adb -s "$device" logcat -s FrameInterceptor,LocationInterceptor,SensorInterceptor \
> "$REPORTS_DIR/${device}_full.log" &
echo $! >> "$REPORTS_DIR/logcat_pids.txt"
done
# ... run your engagement ...
# Stop all logcat processes when done
while read pid; do kill "$pid" 2>/dev/null; done < "$REPORTS_DIR/logcat_pids.txt"

Cloud device farms — AWS Device Farm, Firebase Test Lab, Samsung Remote Test Lab — present additional challenges. You typically cannot push arbitrary files to /sdcard/ before your test runs. The workaround is to bundle payloads into the APK’s assets directory during the patching step, then have the runtime extract them to the expected locations on first launch.

This is an advanced configuration that requires modifying the patch-tool’s asset bundling. It is beyond the scope of this book, but the architecture supports it: the interceptors check for files in fixed paths, and those files can come from any source — adb push, asset extraction, or network download. The auto-enable logic does not care how the files arrived.


Scaling operations means multiple people running engagements at different times against different targets. Without configuration management, each operator reinvents the wheel. With it, engagements are reproducible — anyone on the team can re-run an assessment from the configuration files alone.

Organize each engagement as a self-contained directory:

engagements/
2026-03-15_bank-app/
scope.md Authorization and scope document
recon/
manifest.txt Decoded manifest
smali_analysis.txt Reconnaissance notes
defenses.md Identified defense layers
payloads/
frames/ Symlinks to ~/payloads/faces/...
location.json Copy or symlink
sensor.json Copy or symlink
patched/
com.bank.app-patched.apk
reports/
patch.log
delivery.log
summary.txt
engagement_report.md
catalog_entry.yaml Updated target catalog entry

The engagement directory captures everything needed to understand and reproduce the assessment. The scope.md proves authorization. The recon/ directory preserves your analysis. The payloads/ directory records exactly which payloads were used — symlinks to the payload library for storage efficiency, or copies if you need the engagement to be fully self-contained. The reports/ directory holds all output. The catalog_entry.yaml is the updated intelligence record that gets copied back to the master catalog.

Version-control the entire engagement tree. Git is the obvious choice. Each engagement becomes a commit or a branch. The payload library is a separate repository (it contains large binary files — use Git LFS or keep it outside the engagement repo with symlinks). The target catalog is its own repository, updated after every engagement.

# Recommended repository structure
security-ops/
target_catalog/ Git repo -- one YAML per target
payloads/ Git LFS repo -- frames, configs, profiles
engagements/ Git repo -- one directory per engagement
scripts/ Git repo -- batch scripts, utilities

The separation matters. The target catalog changes frequently and is read by everyone. The payload library changes rarely and is large. The engagement archive grows monotonically and is primarily write-once. Different change patterns warrant different repositories.

The gold standard for configuration management is this: a team member who was not involved in the original engagement can re-run it from the configuration files alone. They clone the engagement directory, check the scope document, run the patch script with the archived APK, deploy with the archived payloads, and get the same results.

This requires discipline in three areas:

  1. Record exact versions. The target APK version, the patch-tool version, the Android SDK build-tools version, the device OS version. Pin everything.
  2. Archive inputs. The original APK, the exact payload files, the configuration used. Do not rely on “whatever is currently in the payload library” — it may have changed.
  3. Capture outputs. Logs, screenshots, delivery statistics, the final report. These are the evidence that the engagement produced the claimed results.

Reproducibility is not just an operational convenience. It is a professional obligation. When a client asks “can you prove this bypass worked six months ago?”, the answer must be yes. The engagement directory and its version control history provide that proof.


The infrastructure described in this chapter — payload libraries, target catalogs, batch scripts, configuration management — is not overhead. It is the difference between a practitioner who can test one app and an operation that can test a hundred.

The core principle is simple: automate what repeats, customize what varies.

Patching repeats. Deployment repeats. Permission grants repeat. Log capture repeats. Payload organization repeats. Summary reporting repeats. Automate all of it. Write the script once, run it a thousand times.

What varies is the target-specific intelligence. The camera API surface. The liveness challenges. The defense layers. The evasion techniques. The payload selection. This is the human judgment that no script can replace — but the catalog ensures you only exercise that judgment once per target. After the first engagement, the catalog entry captures the decision and the next engagement starts from knowledge instead of ignorance.

The catalog is your institutional memory. People leave teams, change roles, forget details. The catalog does not. When a target you tested eighteen months ago comes back for a re-assessment, the catalog entry tells you everything: what you found, what you applied, what worked. You start from where you left off, not from zero.

Quality over quantity. A clean, documented, reproducible engagement beats ten sloppy ones. A target catalog with fifty well-structured entries is more valuable than two hundred entries with missing fields and vague notes. The batch scripts make speed possible — the discipline to document thoroughly makes that speed meaningful.


This book started with a simple observation: mobile biometric verification trusts data from hardware that the device owner controls completely. Camera frames, GPS coordinates, sensor readings — they all pass through software interfaces where they can be intercepted, modified, or replaced entirely.

Chapter 1 mapped the attack surface. Chapter 2 established the rules. Chapters 3 and 4 built the foundation and the lab. Chapters 5 through 9 developed the individual capabilities — reconnaissance, bytecode modification, camera injection, location spoofing, sensor manipulation. Chapter 10 combined them into coordinated engagements. Chapter 11 covered evidence and reporting.

This chapter addressed the question of what happens after the methodology works. You scale it. You build the libraries, catalogs, and automation that turn a proven technique into a sustainable operation. Not because bigger is always better, but because the targets do not stop shipping new versions, the clients do not stop requesting re-tests, and the defenses do not stop evolving.

The methodology is a loop: reconnaissance, instrumentation, injection, verification, documentation. Each pass through the loop refines your understanding of the target and your confidence in the result. The infrastructure in this chapter makes each pass faster, more consistent, and more valuable than the last.

Build the library. Maintain the catalog. Automate the pipeline. Document everything. The tools work. Now make them scale.

Practice: Lab 11 (Batch Operations) walks you through building and running batch scripts against multiple targets in a single session.

Next: Part IV goes deeper. Chapter 13 teaches you to read and write smali bytecode directly. Chapter 14 shows you how to package manual patches into reusable hook modules. Chapter 15 tackles anti-tamper defenses. Chapter 16 builds fully automated engagement pipelines. And Part V flips the perspective: Chapters 17 and 18 cover detection engineering and defense-in-depth architecture.