前段时间,公司制造的机器里应用装有不良广告,严重影响了儿童客户使用者的思想健康,导致被人投诉。于是乎,就有了想研发一款类似于360广告屏蔽的应用的念头。嗯,事情就是这样,现在切入主题。

目前市场上有很多安全软件,它们拦截第三方应用广告的方式都不一样,比如说有 以so 注入方式来拦截弹出广告
现在我们来看下这种方式的详细情况:

要做到拦截,首先我们得知道广告是怎么出来的,原来第三方应用大部分是以加入广告jar形式加入广告插件,然后在AndroidManifest中声明广告service或者在程序中执行广告Api,广告插件再通过Http请求去加载广告。在java中,有四种访问网络的接口,如apache的http库(如下介绍),这几种方式首先都会通过getaddrinfo函数获取域名地址,然后通过connect函数连接到服务器读取广告信息。

  1. WebView(源码文件在frameworks/base/core/java/android/webkit/WebView.java)。通过WebView类的void loadUrl(String url)、void postUrl(String url, byte[] postData)、void loadData(String data, String mimeType, String encoding)、void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)、void evaluateJavascript(String script, ValueCallback resultCallback)等加载网页。
  2. apache-http(源码目录在external/apache-http/ , HttpGet 和 HttpPost类)。通过external/apache-http/src/org/apache/http/impl/client/DefaultRequestDirector.java中的DefaultRequestDirector类的HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)方法执行访问的网络的动作。
  3. okhttp(源码目录在external/okhttp/)。通过external/okhttp/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java中的HttpEngine类的private void connect(Request request) throws IOException方法连接网络。
  4. URL(源码在libcore/luni/src/main/java/java/net/URL.java)。通过libcore/luni/src/main/java/java/net/URL.java中的URL类的URLConnection openConnection() throws IOException方法和URLConnection openConnection(Proxy proxy) throws IOException方法连接网络。

然后再来说说动态库注入,具体什么是动态库注入,以及如何注入,网上有很多文章,这里就不介绍。动态库注入拦截呢,主要是拦截getaddrinfo,根据条件返回错误来拦截网络请求,达到拦截作用。不过需要注意一点就是拦截之前要确定你所拦截的动态库是否是你需要拦截的库?例如A程序调用了动态库BO和CO,而BO和CO都调用了connect函数,此时需要拦截BO的请求,需要注入到BO动态库并修改GOT表,而不是注入到CO中。

拦截HTTP方式广告在多数广告包中,应用程序首先会通过apache的http库或JDK中的http方法先将广告数据下载过来,然后通过WebView显示。这种方式通过注入拦截进程的/system/lib/libjavacore.so可实现广告地址拦截。

拦截WebView方式广告广告插件也可以直接通过WebView加载URL,通过分析WebView加载流程可知它的网络处理过程均交给libchromium_net库来完成。因此通过注入libjavacore.so是无法实现拦截,而是需要注入到/system/lib/libchromium_net.so。

通过这种方式已经完全能够拦截掉第三方APP广告,但存在一些问题:

1.广告商可以通过JNI方式调用系统getaddrinfo与connect实现自己的解析与连接过程的动态库,从而跳过libjavacore.so导致拦截无效。
2.拦截WebView方式广告虽然能够不显示广告,但通常仍然会有浮动框显示”网页无法打开”,从而影响美观。
3.最重要的是我们机器是没有root权限的!!

第三个问题直接导致了放弃了这种注入做法。
来来去去一段时间后,目前是采用android 系统本地扫描第三方应用广告形式。具体怎么做,请往下看!

如果对这种方式不了解的话,建议先看下这篇 Android系统扫描带广告应用的做法。

所以具体广告插件扫描方案是匹配包名+类名形式的:
1.扫描本地所有第三方应用,列出一个应用中的所有类,将包名+类名方式与广告插件特征库进行匹配
2.将匹配出来的应用所带广告特征,通过系统提供传入接口,将这些规则设置进去。(当然,系统代码是需要改的,做了一些处理,主要是在上面介绍中的几种访问网络方式上做了判断处理)

这种方案的关键在于广告特征库的完善,广告插件特征库收集越全,扫描出来的广告插件就可以越准确。所幸,公司有几位大神,做过类似的事情,所以工作简单了多些。

获取第三方应用:

   /** * 查询机器内非本公司应用 */  public List<PackageInfo> getAllLocalInstalledApps() {  List<PackageInfo> apps = new ArrayList<PackageInfo>();  if(pManager == null){return apps;}//获取所有应用  List<PackageInfo> paklist = pManager.getInstalledPackages(0);  for (int i = 0; i < paklist.size(); i++) {  PackageInfo pak = (PackageInfo) paklist.get(i);//屏蔽掉公司内部应用//...//判断是否为非系统预装的应用程序  if ((pak.applicationInfo.flags & pak.applicationInfo.FLAG_SYSTEM) <= 0) {  // customs applications apps.add(pak);}  }  return apps;  }

获取某个应用的广告特征:

public static List<String> getClassNameByDex(Context context,String packageName) {List<String> datalist = new ArrayList<String>();String path = null;try {path = context.getPackageManager().getApplicationInfo(packageName,0).sourceDir;// 获得某个程序的APK路径} catch (NameNotFoundException e) {e.printStackTrace();}try {if(TextUtils.isEmpty(path)){return datalist;}DexFile dexFile = new DexFile(path);// get dex file of APKEnumeration<String> entries = dexFile.entries();while (entries.hasMoreElements()) {// travel all classesString className = (String) entries.nextElement();String totalname = packageName + "."+className;datalist.add(totalname);}} catch (IOException e) {e.printStackTrace();}return datalist;}

将应用中的所有类名与特征库进行匹配:

for (PackageInfo info : infolsit) {if (info == null) {continue;}data = getClassNameByDex(context,info.packageName);if(data == null){Log.d(TAG,"getAdFlagForLocalApp()  类名解析出错"+info.packageName);continue;}sgPgmap = new HashMap<String, String>();for (String clsname : data) {for (ADSInfo adinfo : flaglist) {String flag = adinfo.getAdFlag();  //广告样本库的某一标识 String adpg = adinfo.getAdName();  //广告样本库的某一包名if (clsname.contains(adpg)) {  //匹配类名与广告特征库里的匹配符,看是否包含关系sgPgmap.put(flag,info.packageName);}}}if(sgPgmap.size() > 0){//AdsPgInfo  一个对应应用里包含了多少个标识adspginfo = new AdsPgInfo(info.packageName, sgPgmap);pglist.add(adspginfo);}}

ps: 在匹配时,有一个很注意的点,有时候单单类名匹配不准,或者会漏掉某些广告,所以应该加上包名,再去匹配特征库里的匹配符,这样才能百无一漏。

在此举例一个指智广告的特征(特征显示形式可自定义,只要符合自己的解析策略即可):

ads.banner.zhidian#指智广告#com/adzhidian/#ad.zhidian3g.cn
  • ads.banner.zhidian 为该类型广告标识,主要是为了匹配时应用对应标识的简洁性,不用直接跟着一群特征到处跑。。
  • 指智广告 该广告名称
  • com/adzhidian/ 该广告用来匹配应用中类名的匹配符,当应用中某一(包名+类名)包含该匹配符时,说明了该应用包含该广告
  • ad.zhidian3g.cn 需要传给系统的一个规则特征。

匹配出所有应用的所属规则特征后,接下来需要传给系统了,系统将满足需求的几个接口提供出来。这边涉及到修改系统层代码,我就主要讲下实现思路,会贴出关键的几个代码。
实现思路:系统根据应用层传入的应用包名以及规则,将其缓存,在webview或http处请求时,对其进行判断处理。

添加某应用规则接口:

/*** add Adblock url of package pkgName*/private boolean addAdblockUrlInner(String pkgName, String url) {synchronized (mAdblockEntries) {HashMap<String, UrlEntry> pkgEntry = mAdblockEntries.get(pkgName);if (pkgEntry == null) {pkgEntry = new HashMap<String, UrlEntry>();if (pkgEntry == null) {Slog.e(TAG, "addAdblockUrl():new HashMap<String, UrlEntry>() fail!");return false;}mAdblockEntries.put(pkgName, pkgEntry);}UrlEntry entry = pkgEntry.get(url);if (entry == null) {pkgEntry.put(url, new UrlEntry(0, false));} else {entry.deleted = false;}}return true;
}

WebView类postUrl处判断处理:

/*** Loads the given URL.** @param url the URL of the resource to load*/public void loadUrl(String url) {checkThread();if (!isAddressable(url)) {return;}if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadUrl=" + url);if(!isChromium && url.startsWith("file://")){Log.e("WebView.java", "loadurl setLocalSWFMode");mProvider.setLocalSWFMode();}/*** Returns true if the url is not included by adblock service*/private boolean isAddressable(String url) {boolean addressable = true;AdblockManager adblockManager = AdblockManager.getInstance();if (adblockManager != null) {String adblockUrl =  adblockManager.containedAdblockUrl(ActivityThread.currentPackageName(), url);if (adblockUrl != null) {addressable = false;adblockManager.increaseNumberOfTimes(ActivityThread.currentPackageName(), adblockUrl);}}return addressable;}

由于系统代码这部分的改动并非是我改的,更深细节处的理论就不清楚了。
应用层的广告特征库为了可以持续更新,建议可以做成网络更新方式。
据此,广告拦截功能实现就完成了,可能会有瑕疵,不过持续优化中。 有大神如果有更好的拦截实现跟策略,请您麻烦私信我,让我好好请教,非常感谢。

Android 第三方应用广告拦截实现相关推荐

  1. Android 抛弃原生WebView,使用腾讯X5内核、并加入广告拦截。

    大家都不知道原生的WebView 存在各种坑.各种适配问题. 最近在使用,总会出现DNS被拦截的情况.预览了各个大神的论坛与博客. 发现可以更改WebView内核.找到了比较火的两个. 分别是:腾讯X ...

  2. android广告拦截原理,WebView 广告拦截浅析

    前言 查豆瓣 使用的是 WebView 加载页面,在豆瓣的移动页面中存在两到三个的广告轮播图,比较影响阅读体验.所以开始着手看看怎么屏蔽掉广告. 在 WebView 中有以下三个方法可以考虑: fun ...

  3. location 拦截所有_电脑广告拦截软件 Adguard Premium

    每日一谈 我们上个网的时候经常会遇到很多烦人的广告.在线跟踪等,不仅导致你的网站加载速度非常的慢,并且还可能会导致你遇到一些恶意软件和威胁.为了避免这种情况的产生,今天我为大家推荐这款广告拦截软件来阻 ...

  4. AdGuard 无与伦比的广告拦截

    一款无与伦比的广告拦截扩展,对抗各式广告与弹窗. AdGuard 广告拦截器可有效的拦截所有网页上的所有类型的广告,甚至是在 Facebook.Youtube 以及其他万千网站上的广告! AdGuar ...

  5. AdGuard免费的电脑手机广告拦截程序

    AdGuard是一款广告拦截和隐私保护跨平台软件,可以保护Microsoft Windows,MacOS,Android和iOS用户免受不必要的广告.弹窗以及跟踪.淫秽内容.恶意软件和网络钓鱼的信息. ...

  6. Google Chrome 新广告拦截器的工作原理

    转自: https://www.ctrl.blog/entry/chrome-adblocker google chrome 将在2018年2月15日开始对某些网站上的广告进行屏蔽. 笔者看了一下Ch ...

  7. AdGuard广告拦截插件V3.6.6

    介绍: AdGuard AdBlocker 是一款广告拦截插件,用以对抗各式广告与弹窗.可以拦截绝大部分常见网站的广告. 例如视频广告,插播广告和浮动广告.从而实现加速页面载入,节省带宽,屏蔽广告和弹 ...

  8. AdGuard2022手机电脑广告拦截工具

    AdGuard 是拥有可获取最佳网络冲浪体验所需全部功能的独特程序.其集合了世界上最高级的广告拦截器,隐私保护模块以及家长控制为一体,还可协同任何浏览器和应⁠用工⁠作. AdGuard 是快速的.小内 ...

  9. adguard拦截规则存在哪里_广告拦截软件Adguard怎样配置才能更全面的发挥作用

    相信很多伙伴都对网上的各种各样的广告感到厌烦,Adguard是一款屏蔽拦截网页的软件, 可以支持市面上几乎所有的浏览器,今天小编就给大家介绍一下如何配置Adguard. 第一步:通过拦截规则开始隐私保 ...

  10. adguard和adblock哪个好_世界上最高级的广告拦截程序AdGuard过滤规则分享

    世界上最高级的广告拦截程序AdGuard过滤规则分享 2020-01-22 13:49:44 5点赞 80收藏 15评论 创作立场声明:原创心得 ## 前言 我和很多人一样一开始用Maxthon傲游浏 ...

最新文章

  1. BZOJ-1010 玩具装箱toy (斜率优化)
  2. java服务端项目开发规范
  3. activiti脚本任务_Activiti中的安全脚本如何工作
  4. 高中学生计算机软件,中学生计算器
  5. 诗与远方:无题(十六)
  6. IDEA 插件 Material Theme UI收费后 免费的办法
  7. 2010考研数学二第(20)题——多元积分学:二重积分计算
  8. powerdesign165破解以及使用教程
  9. 正阅读微信小说分销系统-视频教程-1.渠道商-公众号配置-基础信息
  10. 对比分析163VIP邮箱费用,原来有这么多的好处!
  11. Smartphone--Android真机管理平台
  12. 洛谷P1873 Java
  13. 遇见狂神书说:JavaWeb保姆级教程
  14. 快学Python:函数的使用
  15. 101shell脚本
  16. m基于QPSK调制解调的无线图像传输matlab仿真,包括扩频解扩均衡等模块
  17. 微信小程序 实现报表(表格)双指缩放功能
  18. 黄奇帆:消费互联网垄断、杀熟等不讲道理的盈利模式行不通
  19. Discuz 开启开发者模式并且开始默认安装未上架插件调试的模式-并且关掉应用中心-一颗优雅草科技伊凡
  20. 计算机里s大小,Mbps和mb/s换算知识-电脑维护

热门文章

  1. 山西太原警方侦破涉案100余起跨区域系列盗窃案
  2. 基于VC++的MFC类库实现的简单FTP客户端
  3. tl-wr842n服务器未响应,TL-WR842N路由器怎么重启? 重启路由器的技巧
  4. java fastjson 格式化_json的格式化展示(基于 fastjson)
  5. Linux如何删除用户
  6. 数学专项counting:LA 5846
  7. 手机浏览器自动打开快应用?
  8. java quartz是什么意思_精进 Quartz—Quartz大致介绍(一)
  9. 入门级概述光学相干层析(OCT)原理
  10. 服务器地图自动刷新,怀旧服新版黑莲花全地图刷新点一览 插件数据已更新