Android逆向笔记 -- 记一次解决飞天助手未知模拟器方法

Android逆向笔记 — 记一次解决飞天助手未知模拟器方法

0x0 前言

原来一直使用的飞天助手突然限制了模拟器, 美其名曰: "第三方模拟器盗用数据"云云, 谁不知道其实是想引流. 虽然无可厚非, 但是推荐的模拟器实在是太难用了, 于是修改下成为所有模拟器通用

1708873826326

0x1 逻辑分析

首先, 此界面并不是开始就直接显示, 而是点击运行脚本后再显示, 如果从程序入口来分析将很麻烦, 于是我打算追查是什么启动了此activity

首先检查此activity的包名, 使用adb链接模拟器 adb connect 127.0.0.1:5555, 注意, 每个模拟器的端口都不一样, 用之前检查下

然后使用命令 adb shell dumpsys activity | findstr "mResumed" 查看最上层包名, 结果为 **/ui.activity.AdActivity

1708873845895

0x2 检查逻辑

这里我是用 Android Killer 进行分析, 加载此脚本, 查看 activity, 发现所有的Activity和Service都是灰色的, 这主要是因为新版Android在打包时会分开储存dex, 而android killer的确有点老了, 只会识别第一个dex 我用的ak已经魔改过了, 其实其他dex已经反编译, 自己找找即可

1708873853600

首先寻找 AdActivity, 发现位于 smali_classes3/ui/activity 下, 查看其Java代码

发现一个公共静态方法 public static void startAdActivity, 很明显这个函数就是启动广告的关键, 使用搜索检测是哪里调用了这个方法

1708873887894

在Android Killer里搜索 startAdActivity, 发现一共有两处

1708873899638

首先看下面一个, 阅读smail源码, 可以看见 startAdActivity(context, this.mAdTitle, this.mWebPath) 随后finish(), 最后 return-void

1708873923712

上面一个可以看见 startAdActivity(context, "", ScriptCommandBean.getDLPlatformPrompt()), 从英文上可以明显怀疑为在此检测模拟器, 查看Java代码

1708873935843

可以看见对比 paramBaseBeanNew.getData()).getDLPlatformPrompt() 为0的时候, 代表检测模拟器通过

首先是发现关键词 RetrofitApiManager, 可以知道用的是 Retrofit, 寻找对应的api NormalSwitch(DLPlatformPrompt), 发现请求网址API

1708873964755
1708873987953

使用Postman进行访问, 发现结果

1708873981271

其中 http://lander.gc.com.cn/~preview/cn/campaign/ftldy.htm 就是看到的那个未知模拟器的网站

现在怀疑, 是否通过Header进行检测模拟器? 但是检查okhttp后并没有发现header, 于是我选择抓包进行验证

首先使用"未知模拟器", 抓包结果如图, 并没有Header

1708873998358

然后使用遁地模拟器, 发现根本没有这个请求, 说明这步并不是检测模拟器的核心,, 而是获取模拟器广告的地方, 这里应该为一个开关 如果返回的广告不为地址而为0, 说明不限制其他模拟器, 这里可以作为一个破解点, 即使其返回0, 但是我想看看其检测模拟器的原理, 于是继续追踪 checkDeviceApi

1708874014317

由于JD没法正确解析, 只能读smali源码里, 下面是翻译的伪代码

java
private boolean mIsRfOrDD
this.mIsRfOrDD = TfloatHelp.isPass()
if (this.mIsRfOrDD) {
    startRunScript()
} else {
    if (android.os.Build.VERSION.SDK_INT != 0x13) {
        checkDeviceApi()
    }
}

追踪 isPass(), 发现 ui.util.DundiUtils.isDunDi(), 发现是通过 shell getprop ro.hardware 里是否有遁地进行判断的, 进行测试

image

雷电模拟器:

1708874023447

遁地模拟器:

如何检测遁地模拟器到此明白了

0x3 解除限制

现在解除限制的方法很多

  • 修改 checkDeviceApi(), 将返回的广告改为0, 如果为0说明不做限制, 脚本照样能启动

  • 修改 isPass(), 让其检测自己为遁地模拟器

这里我选择第二种

Lapp/ais/dev/TFloatWinService.smali7106

1708874046756

在这里, 将 if-nez v0, :cond_2 改为 goto :cond_2, 于是代码变成

java
private boolean mIsRfOrDD
this.mIsRfOrDD = TfloatHelp.isPass()
if (true) {
    startRunScript()
} else {
    if (android.os.Build.VERSION.SDK_INT != 0x13) {
        checkDeviceApi()
    }
}

保存后回编译, 安装到模拟器内, 限制已被解除

1708874059012
1708874065986

Android逆向笔记 -- 记一次解决飞天助手未知模拟器方法
https://simonkimi.githubio.io/2020/07/09/android逆向笔记-记一次解决飞天助手未知模拟器方法/
作者
simonkimi
发布于
2020年7月9日
许可协议