From 09088c3a7bfc8382c9e53b9b804e657d5aceee86 Mon Sep 17 00:00:00 2001 From: MRKT_ROOT <70987589+loliconRoot@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:02:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D=E5=BC=80?= =?UTF-8?q?=E5=B1=8F=E5=B9=BF=E5=91=8A=E8=B7=B3=E8=BF=87=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20(#1708)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 注意:采用claude code进行辅助分析和构建,所有代码和设计经过人工审核 测试版本:8.46.0 / 8.95.0 已确认功能可以正常运行,确认成功清除拉取的信息,所有调试日志代码已移除 开屏广告的数据从FastJSON迁移到了Gson,导致原有Hook失效。所以添加了一个GsonHook处理相关数据。 tv.danmaku.bili.ui.splash.SplashData -> tv.danmaku.bili.splash.ad.model.SplashListResponse --- .../me/iacn/biliroaming/BiliBiliPackage.kt | 1 + .../java/me/iacn/biliroaming/XposedInit.kt | 1 + .../java/me/iacn/biliroaming/hook/GsonHook.kt | 52 +++++++++++++++++++ .../biliroaming/hook/gson/GsonProcessor.kt | 12 +++++ .../hook/gson/SplashListProcessor.kt | 17 ++++++ .../hook/gson/SplashShowProcessor.kt | 16 ++++++ 6 files changed, 99 insertions(+) create mode 100644 app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt create mode 100644 app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt create mode 100644 app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt create mode 100644 app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt diff --git a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt index 51081fc945..b00f028898 100644 --- a/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt +++ b/app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt @@ -48,6 +48,7 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex val bangumiApiResponseClass by Weak { mHookInfo.bangumiApiResponse from mClassLoader } val rxGeneralResponseClass by Weak { "com.bilibili.okretro.call.rxjava.RxGeneralResponse" from mClassLoader } val fastJsonClass by Weak { mHookInfo.fastJson.class_ from mClassLoader } + val gsonClass by Weak { "com.google.gson.Gson" from mClassLoader } val bangumiUniformSeasonClass by Weak { mHookInfo.bangumiSeason from mClassLoader } val kingPositionComponentClass by Weak { mHookInfo.autoLike.kingPositionComponent.class_ from mClassLoader } val storyAbsControllerClass by Weak { mHookInfo.autoLike.storyAbsController.class_ from mClassLoader } diff --git a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt index e367abfc88..a4e96979f2 100644 --- a/app/src/main/java/me/iacn/biliroaming/XposedInit.kt +++ b/app/src/main/java/me/iacn/biliroaming/XposedInit.kt @@ -88,6 +88,7 @@ class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit { startHook { CustomThemeHook(lpparam.classLoader) } startHook { TeenagersModeHook(lpparam.classLoader) } startHook { JsonHook(lpparam.classLoader) } + startHook { GsonHook(lpparam.classLoader) } startHook { ShareHook(lpparam.classLoader) } startHook { AutoLikeHook(lpparam.classLoader) } startHook { SettingHook(lpparam.classLoader) } diff --git a/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt new file mode 100644 index 0000000000..f5768c4d7b --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/GsonHook.kt @@ -0,0 +1,52 @@ +package me.iacn.biliroaming.hook + +import me.iacn.biliroaming.BiliBiliPackage.Companion.instance +import me.iacn.biliroaming.hook.gson.GsonProcessor +import me.iacn.biliroaming.hook.gson.SplashListProcessor +import me.iacn.biliroaming.hook.gson.SplashShowProcessor +import me.iacn.biliroaming.utils.Log +import me.iacn.biliroaming.utils.getObjectField +import me.iacn.biliroaming.utils.hookAfterAllMethods + +class GsonHook(classLoader: ClassLoader) : BaseHook(classLoader) { + private val allProcessors = listOf( + SplashListProcessor(), + SplashShowProcessor(), + ) + + private val enabledProcessors: Map> by lazy { + allProcessors + .filter { it.shouldEnable() } + .groupBy { it.targetClassName } + } + + override fun startHook() { + if (enabledProcessors.isEmpty()) return + Log.d("startHook: Gson") + + val gsonClass = instance.gsonClass ?: return + val fromJsonName = instance.gsonFromJson() ?: return + + gsonClass.hookAfterAllMethods(fromJsonName) { param -> + dispatchResult(param.result) + } + } + + private fun dispatchResult(result: Any?) { + if (result == null) return + + // Network path: unwrap GeneralResponse -> T + var target = result + if (result.javaClass == instance.generalResponseClass) { + target = result.getObjectField("data") ?: return + } + + enabledProcessors[target.javaClass.name]?.forEach { processor -> + try { + processor.process(target) + } catch (e: Throwable) { + Log.e("GsonHook processor ${processor.targetClassName} error: $e") + } + } + } +} diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt new file mode 100644 index 0000000000..476dde4f26 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/GsonProcessor.kt @@ -0,0 +1,12 @@ +package me.iacn.biliroaming.hook.gson + +interface GsonProcessor { + /** Full class name of the target deserialized type */ + val targetClassName: String + + /** Return true if this processor's settings are enabled */ + fun shouldEnable(): Boolean + + /** Process the deserialized result object */ + fun process(result: Any) +} \ No newline at end of file diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt new file mode 100644 index 0000000000..7deb0e89e9 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashListProcessor.kt @@ -0,0 +1,17 @@ +package me.iacn.biliroaming.hook.gson + +import me.iacn.biliroaming.utils.sPrefs +import me.iacn.biliroaming.utils.getObjectFieldOrNullAs + +class SplashListProcessor : GsonProcessor { + override val targetClassName = + "tv.danmaku.bili.splash.ad.model.SplashListResponse" + + override fun shouldEnable() = + sPrefs.getBoolean("hidden", false) && sPrefs.getBoolean("purify_splash", false) + + override fun process(result: Any) { + result.getObjectFieldOrNullAs>("splashList")?.clear() + result.getObjectFieldOrNullAs>("strategyList")?.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt new file mode 100644 index 0000000000..bd85d9b681 --- /dev/null +++ b/app/src/main/java/me/iacn/biliroaming/hook/gson/SplashShowProcessor.kt @@ -0,0 +1,16 @@ +package me.iacn.biliroaming.hook.gson + +import me.iacn.biliroaming.utils.sPrefs +import me.iacn.biliroaming.utils.getObjectFieldOrNullAs + +class SplashShowProcessor : GsonProcessor { + override val targetClassName = + "tv.danmaku.bili.splash.ad.model.SplashShowResponse" + + override fun shouldEnable() = + sPrefs.getBoolean("hidden", false) && sPrefs.getBoolean("purify_splash", false) + + override fun process(result: Any) { + result.getObjectFieldOrNullAs>("strategyList")?.clear() + } +} \ No newline at end of file