本来原则是找最旧的,然后找 android 的。但是当时手上暂时没有 android 机,就只能搞 iOS,但是老版本的映客客户端又没有手机登录的功能,于是只能硬着头皮用当前的最新版本。 由于手上没有越狱设备,于是直接从 PP 助手那里下载了一个现成的已经脱过壳的映客版本。以下是破解步骤的流水账记录
unzip inke.ipa
打开 Hopper Disassembler v3,把解压后的 Payload/inke.app/inke 二进制文件拖进 Hopper 里。
手机配代理连 Charles,走一遍手机号登录流程,抓取请求短信验证码和登录的请求。 请求短信验证码:

登录的请求:

根据这些请求里的一些字段,在 Hopper 的 Labels 框里猜测一些关键字。几番尝试后,发现输入 loginphone 后找到了想要找的函数:[UserLoginModel loginPhone:requestId:code:completion:] 然后再顺藤摸瓜,以 UserLoginModel 为关键字继续搜,发现了这个函数:
[UserLoginModel requestVoiceCodeWithPhone:region:completion:]

那就先从发送验证码的函数开始分析吧,反编译该函数后:

可以发现 arg2 就是手机号,然后分别被 [SecurityTool rsaEncrypt1:r5] 和 [SecurityTool md5Encrypt:r4] 加过密。后者看名字就能知道是 md5 加密,所以先自己给手机号 md5 一下看看:

发现结果和请求里的字段貌似并没有什么关联,以为猜错了,后来想起自己登录映客的时候还选过区的,所以手机号可能需要加个 86:

这下果然就对了,结果正好对应着请求里的 secret 字段。那猜测那个 rsa 加密函数的结果应该就是对应着请求里的 phone 字段了。
接着继续搜 SecurityTool 关键字,找到 rsaEncrypt1 函数,反汇编后:

可以发现里面多次出现了带 MIH 前缀的函数,猜测多半是用了什么开源库之类的东东,于是上 github 上搜下其中的 MIHRSAPublicKey 类,果然找到了相关资料,然后各种搜发现了一个叫 MIHCrypto 的开源库,按照教程新建的测试工程后,就开始仿照反汇编后的结果模拟加密逻辑:

这里有个小插曲,反汇编后的那个常量字符串由于太长了,显示不全,直接就显示三个点了…我模拟的加密逻辑始终会 crash 就是因为那个字串不全导致格式不对。又不会怎么用带 UI 版本的 gdb,后来想了很久,发现还有另一款反编译神器 IDA,抱着试一试的态度下载免费版的 IDA 后,果然能看到完整的常量字符串了:

然后运行 demo,结果出来的加密结果跟抓包的 phone 字段不一样,没办法只能再重头再梳理一遍逻辑,看看哪里出问题了。不过研究了很久,真心确定过程并没有什么错误,于是抱着试一试的心理,用 paw 组包发送,居然成功了:

解决了请求验证码的接口后,登录的接口也就很轻松了。登录接口的 code 就是验证码,phone 是和请求验证码一样的加密逻辑,secret 通过看反汇编的代码是
手机号#短信验证码的 md5 的结果,request_id 就是请求短信的返回包里的字段,组包发送,成功:

解决了手机登录后,再尝试下看看第三方联合登录有没有搞头。先拿微信举例,只要获取到映客的 WX_App_ID 和 WX_App_Secret 就可以了。WX_App_ID 是写死在客户端的,这个可以通过反编译拿到。但是 WX_App_Secret 通常都是存在服务器的,感觉没什么出路。正在纠结的时候发现映客是用的友盟集成的第三方登录组件,这个组件好处就是用起来很便利,当然坏处就是不安全,得提供给他们 WX_App_Secret,意味着这个字段或许我们可以在客户端反编译搜出来。果然以 ThirdPlatform 为关键字,搜出了相关方法:


于是在第三方的 app 里用这两个字段模拟微信登录的体验就是:在第三方的 app 里唤起微信的授权页,但是授权页是显示的是映客的 icon 和名称,用户点击允许后返回第三方的 app,然后第三方拿到 openid 和登录态等,用这些再去微信获取用户的基本信息,同理其他联合登录也是一样的方法。
