改变App的运行逻辑去除广告
逆向App之篡改
上几篇介绍了如何抓包
App的网络请求,以及脱壳和反编译App,以及如何Hook App的代码,也理清了App的调用顺序和逻辑,下面介绍下如何修复脱壳后的Dex,继而篡改App逻辑去除广告。
脱壳修复
修复主要是用mt管理器来实现,之前我们通过mt管理器知道该App使用了百度加固,然后通过BlackDex工具进行了脱壳还原dex文件,先将App文件和脱壳后的dex文件拷贝到模拟器指定目录。


在mt管理器,左边视图打开App查看,右边视图选中脱壳后的三个dex文件,长按点击添加到左边App里面去。


删除左边视图原来的classes.dex文件,删除192.25kb的加固残余文件,否则会闪退,它里面包含了,ab.yu、com.baidu、yu.yu.yu等百度加固相关的代码。

将剩余两个cookie开头的dex文件重命名为classes.dex、classes2.dex。

删除baiduk开头相关的加固残余。


替换入口文件将com.sagittarius.v6.StubApplication修改为com.dsdqjx.tvhd.activity.MyApplication,去除签名重新前后安装即可完美运行。

去除图片广告弹窗

前面通过抓包http://xxx.yxtv.cc/api/get_status2024.php请求,并解密响应后知道,知道adData字段里面包含了广告图片地址。

那么我们可以找这个字段在哪里用到了,进而发现展示图片广告的逻辑在GovIjkPlayerActivity的onCreate方法调用initAd()展示广告方法。


那么,我们通过mt管理器,注释掉该逻辑即可。
.line 427
invoke-direct {p0}, Lcom/dsdqjx/tvhd/activity/GovIjkPlayerActivity;->initAd()V

去除首页广告频道

首页直接播放的是广告频道,同上抓包数据返回的"lastEname": "tvad1"就是最后播放的频道这里是广告台,搜索该关键字,找到StartActivity类的goGovAct方法,找配置文件中最后播放频道,如果最后频道没有值则默认播放cctv1hd,再通过数据库查询频道的chid值,通过查询SQLite数据库,cctv1hd的chid值为1,那么我们通过修改逻辑,直接将intent.putExtra("chid", str);中chid焊死为1,那么就不会播放广告台而是中央1台了。

我们通过mt管理器,修改下该逻辑直接给变量v0赋值为1即可。
# 修改前
.line 808
const-string v2, "chid"
invoke-virtual {v1, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
# 修改后
.line 808
const-string v2, "chid"
const-string v0, "1"
invoke-virtual {v1, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
去除列表广告频道

通过查看下载的直播频道文件channel_list.txt,里面就已经包含了广告频道。

进一步分析,该文件内容,最终是被插入到了SQlite数据库中。


我们通过mt管理器,在StartActivity类中的initListData插入数据库方法中修改逻辑,在插入channel_list_table表格数据之后,将广告频道做删除操作即可。
# 修改前
.line 1001
const-string v0, "DELETE FROM source_list_table"
invoke-virtual {v9, v0}, Landroid/database/sqlite/SQLiteDatabase;->execSQL(Ljava/lang/String;)V
:try_end_16e
.catch Ljava/lang/Exception; {:try_start_d2 .. :try_end_16e} :catch_52c
const/4 v0, 0x0
# 修改后
.line 1001
const-string v0, "DELETE FROM source_list_table"
invoke-virtual {v9, v0}, Landroid/database/sqlite/SQLiteDatabase;->execSQL(Ljava/lang/String;)V
const-string v0, "DELETE FROM channel_list_table where ename like \'tvad%\'"
invoke-virtual {v9, v0}, Landroid/database/sqlite/SQLiteDatabase;->execSQL(Ljava/lang/String;)V
:try_end_173
.catch Ljava/lang/Exception; {:try_start_d2 .. :try_end_173} :catch_531
const/4 v0, 0x0


去除空白弹窗

这里我们通过搜索小云TV关键字,可以搜到使用到的是app_name,再进一步搜索该字段,发现有两个类使用到了该字段,查阅代码后猜测大概率是ChannelService类。


然后再通过Hook技术,确定该空白弹窗具体是Dialog、PopupWindow还是其他控件,经过不断尝试最后发现是Service前台通知,具体通过startForeground把Service提升为前台服务,Hook脚本如下。
if (Java.available) {
Java.perform(function () {
console.log("✅ 启动加固兼容模式");
// 循环查找(每 1 秒查一次,直到找到类)
var timer = setInterval(function () {
try {
// ============== 3. Hook Service类,拦截 startForeground 不让它绑定前台通知 ==============
let Service = Java.use("android.app.Service");
Service.startForeground.implementation = function(id, notification) {
console.log("🔴 拦截 startForeground 前台服务通知 id=" + id);
console.log("│ 调用堆栈2:");
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
// 不调用原方法 = 不显示通知、不悬浮、不进通知栏
// this.startForeground(id, notification);
};
console.log("🎯 所有方法 Hook 成功!");
clearInterval(timer); // 找到就停止
} catch (e) {}
}, 1000);
});
}
我们通过mt管理器,在ChannelService和LiveService类中注释掉startForeground方法即可。
# channelservice类
.line 89
invoke-virtual {p0, v1, v0}, Lcom/dsdqjx/tvhd/service/ChannelService;->startForeground(ILandroid/app/Notification;)V
# cond不要删是条件的结束语句
:cond_39
.line 97
iget-object p2, p0, Lcom/dsdqjx/tvhd/service/ChannelService;->notification:Landroid/app/Notification;
invoke-virtual {p0, p1, p2}, Lcom/dsdqjx/tvhd/service/ChannelService;->startForeground(ILandroid/app/Notification;)V
# cond不要删是条件的结束语句
:cond_f
# liveservice类
.line 44
invoke-direct {p0}, Lcom/dsdqjx/tvhd/service/LiveService;->startForegroundService()V