11#! /system/bin/sh
22# AlwaysStrong action button.
3- # Refreshes fingerprint (autopif4), enforces STRONG settings, syncs security
4- # patch, then restarts PI consumers. Runs the whole chain silently and prints
5- # one clean, framed summary: device, security patch, fingerprint, keybox.
3+ # Shows each step progressively with status feedback.
64
75case " $0 " in
86 * /* ) MODPATH=$( cd " ${0%/* } " 2> /dev/null && pwd) ;;
119[ -z " $MODPATH " ] && MODPATH=" $PWD "
1210cd " $MODPATH " 2> /dev/null
1311
14- # disable busybox ash standalone mode — must run in current shell, not subshell
1512set +o standalone 2> /dev/null
1613unset ASH_STANDALONE
1714
1815CONFIG_DIR=/data/adb/tricky_store
19- LINE=" ━━━━━━━━━━━━━━━━━━━━━━━━━ "
16+ LINE=" ========================= "
2017VER=$( grep -m1 ' ^version=' " $MODPATH /module.prop" 2> /dev/null | cut -d= -f2-)
2118
22- # one consistent row style for every line (success or failure)
2319row () { echo " $1 $2 " ; }
2420
21+ # --- ABI + fetchers ---
22+ case " $( uname -m) " in
23+ aarch64) ABI=arm64-v8a ;;
24+ armv7* |armv8l) ABI=armeabi-v7a ;;
25+ * ) ABI=" " ;;
26+ esac
27+ ASFETCH=" "
28+ [ -n " $ABI " ] && [ -x " $MODPATH /bin/$ABI /asfetch" ] && ASFETCH=" $MODPATH /bin/$ABI /asfetch"
29+ BB=" "
30+ for bb in /data/adb/magisk/busybox /data/adb/ksu/bin/busybox /data/adb/ap/bin/busybox \
31+ /data/adb/modules/busybox-ndk/system/* /busybox; do
32+ [ -x " $bb " ] && BB=" $bb " && break
33+ done
34+
35+ # asfetch first (connects IPv4-first, works on IPv6-only-DNS networks); fall
36+ # through to busybox wget / curl if it ever fails on a host.
37+ dl_out () {
38+ if [ -n " $ASFETCH " ]; then $ASFETCH -T 20 " $1 " 2> /dev/null && return 0; fi
39+ if [ -n " $BB " ]; then $BB wget -q -T 20 -O - " $1 " 2> /dev/null && return 0; fi
40+ if command -v curl > /dev/null 2>&1 ; then curl -fsSL --max-time 20 " $1 " 2> /dev/null && return 0; fi
41+ if command -v wget > /dev/null 2>&1 ; then wget -q -T 20 -O - " $1 " 2> /dev/null && return 0; fi
42+ return 1
43+ }
44+ dl_to () {
45+ if [ -n " $ASFETCH " ]; then rm -f " $1 " ; $ASFETCH -T 60 -o " $1 " " $2 " 2> /dev/null; [ -s " $1 " ] && return 0; fi
46+ if [ -n " $BB " ]; then rm -f " $1 " ; $BB wget -q -T 60 -O " $1 " " $2 " 2> /dev/null; [ -s " $1 " ] && return 0; fi
47+ if command -v curl > /dev/null 2>&1 ; then rm -f " $1 " ; curl -fsSL --max-time 60 -o " $1 " " $2 " 2> /dev/null; [ -s " $1 " ] && return 0; fi
48+ if command -v wget > /dev/null 2>&1 ; then rm -f " $1 " ; wget -q -T 60 -O " $1 " " $2 " 2> /dev/null; [ -s " $1 " ] && return 0; fi
49+ return 1
50+ }
51+
52+ # --- Header ---
2553echo " "
2654echo " $LINE "
2755row " 🛡️" " AlwaysStrong ${VER} "
2856echo " $LINE "
2957echo " "
30- row " ⏳" " initializing, please wait "
31- echo " $LINE "
58+ row " ⏳" " initializing... "
59+ sleep 3
3260
33- # --- target.txt + keybox (silent) ----------------------------------------
34- # build_target_txt rewrites target.txt every tap: all user apps (pm -3) +
35- # installed OEM wallet/store apps + forced GMS/GSF/Vending. Count what landed.
61+ # --- Step 1: Target list ---
3662[ -x " $MODPATH /build_target_txt.sh" ] && \
3763 sh " $MODPATH /build_target_txt.sh" " $CONFIG_DIR /target.txt" > /dev/null 2>&1
3864TGT_N=$( grep -cvE ' ^[[:space:]]*$' " $CONFIG_DIR /target.txt" 2> /dev/null)
39- # Keybox: if we already hold a valid one, refresh it in the BACKGROUND so a
40- # slow or unreachable mirror can't stall the Action (some networks reach
41- # Google fine but not the keybox host). With no keybox yet, fetch synchronously
42- # (still bounded by keybox_fetch's own wget timeout) because STRONG needs it now.
43- if [ -x " $MODPATH /keybox_fetch.sh" ]; then
65+ row " 🎯" " ${TGT_N:- 0} apps > target"
66+ sleep 1
67+
68+ # --- Step 2: Keybox ---
69+ # Custom-keybox mode (WebUI toggle): user supplied their own keybox, so we do
70+ # NOT fetch/overwrite it. Keep the note short.
71+ if [ -f " $CONFIG_DIR /custom_keybox" ]; then
72+ if [ -s " $CONFIG_DIR /keybox.xml" ] && head -c 4096 " $CONFIG_DIR /keybox.xml" | grep -q " Keybox" ; then
73+ row " 🔑" " custom keybox — skip fetch"
74+ row " ℹ️" " disable in webui for auto"
75+ else
76+ row " ⚠️" " custom keybox not set"
77+ fi
78+ elif [ -x " $MODPATH /keybox_fetch.sh" ]; then
4479 if [ -s " $CONFIG_DIR /keybox.xml" ] && head -c 4096 " $CONFIG_DIR /keybox.xml" | grep -q " Keybox" ; then
4580 sh " $MODPATH /keybox_fetch.sh" > /dev/null 2>&1 &
81+ row " 🔑" " keybox ok"
4682 else
4783 sh " $MODPATH /keybox_fetch.sh" > /dev/null 2>&1
84+ if [ -s " $CONFIG_DIR /keybox.xml" ] && head -c 4096 " $CONFIG_DIR /keybox.xml" | grep -q " Keybox" ; then
85+ row " 🔑" " keybox updated"
86+ else
87+ row " ⚠️" " keybox missing"
88+ fi
89+ fi
90+ else
91+ row " ⚠️" " keybox fetch not available"
92+ fi
93+ sleep 1
94+
95+ # --- Step 3: Fingerprint ---
96+ # The fingerprint is fetched from Google's Pixel build servers. PlayIntegrityFork
97+ # (autopif4) does this with busybox wget, but its multi-step crawl hangs to its
98+ # timeout on some devices (~2 min wasted). So we run the SAME crawl ourselves
99+ # first (pif_native_fetch — busybox wget for Google is fast/reliable), and only
100+ # fall back to autopif4 (bounded), then an optional mirror, then shipped static
101+ # props. PIF itself still does the attestation spoofing; this only fetches the
102+ # fingerprint it consumes. A fingerprint is ALWAYS produced, and we never surface
103+ # a bare "offline" — a failed primary is shown as "trying fallback".
104+ FP_OK=0
105+ FP_SRC=" "
106+
107+ # Primary: native crawl, bounded to 15s total so a slow network can't make it
108+ # grind through its ~7 requests — it drops to the fallback fast instead.
109+ if [ -x " $MODPATH /pif_native_fetch.sh" ]; then
110+ if command -v timeout > /dev/null 2>&1 ; then
111+ timeout 15 sh " $MODPATH /pif_native_fetch.sh" > " $CONFIG_DIR /autopif.log" 2>&1
112+ else
113+ sh " $MODPATH /pif_native_fetch.sh" > " $CONFIG_DIR /autopif.log" 2>&1
114+ fi
115+ if [ -s " $CONFIG_DIR /pif.prop" ] && grep -q " FINGERPRINT=" " $CONFIG_DIR /pif.prop" ; then
116+ FP_OK=1; FP_SRC=" native"
48117 fi
49118fi
50119
51- # --- autopif4: fetch a fresh Pixel fingerprint from Google ----------------
52- # autopif4 pulls the latest Pixel build from several Google hosts (developer.
53- # android.com, flash.android.com, content-flashstation-pa.googleapis.com, ...)
54- # and exits non-zero if ANY single one fails — that is exactly what shows up
55- # as "fingerprint cached (offline?)". Bound it with a timeout so a stalled
56- # connection can't freeze the Action, retry once for transient failures, and
57- # keep the real output in CONFIG_DIR/autopif.log (instead of /dev/null) so an
58- # "offline" result is actually diagnosable.
59- FP_OK=1
60- if [ -f " $MODPATH /autopif4.sh" ]; then
61- run_autopif () {
120+ if [ " $FP_OK " = 0 ]; then
121+ row " 🔄" " trying with fallback"
122+ sleep 1
123+
124+ # Fallback A: autopif4 (PIF fork) — bounded to 10s so it can't stall the Action.
125+ if [ -f " $MODPATH /autopif4.sh" ]; then
62126 if command -v timeout > /dev/null 2>&1 ; then
63- timeout 60 sh " $MODPATH /autopif4.sh" -s -m
127+ timeout 10 sh " $MODPATH /autopif4.sh" -s -m >> " $CONFIG_DIR /autopif.log " 2>&1 && FP_OK=1
64128 else
65- sh " $MODPATH /autopif4.sh" -s -m
129+ sh " $MODPATH /autopif4.sh" -s -m >> " $CONFIG_DIR /autopif.log" 2>&1 && FP_OK=1
130+ fi
131+ [ " $FP_OK " = 1 ] && FP_SRC=" pif"
132+ fi
133+
134+ # Fallback B: shipped static fingerprints (alternate between 2 each tap) —
135+ # guarantees a fingerprint even with no network at all.
136+ if [ " $FP_OK " = 0 ]; then
137+ IDX_FILE=" $CONFIG_DIR /.fp_idx"
138+ IDX=$( cat " $IDX_FILE " 2> /dev/null)
139+ if [ " $IDX " = " 2" ]; then IDX=1; else IDX=2; fi
140+ echo " $IDX " > " $IDX_FILE " 2> /dev/null
141+
142+ FB=" $MODPATH /pif_fallback_${IDX} .prop"
143+ if [ -s " $FB " ] && grep -q " FINGERPRINT=" " $FB " ; then
144+ cp -f " $FB " " $CONFIG_DIR /pif.prop"
145+ FP_OK=1; FP_SRC=" local"
66146 fi
67- }
68- run_autopif > " $CONFIG_DIR /autopif.log" 2>&1 \
69- || { sleep 2; run_autopif >> " $CONFIG_DIR /autopif.log" 2>&1 || FP_OK=0; }
147+ fi
70148fi
71149
72- # --- enforce STRONG-friendly spoof settings on every pif variant ----------
150+ case " $FP_SRC " in
151+ pif|native) row " 🌐" " fingerprint ok" ;;
152+ local) row " 🌐" " fingerprint ok (local)" ;;
153+ * ) row " ⚠️" " fingerprint failed" ;;
154+ esac
155+ sleep 1
156+
157+ # --- Step 4: Spoof settings + security patch ---
73158for f in " $MODPATH /custom.pif.prop" " $MODPATH /pif.prop" \
74159 " $CONFIG_DIR /custom.pif.prop" " $CONFIG_DIR /pif.prop" ; do
75160 [ -f " $f " ] || continue
@@ -84,42 +169,41 @@ for f in "$MODPATH/custom.pif.prop" "$MODPATH/pif.prop" \
84169 done
85170done
86171
87- # --- sync security patch (attestation + Build) ---------------------------
88- # Pass "boot" so this ALSO resetprops ro.build.version.security_patch (and the
89- # vendor/system variants) to match the spoofed fingerprint. Without it the raw
90- # system prop only gets refreshed at boot, so after an Action-driven fingerprint
91- # bump the TEE patch (security_patch.txt) moves ahead while the system prop stays
92- # at the device's real patch — an inconsistency that both looks like "patch not
93- # updating" and can weaken the STRONG verdict. resetprop is available (root) in
94- # the Action context, same as post-fs-data.
95172PATCH=" "
96173[ -f " $MODPATH /sync_patch.sh" ] && PATCH=$( sh " $MODPATH /sync_patch.sh" boot 2> /dev/null)
97174
98- # --- WebUI: Magisk only → fetch KsuWebUI from GitHub if absent (silent) ----
99- dl_out () {
100- if command -v curl > /dev/null 2>&1 ; then curl -fsSL --max-time 20 " $1 "
101- elif [ -x /data/adb/magisk/busybox ]; then /data/adb/magisk/busybox wget -q -T 20 -O - " $1 "
102- elif command -v wget > /dev/null 2>&1 ; then wget -q -T 20 -O - " $1 "
103- else return 1; fi
104- }
105- dl_to () {
106- if command -v curl > /dev/null 2>&1 ; then curl -fsSL --max-time 60 -o " $1 " " $2 "
107- elif [ -x /data/adb/magisk/busybox ]; then /data/adb/magisk/busybox wget -q -T 60 -O " $1 " " $2 "
108- elif command -v wget > /dev/null 2>&1 ; then wget -q -T 60 -O " $1 " " $2 "
109- else return 1; fi
175+ pick_pif () {
176+ for f in " $CONFIG_DIR /custom.pif.prop" " $MODPATH /custom.pif.prop" \
177+ " $CONFIG_DIR /pif.prop" " $MODPATH /pif.prop" ; do
178+ [ -s " $f " ] && { echo " $f " ; return 0; }
179+ done
180+ return 1
110181}
111- # Only Magisk needs the standalone WebUI app. KSU/KSU-Next/APatch host the
112- # webroot natively from their own manager, so skip them. The APK download used
113- # to run inline, which blocked the Action button for up to a minute on Magisk
114- # on every tap the app wasn't installed yet. Do it in the BACKGROUND so the
115- # summary prints immediately; a lock file keeps repeated taps from stacking
116- # downloads, and a stale lock (tap that never finished) is cleared after 5 min.
117- WEBUI_MSG=" "
182+ PIF=$( pick_pif)
183+ MD=$( grep -m1 ' ^MODEL=' " $PIF " 2> /dev/null | cut -d= -f2-)
184+ [ -z " $PATCH " ] && PATCH=$( grep -m1 ' ^SECURITY_PATCH=' " $PIF " 2> /dev/null | cut -d= -f2-)
185+
186+ row " 🗓️" " ${PATCH:- unknown} "
187+ sleep 1
188+
189+ # --- Step 5: Device ---
190+ row " 📱" " ${MD:- unknown} "
191+ sleep 1
192+
193+ # --- Restart PI + status ---
194+ killall -9 com.google.android.gms.unstable 2> /dev/null
195+ killall -9 com.android.vending 2> /dev/null
196+ am force-stop com.android.vending > /dev/null 2>&1
197+
198+ if [ -x " $MODPATH /status_fetch.sh" ]; then
199+ MODPATH=" $MODPATH " sh " $MODPATH /status_fetch.sh" manual > /dev/null 2>&1
200+ fi
201+
202+ # --- WebUI: Magisk only (background, silent) ---
118203if [ -d /data/adb/magisk ] && [ " $KSU " != " true" ] && [ " $APATCH " != " true" ]; then
119204 PKG=io.github.a13e300.ksuwebui
120205 [ -n " $( find " $MODPATH /.webui_busy" -mmin +5 2> /dev/null) " ] && rm -f " $MODPATH /.webui_busy" 2> /dev/null
121206 if ! pm path " $PKG " > /dev/null 2>&1 && [ ! -f " $MODPATH /.webui_busy" ]; then
122- WEBUI_MSG=" 📲|installing WebUI app (background)"
123207 : > " $MODPATH /.webui_busy"
124208 {
125209 T=/data/local/tmp/.aswebui.apk
@@ -136,48 +220,7 @@ if [ -d /data/adb/magisk ] && [ "$KSU" != "true" ] && [ "$APATCH" != "true" ]; t
136220 fi
137221fi
138222
139- # --- restart PI (silent) -------------------------------------------------
140- killall -9 com.google.android.gms.unstable 2> /dev/null
141- killall -9 com.android.vending 2> /dev/null
142- am force-stop com.android.vending > /dev/null 2>&1
143-
144- # --- update module.prop status indicator ---------------------------------
145- if [ -x " $MODPATH /status_fetch.sh" ]; then
146- MODPATH=" $MODPATH " sh " $MODPATH /status_fetch.sh" manual > /dev/null 2>&1
147- fi
148-
149- # --- summary -------------------------------------------------------------
150- pick_pif () {
151- for f in " $CONFIG_DIR /custom.pif.prop" " $MODPATH /custom.pif.prop" \
152- " $CONFIG_DIR /pif.prop" " $MODPATH /pif.prop" ; do
153- [ -s " $f " ] && { echo " $f " ; return 0; }
154- done
155- return 1
156- }
157- PIF=$( pick_pif)
158- MD=$( grep -m1 ' ^MODEL=' " $PIF " 2> /dev/null | cut -d= -f2-)
159- [ -z " $PATCH " ] && PATCH=$( grep -m1 ' ^SECURITY_PATCH=' " $PIF " 2> /dev/null | cut -d= -f2-)
160-
161- row " 📱" " ${MD:- unknown} "
162- row " 🗓️" " ${PATCH:- unknown} "
163-
164- if [ " $FP_OK " = 1 ]; then
165- row " 🌐" " fingerprint fresh"
166- else
167- row " ⚠️" " fingerprint cached (offline?)"
168- fi
169-
170- KB=" $CONFIG_DIR /keybox.xml"
171- if [ -s " $KB " ] && head -c 4096 " $KB " | grep -q " Keybox" ; then
172- row " 🔑" " keybox ok"
173- else
174- row " ⚠️" " keybox missing"
175- fi
176-
177- [ -n " $TGT_N " ] && row " 🎯" " ${TGT_N} apps → target"
178-
179- [ -n " $WEBUI_MSG " ] && row " ${WEBUI_MSG%% |* } " " ${WEBUI_MSG#* |} "
180-
223+ # --- Done ---
181224echo " $LINE "
182225row " ✅" " done"
183226echo " $LINE "
0 commit comments