#!/bin/sh # Crawl recursively and test custom JSON files for PIF module, # provided by zgfg @ xda echo "Crawl recursively and test custom JSON files for PIF module\ \n - provided by zgfg @ xda\n" FOLDERS_DEPTH="4" # Increase for crawling deeper than to sub-sub-sub-sub-folders USE_MODULE="PI_FORK" # Default, for testing with PI Fork module from Osm0sis #USE_MODULE="PI_FIX" # For testing with PI Fix module from Chiteroman MIGRATE_JSON="yes" # Enable to pre-process JSON files by migrate.sh script from Osm0sis, migration script must be in this script's folder or in the PI Fork module's folder - don't use if testing with PI Fix module DELETE_FAILED="yes" # Enable to automatically delete JSON files that fail to pass Device Integrity TEST_YASNAC="yes" # Set undefined or empty to skip testing SN with YASNAC, or else script will first test SN with YASNAC (to speed-up filtering of JSON files) YASNAC_Y_COORD="1250" # Try with lower y if it fails to automatically kick "Run SafetyNet Check" button in YASNAC YASNAC_WAIT_VERDICT="8" # SafetyNet verdict usually returns in 3-4 seconds, but if you decrease and verdict arrives later, script will miss to read TEST_PI="TEST_SPIC" # Default, for testing PI with Simple Play Integrity Checker #TEST_PI="TEST_PICHECK" # For testing PI with Play Integrity API Checker #TEST_PI="TEST_TBCHECKER" # For testing PI with TB-Checker #TEST_PI="TEST_IAPI" # For testing PI with Integrity API PIF_JSON="*.json" # Default, PIF JSON mask to test all *.json files #PIF_JSON="custom.pif.json" # PIF JSON mask to test only custom.pif.json files #PIF_JSON="vendor.pif.json" # PIF JSON mask to test only vendor.pif.json files X_COORD="500" # Should fit for all YASNAC, SPIC, TB-Checker, PI API Checker and Integrity API PI_WAIT_VERDICT="10" # Play Integrity verdict usually returns in 5-6 seconds, but if you decrease and verdict arrives later, script will miss to read SPIC_Y_COORD="1000" # Try with lower y if script fails to automatically kick "Make Play Integrity request" button in SPIC PICHECK_Y_COORD="1600" # Try with lower y if it fails to automatically kick "Check" button in PI API Checker TBCHECKER_Y_COORD="1900" # Try with lower y if it fails to automatically kick "Check Play Integrity" button in TB-Checker IAPI_Y_COORD="350" # Try with lower y if it fails to automatically kick "Request A Universal Integrity Token With The Cloud Project" button in Integrity API # Change the code beyond this line only on your own risk module_path="/data/adb/modules/playintegrityfix" [ "$USE_MODULE" != "PI_FIX" ] && USE_MODULE="PI_FORK" && custom_json="$module_path/custom.pif.json" [ "$USE_MODULE" == "PI_FIX" ] && custom_json="/data/adb/pif.json" script_path=${0%/*} migrate_script="$script_path/migrate.sh" [ ! -f "$migrate_script" ] || [ ! -s "$migrate_script" ] && migrate_script="$module_path/migrate.sh" [ ! -f "$migrate_script" ] || [ ! -s "$migrate_script" ] && migrate_script="" test_path="$1"; [ -z "$test_path" ] && test_path="$script_path" custom_bak="$test_path/custom.pif.bak" results="$test_path/pif-test-results.txt"; rm -f "$results" echo "results=$results" echo "PID=$$" | tee -a "$results" echo "script_path=$script_path, test_path=$test_path" | tee -a "$results" echo "USE_MODULE=$USE_MODULE, custom_json=$custom_json" | tee -a "$results" echo "MIGRATE_JSON=$MIGRATE_JSON, migrate_script=$migrate_script, DELETE_FAILED=$DELETE_FAILED" | tee -a "$results" echo "TEST_YASNAC=$TEST_YASNAC, TEST_PI=$TEST_PI, PIF_JSON=$PIF_JSON" | tee -a "$results" echo "" | tee -a "$results" log="$test_path/pif.log" yasnac_xml="$test_path/yasnac.xml"; spic_xml="$test_path/spic.xml"; picheck_xml="$test_path/picheck.xml"; tbchecker_xml="$test_path/tbchecker.xml"; iapi_xml="$test_path/iapi.xml" yasnac="rikka.safetynetchecker" spic="com.henrikherzig.playintegritychecker" picheck=gr.nikolasspyr.integritycheck tbchecker="krypton.tbsafetychecker" iapi="com.test.integrity.api.qa.googlemanaged" integrities="NO_INTEGRITY MEETS_VIRTUAL_INTEGRITY MEETS_BASIC_INTEGRITY MEETS_DEVICE_INTEGRITY MEETS_STRONG_INTEGRITY" rm -f "$custom_bak"; cp "$custom_json" "$custom_bak" >/dev/null 2>&1 orient=$(settings get system user_rotation) auto_rot=$(settings get system accelerometer_rotation) settings put system user_rotation 0 settings put system accelerometer_rotation 0 (( folders = 0 )); (( tested = 0 )); (( migrated = 0 )); (( setApi25 = 0 )); (( passed = 0 )); (( failed = 0 )); (( inconclusive = 0 )) function f_remove_file() { local file="$1" rm -f "$file" >/dev/null 2>&1 } function f_start_activity() { local activity="$1" am start -n "$activity" >/dev/null 2>&1 } function f_kill_app() { local app="$1" am force-stop "$app" >/dev/null 2>&1 } function f_kill_gms() { logcat -c killall com.google.android.gms.unstable >/dev/null 2>&1 } function f_tap_test() { local y_coord="$1" input tap $X_COORD "$y_coord" >/dev/null 2>&1 } function f_dump_xml() { local xml="$1" uiautomator dump "$xml" >/dev/null 2>&1 } function f_test_yasnac() { local json="$1" cp "$json" $custom_json f_remove_file "$log"; f_remove_file "$yasnac_xml" f_start_activity $yasnac/$yasnac.main.MainActivity sleep 2 f_kill_gms f_tap_test $YASNAC_Y_COORD sleep $YASNAC_WAIT_VERDICT f_dump_xml "$yasnac_xml" f_kill_app $yasnac logcat -d | grep PIF >> "$log" (( pass = 0 )); found=$(cat "$yasnac_xml" | grep "Pass") [ -n "$found" ] && (( pass = 1 )) (( fail = 0 )); found=$(cat "$yasnac_xml" | grep "Fail") [ -n "$found" ] && (( fail = 1 )) (( basic = 0 )); found=$(cat "$yasnac_xml" | grep "BASIC") [ -n "$found" ] && (( basic = 1 )) (( hw = 0 )); found=$(cat "$yasnac_xml" | grep "HARDWARE_BACKED") [ -n "$found" ] && (( hw = 1 )) # echo "SN Pass:$pass Fail:$fail BASIC:$basic HW:$hw" | tee -a "$results" ((( basic + hw != 1 )) || (( pass + fail < 1 ))) && return 0 local sn="SN Basic" (( pass == 0 )) && sn="$sn: Fail" (( pass > 0 )) && sn="$sn: Pass" sn="$sn, CTS" (( hw == 0 )) && sn="$sn: BASIC" (( hw > 0 )) && sn="$sn: HARDWARE_BACKED" (( fail > 0 )) && sn="$sn: Fail" (( fail == 0 )) && sn="$sn: Pass" echo "$sn" | tee -a "$results" (( pass == 0 )) && return 1 (( fail > 0 )) && return 2 (( hw == 0 )) && return 3 return 4 } function f_test_spic() { local json="$1" cp "$json" $custom_json f_remove_file "$log"; f_remove_file "$spic_xml" f_start_activity $spic/$spic.MainActivity sleep 2 f_kill_gms f_tap_test $SPIC_Y_COORD sleep $PI_WAIT_VERDICT f_dump_xml "$spic_xml" f_kill_app $spic logcat -d | grep PIF >> "$log" (( i = 0 )); (( val = i++ )) for meets in $integrities do found=$(cat "$spic_xml" | grep $meets) [ -n "$found" ] && echo $meets | tee -a "$results" && (( val = i )) (( i++ )) done return $val } function f_test_picheck() { local json="$1" cp "$json" $custom_json f_remove_file "$log"; f_remove_file "$picheck_xml" f_start_activity $picheck/$picheck.MainActivity sleep 2 f_kill_gms f_tap_test $PICHECK_Y_COORD sleep $PI_WAIT_VERDICT input tap 870 190 sleep 1 f_dump_xml "$picheck_xml" f_kill_app $picheck logcat -d | grep PIF >> "$log" (( i = 0 )); (( val = i++ )) for meets in $integrities do found=$(cat "$picheck_xml" | grep $meets) [ -n "$found" ] && echo $meets | tee -a "$results" && (( val = i )) (( i++ )) done (( val > 0 )) && return $val local deviceIntegrity=$(cat "$picheck_xml" | grep -o "deviceIntegrity") local deviceRecognition=$(cat "$picheck_xml" | grep -o "deviceRecognitionVerdict") # echo "integrity=$deviceIntegrity, recognition=$deviceRecognition" | tee -a "$results" [ -n "$deviceIntegrity" ] && [ -z "$deviceRecognition" ] && echo NO_INTEGRITY | tee -a "$results" && (( val = 1 )) return $val } function f_test_tbchecker() { local json="$1" cp "$json" $custom_json f_remove_file "$log"; f_remove_file "$tbchecker_xml" f_start_activity $tbchecker/$tbchecker.main.MainActivity sleep 2 f_kill_gms f_tap_test $TBCHECKER_Y_COORD sleep $PI_WAIT_VERDICT f_dump_xml "$tbchecker_xml" f_kill_app $tbchecker logcat -d | grep PIF >> "$log" local pass=$(cat "$tbchecker_xml" | grep -o 'Pass' | wc -l) local fail=$(cat "$tbchecker_xml" | grep -o 'Fail' | wc -l) # echo "PI Pass:$pass Fail:$fail" | tee -a "$results" (( val = pass+2 )) (( pass == 1 )) && meets=MEETS_BASIC_INTEGRITY (( pass == 2 )) && meets=MEETS_DEVICE_INTEGRITY (( pass == 3 )) && meets=MEETS_STRONG_INTEGRITY (( pass == 0 )) && meets=NO_INTEGRITY && (( val = 1 )) (( pass == 0 )) && (( fail == 0 )) && meets="" && (( val = 0 )) [ -n "$meets" ] && echo $meets | tee -a "$results" return $val } function f_test_iapi() { local json="$1" cp "$json" $custom_json f_remove_file "$log"; f_remove_file "$iapi_xml" f_start_activity $iapi/com.dynamic.integrity.MainActivity sleep 2 f_kill_gms f_tap_test $IAPI_Y_COORD sleep $PI_WAIT_VERDICT f_dump_xml "$iapi_xml" f_kill_app $iapi logcat -d | grep PIF >> "$log" (( i = 0 )); (( val = i++ )) for meets in $integrities do found=$(cat "$iapi_xml" | grep $meets) [ -n "$found" ] && echo $meets | tee -a "$results" && (( val = i )) (( i++ )) done return $val } function f_test_pi() { local json="$1"; local verbose="$2" local prop=$(cat "$json" | grep -o '"\SECURITY_PATCH"[^,}]*') [ -n "$verbose" ] && [ -n "$prop" ] && echo "$prop" | tee -a "$results" prop=$(cat "$json" | grep -o '"\_ORIGINAL_FIRST_API_LEVEL"[^,}]*') [ -n "$verbose" ] && [ -n "$prop" ] && echo "$prop" | tee -a "$results" prop=$(cat "$json" | grep -o '"\*api_level"[^,}]*') [ -n "$prop" ] && echo "$prop" | tee -a "$results" prop=$(cat "$json" | grep -o '"\DEVICE_INITIAL_SDK_INT"[^,}]*') [ -n "$prop" ] && echo "$prop" | tee -a "$results" prop=$(cat "$json" | grep -o '"\FIRST_API_LEVEL"[^,}]*') [ -n "$prop" ] && echo "$prop" | tee -a "$results" case "$TEST_PI" in TEST_PICHECK) f_test_picheck "$json" ;; TEST_TBCHECKER) f_test_tbchecker "$json" ;; TEST_IAPI) f_test_iapi "$json" ;; TEST_SPIC|*) f_test_spic "$json" ;; esac (( val = $? )); return $val } function f_set_api_25() { local json="$1" sed -i 's/"\*api_level"[^,}]*/"\*api_level": "25"/' "$json" sed -i 's/"DEVICE_INITIAL_SDK_INT"[^,}]*/"DEVICE_INITIAL_SDK_INT": "25"/' "$json" sed -i 's/"FIRST_API_LEVEL"[^,}]*/"FIRST_API_LEVEL": "25"/' "$json" (( setApi25++ )) } function f_migrate_json() { local json="$1"; local folder="$2" local custom="" [ -f "$migrate_script" ] && sh "$migrate_script" -i -f -o -a "$json" && custom="$folder/custom.pif.json" [ -f "$custom" ] && mv "$custom" "$json" && (( migrated++ )) } function f_prep_json() { local json="$1"; local folder="$2" [ -n "$MIGRATE_JSON" ] && f_migrate_json "$json" "$folder" # sed -i 's/"VNDK_VERSION"/"ignore-VNDK_VERSION"/' "$json" [ "$USE_MODULE" == "PI_FORK" ] && api25=$(cat "$json" | grep -o '"\*api_level"[^,}]*' | grep -o '25') local prop=$(cat "$json" | grep -o '"FIRST_API_LEVEL"[^,}]*') [ "$USE_MODULE" == "PI_FIX" ] && [ -n "$api25" ] && api25=$(echo "$prop" | grep -o '25') prop=$(cat "$json" | grep -o '"DEVICE_INITIAL_SDK_INT"[^,}]*') [ "$USE_MODULE" == "PI_FORK" ] && [ -n "$prop" ] && [ -n "$api25" ] && api25=$(echo "$prop" | grep -o '25') # echo "api25=$api25" | tee -a "$results" } function f_test_json() { local json="$1"; local folder="$2" echo "$json" | tee -a "$results" (( tested++ )) f_prep_json "$json" "$folder" (( val = 0 )); local changeApi="" if [ -n "$TEST_YASNAC" ]; then f_test_yasnac "$json"; (( val = $? )) (( val == 2 )) && changeApi="yes" fi # echo "api25=$api25, changeApi=$changeApi" | tee -a "$results" [ -z "$api25" ] && [ -n "$changeApi" ] && f_set_api_25 "$json" (( val != 1 )) && f_test_pi "$json" "yes" && (( val = $? )) (( val > 1 )) && (( val < 4 )) && [ -z "$api25" ] && [ -z "$changeApi" ] && f_set_api_25 "$json" && f_test_pi "$json" && (( val = $? )) (( val > 0 )) && (( val < 4 )) && (( failed++ )) (( val > 0 )) && (( val < 4 )) && [ -n "$DELETE_FAILED" ] && echo "Deleted" | tee -a "$results" && f_remove_file "$json" (( val == 0 )) && echo "Inconclusive" | tee -a "$results" && (( inconclusive++ )) (( val >= 4 )) && (( passed++ )) # echo "tested=$tested, setApi25=$setApi25, passed=$passed" | tee -a "$results" # echo "failed=$failed, inconclusive=$inconclusive" | tee -a "$results" echo "" | tee -a "$results" return $val } function f_test_folder() { local folder="$1" local list=$( ls "$folder"/$PIF_JSON 2>/dev/null ) [ -z "$list" ] && return (( folders++ )) for json in $list do [ -n "$json" ] && [ -f "$json" ] && [ -r "$json" ] && [ -s "$json" ] && f_test_json "$json" "$folder" done } list=$( find "$test_path" -maxdepth $FOLDERS_DEPTH -type d 2>/dev/null ) for folder in $list do [ -n "$folder" ] && [ -e "$folder" ] && f_test_folder "$folder" done echo "folders=$folders" | tee -a "$results" echo "tested=$tested, migrated=$migrated, setApi25=$setApi25" | tee -a "$results" echo "passed=$passed, failed=$failed, inconclusive=$inconclusive" | tee -a "$results" echo "" | tee -a "$results" f_remove_file "$custom_json"; cp "$custom_bak" "$custom_json" >/dev/null 2>&1 f_kill_gms f_kill_app $yasnac; f_kill_app $spic; f_kill_app $picheck; f_kill_app $tbchecker; f_kill_app $iapi f_remove_file "$yasnac_xml"; f_remove_file "$spic_xml"; f_remove_file "$picheck_xml"; f_remove_file "$tbchecker_xml"; f_remove_file "$iapi_xml" settings put system user_rotation "$orient" settings put system accelerometer_rotation "$auto_rot"