背景
目标应用是一款网络摄像头工具,家里人平时拿它看摄像头画面,但这软件里塞了一大堆牛皮癣广告。
广告行为集中在几个地方:开屏广告、热点区域广告、摇一摇跳转。关闭按钮设计得很小,稍不注意就会误触跳转,对老年用户尤其不友好。
有意思的是,软件还会对新老用户区别对待——新用户有一段时间的免广告期,老用户直接就没有这个待遇。

定位广告来源
第一步先确认广告是从哪里加载的。好在反编译出来的代码没有经过混淆,直接用关键字搜索就能定位到开屏广告的位置。

从 showSplashAd() 这个方法入手,向上追一下调用关系,发现入口在 AndroidManifest.xml 里声明的 LauncherActivity。广告的起点就在这里。


去广告
接下来分析广告展示逻辑,看看能不能直接跳过它。

可以看到这里有一个广告开关。继续追一下怎么切换到免广告状态。

AdControl.sFreeAd 控制的就是新用户免广告逻辑。再看另一个条件分支。

这看起来像是软件内置的广告总开关。继续往后追,发现这其实是一个开发者留下的后门控制开关。

既然有这个后门,那就直接从这里下手。先看一下对应的 smali 代码。

只需要让 906 行的条件判断进入 sThirdAdType = 0; 这个分支就行。具体做法是在 905 行插入一行 const/4 p0, 0x1,把 p0 寄存器强制改为 true。改完的效果如下。

到这里,广告开关就已经被强制关闭了。
重打包
接下来需要重新打包并签名。但先要处理签名校验问题。反编译代码里可以看到有一个校验逻辑。

appVerification 方法会在每个 Activity 的 onCreate 中触发。这里也有开关控制,而且是编译期常量。

所以还是继续改 smali。

把 sput-boolean v0, Lcom/macrovideo/sdk/GlobalConfiguration;->sIsSignatureVerification:Z 里的 v0 寄存器改成 v1 就可以了。

顺手把 sIsCheckRoot 也一起改成了 false。然后打包、签名、安装,结果应用启动后直接闪退了。
用 logcat 看一下闪退的位置:
--------- beginning of crash
08-10 17:45:51.946 15265 15281 E AndroidRuntime: FATAL EXCEPTION: Thread-2
08-10 17:45:51.946 15265 15281 E AndroidRuntime: Process: com.***.***, PID: 15265
08-10 17:45:51.946 15265 15281 E AndroidRuntime: java.lang.RuntimeException: entry classes6.dex is tamper
08-10 17:45:51.946 15265 15281 E AndroidRuntime: at com.security.shell.V5App$31.v(Native Method)
08-10 17:45:51.946 15265 15281 E AndroidRuntime: at com.security.shell.V5App$1.e(Unknown Source:11)
08-10 17:45:51.946 15265 15281 E AndroidRuntime: at com.security.shell.V5App$31.v(Native Method)
08-10 17:45:51.946 15265 15281 E AndroidRuntime: at com.security.shell.V5App$1.run(Unknown Source:8)
08-10 17:45:51.946 15265 15281 E AndroidRuntime: at java.lang.Thread.run(Thread.java:1563)
搜索 com.security.shell.V5App 这个关键字,发现软件用的是顶象加固。按理说接下来该准备脱壳了,但反编译代码分析后发现 dex 代码并没有被壳加密,所以直接改 AndroidManifest.xml 里的 application 配置就行。

这里的 appComponentFactory 也要一起改掉:

然后重新打包、签名、安装。这次应用启动成功了,广告也正常关闭。
总结
整个过程还算顺利:先定位广告来源,分析展示逻辑并强制关闭,绕过签名校验,替换加固代码入口,最后重打包。因为操作都集中在 Java 层,而且应用本身就有关闭广告的逻辑,所以整体难度不大。没有经过混淆的代码,看起来确实舒服太多了。
本文仅用于软件逆向分析与技术经验分享,旨在探讨移动应用的实现原理及相关技术。
文中涉及的应用名称、关键参数、接口信息、代码及其他敏感内容均已进行脱敏或适当处理。本文内容仅供学习、研究和技术交流使用,请勿将相关技术用于侵犯他人合法权益、破坏软件正常运行或其他违法违规行为,由此产生的任何后果与本文作者无关。
如涉及相关软件的合法权益,请联系作者进行处理。