新版本ColorOS使用dexdump脱壳遇到的问题及解决

问题

最近在更新后的ColorOS上使用frida-dexdump进行脱壳时,发现使用原有脚本脱出来的dex文件全都是名为com.coloros.phonemanager-idleoptimize的系统进程。

1
2
3
4
INFO:frida-dexdump:[+] Starting dump to 'F:\apks\top2000-4262\com.coloros.phonemanager-idleoptimize'...
INFO:frida-dexdump:[+] DexMd5=1d1ffe171610319311dda1f25b808f5f, SavePath=F:\apks\top2000-4262\com.coloros.phonemanager-idleoptimize\classes.dex, DexSize=0x6850b4
INFO:frida-dexdump:[+] DexMd5=d047d1f63deeed86ec6d3ab61c38a840, SavePath=F:\apks\top2000-4262\com.coloros.phonemanager-idleoptimize\classes2.dex, DexSize=0x128f000
INFO:frida-dexdump:[+] DexMd5=a2827813aa1c63baccb7ec0660dce01b, SavePath=F:\apks\top2000-4262\com.coloros.phonemanager-idleoptimize\classes3.dex, DexSize=0x691044

尝试

顾名思义,该进程属于系统自带的手机管家,用于优化系统资源与释放内存空间。在网上搜了半天也没有找到碰到一样问题的人,一开始觉得既然如之前的博客所述,frida-dexdump的原理是运行加壳应用,并利用frida来dump出当前正在运行的dex格式文件。那可能是系统更新后自带的进程造成了干扰,把该进程强制关闭应该就好。于是通过adb输入了以下指令:

1
adb shell pm uninstall -k --user 0 com.coloros.phonemanager

重启后,结果倒是不会输出该系统进程了,但是又换了一个com.android.statementservice,脱出来的dex文件全变成了Android的系统服务,这就让人有点难以琢磨了。

1
2
3
4
INFO:frida-dexdump:[+] Starting dump to 'F:\apks\top2000-4262\com.android.statementservice'...
INFO:frida-dexdump:[+] DexMd5=1d1ffe171610319311dda1f25b808f5f, SavePath=F:\apks\top2000-4262\com.android.statementservice\classes.dex, DexSize=0x6850b4
INFO:frida-dexdump:[+] DexMd5=d047d1f63deeed86ec6d3ab61c38a840, SavePath=F:\apks\top2000-4262\com.android.statementservice\classes2.dex, DexSize=0x128f000
INFO:frida-dexdump:[+] DexMd5=a2827813aa1c63baccb7ec0660dce01b, SavePath=F:\apks\top2000-4262\com.android.statementservice\classes3.dex, DexSize=0x691044

在这之后又尝试了更新frida版本等多种处理方法,都没有什么作用,去frida-dexdump的GitHub上看也已经很久都没有更新了,看来这个问题还只能自己来解决。经过反复观看frida的输出日志,终于是发现了一丝端倪:每次脱不同应用时,脱出来的dex文件Md5编码以及size好像都不太一样,是不是说明了每次脱出来的文件其实是对的,只是输出对应进程时出错了呢?

1
2
3
4
5
6
7
8
9
def get_package_name(self):
try:
pid = self._session._impl.pid
for process in self._device.enumerate_processes():
if process.pid == pid:
return process.name
return "dexdump.unnamed.{}".format(pid)
except:
return "dexdump.unnamed"

改正

接着又去研究了一下frida-dexdump的源码,发现其输出文件夹的名称,是在get_package_name方法中通过进程的pid去进行查询得到的,于是使用’frida-ps -Ua’指令debug了一下系统当前的进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
INFO:Agent:DexDumpAgent<Connection(pid=Session(pid=31748), connected:True), attached=True>: Attach.

PID Name Identifier
----- ----------------- -------------------------
30782 App Market com.heytap.market
32133 Breeno Shortcuts com.coloros.shortcuts
30213 Clock com.coloros.alarmclock
1101 DingTalk com.alibaba.android.rimet
30738 Game Center com.nearme.gamecenter
29788 Magisk com.topjohnwu.magisk
2359 QQ com.tencent.mobileqq
24653 SIM Toolkit com.android.stk
24653 SIM Toolkit com.android.stk
30943 Snapchat com.snapchat.android
3289 WhatsApp com.whatsapp
3359 WhatsApp Business com.whatsapp.w4b
31748 学习强国 cn.xuexi.android
13933 山西银行 com.csii.jincheng

对照后发现与DexDumpAgent所启动后的进程是一致的,但在最后输出时所用的pid还是启动前的,并未更新的31748,被android.statementservice进程所使用。所以才会反复输出该进程名的dex文件夹。

知道问题后就好办了,首先尝试修改了frida-dexdump的源码逻辑,将查询pid并确定输出目录名的过程放在_resume后:

1
2
3
4
5
6
7
8
self.connection = SessionConnection(self._device, self._session)
self.agent = DexDumpAgent(self.connection)
self._resume()
self.package_name = self.get_package_name()
if not self.output:
self.output = os.path.join(os.getcwd(), self.package_name.replace(":", "-"))
os.makedirs(self.output, exist_ok=True)
# self._resume()

这里由于并接触不到_resume的内部源码,也只是多次实验后的尝试。结果又有一点新问题,获取到的中文应用的进程名字也是中文,而不是应用对应的包名,不利于我们脱壳之后的重打包工作,于是经过对于frida接口的一番查询之后,尝试使用process.identifier,即当前运行应用的包名来进行查询,但不知道是版本问题还是其他原因,查询并不能正常进行。左思右想后采取了稍微折中的解决方法,拿到脱壳后的中文文件夹后,再使用Androgurad来对该应用的包名进行查询。

部分参考资料:

frida-dexdump源码:https://github.com/hluwa/frida-dexdump

之前写的使用说明文章:https://canonize.github.io/2023/03/31/shell-apk/

一些其他的博客:

https://blog.csdn.net/qq_40644809/article/details/106814146

https://www.52pojie.cn/thread-1572220-1-1.html

https://blog.csdn.net/weixin_45746055/article/details/119761343