1 需求
在市面上有些比较实用的app应用,比如说:日历app、文件管理app,视频播放器app。这些app中大部分都内置了广告。
其实有广告也是情有可原的,因为这些app的开发都是需要成本的,开发者制作后将其供用户们免费使用,为了能够套现,所以很多开发者选择往应用中植入各种第三方广告平台的SDK。这样,用户们打开这些应用时,就会遭受各式各样的广告,比如说像这样:
像这样:
很多用户会抱怨一不小心就会点到那个广告,如果是在移动网络下,还会浪费流量,因为点到了广告后,手机可能就会打开一个网页让你去玩“老婆不在家玩的游戏”。
这篇博客的目的就是将这些广告从app中去掉,过程中需要涉及到apk的反编译。
2 工具准备
为了能够去掉这些广告,我使用到了这些工具:
- apktool
- apktoolBox
其中,apktool用来将apk文件进行反编译,便于接下来去修改代码。而apktoolBox则是一款集成了各种Android反编译工具的合集,它包含了apktool的功能,除此之外,还能用来查看apk中代码、给apk签名等等。
最后我们再准备一款有广告的应用,这里我用的是一款文件管理应用:
RE文件浏览器
注意:apk下载后,将其改名(名字不要带中文),然后将其放到一个不带中文的路径下,这样做是为了避免后期的工作失败。
3 开始反编译
打开apktoolBox,进行反编译。
生成了一堆文件后,来到反编译出来的目录,打开AndroidManifest.xml,找到跟广告相关的代码。如下图:
广告单词缩写为ad,将百度相关的广告的value改成0,然后再用apktoolbox进行回编译(重新打包生成apk)。运行新打包的apk,可以发现广告里面的内容已经不见了。但是一个空白的广告条还是在底部占着位置。
4 去掉广告条占位
先看看这个广告条所在的页面的布局情况,这里采用hierarchyViewer查看手机上当前页面的布局(hierarchyViewer程序位于Android SDK目录中tools文件夹里)。
通过它可以查看到对应的布局,定位到页面底部广告,发现控件层次如下:
在底部的空白广告条是一个类型叫AdView的控件,我们如果需要去掉它,得知道关于AdView控件是在layout资源文件中加上去的,还是在java代码中加上去的。
这里通过notepad++工具在res资源文件夹中搜索了一番,并没有找到,说明AdView控件是在java代码里添加的。
在java代码中,apk作者在页面中调用一些方法将控件添加到了页面上并做了初始化等一系列操作。
要修改该控件的添加效果,有两种方案:
- 在添加控件、初始化控件的那一系列操作上做手脚。
- 直接从源头上入手,找到AdView这个自定义控件的代码,并从中做修改。
这里我采用的是第二种方案,通过apktoolbox里集成的jadx工具,通过它打开apk文件可以查看里面的java代码。如下:
虽然代码有被混淆过,但是通过观察,还是可以看到一些蛛丝马迹的,其中有两个地方比较有意思,一个是构造函数中的addView(),这个是往里面添加一个子控件。
public AdView(Context context, AttributeSet attributeSet, boolean z, AdSize adSize, String str) {
super(context, attributeSet);
this.b = new AtomicBoolean(false);
this.a = new a(this);
View adVar = new ad(context);
this.c = new a(context, adVar, str, z);
this.c.addEventListener(IXAdEvent.AD_LOADED, this.a);
this.c.addEventListener(IXAdEvent.AD_ERROR, this.a);
this.c.addEventListener(IXAdEvent.AD_STARTED, this.a);
this.c.addEventListener("AdUserClick", this.a);
adVar.a(new b(this));
addView(adVar, new LayoutParams(-1, -1));
}
还有一个地方是这个AdView控件复写了setLayoutParams方法。该方法是这样写的:
public void setLayoutParams(LayoutParams layoutParams) {
l.a().f().d("AdView.setLayoutParams=", Integer.valueOf(layoutParams.width), Integer.valueOf(layoutParams.height), Integer.valueOf(getWidth()), Integer.valueOf(getHeight()));
int i = layoutParams.width;
int i2 = layoutParams.height;
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService("window")).getDefaultDisplay().getMetrics(displayMetrics);
int i3 = displayMetrics.widthPixels;
int i4 = displayMetrics.heightPixels;
float f = displayMetrics.density;
l.a().f().d("AdView.setLayoutParams", Integer.valueOf(i3), Integer.valueOf(i4), Float.valueOf(f));
if (i <= 0) {
i = Math.min(i3, i4);
} else if (i > 0 && ((float) i) < 200.0f * f) {
i = (int) (200.0f * f);
}
int min = i2 <= 0 ? (int) (((float) Math.min(i3, i4)) * 0.15f) : (i2 <= 0 || ((float) i2) >= 30.0f * f) ? i2 : (int) (30.0f * f);
layoutParams.width = i;
layoutParams.height = min;
l.a().f().d("AdView.setLayoutParams adapter", Integer.valueOf(layoutParams.width), Integer.valueOf(layoutParams.height));
super.setLayoutParams(layoutParams);
}
大概读一遍,可以发现在这个方法里,去根据一些手机的分辨率情况去设置当前AdView的width和height,我们就修改这里的代码,将width或height设置为0,再来重打包观察效果如何。
要修改代码需要去反编译出来的smail目录中,找到该AdView对应包下的smail文件进行修改。
smail文件格式不友好,但是跟java代码相比,还是有迹可循的。这里通过一些特殊字眼(一些字符串常量都会被予以保留),比如我搜索“setLayoutParams”,就可以定位到setLayoutParams方法的定义处。
定位到这个setLayoutParams方法,里面有很多const申明,比如该方法里第一句日志中的“AdView.setLayoutParams=”字符串,就会被这样申明:
const-string v2, "AdView.setLayoutParams="
这是字符串,如果是数字int,那么就是:
const/4 v11, 0x3
const/4 v10, 0x2
const/4 v9, 0x1
const/4 v8, 0x0
v11、v10、v9这些代表常量名,后面的0x3、0x2这些代表常量值。
前提交代完毕后,接下来开始修改,我改的是setLayoutParams方法中这一句代码:
layoutParams.width = i;
layoutParams.height = min;
将其修改不再为i,改为0。这几句代码在smail中就是这一句:
.line 156
iget v2, p1, Landroid/view/ViewGroup$LayoutParams;->width:I
.line 157
iget v1, p1, Landroid/view/ViewGroup$LayoutParams;->height:I
这几句,其实就是v2赋值给layoutParams.width,v1赋值给layoutParams.height。我这里将v8赋值给width和height,因为v8的值为0x0
iput v8, p1, Landroid/view/ViewGroup$LayoutParams;->width:I
.line 179
iput v8, p1, Landroid/view/ViewGroup$LayoutParams;->height:I
这里不建议大家自己去创建一个const,可能会导致编译不通过,或者会运行重打包apk时报错。
另外,如果smail代码修改的有误,使用apktoolbox是没有提示的,如果一直无法重打包apk,那么建议使用apktool工具来打包,它会及时的告诉你smail文件的报错位置。
最后使用工具进行重打包回编译apk,并签名。安装以后,可以发现底部的广告条已经不见啦。
如果对新生成的apk用jadx打开观察java代码的话,可以发现width和height已经被设置为0.