吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4649|回复: 100
收起左侧

[Android 原创] 某克浏览器小说阅读去广告初步

  [复制链接]
zzzlanging 发表于 2025-7-20 09:59

注意:本文仅用于技术学习与研究目的,旨在分享 Android 逆向分析思路与实践。修改第三方应用程序的行为可能违反其用户服务条款。侵删

前言

由于在使用该浏览器阅读小说的过程被其不断弹出的广告所困扰,所以决定尝试改善使用该浏览器看小说的体验。主要针对的是底部的横幅广告和翻页过程中出现的广告。

定位

使用开发者助手查看广告控件的属性以及其值

image
然后使用Jadx查看App的源码,在资源文件中搜索这个控件的id

image-20250719125238126

这里选择第一个名称看起来最符合广告的布局文件,查看它的引用,R文件相关的不管,直接去看使用的类

image-20250719125617982

package com.noah.sdk.business.render.container;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import com.noah.api.DownloadApkInfo;
import com.noah.api.SdkRenderRequestInfo;
import com.noah.api.bean.TemplateStyleBean;
import com.noah.logger.util.RunLog;
import com.noah.sdk.business.render.g;
import com.noah.sdk.business.render.template.e;

/* compiled from: ProGuard */
/* loaded from: classes5.dex */
public class c extends b {
    private static final String TAG = "SdkInsideTemplateStyle";
    private TemplateStyleBean aMP;
    private boolean aMQ;
    private int aMd;

    public c(TemplateStyleBean templateStyleBean, boolean z) {
        this.aMQ = z;
        this.aMd = templateStyleBean.getTemplateId();
        this.aMP = templateStyleBean;
    }

    @Override // com.noah.sdk.business.render.container.b
    protected int T(Context context) {
        int i12 = this.aMd;
        String str = "noah_sdk_template_native_ad_layout";
        if (i12 != 1) {
            if (i12 == 3) {
                str = this.aMQ ? "noah_sdk_template_banner_apk_layout" : "noah_sdk_template_banner_ad_layout";
            } else if (i12 == 16) {
                str = "noah_sdk_template_mt_banner_ad_layout";
            } else if (i12 == 17) {
                str = "noah_sdk_template_three_combine_layout";
            } else if (i12 == 5) {
                str = "noah_sdk_template_native_app_info_ad_layout";
            } else if (i12 == 6) {
                str = "noah_sdk_template_banner_three_ad_layout";
            } else if (i12 == 9) {
                str = "noah_sdk_template_native_live_layout";
            } else if (i12 == 10) {
                str = "noah_sdk_template_native_bubble_layout";
            } else if (i12 == 11) {
                str = "noah_sdk_template_native_ad_tv1_layout";
            } else if (i12 == 12) {
                str = "noah_sdk_template_native_ad_tv2_layout";
            } else if (i12 == 13) {
                str = "noah_sdk_template_native_live_tv_layout";
            } else if (i12 == 14) {
                str = "noah_sdk_template_banner_live_layout";
            } else if (i12 == 15) {
                str = "noah_sdk_template_rect_shape";
            }
        }
        RunLog.d(TAG, "使用渲染模版 template id :".concat(str), new Object[0]);
        return g.fI(str);
    }

    @Override // com.noah.sdk.business.render.container.b
    public com.noah.sdk.business.render.a a(SdkRenderRequestInfo sdkRenderRequestInfo, DownloadApkInfo downloadApkInfo) {
        return new e(this, sdkRenderRequestInfo, downloadApkInfo);
    }

    @Override // com.noah.api.delegate.ISdkTemplateContainer
    public int getTemplateId() {
        return this.aMd;
    }

    @Override // com.noah.api.delegate.ISdkTemplateContainer
    public TemplateStyleBean getTemplateStyleBean() {
        return this.aMP;
    }

    @Override // com.noah.api.delegate.ISdkTemplateContainer
    public View getTemplateView(Context context) {
        return com.noah.sdk.business.render.e.xk().openLayoutInflater(context).inflate(T(context), (ViewGroup) null);
    }
}

这里有几个关键方法:

protected int T(Context context),根据构造函数传入的模板ID,从多个布局文件(也就是我们之前搜索到的)选择一个具体要使用的布局文件名,然后把布局文件名转成真正的资源ID。

public View getTemplateView(Context context),它调用了安卓的 inflate 方法,把上一步 T(context) 方法选择的那个 XML 布局文件,真正地转换成了一个可以显示在屏幕上的 View 对象。

我们这里可以hook getTemplateView让它返回空,这样就不会对广告进行渲染。

Hook 广告渲染
/**
 * 目标: 在广告视图被创建的瞬间进行拦截,阻止其返回。
 * 策略: Hook com.noah.sdk.business.render.container.c 类的 getTemplateView 方法。
 */
console.log("
  • 最终广告拦截脚本已加载..."); Java.perform(() => {     console.log("
  • Java 环境就绪,准备 Hook 广告视图工厂...");     try {         const CLASS_TO_HOOK = "com.noah.sdk.business.render.container.c";         const AdContainer = Java.use(CLASS_TO_HOOK);         // Hook getTemplateView(Context context) 方法         AdContainer.getTemplateView.overload('android.content.Context').implementation = function(context) {             console.log(`[!!!] 成功拦截到广告视图创建调用: ${CLASS_TO_HOOK}.getTemplateView()`);             // 我们可以通过调用 this.getTemplateId() 来获取当前准备加载的广告模板ID,用于调试             const templateId = this.getTemplateId();             console.log(`
  • 准备加载的广告模板 ID 为: ${templateId}`);             // === 核心拦截操作 ===             // 策略一 (推荐): 直接返回 null,让广告视图创建失败。             console.log("
  • 已阻止广告视图创建,返回 null。");             return null;         };         console.log(`[+] 已成功部署对 ${CLASS_TO_HOOK}.getTemplateView 的 Hook。`);     } catch (error) {         console.error(`[!] 最终 Hook 失败: ${error.message}`);         console.error("[!] 请确认类名和方法签名是否完全正确。");     } });
  • image202507201

    hook之后底部广告和广告页的广告都不在渲染,但是还有夸克自带的“开会员免广告”这个广告,同样使用开发者助手和Jadx进行定位即可(过程同上,这里就不多写了),直接给代码

    /**
     * Frida 终极组合拦截脚本
     * 目标: 彻底去除夸克小说中的所有翻页广告(包括第三方SDK广告和App自有备用广告)。
     * 策略: 同时 Hook 两个关键入口点,形成双重保险。
     */
    
    console.log("
  • 终极组合广告拦截脚本已加载..."); Java.perform(() => {     console.log("
  • Java 环境就绪,准备部署多点 Hook...");     // --- 防线 1: 禁用第三方广告SDK (Noah SDK) 的顶层服务入口 ---     try {         const SdkService = Java.use("com.noah.sdk.business.render.container.c");         SdkService.getTemplateView.overload('android.content.Context').implementation = function(reqInfo) {             console.log("[!!!] 防线1: 已拦截第三方广告SDK入口 (getTemplateView)。返回 null。");             return null;         };         console.log("[+] 防线1部署成功");     } catch (error) {         console.error(`[!] 防线1部署失败: ${error.message}`);     }     // --- 防线 2: 禁用App自身的广告页面渲染入口 ---     try {         const AdPageView = Java.use("com.uc.application.novel.ad.view.NovelMixedAdPageView");         AdPageView.drawPageData.overload('com.uc.application.novel.reader.NovelPage').implementation = function(novelPage) {             console.log("[!!!] 防线2: 已拦截App广告页面渲染入口 (drawPageData)。");             // 直接返回,不执行任何绘制操作             return;         };         console.log("[+] 防线2部署成功");     } catch (error) {         console.error(`[!] 防线2部署失败: ${error.message}`);     } });
  • Xposed模块开发

    考虑到去广告需要长久hook,所以这里将frida脚本改写成一个Xposed模块。该Xposed模块我用的是kotlin语言编写,hook的点是com.noah.sdk.business.render.container.c的上层引用中动态渲染广告的函数(均能实现相应效果)。

    1. 创建 Xposed 模块项目

    使用 Android Studio 创建一个标准的 "Empty Views Activity" 项目,并进行如下配置:

    • settings.gradle.kts: 添加 Xposed 官方仓库地址。

      dependencyResolutionManagement {
        repositories {
            google()
            mavenCentral()
            maven { url = uri("https://api.xposed.info/") }
        }
      }
    • build.gradle.kts: 添加 Xposed API 依赖。

      dependencies {
        compileOnly("de.robv.android.xposed:api:82")
        compileOnly("de.robv.android.xposed:api:82:sources")
      }
    • AndroidManifest.xml: 声明这是一个 Xposed 模块。

      <application ...>
        <meta-data android:name="xposedmodule" android:value="true" />
        <meta-data android:name="xposeddescription" android:value="用于去除夸克小说中的广告" />
        <meta-data android:name="xposedminversion" android:value="52" />
      </application>
    2. 编写 Hook 核心逻辑

    我们将 Frida 的“双重防御”策略,用 Xposed API 的语法“翻译”过来。创建一个 HookEntry.kt 作为模块入口:

    package com.example.quarkadblocker
    
    import de.robv.android.xposed.IXposedHookLoadPackage
    import de.robv.android.xposed.XC_MethodHook
    import de.robv.android.xposed.XposedBridge
    import de.robv.android.xposed.XposedHelpers
    import de.robv.android.xposed.callbacks.XC_LoadPackage
    
    class HookEntry : IXposedHookLoadPackage {
    
        private val TARGET_PACKAGE_NAME = "com.quark.browser"
    
        override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
            if (lpparam.packageName != TARGET_PACKAGE_NAME) {
                return
            }
            XposedBridge.log("[QuarkAdBlocker] 已成功注入夸克浏览器进程...")
    
            // --- 防线 1: 禁用第三方广告SDK (Noah SDK) 的顶层服务入口 ---
            try {
                XposedHelpers.findAndHookMethod(
                    "com.noah.sdk.business.render.DynamicRenderService",
                    lpparam.classLoader,
                    "getNativeRender",
                    "com.noah.api.SdkRenderRequestInfo",
                    object : XC_MethodHook() {
                        override fun beforeHookedMethod(param: MethodHookParam) {
                            XposedBridge.log("[QuarkAdBlocker] 防线1: 已拦截 getNativeRender。")
                            param.result = null // 直接返回 null,阻止渲染器创建
                        }
                    }
                )
                XposedBridge.log("[QuarkAdBlocker] 防线1部署成功!")
            } catch (e: Throwable) {
                XposedBridge.log("[QuarkAdBlocker] 防线1部署失败: ${e.message}")
            }
    
            // --- 防线 2: 禁用App自身的广告页面渲染入口 ---
            try {
                XposedHelpers.findAndHookMethod(
                    "com.uc.application.novel.ad.view.NovelMixedAdPageView",
                    lpparam.classLoader,
                    "drawPageData",
                    "com.uc.application.novel.reader.NovelPage",
                    object : XC_MethodHook() {
                        override fun beforeHookedMethod(param: MethodHookParam) {
                            XposedBridge.log("[QuarkAdBlocker] 防线2: 已拦截 drawPageData。")
                            param.result = null // 阻止页面渲染任何内容
                        }
                    }
                )
                XposedBridge.log("[QuarkAdBlocker] 防线2部署成功!")
            } catch (e: Throwable) {
                XposedBridge.log("[QuarkAdBlocker] 防线2部署失败: ${e.message}")
            }
        }
    }

    最后,在 assets/xposed_init 文件中指定这个入口类。

    3. 部署与激活
    1. 构建 APK: 在 Android Studio 中 Build -> Build APK(s)
    2. 安装 LSPatch: 从官方渠道下载并安装 LSPatch Manager。
    3. 修补应用: 使用 LSPatch 的“便携模式”修补夸克浏览器,生成一个新的 APK。
    4. 安装与激活:
      • 卸载原版夸克,安装修补版。
      • 安装自己构建的 QuarkAdBlocker.apk 模块。
      • 在 LSPatch Manager 中为夸克浏览器启用我们的模块。
    5. 重启生效: 强制停止并重启夸克浏览器。
    最终效果

    image202507202imiage202507203

    image202507204image202507205

    免费评分

    参与人数 21吾爱币 +23 热心值 +16 收起 理由
    5uudcn + 1 + 1 我很赞同!
    Tomlls + 1 谢谢@Thanks!
    xiekai2025 + 1 + 1 用心讨论,共获提升!
    Ypndpll + 1 + 1 热心回复!
    正己 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    nmchzh + 1 + 1 谢谢@Thanks!
    thornjay + 1 + 1 谢谢@Thanks!
    zaitianzhiqi + 1 + 1 用心讨论,共获提升!
    hanyaqi + 1 谢谢@Thanks!
    反正不是我 + 1 热心回复!
    huayecai + 1 鼓励转贴优秀软件安全工具和文档!
    a337100 + 1 + 1 谢谢@Thanks!
    Tantian0430 + 1 用心了
    半度微凉111 + 2 + 1 我很赞同!
    neolam + 1 我很赞同!
    coffee13 + 1 谢谢@Thanks!
    justWant404 + 1 用心讨论,共获提升!
    德の社会 + 1 谢谢@Thanks!
    theSeven + 1 + 1 鼓励转贴优秀软件安全工具和文档!
    Miaoq + 1 谢谢@Thanks!
    ytfh1131 + 1 + 1 谢谢@Thanks!

    查看全部评分

    发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

    jianfengjx 发表于 2025-7-21 14:14
    伸手党坐等成品
    ivnmisn 发表于 2025-8-5 09:10
    其实可以用夸克浏览器看小说,它自带的看书功能可以把很多源都转化成一个阅读模式,而且没有广告
     楼主| zzzlanging 发表于 2025-7-20 10:02
    Cxcj 发表于 2025-7-21 11:40
    hahaha这个好
    1haoren88 发表于 2025-7-21 13:19
    图片好大 正常吗? 还是先支持一下
    Beeceelee 发表于 2025-7-21 13:30
    比较强的,实用工具
    jhwwan 发表于 2025-7-21 13:59
    很实用的工具,谢谢分享
    Luxanna 发表于 2025-7-21 14:46
    感谢分享!
    iancr7 发表于 2025-7-21 14:50
    不错,谢谢分享,
    wnllf 发表于 2025-7-21 15:10
    不错 ,感谢分享
    您需要登录后才可以回帖 登录 | 注册[Register]

    本版积分规则

    返回列表

    RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

    GMT+8, 2026-4-15 15:24

    Powered by Discuz!

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表