webjs - 网易云音乐加密

分析问题

在浏览网易云音乐网站时候发现,很多操作譬如听歌、查看评论等操作,提交参数均为params+encSecKey组合提交。encSecKey:一直是256位。

分析加密字段

以常规方式,通过搜索看看能否定位到加密入口。

image.png

入口函数d及参数

function d(d, e, f, g) {
  var h = {}
  , i = a(16);
  return h.encText = b(d, g),
    h.encText = b(h.encText, i),
    h.encSecKey = c(i, e, f),
    h
}

函数d有四个参数,内部调用了函数a、函数b、函数c。尝试逐一突破。

首先观察函数d的四个参数分别是什么,通过断点调试。

参数名称参数内容参数类型
d"{"id":"1471802279","c":"[{\"id\":\"1471802279\"}]","csrf_token":"799f81df17fd9175b69bb9ff314ca3d8"}"str
e"010001"str
f

"00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b72

5152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e03

12ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b

424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"

str
g"0CoJUm6Qyw8W8jud"str

 

 

 

 

 

 

 

 

 

以上参数通过多次观察,只有参数d是变动的,其中变动的值为id,即歌曲id。

之后的调试结果均以以上参数为基础做调试。

函数a

函数a的入口为:i = a(16)

function a(a) {
  var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
  for (d = 0; a > d; d += 1)
    e = Math.random() * b.length,
      e = Math.floor(e),
      c += b.charAt(e);
  return c
}

有点JavaScript基础的应该看出来,传入变量a,输出变量a个随机字符。

那入口函数a传入变量参数16,即生成16个随机字符。

函数b

h.encText = b(d, g),

h.encText = b(h.encText, i),

function b(a, b) {
  var c = CryptoJS.enc.Utf8.parse(b)
  , d = CryptoJS.enc.Utf8.parse("0102030405060708")
  , e = CryptoJS.enc.Utf8.parse(a)
  , f = CryptoJS.AES.encrypt(e, c, {
    iv: d,
    mode: CryptoJS.mode.CBC
  });
  return f.toString()
}

函数b是一个典型的利用Crypto库进行AES加密。如果对某个加密库不了解不妨google一下

// Custom Key and IV
var key = CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
var iv = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f");
var encrypted = CryptoJS.AES.encrypt("Message", key, { iv: iv });

// Block Modes and Padding
var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase", {
  mode: CryptoJS.mode.CFB,
  padding: CryptoJS.pad.AnsiX923
});

引用来源:https://cryptojs.gitbook.io/docs/#ciphers

对应的,我下载了Python的Crypto包,找到了里面的Cipher/AES.py源码观察了下

For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long.

所加参数必须是16字节长。

:Return: an AES object, of the applicable mode.

返回是一个AES对象。

进入这个AES对象方法encrypt

def encrypt(self, plaintext, output=None):
    """
   	:Parameters:
          plaintext : bytes/bytearray/memoryview
            The piece of data to encrypt.
            Its lenght must be multiple of the cipher block size.
        :Keywords:
          output : bytearray/memoryview
            The location where the ciphertext must be written to.
            If ``None``, the ciphertext is returned.
        :Return:
          If ``output`` is ``None``, the ciphertext is returned as ``bytes``.
          Otherwise, ``None``.
        """

 

必须是block size的倍数,block size 默认是16

于是就有了以下方法,用来构建加密。

这里可能会疑问,key和iv不应该都要16字节吗?其实是因为网易云音乐传入的固定iv和key值都已经是16字节了,通过print(len(iv.encode())),就观察到了。

def encrypt(text, key, iv):
    # 将传入的文本进行block_size倍数填充
    clear_text = pad(data_to_pad=text.encode(), block_size=AES.block_size)
    # 创建AES cipher
    encryptor = AES.new(key.encode(), AES.MODE_CBC, iv=iv.encode())
    # 进行MODE_CBC加密
    ciphertext = encryptor.encrypt(clear_text)
    # 转码输出
    ciphertext = base64.b64encode(ciphertext).decode()
    return ciphertext

函数b的第二种方法

第一种是利用python的Crypto包实现了函数b的功能。

第二种方法我准备用现有的crypto加密js文件,直接进行加密。

在python中就很简单的利用execjs库直接调用JS文件

import execjs

with open('cryptoJS.js', 'r', encoding='utf-8') as f:
    js_str = f.read()

js_obj = execjs.compile(js_str)
word = '{"id":"1476219294","c":"[{\\"id\\":\\"1476219294\\"}]","csrf_token":""}'
key = "0CoJUm6Qyw8W8jud"
print(js_obj.call('getpasss', word, key))

函数c

function c(a, b, c) {
  var d, e;
  return setMaxDigits(131),
    d = new RSAKeyPair(b,"",c),
    e = encryptedString(d, a)
}

函数c就是一个RSA加密了,我同以上函数b的经验。找到了RSA的js文件,执行利用execjs调用,简单粗暴,哈哈哈。

image.png

with open('RSAKEY.js', 'r', encoding='utf-8') as f:
    js_str = f.read()

js_obj = execjs.compile(js_str)

p_a = "PsH7lXqqXnEZXpvF"
p_b = "010001"
p_c = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"


print(js_obj.call('get_c', p_a, p_b, p_c))

总结

再次看函数d的时候就发现各个内部函数已经被逐一攻破

h.encText即params

h.encSecKey即encSecKey

验证正确性

image.png

image.png

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值