From fa21d36b4fc2c1cc80669ec705f8ff6dbf137978 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:57:12 +0200 Subject: [PATCH 1/7] Add Privacy Advisor activity to menu options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I added a new “Privacy Advisor” feature inside the app that scans installed apps for telephony/SIM-related permissions, shows results, and lets you copy ADB commands to clamp them. Contribution by Gittensor, learn more at https://gittensor.io/ --- .../java/com/secupwn/aimsicd/ui/activities/MainActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/MainActivity.java b/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/MainActivity.java index 45bb9fd1d..7875d65d3 100644 --- a/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/MainActivity.java +++ b/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/MainActivity.java @@ -558,6 +558,10 @@ public boolean onOptionsItemSelected(MenuItem item) { Intent i = new Intent(this, DebugLogs.class); startActivity(i); break; + case R.id.privacy_advisor: + Intent pa = new Intent(this, PrivacyAdvisorActivity.class); + startActivity(pa); + break; } return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item); From 0438785e50954b300112dbd824a64da47a70ae1a Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:58:39 +0200 Subject: [PATCH 2/7] Create PrivacyAdvisorActivity.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I added a new “Privacy Advisor” feature inside the app that scans installed apps for telephony/SIM-related permissions, shows results, and lets you copy ADB commands to clamp them. --- .../ui/activities/PrivacyAdvisorActivity.java | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/PrivacyAdvisorActivity.java diff --git a/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/PrivacyAdvisorActivity.java b/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/PrivacyAdvisorActivity.java new file mode 100644 index 000000000..2a73de62d --- /dev/null +++ b/AIMSICD/src/main/java/com/secupwn/aimsicd/ui/activities/PrivacyAdvisorActivity.java @@ -0,0 +1,256 @@ +/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project + * ----------------------------------------------------------- + * LICENSE: http://git.io/vki47 | TERMS: http://git.io/vki4o + * ----------------------------------------------------------- + */ +package com.secupwn.aimsicd.ui.activities; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.secupwn.aimsicd.R; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +public class PrivacyAdvisorActivity extends BaseActivity { + + private ListView listView; + private ProgressBar progressBar; + private TextView emptyView; + + private ArrayAdapter adapter; + private final List items = new ArrayList<>(); + + private static final Set TELEPHONY_PERMS = new HashSet<>(Arrays.asList( + android.Manifest.permission.READ_PHONE_STATE, + android.Manifest.permission.READ_PHONE_NUMBERS, + android.Manifest.permission.READ_SMS, + android.Manifest.permission.READ_CALL_LOG + )); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_privacy_advisor); + + listView = (ListView) findViewById(R.id.privacy_list); + progressBar = (ProgressBar) findViewById(R.id.privacy_progress); + emptyView = (TextView) findViewById(R.id.privacy_empty); + + adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_2, android.R.id.text1, items) { + @Override + public View getView(int position, View convertView, android.view.ViewGroup parent) { + View v = super.getView(position, convertView, parent); + TextView t1 = (TextView) v.findViewById(android.R.id.text1); + TextView t2 = (TextView) v.findViewById(android.R.id.text2); + AppPerms ap = getItem(position); + if (ap != null) { + t1.setText(ap.label + " (" + ap.packageName + ")"); + t2.setText(getString(R.string.privacy_perms_count, ap.relevantGrantedCount, ap.relevantRequestedCount)); + } + return v; + } + }; + listView.setAdapter(adapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + AppPerms ap = adapter.getItem(position); + if (ap != null) { + showDetailsDialog(ap); + } + } + }); + + loadData(); + } + + private void loadData() { + progressBar.setVisibility(View.VISIBLE); + emptyView.setVisibility(View.GONE); + listView.setVisibility(View.GONE); + + new Thread(new Runnable() { + @Override + public void run() { + final List result = scanInstalled(); + runOnUiThread(new Runnable() { + @Override + public void run() { + items.clear(); + items.addAll(result); + adapter.notifyDataSetChanged(); + + progressBar.setVisibility(View.GONE); + if (items.isEmpty()) { + emptyView.setVisibility(View.VISIBLE); + listView.setVisibility(View.GONE); + } else { + listView.setVisibility(View.VISIBLE); + emptyView.setVisibility(View.GONE); + } + } + }); + } + }).start(); + } + + private List scanInstalled() { + PackageManager pm = getPackageManager(); + List pkgs = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS); + List result = new ArrayList<>(); + + for (PackageInfo pi : pkgs) { + if (pi.requestedPermissions == null || pi.requestedPermissions.length == 0) { + continue; + } + List requested = new ArrayList<>(); + List granted = new ArrayList<>(); + + for (int i = 0; i < pi.requestedPermissions.length; i++) { + String perm = pi.requestedPermissions[i]; + if (!TELEPHONY_PERMS.contains(perm)) continue; + + requested.add(perm); + boolean isGranted = false; + if (pi.requestedPermissionsFlags != null && pi.requestedPermissionsFlags.length > i) { + isGranted = (pi.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; + } else { + isGranted = pm.checkPermission(perm, pi.packageName) == PackageManager.PERMISSION_GRANTED; + } + if (isGranted) { + granted.add(perm); + } + } + + if (!requested.isEmpty()) { + CharSequence label; + try { + label = pm.getApplicationLabel(pm.getApplicationInfo(pi.packageName, 0)); + } catch (PackageManager.NameNotFoundException e) { + label = pi.packageName; + } + result.add(new AppPerms(pi.packageName, label.toString(), requested, granted)); + } + } + + Collections.sort(result, new Comparator() { + @Override + public int compare(AppPerms o1, AppPerms o2) { + // Sort by granted count desc, then label + int g = Integer.valueOf(o2.relevantGrantedCount).compareTo(o1.relevantGrantedCount); + if (g != 0) return g; + return o1.label.compareToIgnoreCase(o2.label); + } + }); + + return result; + } + + private void showDetailsDialog(final AppPerms ap) { + StringBuilder sb = new StringBuilder(); + sb.append(getString(R.string.privacy_dialog_pkg)).append(" ").append(ap.packageName).append("\n\n"); + if (!ap.relevantRequested.isEmpty()) { + sb.append(getString(R.string.privacy_dialog_requested)).append("\n"); + for (String rp : ap.relevantRequested) { + sb.append("• ").append(humanizePermission(rp)); + if (ap.relevantGranted.contains(rp)) { + sb.append(" ").append(getString(R.string.privacy_dialog_granted)); + } else { + sb.append(" ").append(getString(R.string.privacy_dialog_denied)); + } + sb.append("\n"); + } + } + + final String adb = buildAdbCommands(ap.packageName, ap.relevantRequested); + + new AlertDialog.Builder(this) + .setTitle(getString(R.string.privacy_dialog_title, ap.label)) + .setMessage(sb.toString()) + .setPositiveButton(R.string.privacy_copy_cmds, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + copyToClipboard(adb); + } + }) + .setNegativeButton(android.R.string.cancel, null) + .show(); + } + + private String humanizePermission(String perm) { + if (android.Manifest.permission.READ_PHONE_STATE.equals(perm)) return getString(R.string.perm_read_phone_state); + if (android.Manifest.permission.READ_PHONE_NUMBERS.equals(perm)) return getString(R.string.perm_read_phone_numbers); + if (android.Manifest.permission.READ_SMS.equals(perm)) return getString(R.string.perm_read_sms); + if (android.Manifest.permission.READ_CALL_LOG.equals(perm)) return getString(R.string.perm_read_call_log); + return perm; + } + + private void copyToClipboard(String text) { + ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + if (cm != null) { + cm.setPrimaryClip(ClipData.newPlainText("adb", text)); + } + } + + private String buildAdbCommands(String pkg, List perms) { + StringBuilder sb = new StringBuilder(); + sb.append("# Replace PKG if needed\n"); + sb.append("PKG=").append(pkg).append("\n\n"); + for (String p : perms) { + sb.append("adb shell pm revoke $PKG ").append(p).append("\n"); + } + // App-ops clamps + sb.append("\n# App-ops clamps (Android 10+)\n"); + sb.append("adb shell cmd appops set $PKG READ_DEVICE_IDENTIFIERS ignore\n"); + sb.append("adb shell cmd appops set $PKG READ_PHONE_STATE ignore\n"); + sb.append("adb shell cmd appops set $PKG READ_PHONE_NUMBERS ignore\n"); + sb.append("adb shell cmd appops set $PKG READ_SMS ignore\n"); + sb.append("adb shell cmd appops set $PKG READ_CALL_LOG ignore\n"); + sb.append("\n# Reset app\n"); + sb.append("adb shell am force-stop $PKG\n"); + sb.append("adb shell pm clear $PKG\n"); + return sb.toString(); + } + + @AllArgsConstructor + @ToString + private static class AppPerms { + @Getter + final String packageName; + @Getter + final String label; + @Getter + final List relevantRequested; + @Getter + final List relevantGranted; + + final int relevantRequestedCount() { return relevantRequested == null ? 0 : relevantRequested.size(); } + final int relevantGrantedCount() { return relevantGranted == null ? 0 : relevantGranted.size(); } + } +} + + From 2dd3c139233f29eb62e1c8693f96f7e4104383b1 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:59:58 +0200 Subject: [PATCH 3/7] Update AndroidManifest.xml --- AIMSICD/src/main/AndroidManifest.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AIMSICD/src/main/AndroidManifest.xml b/AIMSICD/src/main/AndroidManifest.xml index 983b980d2..91d27ad02 100644 --- a/AIMSICD/src/main/AndroidManifest.xml +++ b/AIMSICD/src/main/AndroidManifest.xml @@ -104,6 +104,16 @@ + + + + + + Date: Wed, 12 Nov 2025 12:00:56 +0200 Subject: [PATCH 4/7] Create activity_privacy_advisor.xml --- .../res/layout/activity_privacy_advisor.xml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 AIMSICD/src/main/res/layout/activity_privacy_advisor.xml diff --git a/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml b/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml new file mode 100644 index 000000000..1fad2bddf --- /dev/null +++ b/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + From c19715da1ea2d324ba8ac16d505e41c423235ec0 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:01:55 +0200 Subject: [PATCH 5/7] Update main_menu.xml --- AIMSICD/src/main/res/menu/main_menu.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/AIMSICD/src/main/res/menu/main_menu.xml b/AIMSICD/src/main/res/menu/main_menu.xml index ee63df847..1770d88f7 100644 --- a/AIMSICD/src/main/res/menu/main_menu.xml +++ b/AIMSICD/src/main/res/menu/main_menu.xml @@ -31,4 +31,9 @@ android:icon="@drawable/ic_action_computer" android:title="@string/debugging" app:showAsAction="never" /> - \ No newline at end of file + + From 6af68363ef6b71922f098a843f180a156abe6349 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:02:32 +0200 Subject: [PATCH 6/7] Update strings.xml added new string. --- AIMSICD/src/main/res/values/strings.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/AIMSICD/src/main/res/values/strings.xml b/AIMSICD/src/main/res/values/strings.xml index 5ecd90551..c7bbe5784 100644 --- a/AIMSICD/src/main/res/values/strings.xml +++ b/AIMSICD/src/main/res/values/strings.xml @@ -1,4 +1,18 @@ Antenna Map Viewer - \ No newline at end of file + Privacy Advisor + Apps requesting phone/SIM permissions (tap for details) + No installed apps request telephony-related permissions. + %1$d granted of %2$d requested + %1$s + Package: + Requested telephony permissions: + (granted) + (denied) + Copy ADB commands + Read phone state + Read phone numbers + Read SMS + Read call log + From 47cc246d5044a880c1056fb36bb8e3991e05ce12 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:04:47 +0200 Subject: [PATCH 7/7] Create TikTok-SIM-Privacy.md --- AIMSICD/TikTok-SIM-Privacy.md | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 AIMSICD/TikTok-SIM-Privacy.md diff --git a/AIMSICD/TikTok-SIM-Privacy.md b/AIMSICD/TikTok-SIM-Privacy.md new file mode 100644 index 000000000..82b5ad5eb --- /dev/null +++ b/AIMSICD/TikTok-SIM-Privacy.md @@ -0,0 +1,45 @@ +## TikTok SIM/Telephony Privacy (Non‑root) + +This guide explains practical steps to prevent apps (e.g., TikTok) from learning SIM/phone identifiers on Android devices without root. + +### 1) Deny phone/SIM permissions +- Settings → Apps → TikTok → Permissions → Phone → Deny. Also deny SMS/Call log if present. +- Force stop TikTok, then Clear storage. + +### 2) Stronger enforcement with ADB (no root) +```bash +# Replace PKG with the exact package of TikTok (e.g., com.zhiliaoapp.musically or com.ss.android.ugc.trill) +PKG=com.zhiliaoapp.musically + +# Revoke telephony-related dangerous permissions +adb shell pm revoke $PKG android.permission.READ_PHONE_STATE +adb shell pm revoke $PKG android.permission.READ_PHONE_NUMBERS +adb shell pm revoke $PKG android.permission.READ_SMS +adb shell pm revoke $PKG android.permission.READ_CALL_LOG + +# Clamp app-ops (Android 10+) +adb shell cmd appops set $PKG READ_DEVICE_IDENTIFIERS ignore +adb shell cmd appops set $PKG READ_PHONE_STATE ignore +adb shell cmd appops set $PKG READ_PHONE_NUMBERS ignore +adb shell cmd appops set $PKG READ_SMS ignore +adb shell cmd appops set $PKG READ_CALL_LOG ignore + +# Reset the app +adb shell am force-stop $PKG +adb shell pm clear $PKG +``` + +### 3) Use a secondary Android user without telephony +- Settings → System → Multiple users → Add user. +- Do not enable “Phone calls & SMS for this user.” +- Switch, install TikTok, use Wi‑Fi. + +### 4) Temporarily disable the SIM subscription +- Settings → Network & Internet → SIMs → toggle OFF the problematic SIM. +- Keep Wi‑Fi ON. Force stop + Clear storage for TikTok before testing. + +### Notes +- Intercepting app traffic is not feasible non‑root due to TLS pinning. +- Use the new “Privacy Advisor” (App → Menu → Privacy Advisor) to see which installed apps request telephony permissions and copy ready‑made ADB commands. + +