前段时间,公司制造的机器里应用装有不良广告,严重影响了儿童客户使用者的思想健康。导致被人投诉。

于是乎。就有了想研发一款相似于360广告屏蔽的应用的念头。嗯。事情就是这样。如今切入主题。

眼下市场上有非常多安全软件。它们拦截第三方应用广告的方式都不一样,比方说有 以so 注入方式来拦截弹出广告

如今我们来看下这样的方式的详细情况:

要做到拦截,首先我们得知道广告是怎么出来的。原来第三方应用大部分是以增加广告jar形式增加广告插件,然后在AndroidManifest中声明广告service或者在程序中运行广告Api。广告插件再通过Http请求去载入广告

在java中,有四种訪问网络的接口。如apache的http库(例如以下介绍),这几种方式首先都会通过getaddrinfo函数获取域名地址,然后通过connect函数连接到server读取广告信息。

  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 APK
Enumeration<String> entries = dexFile.entries();
while (entries.hasMoreElements()) {// travel all classes
String 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. Chrome-AdGuard 无与伦比的广告拦截扩展

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

  2. firefox广告拦截插件

    firefox广告拦截插件: Adblock Plus  Adblock Edge Adblock Plus Pop-up Addon 如果不能更新,则需要修改HOST: 117.18.232.191 ...

  3. Android 第三方开源库收集整理(转)

    原文地址:http://blog.csdn.net/caoyouxing/article/details/42418591 Android开源库 自己一直很喜欢Android开发,就如博客签名一样,  ...

  4. 45.Android 第三方开源库收集整理(转)

    原文地址:http://blog.csdn.net/caoyouxing/article/details/42418591 Android开源库 自己一直很喜欢Android开发,就如博客签名一样,  ...

  5. Android第三方开源对话消息提示框:SweetAlertDialog(sweet-alert-dialog)

    Android第三方开源对话消息提示框:SweetAlertDialog(sweet-alert-dialog) Android第三方开源对话消息提示框:SweetAlertDialog(sweet- ...

  6. Android 第三方应用接入微信平台(2)

    微信平台开放后倒是挺火的,许多第三方应用都想试下,毕竟可以利用微信 建立起来的关系链来拓展自己的应用还是挺不错的,可以节约很多在社交方 面的开销,我最近由于实习需要也在研究这个东西,不过发现网上的相关 ...

  7. Android 第三方应用接入微信平台(1)

    关键字:微信开放平台   Android第三方应用接入微信 微信平台开放后倒是挺火的,许多第三方应用都想试下接入微信这个平台, 毕竟可以利用微信建立起来的关系链来拓展自己的应用还是挺不错的,可 以节约 ...

  8. Android第三方授权(新浪微博篇)

    Android第三方认证新浪微博,相对微信,也比较简单,并且sina给了一个sdk和sdkdemo,这个demo封装了许多,但是自己不准备记录这个demo,而是直接使用sdk 同样去sina官方下载s ...

  9. iOS 9之Safari广告拦截器(Content Blocker)

    金田( github 示例源码) 相对于谷歌对广告拦截的禁止,苹果与之态度截然相反,继Mac版Safari加入广告拦截工具之后,即将到来的iOS9对Safari也引入了内容拦截插件-Content B ...

随机推荐

  1. APP换肤

    一.需求说明 当一个APP用户量大的时候,就需要给不同的用户做标签,用来彰显身份.比如QQ的会员,VIP等不同的皮肤功能. 二.实现方法. 所谓不同的皮肤,就是不同的权限(身份)显示不同的本地或者网络 ...

  2. 零基础带你看Spring源码——IOC控制反转

    本章开始来学习下Spring的源码,看看Spring框架最核心.最常用的功能是怎么实现的. 网上介绍Spring,说源码的文章,大多数都是生搬硬推,都是直接看来的观点换个描述就放出来.这并不能说有问题 ...

  3. (转)Unity3D在WebPlayer模式下的异常上报探索

    我们知道,Unity3D在WebPlayer的发布模式下是沙箱环境中运行的.根据Unity3D的官方文档所述,WebPlayer模式下不能使用非托管的DLL,也就是说,传统C++游戏客户端的生成Min ...

  4. IO流--FileReader&&FileWriter

    (一)FileReader (1)第一种读取方式 package com.songyan.fileReader; import java.io.FileNotFoundException; impor ...

  5. FFmpeg学习起步 —— 环境搭建

    下面是我搭建FFmpeg学习环境的步骤. 一.在Ubuntu下 从http://www.ffmpeg.org/download.html下载最新的FFmpeg版本,我的版本是ffmpeg-2.7.2. ...

  6. oracle解决连接池不足

       select count(*) from v$process;----系统有多少连接数  select value from v$parameter where name = 'processe ...

  7. Git -- 自己项目关联新建的git

  8. SVG 基础图形

    SVG 基础图形 SVG包含了以下的基础图形元素: 矩形(包括可选的圆角),使用<rect>元素创建 圆形,使用<circle>元素创建 椭圆形,使用<ellipse&g ...

  9. Python 的 LEGB 规则(转载)

    转载:https://mp.weixin.qq.com/s?timestamp=1498528588&src=3&ver=1&signature=DfFeOFPXy44ObCM ...

  10. shareToQQ,qq 4.1.1 for android,闪退

    用shareToQQ函数分享图文消息,在qq 4.1.1 for android版本下打开联系人列表数秒后会闪退!在更高版本的V4.5.2.1,V4.2.1下则没有这个问题(证明各种设置没问题),各位 ...