吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3773|回复: 35
收起左侧

[Android 原创] 【X表之家】的加密分析

  [复制链接]
jidesheng6 发表于 2020-11-11 12:54
本帖最后由 jidesheng6 于 2020-11-11 12:55 编辑

这次分析的原因是因为群里有人想让我帮他做个签到脚本,我晚上无聊看了一下,结果发现这个软件对响应体进行了加密,于是便有了这篇文章

1.准备工作

APP样本

Xposed

反射大师

MT管理器

模拟器

我本人使用的是IOS,所以用模拟器来分析安卓版本的加密过程。

2. 脱壳

安装软件之后,使用MT管理器查看软件的加固方式,可以看到,下面的图片显示:腾讯御安全

1.png

使用反射大师进行脱壳(具体过程不做阐述,站内有教程,只是写出dex记得长按,就能写出所有dex)。

3.抓包

脱壳之后,先不要急着看源码,首先进行抓包
我用的是IOS上的Thor

我用登陆的接口作为演示,首先是登陆的请求头信息,如下图所示(个人觉得没什么有用的信息)

2.png

接着看登陆接口的返回信息,看起来像是AES/DES的某种加密,这样就有思路了,搜索的范围也可以稍微小一点。

3.png

4.代码分析

我们使用MT管理器搜索AES、DES、descrypt等关键字,因为这几个关键字有可能是某个类/方法/字符串,能够极大提高我们找到关键信息的成功率。

4.png

我首先使用AES搜索,这里需要注意,搜索结果会很多,我们一般去看和APP包名一样的packages名的就可以了,如下图所示。

5.png

接着我们点击进去,转换成java(需要更换引擎,几个都试试),这个类中的代码如下:

package com.xbiao.utils;

import android.annotation.SuppressLint;
import android.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESedeUtil {
    private static final String INIT_VECTOR = "6di50aH901duea7d";

    @SuppressLint({"NewApi"})//解密方法
    public static String decrypt(String var0, String var1) {
        try {
            IvParameterSpec var3 = new IvParameterSpec("6di50aH901duea7d".getBytes("UTF-8"));
            SecretKeySpec var2 = new SecretKeySpec(var0.getBytes("UTF-8"), "AES");
            Cipher var5 = Cipher.getInstance("AES/CBC/NOPADDING");
            var5.init(2, var2, var3);
            var0 = new String(var5.doFinal(Base64.decode(var1, 0)));
            return var0;
        } catch (Exception var4) {
            var4.printStackTrace();
            return null;
        }
    }

    @SuppressLint({"NewApi"})//加密方法
    public static String encrypt(String var0, String var1) {
        try {
            IvParameterSpec var2 = new IvParameterSpec("6di50aH901duea7d".getBytes("UTF-8"));
            SecretKeySpec var3 = new SecretKeySpec(var0.getBytes("UTF-8"), "AES");
            Cipher var5 = Cipher.getInstance("AES/CBC/NOPADDING");
            var5.init(1, var3, var2);
            byte[] var6 = var5.doFinal(var1.getBytes());
            var0 = java.util.Base64.getEncoder().encodeToString(var6);
            return var0;
        } catch (Exception var4) {
            var4.printStackTrace();
            return null;
        }
    }
}

我没学过java,只学过类似的c#,上面的encryptdecrypt的算法,还不知道是不是用于解密响应消息的,从代码中我们能得到的信息是:使用了AES的CBC模式,还有一个NOPADDING参数,同时我们从开头的定义还知道了,那个变量的值应该是偏移iv的值,所以也需要留意一下,既然已经知道了方法名,我们就回去搜索一下decrypt,看看哪里调用了这个方法,解密的是什么内容。

我们在一个叫做NetContent的类中找到了如下图所示的字段

6.png

其中有个方法名引起了我的注意:decryptResponse,翻译过来就是解密响应信息,我觉得八九不离十,就是这里了,打开进行反编译,代码段内容如下:

 private static String decryptResponse(String var0, String var1) {
        String var2 = LocalCookieManager.getInstance().getSecretKey();
        if (!TextUtils.isEmpty(var0) && !TextUtils.isEmpty(var2)) {
            var0 = AESedeUtil.decrypt(var2, var0);//调用了decrypt的方法
        } else {
            var0 = "";
        }

        label20: {
            try {
                var2 = changeCharset(var0, "utf-8");
            } catch (UnsupportedEncodingException var3) {
                var3.printStackTrace();
                break label20;
            }

            var0 = var2;
        }

        var2 = var0.trim();
        var0 = var2;
        if (TextUtils.isEmpty(var2)) {
            var0 = "";
        }

        StringBuilder var4 = new StringBuilder();
        var4.append("url:");
        var4.append(var1.replace(NewsAccessor.BASE_HEAD_URL, ""));
        var4.append("  最终结果response***************:");
        var4.append(var0);
        Log.i("liuguangyou", var4.toString());
        return var0;
    }

从上面的代码中,可以看到是调用了我们之前找的那个类里面的方法了的。
所以我们要分析一下参数var2var0是怎么来的
我们看到var2是调用了一个类中的方法来生成的:

String var2 = LocalCookieManager.getInstance().getSecretKey();

由于本身这个decryptResponse也是要被调用的,所以着重分析var2的生成方式

我们看到这里的类叫做LocalCookieManager所以可能就是请求头里面携带的Cookie内容,这样我们的范围就能缩小了一点,再看后面的getSecretKey方法,翻译过来就是密钥,所以var2就是这个算法的解密密钥,我们去MT搜索getSecretKey

搜索到了LocalCookieManager类中,反编译代码的时候,发现如下一串代码:

  private static LocalCookieManager infoManager;
    private String searchCookiePublicKey;
    private String secretKey;

    private LocalCookieManager() {
        this.searchCookiePublicKey = "publicKey=";
    }

因为这个类是Cookie的类,于是回去寻找抓包信息中的Cookie中,是否有这个KEY

果然,在之前的抓包结果中,是有如上的KEY的,一切都证明我们的方向是正确的

在这个类中,一直看到最后,看到了一个方法名subCookieSecretKey,字面意思是分割Cookie密钥,于是猜测,可能是从publicKey的值中生成密钥,因为变量的名字也很明确,searchCookiePublicKey.搜索的就是这个KEY,于是反编译代码:

 public void subCookieSecretKey(String s) {
        if (!TextUtils.isEmpty((CharSequence)s)) {
            s = URLDecoder.decode(s.replaceAll(":eq:", "; "));
            final int index = s.indexOf(this.searchCookiePublicKey);
            if (index != -1) {
                int n;
                if ((n = s.indexOf(";", index)) == -1) {
                    n = s.length();
                }
                final String replace = s.substring(index, n).trim().replace(this.searchCookiePublicKey, "");
                s = replace.substring(0, 5);
                final String substring = replace.substring(replace.length() - 11, replace.length());
                final StringBuilder sb = new StringBuilder();
                sb.append(s);
                sb.append(substring);
                this.secretKey = sb.toString();
                if (TextUtils.isEmpty((CharSequence)this.secretKey)) {
                    this.secretKey = SharedPreferencesPublicKeyUtil.getStringValueFromSP("secretKey");
                }
                SharedPreferencesPublicKeyUtil.setStringDataIntoSP("secretKey", this.secretKey);
            }
        }

前面有一端是判断值是否存在的,所以只要看一部分就好

final String replace = s.substring(index, n).trim().replace(this.searchCookiePublicKey, "");

上面这段可以看出,是把有publicKey=的这一段给替换去除,所以也就是这个KEY的值了,接下来都按照这个思路去走。

                s = replace.substring(0, 5);
                final String substring = replace.substring(replace.length() - 11, replace.length());
                final StringBuilder sb = new StringBuilder();
                sb.append(s);
                sb.append(substring);
                this.secretKey = sb.toString();

上面的代码中,可以看到,用publicKey的值,取其索引第一位第四位
为了方便讲解,我把我的KEY值贴上来。
我的KEY值是:5BJ3e+kjDdAIy9gEvnJasIRXqZFnjfTG3Om4ER/Tcz4=

所以此时s=5BJ3e,接着再取KEY值长度-11的位置到KEY值末尾的索引
这个时候substring=Om4ER/Tcz4=,后面把这两个值进行拼接,赋值给变量secretKey.
所以最后secretKey的值就是5BJ3eOm4ER/Tcz4=

我们逆推,看看secretKey是在哪里,我们在源码中找到如下代码:

 public String getSecretKey() {
        return this.secretKey;
    }

所以这就是在NetContent类中被调用的方法。

回到AES的解密中,看到这段代码:

 IvParameterSpec var3 = new IvParameterSpec("6di50aH901duea7d".getBytes("UTF-8"));
            SecretKeySpec var2 = new SecretKeySpec(var0.getBytes("UTF-8"), "AES");
            Cipher var5 = Cipher.getInstance("AES/CBC/NOPADDING");
            var5.init(2, var2, var3);

推测判断,var3iv偏移量,var2为解密的密钥,参数var0为密文数据,通过var5解密返回原始数据。

为了验证这个猜想,我找到了一个AES解密的网站,分别填入密文解密KEYiv偏移,得到结果如下:

7.png

处理了一下,最终内容如下:

8.png

5.结语

后面的内容我没有继续深入下去,因为这个APP其实定时发送GET进行签到正常没事的,只是加密的内容你不知道是什么而已,我也很感谢那个提供APP的人,让我又学习到了新的东西。

在这过程中,踩了不少坑,比如手机上的iv偏移值不支持输入字符串,不支持选择填充,所以解密数据是不完整的,好在找到了一个不错的AES解密网站。

后期的脚本没有写,本来打算写JS版本的,想想还是算了,最后奉上在这次过程中,用于调试的python代码:

Cookie="5BJ3e+kjDdAIy9gEvnJasIRXqZFnjfTG3Om4ER/Tcz4="
Front_Str = Cookie[0:5]
After_Str = Cookie[len(Cookie)-11:len(Cookie)]
Full_SecKey = Front_Str+After_Str
print(Full_SecKey)
Iv_Str = "6di50aH901duea7d"
'''
Iv_Bytes_Str = ""
for Byte in Iv_Str:
    Iv_Bytes_Str+=str(ord(Byte))

SecKey_Byte_Str = ""
for Key in Full_SecKey:
    SecKey_Byte_Str+=str(ord(Key))
print(SecKey_Byte_Str)
'''

到这里就分析结束啦!也希望能帮到一些和我一样的新手们

免费评分

参与人数 11威望 +1 吾爱币 +29 热心值 +7 收起 理由
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
liulaotou2 + 1 + 1 谢谢@Thanks!
永昌 + 1 谢谢@Thanks!
XS30 + 1 热心回复!
与紫禁之巅 + 1 谢谢@Thanks!
olhoscn + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
阿1 + 1 + 1 热心回复!pwnint
hanekuriboh + 1 用心讨论,共获提升!
宿醉的秃子 + 1 热心回复!
syd1990 + 1 + 1 我很赞同!
lff520520 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| jidesheng6 发表于 2020-11-11 15:16
417788939 发表于 2020-11-11 15:02
表哥之家

这软件好像是手表发烧友的最爱

是滴呢,被发现了
宿醉的秃子 发表于 2020-11-11 13:12
你把气球吹炸了 发表于 2020-11-11 14:21
芽衣 发表于 2020-11-11 15:02
表哥之家

这软件好像是手表发烧友的最爱
大头BigHead 发表于 2020-11-11 15:58
可以的!
twticfvtk 发表于 2020-11-11 16:12
谢谢你的分享
jh767676 发表于 2020-11-11 16:29

谢谢你的分享
tenwool 发表于 2020-11-11 17:10
满满的干货,有东西的!!!
XS30 发表于 2020-11-11 17:31
思路清晰,过程明确,非常棒!感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 17:39

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表