avatar

麦兜的小站

MDO.INK

  • 首页
  • 随笔
  • 知识库
  • 归档
  • 动态
  • 标签
  • 关于
Home 深扒某APP网络请求加密4.经过多次请求可以看到data的值和suffix都在不断变化,而且每次都不一样
文章

深扒某APP网络请求加密4.经过多次请求可以看到data的值和suffix都在不断变化,而且每次都不一样

Posted 2025-06-20 Updated 2025-06- 20
By power 已删除用户
83~107 min read

最近在网上找到一些违规的App,本人主要想获得他的Api接口,并且去学习他的加密技术,以后做app时候可以借鉴参考
今天的主角是:

至于App的下载链接自己网上找,因为某些原因的我就不提供链接了

一、抓包分析

找接口第一件事肯定是抓包的嘞,现在我们去用Fiddler抓包,Fiddle抓手机的包需要稍微配置一下

1.点击选项

2.将https和允许远程连接打开

3.查看电脑端局域网IP,Win+R 输入cmd 输入ipconfig即可 ipv4就是你的局域网IP

4.手机端设置代理,打开wifi点击连接的wifi设置代理

5.手机打开浏览器访问192.168.1.118:8888进去以后安装一下证书

6.打开app刷一刷等待数据加载

我们可以看到请求参数postdata加密,获取的响应也加密了 为了后期方便研究解密
选取一个较短的请求内容和响应内容保存一下,以便等等去研究,把我们需要用到的东西保存下来 请求

请求网址:http://47.56.88.111:8082/app/apidomain

Header(经过尝试除了第一二个其余都不需要)

suffix: 624970 
Content-Type: application/json; charset=utf-8


Content-Length: 508
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.14.2

请求参数

{"post-data":"PzLkqSAItZGaaN0LRHlGdqub8aCPIBKpnA/GyWvmHRnIw9nkaWdIctRkQtHVRiavhMnVU5j3sPR03wPsqJ2QP/uK1+JLRYCbSpVW54m2rf2Qcl6rDyqzdz/tDyOVqsukAo7R/xw/FKsBVBhAjL39jmHCTd5acRul9HI7ZgQYg9HUL5DJbCrxTqvOyoOxcLJIlnFOcGiASqx4PzqobWZ7bhptZiP0IygaSKj7/oIBsqJ6YPu+r+iqc/i0vPvn/H7ZG+LZXjhq3kGBxHg6xdW1wWyO+7K0Mo+iR4rxd/HjIlcN4lKljrjEplzTLRHhn2v38U+M0hJ2GRIkjoeexAqyxhmT0EvnsMsbr4N0F45/c7eU2y0BMhHFDpRBeWni9P7T/06Dp7xJPJO7PESGBDn3aYJd9ZVLFrqanzRf8LgCN0qE/7MRpLKpQZ9YhwwWgJQHSAc7xTVHLNtZIlG+ZzK3KKvbQ+tUGm2jKak5zCxhoRs="}
{
"code":0,
"msg":"u64cdu4f5cu6210u529f",
"data":"ebdPaRiKxsrjeTanIw8V5OMttiNI+q5RQNRUiOcmbu/d0qCdyhtAlALDStCtTSycig8vmYFthZ3yBNYTEbnaUhGNHudQaiAwDQlMJwVXh6k=",
"suffix":"pvYcSk"
}

使用Postman模拟用上面的消息模拟测试一下

1.选择Post输入网址,Headers参数

2.选择Body选择下拉框中的Json,输入post参数

3.点击发送,可以看到模拟成功

4.经过多次请求可以看到data的值和suffix都在不断变化,而且每次都不一样,我们先不探究他是为什么。

5.改变请求参数中的suffix值,发现请求失败

二、拆包分析

梳理一下从抓包到现在所拥有的

  • 用来请求的参数数据
  • 数据是加密的
  • 共同点请求和响应都有suffix
  • 请求的suffix值变了就请求不到
  • 响应内容每次都在变化

我们带着问题去拆包APK,之前我用的是MT反编译,由于大多人都没有会员,这边用电脑分析
需要用到的工具:jadx
(本来是打算用dex2jar和jd-gui的,发现jadx反编译的代码更直观,就换成了这个,jadx使用教程我这里就不赘述了)
下载地址:github.com/skylot/jadx… 搜索Header中的Content-Type参数,当然搜索suffix也可以,随便点进去看看

public Request buildRequest() {
    String str = null;
    if (TextUtils.isEmpty(this.baseUrl)) {
        LogUtil.a("OkHttp", "baseUrl: " + this.baseUrl);
        return null;
    }
    this.map.put("encode_sign", Util.b(this.map));
    String e = Util.e();
    try {
        String jSONObject = new JSONObject(this.map).toString();
        str = Util.a(jSONObject, "AG+BwcnekYZy$9f7X#b2zdB93brfFMmz", "f%Z4F+qtFh" + e);

    } catch (Exception e2) {
        e2.printStackTrace();
    }
    RequestBody create = FormBody.create(MediaType.b("application/json; charset=utf-8"), new GsonBuilder().disableHtmlEscaping().create().toJson((Object) new FormData(str)));
    Request.Builder builder = new Request.Builder();
    Request.Builder a = builder.a(this.baseUrl + this.prefix).a(create);
    Headers.Builder builder2 = new Headers.Builder();
    builder2.a("suffix", e);
    a.a(builder2.a());
    return a.a();
}

我们先来分析一波

在上面我们发现一个这个,我们ctrl点击进去这个a方法瞅瞅

str = Util.a(jSONObject, "AG+BwcnekYZy$9f7X#b2zdB93brfFMmz", "f%Z4F+qtFh" + e);

有没有很惊喜我们得到了加密的方法AES/CBC/PKCS7Padding

public static String a(String str, String str2, String str3) throws Exception {
    try {
        Cipher instance = Cipher.getInstance("AES/CBC/PKCS7Padding");
        int blockSize = instance.getBlockSize();
        byte[] bytes = str.getBytes();
        int length = bytes.length;
        if (length % blockSize != 0) {
            length += blockSize - (length % blockSize);
        }
        byte[] bArr = new byte[length];
        System.arraycopy(bytes, 0, bArr, 0, bytes.length);
        instance.init(1, new SecretKeySpec(str2.getBytes(), "AES"), new IvParameterSpec(str3.getBytes()));

        return new String(Base64.encode(instance.doFinal(bArr), 2));
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

所以

str = Util.a(jSONObject, "AG+BwcnekYZy$9f7X#b2zdB93brfFMmz", "f%Z4F+qtFh" + e);

那么这个e变量是个什么鬼,我们看到上面e调用了这个e方法,我们继续ctrl进去

String e = Util.e();

public static String e() {
    Random random = new Random();
    String str = "";
    for (int i = 0; i < 6; i++) {
        str = str + random.nextInt(10);
    }
    return str;
}

从上面这个方法,我们发现他是随机生成一个0-9的6位数字
好,我们继续向下看

我们发现貌似suffix也是一个随机数,而且这个e和上面的e是同一个值
接下来我们再梳理一下我们拥有的

  • 加密算法:AES/CBC/PKCS7Padding
  • e的值:随机生成6位0-9的随机数(如:849589)
  • 加密密钥:AG+BwcnekYZy$9f7X#b2zdB93brfFMmz
  • 加密偏移:f%Z4F+qtFh + e的值
  • suffix的值:e的值

就这个地方,因为他这个随机值想了两天(混淆视听) 好既然知道了加密密钥和偏移量,我们再回去看看那段请求参数

suffix: 624970 

请求参数

{"post-data":"PzLkqSAItZGaaN0LRHlGdqub8aCPIBKpnA/GyWvmHRnIw9nkaWdIctRkQtHVRiavhMnVU5j3sPR03wPsqJ2QP/uK1+JLRYCbSpVW54m2rf2Qcl6rDyqzdz/tDyOVqsukAo7R/xw/FKsBVBhAjL39jmHCTd5acRul9HI7ZgQYg9HUL5DJbCrxTqvOyoOxcLJIlnFOcGiASqx4PzqobWZ7bhptZiP0IygaSKj7/oIBsqJ6YPu+r+iqc/i0vPvn/H7ZG+LZXjhq3kGBxHg6xdW1wWyO+7K0Mo+iR4rxd/HjIlcN4lKljrjEplzTLRHhn2v38U+M0hJ2GRIkjoeexAqyxhmT0EvnsMsbr4N0F45/c7eU2y0BMhHFDpRBeWni9P7T/06Dp7xJPJO7PESGBDn3aYJd9ZVLFrqanzRf8LgCN0qE/7MRpLKpQZ9YhwwWgJQHSAc7xTVHLNtZIlG+ZzK3KKvbQ+tUGm2jKak5zCxhoRs="}

分析一下上面这个的密钥和偏移 密钥就是固定的,偏移既然是e的值,e的值和suffix是同一个值 那么我们拼接一下

  • 加密密钥:AG+BwcnekYZy$9f7X#b2zdB93brfFMmz
  • 加密偏移:f%Z4F+qtFh624970

我们赶紧去试试
这里我们按照代码中的方法解密一下
我直接去谷歌找了个AES CBC解密的网址做测试

搞定,就这个地方,我弄了好久,脑子没转过来

{
"type":"2",
"timezone":"GMT+08:00",
"imei":"",
"timestamp":"1585785560",
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ODIyMTAxMSwiYmNfdXJsIjoiaHR0cHM6XC9cL2hlZTk4LmNvbVwvI1wvaG9tZT9zZXNzaW9udG9rZW49ODUzMTk2OV8xNTg1Nzg1NTUyIiwidGltZSI6MTU4NTc4NTQ2Nn0.Xkn5XfINeUZVYGgh91mE_N0YjowKTv5R8u21rYR_xGU",
"encode_sign":"dbb976ac0443c6fd95b5baf790b3d20d"
}

为了验证,我们在给他加密回去,出问题了,我们可以看到加密的字符和原来的字符有所差异

先别急,我们尝试用这个post提交去试一下

PzLkqSAItZGaaN0LRHlGdqub8aCPIBKpnA/GyWvmHRnIw9nkaWdIctRkQtHVRiavhMnVU5j3sPR03wPsqJ2QP/uK1+JLRYCbSpVW54m2rf2Qcl6rDyqzdz/tDyOVqsukAo7R/xw/FKsBVBhAjL39jmHCTd5acRul9HI7ZgQYg9HUL5DJbCrxTqvOyoOxcLJIlnFOcGiASqx4PzqobWZ7bhptZiP0IygaSKj7/oIBsqJ6YPu+r+iqc/i0vPvn/H7ZG+LZXjhq3kGBxHg6xdW1wWyO+7K0Mo+iR4rxd/HjIlcN4lKljrjEplzTLRHhn2v38U+M0hJ2GRIkjoeexAqyxhmT0EvnsMsbr4N0F45/c7eU2y0BMhHFDpRBeWni9P7T/06Dp7xJPJO7PESGBDn3aYJd9ZVLFrqanzRf8LgCN0qE/7MRpLKpQZ9YhwwWgJQHfcDJ0xCNNbpvJ4JISotfDg==

我们发现居然请求成功了

至于为什么,其实我到现在还没搞懂
好,现在我们用相同的方法去解密响应里面的请求

{
"code":0,
"msg":"u64cdu4f5cu6210u529f",
"data":"ebdPaRiKxsrjeTanIw8V5OMttiNI+q5RQNRUiOcmbu/d0qCdyhtAlALDStCtTSycig8vmYFthZ3yBNYTEbnaUhGNHudQaiAwDQlMJwVXh6k=",
"suffix":"pvYcSk"
}

这个suffix,就是我们的e值,我们同样方法去拼接,赶紧去试试

有没有很激动,既然响应他会直接给我们,那么我们只需要知道如何解密响应的参数即可,现在我们需要继续去解决请求里面的,抓Api页数什么的接口,继续打开fiddle,一开始我们选择了一个短的去研究解密加密,这次我们选择一个长的,多解密看看,响应是什么

找到了这个接口,解密出来的json数组,我们去格式化一下看看(下面我复制出来一个) 下面这个是格式化好的接口,看来这个就是我们想要的,xxxxxx为手动打码,我们从字面意思了解一下

请求地址:http://47.56.88.111:8082/index/videoByTime
请求参数:
{"post-data":"yLgaZeB96A5Guj+VA6nd2cAM9vyP3CxXYwhqLe1FOCxH0Q5iw63FrZyD3S74ecCl9T6wbwgm9o3fPeXxQ0+mfXs1bt0cZuopfOqkoNBUQA9jY8NLHOxKTGzwtu6R+6G+qMMU4bFEgEn0JvYxJ8M4tcL9mraLcrJmcpQ054WwuEHCkZFwEN8DtZMO3oOzbqAmkpvAQzFY8RPqK98cqlmKwrPj4TRLugoIGvzHfvdC71c="}
suffix值:411657
解密值:
{
"type":"1",
"page":"1",//页数
"row_count":"20",
"timezone":"GMT+08:00",
"imei":"",
"timestamp":"1585809942",
"encode_sign":"230347f77d52df663c57a0c53ca8ffa6"
}
响应参数解密
{
  "total": 16313, 
  "per_page": "20", //一页20个
  "current_page": 9, //当前页
  "last_page": 816, //一共816页
  "data": [
    {
      "id": 65791, //id这个是视频id,下面会去抓视频界面的api
      "title": "国产xxxxxx",
      "thumb": "https://9xxxxxxm/bbc/20200330_x_8s.jpg", 
      "thumb_raw": "https://9xxxxxxm/bbc/20200330_x_8.png", 
      "preview": "https://9xxxxxxm/cover/20200329/1fe51ef94ad58a9210510f561de63ecf.webp", 
      //上面这个是动图,我打开看过
      "definition": 0, 
      "play": 194886, 
      "good": 1193, 
      "bad": 79, 
      "like": 4662, 
      "comment": 901, 
      "uid": 3625827, 
      "description": "", 
      "publish_time": 1585539771, 
      "private": 0, 
      "points": 0, 
      "original": 0, 
      "nickname": "女xxxxxx", 
      "avatar": "https://9xxxxxxm/uploads/avatar/20200321/5e75bfaf15d96790.jpg", 
      "vip_grade": "silver_type", 
      "frame": "", 
      "medals": "8,9,10", 
      "is_dav": 0
    }, 

好现在我们获取到了接口以及传递参数,那么我们现在去请求第二页试试
请求地址:http://47.56.88.111:8082/index/videoByTime
suffix值:411657
我们将下面这个改完页数加密回去

{"type":"1","page":"2","row_count":"20","timezone":"GMT+08:00","imei":"","timestamp":"1585809942","encode_sign":"230347f77d52df663c57a0c53ca8ffa6"}
yLgaZeB96A5Guj+VA6nd2WUenF7sSMd4zluL6vfaoWSz2gm0bVW+9Tnub+mw13d0xtR9cyaL/v3+T6Ev8rc8cFJICWvBQnjQMCtGwCn2wouCrICERVtNabuxvTqFtbXetj002d9Vqgit5jRVnVUlckmTIDvU5i9SBWvro3AZ9sQjwEfaZ7Meiy3K92K4O/wivIflEYTFxbvfkXZwnQnWPQ==

现在去请求试一下,发现会显示签名错误

我们再来看一次这个请求参数

请求参数:
{
"type":"1",
"page":"1",//页数
"row_count":"20",
"timezone":"GMT+08:00",
"imei":"",
"timestamp":"1585809942",
"encode_sign":"230347f77d52df663c57a0c53ca8ffa6"
}
encode_sign我们可以猜测这个就是sign签名,而且猜测问题就出在这,如果前面值变动那么sign值也会变动

我们带着问题去再次去看源码

搜索这个接口的一些片段,第一个很符合我们的要求,点进去
我们可以看到调用了 Util中的b这个方法,而且好像和hasMap有关,猜测一下如果这个和hasMap有关,那么执行到他那里,上面只要有一个地方变换那么,这个值就会不同

    public void d(String str, String str2, String str3, VolleyCallBack volleyCallBack) throws Exception {
        HashMap hashMap = new HashMap();
        hashMap.put("imei", Util.c(APP.a().getBaseContext()));
        hashMap.put("type", str + "");
        hashMap.put("row_count", str2);
        hashMap.put("page", str3);
        hashMap.put("timezone", Util.f());
        hashMap.put("timestamp", Util.c());
        hashMap.put("encode_sign", Util.b((Map<String, String>) hashMap));
        String e = Util.e();
        String jSONObject = new JSONObject(hashMap).toString();
        String a2 = Util.a(jSONObject, "AG+BwcnekYZy$9f7X#b2zdB93brfFMmz", "f%Z4F+qtFh" + e);
        hashMap.clear();
        hashMap.put("post-data", a2);
        a.a(new StringRequest(1, b + "index/videoByTime", hashMap, volleyCallBack, volleyCallBack, e));
    }

我们继续ctrl直接点击确进去,粗略的看他应该是把Map转化为一个数组,最后数组加上那一串乱码,执行a方法,如果有就删除最后执行MD5加密(这个地方又) 改一下,上面这个说法有误正确的说法应该是:执行a方法,如果有双引号就删除最后执行MD5加密 str.replace(""", ""); 这里的”“是转义字符,意思是把字符串中的双引号替换为空

我们直接新建一个Java程序去模拟直接执行,提取出来有用的代码

        hashMap = new HashMap<>();
        hashMap.put("imei", "");
        hashMap.put("type", "1");
        hashMap.put("row_count", "20");
        hashMap.put("page", "2");
        hashMap.put("timezone", "GMT+08:00");
        hashMap.put("timestamp", "1585809942");
        hashMap.put("encode_sign", b(hashMap));
    public static String b(Map<String, String> map) {
        String str = "";
        ArrayList arrayList = new ArrayList(map.entrySet());
        Collections.sort(arrayList, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> entry, Map.Entry<String, String> entry2) {
                return entry.getKey().compareTo(entry2.getKey());
            }
        });
        for (int i = 0; i < arrayList.size(); i++) {
            if (!(((Map.Entry) arrayList.get(i)).getValue() == null || ((String) ((Map.Entry) arrayList.get(i)).getValue()).length() == 0)) {
                str = str + ((Map.Entry) arrayList.get(i)).getKey() + "=" + ((Map.Entry) arrayList.get(i)).getValue() + "&";
            }
        }
        Log.e("Map转字符串后:----->", a(str + "6Bf2_kh*P?4tuB*C#@WEVf752x8beCE@uB-Z"));
        Log.e("加密后的Sign值:----->", MD5.a(a(str + "6Bf2_kh*P?4tuB*C#@WEVf752x8beCE@uB-Z")));
        return MD5.a(a(str + "6Bf2_kh*P?4tuB*C#@WEVf752x8beCE@uB-Z"));
    }

运行,我们发现他的sign值和我们上面的请求参数解密出来的sign值是一样的

sign值的计算方法
"type":"1",
"page":"1",//页数
"row_count":"20",
"timezone":"GMT+08:00",
"imei":"",
"timestamp":"1585809942",
将上面的json数组变成:page=1&row_count=20&timestamp=1585809942&timezone=GMT+08:00&type=1&
之后在最后补上 (6Bf2_kh*P?4tuB*C
拼接为:page=1&row_count=20&timestamp=1585809942&timezone=GMT+08:00&type=1&6Bf2_kh*P?4tuB*C
之后查找这一串字符串中是否含有“”斜杠,如果有就删掉
最后把这串字符串MD5加密,就生成了sign签名

ok了,现在我们知道了签名值的算法,我们再来尝试一下

{"type":"1","page":"2","row_count":"20","timezone":"GMT+08:00","imei":"","timestamp":"1585809942","encode_sign":"230347f77d52df663c57a0c53ca8ffa6"}

还是这个改了page2,然后我们还得修改修改 先将数组里面刚才的数据变成:

page=2&row_count=20&timestamp=1585809942&timezone=GMT+08:00&type=1&6Bf2_kh*P?4tuB*C

之后我们获取MD5值 32位小写

28c84a8b91b0541a1b6b96bbd6470ca1

最终修改好的值为(将encode_sign修改为上面的MD5值)

{"type":"1","page":"2","row_count":"20","timezone":"GMT+08:00","imei":"","timestamp":"1585809942","encode_sign":"28c84a8b91b0541a1b6b96bbd6470ca1"}

之后我们再去利用一个suffix的值去加密,我这里就用123456了,下面这个就是加密的值 关于这个suffix的值,在代码中我们一共有3个suffix值

  • 加密密钥
  • 请求参数
  • 响应参数

既然他是随机的,我们给定他一个值固定值,由于加密密钥和请求参数的随机值是一样的,所以我们在发送请求的时候和加密密钥时候使用同一个suffix的值就可以了

JtWC52qzRnKwi703B+GapxR0a39cdYwBoGXmezIAadQiY/EOyI65c3nJ21wTjzxDRe62iTXGSlPQJjJQOMyvyrwiTOxFC0ctdNxGBKtezBqHyWv360ia3MFvFwFZnprHFYqHMfTQSOgFvpjAGcwY3ejTFqw+aFNmJJBRDD8sGAMXKADnHiIXEZSr15hdhjay+lNH+UZRg1hN71FzOA1vuw==

Postman请求一下,首先修改post-data值为上面的这个加密好的值

之后再去修改这个suffix值,这个值

我们看到终于请求成功了

再次梳理一下,现在我们都已经获取到了视频列表的api

请求网址:http://47.56.88.111:8082/index/videoByTime
请求参数:{"type":"1","page":"2","row_count":"20","timezone":"GMT+08:00","imei":"","timestamp":"1585809942","encode_sign":"28c84a8b91b0541a1b6b96bbd6470ca1"}
请求参数设置规则首先在page页改完之后,sign的值将前面的数组转为字符串,加上(6Bf2_kh*P?4tuB*C
转为MD5值之后,再把整个数组内容利用AES/CBC/PKCS7Padding加密
加密密钥为AG+BwcnekYZy$9f7X
偏移量为f%Z4F+qtFh  +  随便一个6位数值
请求的Header值有两个
suffix:和上面偏移量中的六位数字匹配
Content-Type:application/json

在获取到响应参数之后
参数中有一个suffix值
我们通过AES/CBC/PKCS7Padding解密
加密密钥为AG+BwcnekYZy$9f7X
偏移量为f%Z4F+qtFh  +  响应参数中是suffix值

获取视频详情页的视频直链播放地址,任然还是抓包,由于App端有限制,我们换网页端去抓包,网页端可以直接观看,随便打开一个视频抓包

锁定了这个地方,我们解密请求看看没错了,这次就是我们所需要的详情页的参数

我们再去看看post了一个什么数值

请求地址:https://alipaydatabase.com/video/getVideoUrl
请求参数:{"post-data": "w02dFmxKD9sIdHMDaWQNVvg/0dW73kHAGsQZQTtetjENm8YI0sTtohJ5uDCWThA4CzBxLsXBXKvSlkY/kIS5mroVkZyn2FL/BZA7V/c+t+iKeQpr/zA7AoWEwfVyLTiQbmmb4PGAlMufR0ue6o2u/Xz2yziDOT0HjFrO/OP2RRs="}
suffix值:MQB9KE
参数解密:{"vid":65548,"road":"default1","timestamp":1585815671868,"devicetype":"pc","encode_sign":"0cf73acfd484ca591f8b2c93702e141d"}

响应参数:{"code":0,"msg":"u64cdu4f5cu6210u529f","data":"9/SWHCfjHGyamn1ot0XbiAYp/FbT09tfGcyjk8R2yR0jKOoX7+OsNySN0ln3IF7fiLjl8asVU6bdu6uj2GbWJ0STiBoqsc2BBMKDAOerRJ8mPOS909e5VCpY0rXWbhTECKtnzeX6iDrMhxlXiAXKy1EUzIOqPAaUWbVhPiqcaTwVq00FajSC/yGwc2xFlQo8+sdoM93/JE6upKSwnBxb8unCq+WLhBd/l4grm+8Ames+HZAWkuTU9ozjLjIlUk4o","suffix":"x6oxf5"}
参数解密:{"data":{"video_url":"https://cdn.iicgs.org/20200326/606f9222b8dd2392b47c80102ebb3c7a.mp4/index.m3u8","is_full":1,"share_url":"https://aes59.com//video/detail?id=65548"}}

我们发现上面请求参数里面有个vid的值,这个值我尝试之后正好对应上面视频列表中的id值

所以当我们拥有了视频列表里面的id值,循环执行加密解密操作就能获取到每个视频的链接
可能大家也发现了这里电脑请求的suffix值含有英文字母 这里我们可以去看看网页的代码

可以看到他也是6位随机数,只不过不仅是0-9,还加了字母进去
一开始因为这个随机数很懵,太混淆视听了
好了,现在我想要的两个api就已经到手了,我们最后再梳理一遍俩api

视频列表api
请求网址:http://47.56.88.111:8082/index/videoByTime
请求参数:{"type":"1","page":"2","row_count":"20","timezone":"GMT+08:00","imei":"","timestamp":"1585809942","encode_sign":"28c84a8b91b0541a1b6b96bbd6470ca1"}
请求参数设置规则首先在page页改完之后,sign的值将前面的数组转为字符串,加上(6Bf2_kh*P?4tuB*C
转为MD5值之后,再把整个数组内容利用AES/CBC/PKCS7Padding加密
加密密钥为AG+BwcnekYZy$9f7X
偏移量为f%Z4F+qtFh  +  随便一个6位数值
请求的Header值有两个
suffix:和上面偏移量中的六位数字匹配
Content-Type:application/json

在获取到响应参数之后
参数中有一个suffix值
我们通过AES/CBC/PKCS7Padding解密
加密密钥为AG+BwcnekYZy$9f7X
偏移量为f%Z4F+qtFh  +  响应参数中是suffix值
视频直链api
请求地址:https://alipaydatabase.com/video/getVideoUrl
请求参数:{"post-data": "w02dFmxKD9sIdHMDaWQNVvg/0dW73kHAGsQZQTtetjENm8YI0sTtohJ5uDCWThA4CzBxLsXBXKvSlkY/kIS5mroVkZyn2FL/BZA7V/c+t+iKeQpr/zA7AoWEwfVyLTiQbmmb4PGAlMufR0ue6o2u/Xz2yziDOT0HjFrO/OP2RRs="}
suffix值:MQB9KE
参数解密:{"vid":65548,"road":"default1","timestamp":1585815671868,"devicetype":"pc","encode_sign":"0cf73acfd484ca591f8b2c93702e141d"}

响应参数:{"code":0,"msg":"u64cdu4f5cu6210u529f","data":"9/SWHCfjHGyamn1ot0XbiAYp/FbT09tfGcyjk8R2yR0jKOoX7+OsNySN0ln3IF7fiLjl8asVU6bdu6uj2GbWJ0STiBoqsc2BBMKDAOerRJ8mPOS909e5VCpY0rXWbhTECKtnzeX6iDrMhxlXiAXKy1EUzIOqPAaUWbVhPiqcaTwVq00FajSC/yGwc2xFlQo8+sdoM93/JE6upKSwnBxb8unCq+WLhBd/l4grm+8Ames+HZAWkuTU9ozjLjIlUk4o","suffix":"x6oxf5"}
参数解密:{"video_url":"https://cdn.iicgs.org/20200326/606f9222b8dd2392b47c80102ebb3c7a.mp4/index.m3u8","is_full":1,"share_url":"https://aes59.com//video/detail?id=65548"}

具体的加密解密操作就是上面那个视频列表的操作

对了,视频网站还有4个线路,我们同样通过抓包来获取,我这边过程就不去演示了

解密出来的接口是下面这四个,这边我手动打码
接口1:https://cdn.xxxxxx.org/20200401/15fd047c0b1630847deaea6888fb9dde.mp4/index.m3u8
接口2:https://9xxxxxx.com/20200401/15fd047c0b1630847deaea6888fb9dde.mp4/index.m3u8
接口3:https://daxxxxxx.com/20200401/15fd047c0b1630847deaea6888fb9dde.mp4/index.m3u8
接口4:https://moxxxxxx.com/20200401/15fd047c0b1630847deaea6888fb9dde.mp4/index.m3u8
后面我测试,同一个视频地址,如果需要更换线路,只需要修改域名就好,后面不需要修改

OJBK,这个软件的分析就到此结束,我终于获取到了想要的东西
关于安全:我建议此软件再加个字符串混淆,类名混淆,请求参数中的时间戳是一个摆设,密钥前后可以加几个字符串,来让反编译者混淆视听,把网站也设置为登录可看视频。
其实再此之前我用过动态调试,用过Hook乱七八糟各种各样的方法,上面这篇是我从失败中总结出来的,文章中可能有少许错误,有错误大家可以评论区提醒一下。
欢迎添加我的微信,互相学习。

知识库
License:  CC BY 4.0
Share

Further Reading

Jul 31, 2025

如何实现接口幂等性

通俗的说,用户在系统中有操作,不管重复多少次,都应该产生一样的效果或返回一样的结果的。 幂等性的概念 幂等(Idempotent)是一个数学与计算机学的概念,常见于抽象代数中。 f(n)=1^n//无...

Jul 19, 2025

10个npm工具包

有了npm之后,前端人员真的是过上好日子了。我们可以直接把别人写好的工具包拿来用,非常的方便。 1.day.js-轻量日期处理 npminstalldayjs importdayjsfrom'd...

Jul 17, 2025

How to set up PHP7.4 on MacOS.

Thisisallverywellandgood.Apartfromonesmallinsignificantthing… TheversionofPHPinuseiscurrently7.4. Th...

OLDER

API接口加解密技术方案

NEWER

Express模板引擎和视图Express 框架提供了强大的模板引擎和视图功能

Recently Updated

  • 如何实现接口幂等性
  • 10个npm工具包
  • How to set up PHP7.4 on MacOS.
  • Automa:一键自动化,网页数据采集与工作流程优化专家Automa:解锁自动化
  • Mac 下用 brew 搭建 LNMP

Trending Tags

thinkphp clippings

Contents

©2025 麦兜的小站. Some rights reserved.

Using the Halo theme Chirpy