带壳App去除强制升级

  • A+
所属分类:移动安全

这是一款带壳的APP,打开之后要求强制升级最新版,否则无法使用,针对此APP可以进行脱壳后定位关键代码,然后重打包进行消除强制升级弹窗。


DEXDump三种使用模式脱壳


1、使用objection加载frida_dexdump

objection -g com.xxx exploreplugin load /root/.objection/plugins/dexdump/frida_dexdumpplugin dexdump dump


2、直接运行

objection -g com.xxx explorepython3 main.py

会自动判断前台运行的App

3、利用pip安装后运行frida-dexdump

objection -g com.xxx explorepip3 install frida-dexdumpfrida-dexdump


脱壳成功后,发现生成了4个dex文件,然后搜索带有MainActivity的dex文件

grep -ril "MainActivity"


Objection快速自动化定位

正常方式首先以开发者的角度来思考是如何实现窗口弹出功能

https://www.jianshu.com/p/18e1f518c625

一 activity以窗口形式呈现

二 Android:将activity设置为弹出式的并设置为透明的

三 Dialog

1、如果是弹出的activity,可以hook所有的activities进行启动查看

 android hooking list activities

启动可疑的Activity,尝试能不能绕过,然后发现界面到了app信息页面,但是返回后还是要求升级的界面,说明此路不通。

android intent launch_activity xxx.ui.activity.About Activity

查看一个函数能不能hook,可以将它所有的类打印出来,然后过滤,如果有则可以hook

android hooking list classescat .objection/objection.log |grep -i window   


发现有android.view.Window,然后尝试hook

objection -g com.xxx explore --startup-command "android hooking watch class android.view.Window"

注:

也可以不需要--startup-command,进去app之后再hook也来得及

当点击“立即升级”发现会立即跳出下图内容,说明与升级框相关android.view.Window.getWindowManager()

2、尝试下dialog

 cat .objection/objection.log |grep -i dialog

先hook看一下android.app.AlertDialog

android hooking watch class android.app.AlertDialog

发现点升级没有任何反应,故判断此API与升级框没关系

然后再尝试hook下android.app.Dialog看有没有反应

objection -g com.xxx explore --startup-command "android hooking watch class android.app.Dialog"

点击新版本框空白地方会出现

点击“立即升级”出现

看到存在android.app.Dialog.setCancelable (用返回键无法取消)

然后hook该方法

android hooking watch class_method android.app.Dialog.setCancelab le --dump-args --dump-backtrace --dump-return

找到对应位置,发现与界面上的版本号、文件升级相关联,从而定位到了代码的关键位置。

这里是明文,所以很明显就可以判断定位的对错。如果关键字符串做了加密混淆,搜索大法也就无效了,可以使用wallbreaker内存可视化漫游,所见即所得。

Wallbreaker内存可视漫游


wallbreaker四种模式:

 classdump 查看一个类的结构
classsearch 根据类名来找类
objectsearch 查看一个类的实例内容
objectdump 查看对象的属性


使用objection加载Wallbreaker搜索值得怀疑的地方

plugin load /root/.objection/plugins/Wallbreakerplugin wallbreaker objectsearch xxx.ui.fragment.dialog.UpdateDialogFragment

找到之后,打印该对象的属性

 plugin wallbreaker objectdump --fullname 0x276a

看到xxx.bean.VersionBean$Version _a; => [0x2266]:

然后将其打印出来

plugin wallbreaker objectdump --fullname 0x2266

可以看到打印出的内容,与界面所展示的一致,验证了所见即所得原理。


所见即所得的代码定位思路

定位完之后,我们继hookxxx.ui.fragment.dialog.UpdateDialogFragment

android hooking watch class xxx.ui.fragment.dialog.UpdateDialogFragment

打印调用栈

xxx.ui.fragment.dialog.UpdateDialogFragment.b

android hooking watch class_method xxx.ui.fragment.dialog.UpdateDialogFragment.b --dump-args --dump-backtrace --dump-return

根据打印的结果看到

xxx.ui.fragment.dialog.UpdateDialogFragment.b是从xxx.ui.activity.MainActivity.a该类过来,然后定位该类,发现也是做了个条件判断。

修改源码重打包去强制升级


接着我们进行修改代码去掉升级框并重打包,首先因为是带壳的APP,无法直接使用apktool进行反编译,不然壳也会被反编译为smali。所以我们使用apktool保留classes.dex文件进行解包,然后删除apk原有的classes.dex文件,并将脱壳后的classes.dex放入

apktool -s d xxx.apkrm classes.dex

按照文件大小重命名后放入该文件夹中

搜索extends Application

查找AndroidManifest.xml内容,将android:name的内容替换为xxx.base.App将入口点改为脱壳后的入口点

然后回编译、首次使用需先生成keytool、签名

 apktool b xxx keytool  -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore   # 生成keytool jarsigner -verbose -keystore abc.keystore -signedjar xxxsigned.apk xxx.apk abc.keystore

测试可以成功运行后,我们接着反编译,搜索之前定位的类名含MainActivity的smali文件,编辑查找UpdateDialogFragment找到之后修改判断语句

 apktool d xxxsigned.apk tree -NCfhl |grep -i MainActivity nano smali/cn/net/tokyo/ccg/ui/activity/MainActivity.smali

改完之后回编译、签名、运行

 apktool b xxxsigned/ jarsigner -verbose -keystore abc.keystore -signedjar xxx2signed.apk xxx2.apk abc.keystore

发现已经没有了强制升级的弹窗。

       



E

N

D



我知道你在看

本文始发于微信公众号(SecPulse安全脉搏):带壳App去除强制升级

发表评论