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() }