diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4782d63..ac58a71 100755
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -59,4 +59,6 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
+ compileOnly("de.robv.android.xposed:api:82")
+ compileOnly("de.robv.android.xposed:api:82:sources")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 49e30ac..2609d98 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -39,6 +39,17 @@
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/xpsoed_init b/app/src/main/assets/xpsoed_init
new file mode 100644
index 0000000..8a8e2ae
--- /dev/null
+++ b/app/src/main/assets/xpsoed_init
@@ -0,0 +1 @@
+io.sixminutes.ridicule.hook
\ No newline at end of file
diff --git a/app/src/main/java/io/sixminutes/ridicule/hook.java b/app/src/main/java/io/sixminutes/ridicule/hook.java
new file mode 100644
index 0000000..840fedb
--- /dev/null
+++ b/app/src/main/java/io/sixminutes/ridicule/hook.java
@@ -0,0 +1,556 @@
+package io.sixminutes.ridicule;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.robv.android.xposed.IXposedHookLoadPackage;
+import de.robv.android.xposed.XC_MethodHook;
+import de.robv.android.xposed.XposedHelpers;
+import de.robv.android.xposed.XposedBridge;
+import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
+import de.robv.android.xposed.IXposedHookZygoteInit;
+
+public class hook implements IXposedHookZygoteInit, IXposedHookLoadPackage{
+ private static final int screen_height = 2340;
+ private static final int screen_width = 2340;
+
+ private static final String device_model = "A001XM";
+ private static final String manufacturer = "Xiaomi";
+ private static final String os_version = "11";
+ private static final Integer SDK_INT = 30;
+ private static final String device_id = "1ac1af0be39f7991";
+
+
+ private static final String country_code = "JP";
+
+ private static final String carrier = "SoftBank";
+ private static final String CUSTOM_ADVERTISING_ID = "48442068-7132-4bd3-9349-707695891ce8";
+
+ public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
+
+ try {
+
+ XposedHelpers.setStaticObjectField(Build.class,"MODEL",device_model);
+ XposedHelpers.setStaticObjectField(Build.class,"MANUFACTURER",manufacturer);
+ XposedHelpers.setStaticObjectField(Build.class,"BRAND",manufacturer);
+ XposedHelpers.setStaticObjectField(Build.VERSION.class,"RELEASE",os_version);
+ XposedHelpers.setStaticIntField(Build.VERSION.class,"SDK_INT",SDK_INT);
+
+ // 修改Device ID
+ XposedHelpers.findAndHookMethod(
+ "android.telephony.TelephonyManager", lpparam.classLoader,
+ "getDeviceId",
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
+ // 修改 getDeviceId 方法的返回值
+ param.setResult(device_id);
+ }
+ });
+
+ // 修改广告ID
+ XposedHelpers.findAndHookMethod(
+ "com.google.android.gms.ads.identifier.AdvertisingIdClient$Info",
+ lpparam.classLoader,
+ "getId",
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ // 返回伪造的广告ID
+ param.setResult(CUSTOM_ADVERTISING_ID);
+ }
+ }
+ );
+ XposedHelpers.findAndHookMethod(
+ "com.google.android.gms.ads.identifier.AdvertisingIdClient",
+ lpparam.classLoader,
+ "getAdvertisingIdInfo",
+ Context.class,
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ try {
+ Object info = param.getResult();
+ if (info == null) return;
+ XposedHelpers.findAndHookMethod(
+ info.getClass(),
+ "getId",
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ param.setResult(CUSTOM_ADVERTISING_ID);
+ }
+ }
+ );
+ } catch (Throwable e) {
+ XposedBridge.log("Error in hooking getAdvertisingIdInfo: " + e);
+ }
+ }
+ }
+ );
+
+// //修改分辨率
+// // 修改全局DisplayMetrics
+// XposedHelpers.findAndHookMethod(
+// "android.content.res.Resources", // 目标类
+// lpparam.classLoader, // 类加载器
+// "getDisplayMetrics", // 方法名
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// DisplayMetrics metrics = (DisplayMetrics) param.getResult();
+// if (metrics == null) return;
+//
+// // 修改分辨率
+// metrics.widthPixels = 1080; // 屏幕宽度
+// metrics.heightPixels = 1920; // 屏幕高度
+// metrics.density = 420 / 160f; // density = dpi / 160
+// metrics.densityDpi = 420; // DPI
+// metrics.scaledDensity = metrics.density; // 字体缩放密度(通常与density一致)
+//
+// param.setResult(metrics); // 返回修改后的metrics
+// }
+// }
+// );
+// // Hook WindowManager.getDefaultDisplay().getRealMetrics()
+// XposedHelpers.findAndHookMethod(
+// "android.view.Display", // 目标类
+// lpparam.classLoader,
+// "getRealMetrics",
+// DisplayMetrics.class, // 参数类型
+// new XC_MethodHook() {
+// @Override
+// protected void beforeHookedMethod(MethodHookParam param) {
+// DisplayMetrics metrics = (DisplayMetrics) param.args[0];
+// if (metrics == null) return;
+//
+// // 修改传入的DisplayMetrics对象
+// metrics.widthPixels = 1080;
+// metrics.heightPixels = 1920;
+// metrics.densityDpi = 420;
+// }
+// }
+// );
+// // Hook Display.getRealSize()
+// XposedHelpers.findAndHookMethod(
+// "android.view.Display",
+// lpparam.classLoader,
+// "getRealSize",
+// Point.class, // 参数类型为Point
+// new XC_MethodHook() {
+// @Override
+// protected void beforeHookedMethod(MethodHookParam param) {
+// Point point = (Point) param.args[0];
+// if (point == null) return;
+//
+// point.x = 1080; // 修改宽度
+// point.y = 1920; // 修改高度
+// }
+// }
+// );
+
+
+// // 修改运营商信息
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.SubscriptionManager",
+// lpparam.classLoader,
+// "getActiveSubscriptionInfoList",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// // 创建一个伪造的 SubscriptionInfo 列表(即使原列表为空)
+// List fakeList = new ArrayList<>();
+// fakeList.add(createFakeSubscriptionInfo());
+// param.setResult(fakeList);
+// }
+// }
+// );
+// // Hook getNetworkOperator() 返回伪造的 MCC-MNC
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.TelephonyManager",
+// lpparam.classLoader,
+// "getNetworkOperator",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult("310260");
+// }
+// }
+// );
+//
+//// Hook getSimOperator()
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.TelephonyManager",
+// lpparam.classLoader,
+// "getSimOperator",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult("310260");
+// }
+// }
+// );
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.ServiceState",
+// lpparam.classLoader,
+// "getOperatorNumeric",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult("310260");
+// }
+// }
+// );
+//
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.ServiceState",
+// lpparam.classLoader,
+// "getOperatorAlphaLong",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult("Fake Carrier");
+// }
+// }
+// );
+// // 设置运营商 MCC-MNC
+// XposedHelpers.callStaticMethod(
+// lpparam.classLoader.loadClass("android.os.SystemProperties"),
+// "set",
+// "gsm.operator.numeric",
+// "310,260"
+// );
+//
+//// 设置运营商名称
+// XposedHelpers.callStaticMethod(
+// lpparam.classLoader.loadClass("android.os.SystemProperties"),
+// "set",
+// "gsm.operator.alpha",
+// "Fake Carrier"
+// );
+//
+//// 设置 SIM 卡状态为就绪
+// XposedHelpers.callStaticMethod(
+// lpparam.classLoader.loadClass("android.os.SystemProperties"),
+// "set",
+// "gsm.sim.state",
+// "READY"
+// );
+// // Hook TelephonyManager.getSimState()
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.TelephonyManager",
+// lpparam.classLoader,
+// "getSimState",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult(TelephonyManager.SIM_STATE_READY); // SIM 卡已就绪
+// }
+// }
+// );
+// XposedHelpers.findAndHookMethod(
+// "android.telephony.TelephonyManager",
+// lpparam.classLoader,
+// "getSimSerialNumber",
+// new XC_MethodHook() {
+// @Override
+// protected void afterHookedMethod(MethodHookParam param) {
+// param.setResult("89014103211118510720"); // 伪造的 ICCID
+// }
+// }
+// );
+
+ } catch (Exception e) {
+ XposedBridge.log("修改设备型号时出错: " + e.getMessage());
+ }
+
+ }
+
+ // 通用Hook方法:记录方法调用和堆栈
+ private void hookTelephonyMethod(String className, String methodName, ClassLoader classLoader) {
+ try {
+ XposedHelpers.findAndHookMethod(
+ className,
+ classLoader,
+ methodName,
+ new XC_MethodHook() {
+ @Override
+ protected void beforeHookedMethod(MethodHookParam param) {
+ // 记录方法调用
+ String log = String.format(
+ "[Carrier Probe] Called: %s.%s() from %s",
+ className,
+ methodName,
+ getCallingPackage(param)
+ );
+ XposedBridge.log(log);
+
+ }
+ }
+ );
+ } catch (Throwable e) {
+ XposedBridge.log("Hook failed: " + e);
+ }
+ }
+
+ // 获取调用者包名
+ private String getCallingPackage(XC_MethodHook.MethodHookParam param) {
+ try {
+ return param.thisObject.getClass().getPackage().getName();
+ } catch (Exception e) {
+ return "unknown";
+ }
+ }
+
+
+
+ @Override
+ public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) throws Throwable {
+ try {
+ // Hook WindowManager 的 updateViewLayout 方法
+ XposedHelpers.findAndHookMethod(
+ "android.view.WindowManagerGlobal", null, "updateViewLayout",
+ android.view.View.class, android.view.ViewGroup.LayoutParams.class,
+ new XC_MethodHook() {
+// @Override
+// protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
+// android.view.ViewGroup.LayoutParams params = (android.view.ViewGroup.LayoutParams) param.args[1];
+// // 修改布局参数的宽度和高度
+// params.width = convertDpToPx(screen_width);
+// params.height = convertDpToPx(screen_height);
+// XposedBridge.log("Resolution modified in initZygote: " + screen_width + "dp x " + screen_height + "dp");
+// }
+ });
+ } catch (Exception e) {
+ XposedBridge.log("Error hooking WindowManagerGlobal: " + e.getMessage());
+ }
+ }
+
+ // 辅助方法:将 dp 转换为 px
+ private int convertDpToPx(int dp) {
+ final float scale = android.util.TypedValue.applyDimension(
+ android.util.TypedValue.COMPLEX_UNIT_DIP, dp,
+ android.content.res.Resources.getSystem().getDisplayMetrics());
+ return (int) (scale + 0.5f);
+ }
+
+// private SubscriptionInfo createFakeSubscriptionInfo(SubscriptionInfo original, LoadPackageParam lpparam) {
+// return (SubscriptionInfo) Proxy.newProxyInstance(
+// lpparam.classLoader,
+// new Class[]{SubscriptionInfo.class},
+// new InvocationHandler() {
+// @Override
+// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+// String methodName = method.getName();
+// // 修改关键字段的返回值
+// switch (methodName) {
+// case "getCarrierName":
+// return "Fake Carrier"; // 运营商名称
+// case "getMcc":
+// return 310; // 伪造 MCC
+// case "getMnc":
+// return 260; // 伪造 MNC
+// case "getCountryIso":
+// return "us"; // 国家代码
+// case "getNumber":
+// return "+1234567890"; // 伪造手机号
+// case "getDataRoaming":
+// return 0; // 关闭数据漫游
+// case "getSimSlotIndex":
+// return 0;
+// default:
+// // 保留原始对象其他属性
+// return method.invoke(original, args);
+// }
+// }
+// }
+// );
+// }
+
+ private SubscriptionInfo createFakeSubscriptionInfo() {
+ try {
+ // 使用反射调用隐藏的 SubscriptionInfo 构造函数
+ Class> clazz = Class.forName("android.telephony.SubscriptionInfo");
+ Constructor> constructor = clazz.getDeclaredConstructor(
+ int.class, // subscriptionId
+ String.class, // iccId
+ int.class, // simSlotIndex
+ CharSequence.class, // displayName
+ CharSequence.class, // carrierName
+ int.class, // mcc
+ int.class, // mnc
+ String.class, // countryIso
+ int.class, // dataRoaming
+ Bitmap.class, // iconBitmap
+ String.class, // number
+ int.class, // dataRoaming
+ int.class, // mcc
+ int.class, // mnc
+ String.class, // countryIso
+ boolean.class, // isEmbedded
+ String.class, // cardString
+ String.class // groupUUID
+ );
+ constructor.setAccessible(true);
+
+ return (SubscriptionInfo) constructor.newInstance(
+ 1, // subscriptionId
+ "89014103211118510720", // 伪造的 ICCID
+ 0, // simSlotIndex (卡槽0)
+ "Fake Carrier", // displayName
+ "Fake Carrier", // carrierName
+ 310, // MCC (美国)
+ 260, // MNC (AT&T)
+ "us", // countryIso
+ 0, // dataRoaming (关闭)
+ null, // iconBitmap (无图标)
+ "+1234567890", // 手机号
+ 0, // dataRoaming
+ 310, // mcc
+ 260, // mnc
+ "us", // countryIso
+ false, // isEmbedded
+ "00000000", // cardString
+ "group-001" // groupUUID
+ );
+ } catch (Throwable e) {
+ XposedBridge.log("Failed to create fake SubscriptionInfo: " + e);
+ return null;
+ }
+ }
+
+
+// private SubscriptionInfo createFakeSubscriptionInfo() {
+// try {
+// // 获取 Builder 类
+// Class> builderClass = Class.forName("android.telephony.SubscriptionInfo$Builder");
+// Object builder = XposedHelpers.newInstance(builderClass);
+//
+// // 链式调用设置参数
+// XposedHelpers.callMethod(builder, "setId", 1);
+// XposedHelpers.callMethod(builder, "setIccId", "89014103211118510720");
+// XposedHelpers.callMethod(builder, "setSimSlotIndex", 0);
+// XposedHelpers.callMethod(builder, "setDisplayName", "Fake Carrier");
+// XposedHelpers.callMethod(builder, "setCarrierName", "Fake Carrier");
+// XposedHelpers.callMethod(builder, "setMcc", 310);
+// XposedHelpers.callMethod(builder, "setMnc", 260);
+// XposedHelpers.callMethod(builder, "setCountryIso", "us");
+// // ... 其他参数
+//
+// // 构建 SubscriptionInfo
+// return (SubscriptionInfo) XposedHelpers.callMethod(builder, "build");
+// } catch (Throwable e) {
+// XposedBridge.log("Error using Builder: " + e);
+// return null;
+// }
+// }
+// private SubscriptionInfo createFakeSubscriptionInfo() {
+// try {
+// // 通过反射获取 Builder 类
+// Class> subscriptionInfoClass = Class.forName("android.telephony.SubscriptionInfo");
+// Class> builderClass = Class.forName("android.telephony.SubscriptionInfo$Builder");
+//
+// // 创建 Builder 实例
+// Object builder = XposedHelpers.newInstance(builderClass);
+//
+// // 链式调用设置参数
+// XposedHelpers.callMethod(builder, "setId", 1);
+// XposedHelpers.callMethod(builder, "setIccId", "89014103211118510720");
+// XposedHelpers.callMethod(builder, "setSimSlotIndex", 0);
+// XposedHelpers.callMethod(builder, "setDisplayName", "Fake Carrier");
+// XposedHelpers.callMethod(builder, "setCarrierName", "Fake Carrier");
+// XposedHelpers.callMethod(builder, "setMcc", 310);
+// XposedHelpers.callMethod(builder, "setMnc", 260);
+// // ... 其他参数
+//
+// // 调用 build() 方法生成对象
+// return (SubscriptionInfo) XposedHelpers.callMethod(builder, "build");
+// } catch (Throwable e) {
+// XposedBridge.log("Fallback to proxy due to error: " + e);
+// return createFakeSubscriptionInfo(); // 回退到动态代理
+// }
+// }
+
+ // private SubscriptionInfo createFakeSubscriptionInfo(LoadPackageParam lpparam) {
+// return (SubscriptionInfo) Proxy.newProxyInstance(
+// lpparam.classLoader,
+// new Class[]{SubscriptionInfo.class},
+// (proxy, method, args) -> {
+// String methodName = method.getName();
+// switch (methodName) {
+// case "getCarrierName":
+// return "Fake Carrier";
+// case "getMcc":
+// return 310;
+// case "getMnc":
+// return 260;
+// case "getSimSlotIndex":
+// return 0;
+// case "getSubscriptionId":
+// return 1;
+// case "toString":
+// return "FakeSubscriptionInfo";
+// default:
+// // 返回默认值或抛出异常(根据方法返回值类型)
+// Class> returnType = method.getReturnType();
+// if (returnType == boolean.class) return false;
+// if (returnType == int.class) return 0;
+// return null;
+// }
+// }
+// );
+// }
+ private SubscriptionInfo createProxySubscriptionInfo(LoadPackageParam lpparam) {
+ return (SubscriptionInfo) Proxy.newProxyInstance(
+ lpparam.classLoader,
+ new Class[]{SubscriptionInfo.class},
+ (proxy, method, args) -> {
+ switch (method.getName()) {
+ case "getCarrierName": return "Fake Carrier";
+ case "getMcc": return 310;
+ case "getMnc": return 260;
+ case "getSimSlotIndex": return 0;
+ default:
+ // 处理其他方法(返回合理默认值)
+ if (method.getReturnType() == boolean.class) return false;
+ if (method.getReturnType() == int.class) return 0;
+ return null;
+ }
+ }
+ );
+ }
+
+ private void hookTelephonyMethods(ClassLoader classLoader) {
+ XposedHelpers.findAndHookMethod(
+ "android.telephony.TelephonyManager",
+ classLoader,
+ "getNetworkOperator",
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ param.setResult("310260");
+ }
+ }
+ );
+
+ XposedHelpers.findAndHookMethod(
+ "android.telephony.TelephonyManager",
+ classLoader,
+ "getSimState",
+ new XC_MethodHook() {
+ @Override
+ protected void afterHookedMethod(MethodHookParam param) {
+ param.setResult(TelephonyManager.SIM_STATE_READY);
+ }
+ }
+ );
+ }
+}
diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml
new file mode 100644
index 0000000..8b017cf
--- /dev/null
+++ b/app/src/main/res/values/array.xml
@@ -0,0 +1,6 @@
+
+
+
+ - io.sixminutes.breakingnews
+
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f6cb273..86c278f 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Thu Jan 23 16:34:58 CST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9f77fb6..e0e3b97 100755
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -14,6 +14,7 @@ pluginManagement {
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
+ maven { setUrl("https://maven.aliyun.com/repository/public") }
google()
mavenCentral()
}