此文不涉及任何道义和伦理的讨论

距离上一次做反编译已经一个月过去了,这次要解开另一个谜题,也算是多了解一个接口加密的设计方案。

这个APP包含android和ios两个版本。 android下的版本是经过360安全加固过的,目前的技术能力和时间投入都无法支撑对加固后代码的反编译。 ios由于特殊的生态环境,很少有公司能意识到对ios下的客户端做代码保护。 所以这次主要从ios客户端入手。

砸壳

ios应用提交到apple store审核通过之后默认会做一层加固保护,就是俗称的。 如何砸开这个壳获取里面的可执行文件有很多方法,网上一搜可以搜到很多相关的文章,唯一需要的就是一台越狱后的ios设备。

小技巧

如果你的ios应用是直接通过手机中的itunes安装的,砸壳出来的可执行文件可以反编译获得汇编语言,但是由于是一个64位的版本,当前版本的Hopper Disassembler和大名鼎鼎的IDAHEX-RAYS插件都无法生成相应的伪代码。 Hopper Disassembler的提示:

(The CPU backend cannot create pseudo-code for this CPU or CPU mode.)

IDA则体现为F5功能键在X64版本下是无效的。

为了绕开这个限制,可以通过Mac端的itunes下载APP到电脑,之后通过itunes同步到手机。通过这种方法安装的APP砸壳出来的代码是可以通过32位版本的IDA来执行反编译的,同样hopper也可以支持生成对应的伪代码。

选择 ARM v7打开即可。IDA通过可通过32位版本打开。

定位

先来看一下这个APP的接口加密特征: 每个请求都携带了一个名为payload的参数,包含了用2个.号分隔的3段字符串,稍加了解,就能知道这个接口的加密方式是JWT

JWT与之前谈到过的正向hash校验是同样的思想,请求中携带了所有参与hash的请求参数和一串计算得到的hash值,后台通过相同的正向hash过程得到的hash值与客户端提交的进行比对来判断这个请求是否合法。

上一篇中已经说到:

单向hash的缺点就在于不可逆(排除碰撞的可能),由于http是无状态的,计算单向hash传入的参数都需要显式传递给后端,或者取前后端预先约定好的一个值,这就意味着,如果计算单向hash的算法暴露了,只需要根据算法计算对应的hash值,就可以很容易的构造出一个合法的请求。 而且,如果方案暴露,所有接口都无一幸免,因为参数都是明文,对于所有请求加密都形同虚设。

所以,我们的目标就是在反编译的客户端代码中找到这把钥匙。

这里我用了一个比较巧妙的方法,有个前情提要是是该APP的安卓客户端在某个版本之前是没有做加固处理的(在上一篇中我也提到,会对历史版本做一些分析),所以我拿到了之前某个版本的客户端源代码,对应的加密逻辑是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public static String generateParams(String params){
        HmacKey key = null;
        try {
            key = new HmacKey(("2**********i-" + DateConvert.getStringDateShort()).getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(params);
        jws.setHeader("typ","JWT");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
        jws.setKey(key);
        jws.setDoKeyValidation(false);
        String jwt = null;
        try {
            jwt = jws.getCompactSerialization();
        } catch (JoseException e2) {
            e2.printStackTrace();
        }
        return jwt;
    }

是jwt提供的标准实现,使用的密钥是一串固定的字符串加上当前的日期(格式YYYYMMDD)。

通过这个安卓客户端的代码,如何快速定位到ios的加密逻辑位置呢? 我通过iTunes下载到了ios客户端下的对应版本,然后搜索了一下这个字符串,就定位到了加密的逻辑所在的方法位置:

而且果不其然的是,最新的客户端中,加密代码的逻辑,依然是这个方法:

在IDA的帮助下,我们找到了钥匙,成功解开了这道谜题: