Distinct new capability: instead of only replacing method bodies with a
return, the patcher can now INJECT working code. Used to defeat the IAB TCF
consent dialog at the root: in Subway Surfers 28 classes across 13 SDKs read
the IABTCF_* SharedPreferences to decide whether to track, so writing a
reject-all state there makes every TCF-honoring SDK self-limit and removes
the nag.
Mechanism (documented as its own feature in references/consent-neutralization.md):
- targets-file lines gain an optional 3rd field <class>:<method>:<inject-kind>
(back-compatible: 2-field lines and wildcards unchanged; verified no
regression on the other 47 entries). _schema.json adds category `consent`
and an `inject` field (stub optional). registry-scan.py emits the 3rd field.
neutralize.sh gains a guarded code-injection branch (SKIP_INJECT on
signature mismatch), bash 3.2/BSD-safe, no new GNU-isms.
- registry/consent-umptcf.json (google-ump-consent): writes reject-all
IABTCF_* (consent AND legitimate-interest all-zero, gdprApplies=1 always,
AddtlConsent="1~", plus a decode-verified reject-all TCString) to the
default SharedPreferences on BOTH requestConsentInfoUpdate (the near-
universal first UMP call) and loadAndShowConsentFormIfRequired, then fires
the success/dismiss callbacks; canRequestAds=true and getConsentStatus=
OBTAINED keep the app from re-showing the form. If neither hook is present
it is a safe no-op.
Complements, does not replace, SDK neutralization: non-TCF trackers (Firebase,
Singular) ignore IABTCF and still need direct stubbing. Reviewed twice
(build + adversarial), assembled and rebuilt on Subway; on-device behavior
still to be confirmed. Docs updated to 48 SDKs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
SYBO (Subway Surfers' publisher) ships com.sybo.analytics.AnalyticsBridge,
the game-facing layer that schedules WorkManager jobs to flush/upload event
data over HTTPS — including while the app is closed. Per-SDK neutralization
(Singular, Firebase) already drops the events, but the SYBO scheduler was
untouched. Stub SetupWorkerForAppClosed/SetupWorkerForAppRunning/
StopWorkerForAppRunning (all void) so no upload worker is ever scheduled.
Fire-and-forget: the game does not await the flush, so the void stubs can't
hang it. GetCountryISO3CodeUpper and the FlushWhileRunningCallback bridge
(GetData/HasData/OnDataSendComplete) are protected. com.sybo.consent
(age-gate) and com.sybo.native_sharing are intentionally left alone. Verified
by dry-run on subway-decoded (3 methods). Docs updated to 47 SDKs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Rovio games (Bad Piggies, Angry Birds…) drive ads through their own
com.rovio.beacon layer, not the networks directly, so per-network
neutralization left an interstitial running. This entry stubs the game-facing
choke point AdsSdk.load/show/hide/poke (one lever kills every adapter and the
WebView house-ad path: WebViewAd/WebViewAdFactory/MRAIDController) plus the
fire-and-forget analytics/tracking beacons (RovioTrackingInterface,
WebViewWrapper.onRovioTrackEvent, VideoPlayer track events).
Callback-aware: the onAd* bridge back to the game and the attribution/ID
surface (Attribution.checkLicense/getInstallReferrer, DeviceInfo async IDs,
Globals.getActivity) are protected so a stub cannot hang or NPE the game. The
com.rovio.fusion.VideoPlayerActivity manifest component was intentionally NOT
disabled (it is engine cutscene glue, not an ad component).
Verified on device: Bad Piggies HD 2.4.3379 runs and the interstitial is
gone. Detected automatically by detect-adwrapper (in_house_wrapper:true).
Docs updated to 46 SDKs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Both meta-mediators matched but stubbed almost nothing, so on mediated apps
(Subway Surfers, Bad Piggies, Alto, 1945…) the ad waterfall stayed live —
the app calls ONE mediator and its adapters drive every other network, so
this is the highest-impact gap.
- applovin: the MAX ad targets used the wrong package
(com.applovin.mediation.MaxInterstitialAd). Real classes are under
com.applovin.mediation.ads.* — added MaxInterstitialAd/MaxRewardedAd/
MaxAppOpenAd load/show/isReady/destroy (+ MaxAdView), kept AppLovinSdk.init
and the legacy .mediation.* targets as harmless fallbacks. Subway: 1→41
methods matched; Bad Piggies: 4→32.
- ironsource: the legacy com.ironsource.mediationsdk.IronSource methods are
gone in 9.x (0 patched). Extended with the modern init
com.unity3d.ironsourceads.IronSourceAds and com.unity3d.mediation.LevelPlay,
the LevelPlay ad loaders/ads, and the Unity bridge
com.ironsource.unity.androidbridge.LevelPlayBridge (what IL2CPP games call);
legacy + ISDemandOnly targets kept. Subway: 0→68 methods matched.
Extend-not-replace: legacy targets stay for the many APKs still shipping old
SDKs; absent classes/methods are skipped by the patcher. Callback bridges and
object getters protected so a stub can't strand the app on a missing callback.
Verified by neutralize.sh --dry-run on the real subway/bad-piggies decodes.
Docs updated to 362 entry points / 337 ad operations.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
From research on the most-played children's Android apps of 2026: the ad
SDKs and (equally important) the trackers/telemetry that these apps ship and
the registry did not yet cover. Each entry was built from the official Maven
AARs, inspected across versions with javap/jadx, every target method's real
return type confirmed by a neutralize.sh dry-run on the real bytecode, and
validated against _schema.json.
Ads:
- superawesome (tv.superawesome) — the kids-focused ad SDK (Talking Tom/Angela, Subway Surfers)
- appodeal (com.appodeal.ads/com.explorestack, mediation; explorestack kept detection-only, not deep-stubbed, to avoid nulling its shaded-protobuf/IAB getters)
- mytarget (com.my.target), hyprmx (com.hyprmx.android), maio (jp.maio, v1+v2)
Trackers / analytics / attribution:
- singular (com.singular.sdk), amplitude (com.amplitude, v1+v2 — v2 is a fluent
builder so only flush() is stubbed, chained methods protected),
google-analytics (Universal/legacy, distinct from the Firebase Analytics/GA4 entry)
Crash / telemetry (Exodus classifies these as trackers):
- sentry (io.sentry), bugsnag (com.bugsnag), backtrace (backtraceio)
Init + capture/send stubbed and auto-init providers disabled, while
object/scope getters and singletons the app chains on are protected so a
stub cannot itself crash the app (e.g. Bugsnag's static facade throws before
start(), so its delegators are stubbed to no-op).
Verified on real decodes where present: Appodeal on 1945 Air Force, Singular
and Google Analytics on Block Craft; the rest are AAR-verified pending a
decoded app. Docs updated to 45 SDKs / 337 entry points / 281 ad operations.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Per-network neutralization misses a publisher's own mediation layer, which
calls the networks (or serves house/WebView ads) on the app's behalf — e.g.
Rovio Beacon in Bad Piggies kept serving an interstitial with every network
SDK stubbed; Guru Fusion is the same shape.
New detect-adwrapper.{sh,ps1} score a candidate namespace under the app's
own vendor root (excluding known-SDK and common-lib roots) by: references to
>=2 ad-network packages, its own WebView+MRAID ad path, and analytics/
attribution classes. Emit ADWRAPPER_DETECTED:<pkg>:<confidence>:<evidence>
and ADWRAPPER_SUMMARY, always exit 0; decode-apk runs it after decode and
points the user at the discovery workflow. Registry entries flagged
in_house_wrapper:true (new optional schema property; guru-fusion marked) are
NOT excluded — a matched candidate is annotated registry=<sdk_id>.
Detection and reporting only — nothing removes, disables or bypasses a
wrapper. True positive on Rovio (com.rovio.beacon) and The Fun Games
(com.tfg.libs, Block Craft); no false positives on Alto/HeartStar/1945/
Bulldozer. sh/ps1 output is byte-identical (verified via the PowerShell 5.1
interop).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Real apps still ship the old package names of SDKs that later renamed, and
AdColony was not covered at all — so a full-registry pass left ads running
(seen in Bad Piggies HD 2.4.3379, which ships com.vungle.warren and
com.adcolony).
- adcolony (new entry): com.adcolony.sdk.AdColony configure/request*/show/
isExpired (all boolean -> return-false/0) + the two AdColony activities;
built from com.adcolony:sdk 4.8.2/4.6.0 and the version in Bad Piggies.
- vungle: add legacy com.vungle.warren (6.x Vungle facade: init/loadAd/
playAd/canPlayAd, Banners, NativeAd) and com.vungle.publisher (4.x/5.x
VunglePub), plus their manifest components incl. the warren auto-init
ContentProvider; new com.vungle.ads targets kept. From publisher-sdk-android
6.12.1/6.9.1/5.3.2/5.3.0 and the warren classes in Bad Piggies.
- ogury: add legacy io.presage (Presage/PresageSdk/Ads init, interstitial
and optin-video ops) and 14 io.presage manifest components; new com.ogury.*
targets kept. From co.ogury:ogury-sdk 4.9.1/4.3.13.
Every target and return type verified against real bytecode; entries
validate against _schema.json and match on Bad Piggies (registry-scan +
neutralize dry-run). Docs updated to 34 SDKs / 208 entry points /
241 ad operations.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
A rebuilt and re-signed APK of a protected app will not run (signature
check, VM-encrypted code, or a license gate), so warn the user up front
instead of spending time on a rebuild that can't be installed.
New detect-protection.{sh,ps1} operate on a decoded dir and emit
PROTECTION_DETECTED:<id>:<category>:<confidence>:<evidence> plus a final
PROTECTION_SUMMARY (none|integrity|license|hardener|signature-vm), always
exiting 0 (informational; the caller decides). PairIP is split into the
hard blocker (signature-vm: SignatureCheck/VMRunner/VmDecryptor/
libpairipcore.so) and the softer license-only variant. Also covers Google
LVL, Play Integrity/SafetyNet (low/informational) and common commercial
hardeners (DexGuard, Promon, AppDome, Verimatrix, Arxan, SecNeo/Bangcle,
Jiagu/360, Tencent Legu, iJiami, Baidu, Alibaba, NetEase Yidun,
DexProtector, AppSealing, LIAPP). Non-PairIP signatures were verified
against APKiD's YARA rules; only file/class/manifest signals a decoded
tree can express are used, with confidence marked accordingly.
decode-apk.{sh,ps1} run the check after a successful decode and print a
prominent warning for a hard blocker; the decode exit code is unchanged.
This is detection and warning only — no rule, code path or doc removes,
disables or bypasses any protector.
Wired into SKILL.md (Phase 2b), commands/neutralize.md (Step 4b),
CLAUDE.md, README and the neutralization guide. Verified on real apps:
1945 Air Force 15.82 -> signature-vm, Bulldozer Master 11.1.0 -> license,
Block Craft / Alto's Adventure / HeartStar -> none; the Facebook
CrashShield false positive is ruled out. sh/ps1 output parity checked
through the Windows PowerShell 5.1 interop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Decoding only the base APK of an XAPK made apktool write @null for every
reference to a resource living in a split (e.g. density drawables), and no
post-decode merge could repair that. Splits (XAPK/APKM/APKS or a directory)
are now merged with APKEditor (REAndroid, Apache-2.0, pinned 1.4.9 with
SHA-256 verification) before `apktool d`, so the decoded tree is complete.
- decode-apk: bundle input is merged first; old behaviour kept as the
deprecated --keep-splits / -KeepSplits mode
- rebuild-apk: always a single APK by default; stored native libs are
page-aligned (zipalign -P 16, -p fallback) and verified after signing
(ALIGN_OK / ALIGN_WARNING / ALIGN_FAIL); ABI_WARNING for 32-bit-only
output; stable user-level debug key shared by --auto-keystore and the
default mode; apksigner looked up in SDK build-tools, v1-only jarsigner
refused for targetSdk >= 30; --no-res removed (no-op on apktool 2.10)
- install-dep: new `apkeditor` and `build-tools` (pinned Build-Tools 36.0.0,
per-platform SHA-256, explicit Android SDK license acceptance required);
per-user tools are no longer installed under sudo
- check-neutralize-deps: reports APKEditor, zipalign page-alignment support,
unzip and build-tools
- new PowerShell 5.1 twins: decode-apk.ps1, rebuild-apk.ps1,
check-neutralize-deps.ps1 (non-ASCII and cmd-metacharacter paths staged,
UTF-8 output restored on exit, ZIP64-aware alignment check)
- merge-splits.sh removed: obsolete with the pre-decode merge
- docs: SKILL.md, neutralize command, CLAUDE.md, setup guide, README
(XAPK output deprecation note)
Tested end to end on Linux and Windows PowerShell 5.1 with Block Craft 3D,
Bulldozer Master, Water Sort Puzzle, HeartStar, Alto's Adventure and
1945 Air Force; reviewed twice independently.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
Four new registry entries built from the official SDK artifacts (Maven),
inspected across several versions each (javap/jadx) so that every target
method, return type and manifest component is backed by real bytecode:
- tapjoy: Tapjoy Offerwall 11.x-14.x (connect entry points, TJPlacement ops)
- yandex-ads: Yandex Mobile Ads 5.x-8.x (MobileAds/YandexAds init, loaders)
- google-tag-manager: GTM v3/v4/v5 (void-only targets; object-returning APIs protected)
- appmetrica: io.appmetrica.analytics and legacy com.yandex.metrica
Validated against _schema.json and exercised with registry-scan.py and
neutralize.sh on real APKs (Bulldozer Master 11.1.0, Block Craft 3D 4.5.1).
Docs updated to 33 SDKs / 201 entry points / 210 ad operations; examples
now use neutral placeholder packages instead of a specific vendor.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tae7iP5Zh8tax1Sn9p3A5
* feat: add Windows/PowerShell support
Add PowerShell equivalents of all bash scripts for Windows users:
- check-deps.ps1: Dependency verification with PATH refresh
- install-dep.ps1: Install via winget/scoop/choco or direct download
- decompile.ps1: APK/XAPK/JAR/AAR decompilation with split APK detection
- find-api-calls.ps1: API endpoint extraction (Retrofit, URLs, auth)
Update SKILL.md with Windows-specific instructions and notes for
each workflow phase.
PowerShell scripts support the same options as their bash counterparts
and automatically refresh PATH after installations.
* fix: check-deps.ps1 jadx fallback path version check, decompile.md lint fixes
Replaces hardcoded smali patterns with a data-driven SDK registry: 29 JSON
definitions covering ad networks, mediation, attribution, and analytics SDKs
(123 entry points, 156 ad operations, 30 deep patterns, 64 manifest components).
- Add plugins/.../sdk-neutralizer/registry/ with _schema.json + 29 SDK files
(Adjust, Braze, CleverTap, Guru Fusion, Mintegral, Mixpanel, MobileFuse,
Moloco, PubMatic, TradPlus, plus the prior 19)
- Add registry-scan.py to consume the registry and emit targets-file +
manifest-components-file consumed by neutralize.sh
- Extend neutralize.sh with --no-builtin-targets, --targets-file,
--manifest-components-file, --package, --cleanup-backups
- Extend find-ads.sh and find-trackers.sh with --summary and --json output
- Mark python3 as INSTALL_OPTIONAL in check-neutralize-deps.sh (fallback
to builtin hardcoded targets when unavailable)
- Bump plugin and marketplace to 1.3.1
- Add .gitignore for __pycache__/, *.pyc, *.pyo
- Update CLAUDE.md, SKILL.md, neutralize.md to reflect registry-driven flow
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- decode-apk.sh preserves XAPK structure (.xapk-origin/) with splits, manifest, and metadata for automatic reassembly
- rebuild-apk.sh detects .xapk-origin/, re-signs all split APKs, and assembles final .xapk output
- Add --auto-keystore flag: prioritizes ~/.android/debug.keystore → previous debug key → generated key
- Add neutralize-all compound target to install-dep.sh (java + apktool + apksigner + zip in one command)
- Add apktool version check (>= 2.9.0) with automatic upgrade from GitHub releases
- Add install_zip() and zip dependency check for XAPK rebuild
- All scripts now prepend ~/.local/bin to PATH for user-local tool installs
- Update SKILL.md Phase 3 with built-in catalog detection workflow and custom SDK discovery using Claude Code tools
- Update neutralize.md, CLAUDE.md, and README.md with XAPK and auto-keystore documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six improvements from real-world testing on Water Sort Puzzle XAPK:
- Fix manifest patching creating duplicate android:enabled attributes when
the component already has android:enabled="true" (3-way check logic)
- Add decode-apk.sh with XAPK support (auto-extracts base APK, skips splits)
- Add apktool >= 2.9.0 minimum version check in check-neutralize-deps.sh
- Add --no-res fallback in rebuild-apk.sh when apktool build fails on resources
- Add 13 missing manifest components (Vungle new SDK, Meta AN provider,
AppLovin/BidMachine/IronSource init providers, Amazon APS, Pangle/Mintegral
activities, Smaato, AppsFlyer internal receiver)
- Add patch persistence via neutralize-manifest.json and --replay flag
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces two new skills for privacy auditing of decompiled Android apps:
- tracker-analysis: 4-phase workflow detecting Firebase, Adjust, AppsFlyer,
Mixpanel, Amplitude, Segment, Braze, CleverTap, Flurry with init/events/
consent/data exfiltration analysis
- ad-analysis: 3-phase workflow detecting AdMob, Unity, IronSource, AppLovin,
Meta AN, Vungle, InMobi, Chartboost, Pangle, Mintegral with ad format
mapping, mediation analysis, and consent framework detection
Key addition: --entrypoints flag in find-ads.sh distinguishes SDKs actively
called by app code from passive mediation adapter dependencies, enabling
accurate "Ad Architecture" classification (single mediator / multiple direct /
hybrid).
Also improves install-dep.sh sudo detection for non-interactive environments
(Claude Code, CI, pipes) and adds CLAUDE.md project instructions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add keywords, skills and commands paths to plugin.json
- Add argument-hint to decompile command for better UX
- Add description to SKILL.md frontmatter for skill auto-matching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>