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.
The Timing Problem
Section titled “The Timing Problem”Here is a realistic breakdown of a single manual engagement:
| Step | Time |
|---|---|
| Decode the APK with apktool | 2 min |
| Reconnaissance (camera API, location API, sensors, defenses) | 3 min |
| Patch with patch-tool | 3 min |
| Install, grant permissions, push payloads | 3 min |
| Launch and verify injection via logcat | 3 min |
| Capture evidence and write notes | 3 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.
The Payload Library
Section titled “The Payload Library”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.
Recommended Directory Structure
Section titled “Recommended Directory Structure”~/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 framesThe 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.
Why Organize by Demographic
Section titled “Why Organize by Demographic”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.
The Matched Pairs Principle
Section titled “The Matched Pairs Principle”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 Sequence | Sensor Config | Use Case |
|---|---|---|
neutral/ | holding.json | Static 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.
Creating New Frame Sequences
Section titled “Creating New Frame Sequences”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:
# Record 3-5 seconds at selfie camera resolution# Then extract at 15fps:ffmpeg -i recording.mp4 -vf "fps=15,scale=640:480" frames/%03d.pngThe 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 Config Library
Section titled “Location Config Library”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.
Sensor Profile Library
Section titled “Sensor Profile Library”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.
The Target Catalog
Section titled “The Target Catalog”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.
The YAML Format
Section titled “The YAML Format”Each target gets a YAML file named after its package:
package: com.bank.appversion_tested: "3.2.1"last_tested: "2026-03-15"
# API surfacescamera_api: cameraxlocation_api: fusedsensors: accel + gyro
# Liveness configurationliveness_type: activeactive_challenges: - tilt_left - tilt_right - nod
# Defense layersanti_tamper: signature_check: "SecurityManager.verifySignature()" dex_integrity: none cert_pinning: "OkHttp CertificatePinner on api.bank.com" installer_check: none
# What we appliedhooks_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 workedpayloads_used: frames: "male_caucasian_30s/neutral + tilt_left + nod" location: "times-square.json" sensors: "holding.json + tilt-left.json + nod.json"
# Outcomeresult: FULL_BYPASSnotes: | 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.Key Fields Explained
Section titled “Key Fields Explained”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.
Using the Catalog for Re-engagement
Section titled “Using the Catalog for Re-engagement”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.
Building Institutional Knowledge
Section titled “Building Institutional Knowledge”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.
Batch Operations
Section titled “Batch Operations”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.
Patch All Targets
Section titled “Patch All Targets”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 directoryset -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=0failed=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.
Deploy and Verify All
Section titled “Deploy and Verify All”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 injectionset -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 ""doneNotice 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.
Summary Report
Section titled “Summary Report”After all deployments complete, generate a summary table:
#!/bin/bash# summary.sh -- Generate engagement summary from delivery logsREPORTS_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=0active=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.
Error Handling in Batch Scripts
Section titled “Error Handling in Batch Scripts”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.
Device Farm Operations
Section titled “Device Farm Operations”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.
Headless Mode
Section titled “Headless Mode”The auto-enable conditions are simple:
| Subsystem | Auto-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.
Multi-Device Parallel Deployment
Section titled “Multi-Device Parallel Deployment”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 parallelAPK="./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 parallelfor device in $(adb devices | grep -w 'device' | awk '{print $1}'); do deploy_to_device "$device" &done
waitecho "=== 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.
Per-Device Log Capture
Section titled “Per-Device Log Capture”For extended runs — where you need logs from the entire engagement, not just the first five seconds — use a persistent logcat process per device:
# Start persistent log capture for each devicefor 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 donewhile read pid; do kill "$pid" 2>/dev/null; done < "$REPORTS_DIR/logcat_pids.txt"Cloud Device Farm Considerations
Section titled “Cloud Device Farm Considerations”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.
Configuration Management
Section titled “Configuration Management”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.
Engagement Directory Structure
Section titled “Engagement Directory Structure”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 entryThe 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
Section titled “Version Control”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 structuresecurity-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, utilitiesThe 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.
Reproducible Engagements
Section titled “Reproducible Engagements”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:
- Record exact versions. The target APK version, the patch-tool version, the Android SDK build-tools version, the device OS version. Pin everything.
- 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.
- 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 Scaling Mindset
Section titled “The Scaling Mindset”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.
Closing
Section titled “Closing”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.