某麦购票Xposed脚本(一)
本文仅研究了某麦app的购票接口,不涉及破盾方法。
本文仅供研究学习使用,请勿用于任何商业和非法用途。否则后果自负。
在之前的文章中我们详细分析了大麦的购票协议接口,并使用了 Python + Frida RPC 的方式成功实现了购票。本文我们尝试将其改为用 Xposed 来实现。
环境
设备:pixel 5(Android11已root)
app平台:Android
app版本:8.10.9
工具:
抓包:Postern + Charles
动态静态分析:jadx、frida
LSPosed版本:1.9.2
Magisk版本:26.1
流程拆解
先来分解一下我们之前获取订单详情的 frida hook 流程:

构建
MtopContext
对象作为参数主动调用buildParams
获取加密参数
构建
MtopContext
对象 构造 MtopRequest 对象
构造 MtopBusiness 对象
构造 MtopContext 对象
主动调用
buildParams
主动调用
CookieManager.d
获取Cookie
向服务器发送请求并获取返回值,从中提取
signKey
用于订单构建
androidStudio 环境配置
创建一个空项目
改一下项目名称,这里我们使用java写
拷贝 XposedBridgeApi.jar 到新建工程的libs目录
- 没有 libs 目录的话就在这里新建一个
修改app目录下的 build.gradle 文件,在AndroidManifest.xml 中增加Xposed相关内容
新建 assets 文件夹,然后在 assets 目录下新建文件 xposed_init,在里面写上 hook 类的完整路径
开始分析
获取 realClassLoader 原理
Xposed hook的时机非常早,因为首先拿到的是壳的 classLoader
,而非脱壳后真正的 realClassLoader
。所以在有壳的情况下直接hook目标函数是无法找到目标函数的。
那么我们得先拿到脱壳后的 realClassLoader
。
加壳app的启动流程
启动时只加载壳自己的
StubApplication
(不是业务代码)壳在
attachBaseContext()
或onCreate()
里:加载加密的 dex
解密原始 dex
使用
DexClassLoader
/PathClassLoader
加载业务代码有时还会用反射把真实的
Application
替换进去
最后才进入真实代码逻辑
所以,我们要hook attachBaseContext()
或者 onCreate()
方法名 | 原因 |
---|---|
attachBaseContext(Context) |
加壳 App 最早可执行逻辑,通常在此加载原始 dex |
onCreate() |
有些壳把 dex 加载延后到这一步 |
两者之后 | ClassLoader 已经被替换或补充,可以安全用来加载真实类 ✅ |
确定 hook 入口
查看壳的入口,找到attachBaseContext(Context)
或者onCreate()
方法的地址

- 查看 AndroidManifest.xml 从
application
中可以找到壳的入口com.ali.mobisecenhance.ld.StubApplication

- 进来之后可以看到这个类本身没有
attachBaseContext(Context)
或者onCreate()
,那么跟进它继承的父类看看

- 进来之后可以看到这两个方法
- 一般来说我们优先选择
attachBaseContext()
,onCreate()
可作为补充
获取 realClassLoader

- 这里我们通过 hook
attachBaseContext()
成功的拿到了脱壳后的realClassLoader
- 拿到了
realClassLoader
之后就可以编写代码继续之后的流程了
代码编写
按照之前的拆解流程,构建出 MtopContext
对象之后就可以调用 buildParams()
方法获取到加密参数了
构建MtopContext
对象
构造 MtopRequest 对象

构造成功说明我们成功的加载了类对象,访问类对象的方法也没有问题。
访问的时候需要注意一下是静态的还是非静态的,分别使用
callStaticMethod()
、callMethod()
…
构造 MtopBusiness 对象

这里调用静态工厂方法
build()
拿到实例
构造 MtopContext 对象并调用 buildParams()

- 执行没有报错,但是调用
buildParams()
的返回值为空 - 经过尝试可能是因为
attachBaseContext()
执行完成后业务代码还没有加载完毕,换为hookonCreate()
可以正常执行返回加密数据
更换 hook 时机为 onCreate()

- 现在可以正常打印出加密参数
主动调用CookieManager.d
获取Cookie

向服务器发送请求并获取返回值
接下来手动用 HttpURLConnection
发起 GET 请求,格式跟之前 python 中保持相同即可

- 需要注意,因为 Android 默认是不允许在主线程进行网络 I/O 的。解决办法是把网络请求放到子线程中执行。
提取返回值中的 signKey

- 提取到之后保存下来,用于构建订单使用