Learn how to convert NCM files to MP3——What important things should you do after charging the network and suppressing cloud members?

Not much to say, just because VIP's songs are in ncm format, they cut my leeks hard!

I’m using Wangyiyun to listen to music, and then I’ve recharged as a VIP. Don’t ask, it’s because I like listening to unpopular songs, otherwise I would have used QQ Music long ago, wouldn’t I?

After searching and searching, I found that caring people have developed websites for converting music in various formats:

here is

The lazy dog ​​saw that it could already be rowed away, and the rest was for tossing.

However, it is really slow to pack the website into a zip. Downloading one by one feels like a part-time job . Although you can prostitute for free (sorry, I really didn’t reward) , but I still want to use it more conveniently, so I went to Search other people's leftover codes on github , there are all kinds of C#, PHP, python, java, after thinking about it, I have installed so many virtual environments, and it seems that I don't use a graphical interface (rarely don't use a graphical interface ) , so I plan to use python scripts for batch processing, and finally use bat files to realize automatic processing, wouldn't it be beautiful?

Recently, I got dizzy playing Xingqiong Railway, and it's not that I didn't study, but it was hard to encounter a game that felt like an onmyoji, and it took me back to the time when I just played mobile games in the first day of junior high school. The day after tomorrow, I will go to the Hell Training Factory for an internship. I don’t know how many days I can be happy?

I mainly refer to the codes of two guys, one is the java guy, a set of graphics comes with an explanation, the other is the main code of the python guy, I slightly modified it according to my own needs.

java guy python guy

I didn’t feel that there was anything wrong at the beginning. After installing ffmpeg, I went directly to it, and then it directly threw an encoding error to me, and I realized it. It’s easy to decode it for you, so why play VIP?? Later Knowing that ncm is segmented encryption, including the encryption of several mainstream ciphers, the key should be cracked by the guy. After knowing the key and algorithm, you can decrypt it happily!

I used to study cryptography, so I saw the same thing. Friends who don’t know don’t need to worry too much, because if you don’t write a thesis to design encryption, you don’t need to know too much detail, just know the principle and use it.

Attached here is the analysis of the java guy, it is very well written, and I will not change it. Because I'm lazy. (I suck)

information size Remark
Magic Header 10 bytes jump over
KEY Length 4 bytes The length of the RC4 key encrypted with AES128 (little endian byte order, unsigned integer)
KEY From AES128 Decode KEY Length (actually 128 bytes) RC4 key encrypted with AES128 (Note: 1. XOR 0x64 by byte 2. AES decryption (the PKCS5Padding filling mode will remove the padding at the end;) 3. Remove the first 17 bytes neteasecloudmusic;
Mata Length 4 bytes The length of Mata's information (little endian byte ordering, unsigned integer)
Head Data(JSON) Mata Length Mata information in JSON format (Note: 1. XOR 0x63 by byte; 2. Remove the first 163 key(Don't modify):22 bytes; 3. Base64 decode; 4. AES decryption; 5. music:Get after removing the first 6 bytes JSON)
CRC check code 4 bytes jump over
Gap 5 bytes jump over
Image Size 4 bytes Image size
Image Image Size image data
Music Data - RC4-KSA generates s-box, RC4-PRGA decrypts

It should design a special decryption system in the software, and then match this to decrypt and play, but I want to know why the key is fixed, so it can be cracked by others? ? ? How lazy, because this way you don’t have to save so many keys, and most people don’t know how to crack it... One is because they are too lazy to know, and the other is because they think it is unnecessary, uh, but I purchased the service and it is still Unclean, at least give me the source data, can I save the key myself?

Into the title

Those who have not installed this password library need to install it in your environment/virtual environment :

pip install pycryptodome

Scenario 1: Run the script manually

The fixed folder is like this: there are two folders under your main file, one for ncm suffix files and one for mp3 suffix files.

After running the code, all the songs in the ncm folder will be converted into mp3 format and placed in the mp3 folder.

Name it convert_ncm_to_mp3.py and place it under the convert_ncm_to_mp3 folder.

If there is a problem, please do so here.

# 注意ncm是加密过的 所以使用ffmpeg只能对没有加密的处理
import binascii
import struct
import base64
import json
import os
from Crypto.Cipher import AES


def run(input_file, out_file):
    ncm_files = [file for file in os.listdir(input_file) if file.lower().endswith('.ncm')]
    for ncm_file in ncm_files:
        file_path = os.path.join(input_file, ncm_file).replace('\\', '/')
        dump(file_path, out_file)
        song_name = file_path.split('.')[1]
        song_name = song_name.split('/')[2]
        print('{}.ncm 文件转换成 {}.mp3 文件完成!'.format(song_name,song_name))
    print("批量转换完成!")



def dump(file_path,out_path):
    # 687A4852416D736F356B496E62617857 (Hex) -> hzHRAmso5kInbaxW    (Text)
    core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857")
    # 2331346C6A6B5F215C5D2630553C2728 (Hex) -> #14ljk_!\]&0U<'(    (Text)
    meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728")
    # 定义 lambda 表达式
    unpad = lambda s: s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))]
    # 以二进制读模式打开传入的 ncm 文件
    f = open(file_path, 'rb')
    song_name = file_path.split('.')[1]
    song_name = song_name.split('/')[2]
    # 读八字节
    header = f.read(8)
    # 确认其为 ncm 格式标记
    assert binascii.b2a_hex(header) == b'4354454e4644414d'
    # 后移 2 字节(多余字节)
    f.seek(2, 1)
    # 读四字节
    key_length = f.read(4)
    # 以小端方式转换 key_length 为 integer
    # 80 00 00 00 (Hex) -> 128 (int)
    key_length = struct.unpack('<I', bytes(key_length))[0]
    # 向后读文件的 128 字节
    key_data = f.read(key_length)
    # 将 key_data 转化为字符数组
    key_data_array = bytearray(key_data)
    # 将 key_data_array 中的每个字节与 0x64 做异或运算
    for i in range(0, len(key_data_array)): key_data_array[i] ^= 0x64
    # 将 bytearray key_data_array 转型为 bytes
    key_data = bytes(key_data_array)
    # 使用之前定义的 core_key 创建了 AES_ECB 解密器 cryptor
    cryptor = AES.new(core_key, AES.MODE_ECB)
    # 首先看 cryptor.decrypt(key_data):解析 key_data,解析出来的数据开头是 neteasecloudmusic,即 ncm 的全称
    # 通过开头定义的 lambda 函数 unpad 去掉末尾的 \r 和开头的 neteasecloudmusic
    # 17 为 len("neteasecloudmusic")
    key_data = unpad(cryptor.decrypt(key_data))[17:]
    # 更新 key_length 的值(即 data 的长度)
    key_length = len(key_data)

    # 将 key_data 转型为 bytearray 类型
    key_data = bytearray(key_data)

    # 以下是 RC4-KSA 算法
    key_box = bytearray(range(256))
    c = 0
    last_byte = 0
    key_offset = 0
    for i in range(256):
        swap = key_box[i]
        c = (swap + last_byte + key_data[key_offset]) & 0xff
        key_offset += 1
        if key_offset >= key_length: key_offset = 0
        key_box[i] = key_box[c]
        key_box[c] = swap
        last_byte = c

    # 读取四字节长度,和前面的 key_length 相似
    meta_length = f.read(4)
    # 以小端方式将 meta_length 转化为 int
    meta_length = struct.unpack('<I', bytes(meta_length))[0]
    # 读取 meta_kength 字节长度数据赋给 meta_data
    meta_data = f.read(meta_length)
    # 类型转换
    meta_data_array = bytearray(meta_data)
    # 与 0x63 做异或
    for i in range(0, len(meta_data_array)): meta_data_array[i] ^= 0x63
    # 转型
    meta_data = bytes(meta_data_array)
    # 这里可以打断点看下 meta_data 的值,开头是 "163 key(Don't modify):",共 22 位
    # 这里去掉无关的前 22 位然后使用 base64 解码
    meta_data = base64.b64decode(meta_data[22:])
    # 再和上面类似,构造 ECB 进行解密
    cryptor = AES.new(meta_key, AES.MODE_ECB)
    # 此处 meta_data 的一个参考数据:
    # b'music:{"musicId":441491828,"musicName":"\xe6\xb0\xb4\xe6\x98\x9f\xe8\xae\xb0","artist":[["\xe9\x83\xad\xe9\xa1\xb6",2843]],"albumId":35005583,"album":"\xe9\xa3\x9e\xe8\xa1\x8c\xe5\x99\xa8\xe7\x9a\x84\xe6\x89\xa7\xe8\xa1\x8c\xe5\x91\xa8\xe6\x9c\x9f","albumPicDocId":2946691248081599,"albumPic":"https://p4.music.126.net/wSMfGvFzOAYRU_yVIfquAA==/2946691248081599.jpg","bitrate":320000,"mp3DocId":"668809cf9ba99c3b7cc51ae17a66027f","duration":325266,"mvId":5404031,"alias":[],"transNames":[],"format":"mp3"}\r\r\r\r\r\r\r\r\r\r\r\r\r'
    # 去掉前六位 "music:"
    meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:]
    # 转换成 json
    meta_data = json.loads(meta_data)

    # CRC32 校验码
    crc32 = f.read(4)
    crc32 = struct.unpack('<I', bytes(crc32))[0]
    # 后移五字节
    f.seek(5, 1)
    # 获取歌曲封面大小
    image_size = f.read(4)
    # 以小端方式将读取到的 Hex 数据转换成 int
    image_size = struct.unpack('<I', bytes(image_size))[0]
    # 读封面大小长度的数据,赋值给 image_data
    image_data = f.read(image_size)
    # 从之前构造的 json 中取歌曲名和文件拓展名,赋给 file_name
    # file_name = meta_data['musicName'] + '.' + meta_data['format']
    file_name = song_name + '.' + meta_data['format']
    # 以二进制写方式打开要生成的文件(若文件不存在会自动创建)
    m = open(os.path.join(out_path, file_name).replace('\\', '/'), 'wb')
    chunk = bytearray()

    # 以下是 RC4-PRGA 算法,进行还原并输出文件
    while True:
        chunk = bytearray(f.read(0x8000))
        chunk_length = len(chunk)
        if not chunk:
            break
        for i in range(1, chunk_length + 1):
            j = i & 0xff;
            chunk[i - 1] ^= key_box[(key_box[j] + key_box[(key_box[j] + j) & 0xff]) & 0xff]
        m.write(chunk)
    m.close()
    f.close()


if __name__ == '__main__':
    import sys
    input_file = './ncm'
    out_file = './mp3'
    # 固定文件夹版本
    run(input_file, out_file)

Solution 2: Turn into bat to run automatically

I don't want to open pycharm manually, I'm really lazy! In this way, write a script, but since I installed a virtual environment, I need to start my virtual environment class38 first , add it to the script, and then rewrite a new script file to call the python file in a fixed format.

Name it convert_ncm_to_mp3_script.py and place it in the convert_ncm_to_mp3 folder

import argparse
import os
import convert_ncm_to_mp3 as convert

if __name__ == '__main__':
    # 创建参数解析器
    parser = argparse.ArgumentParser(description='Process input and output files.')

    # 添加输入文件路径参数
    parser.add_argument('input', help='Input file path.')

    # 添加输出文件路径参数
    parser.add_argument('output', help='Output file path.')

    # 解析命令行参数
    args = parser.parse_args()

    # 获取输入文件路径和输出文件路径
    input_path = args.input
    output_path = args.output

    # 确保输出文件所在的目录存在
    os.makedirs(os.path.dirname(output_path), exist_ok=True)

    convert.run(input_path, output_path)

Create a new convert_run.txt and write the following in it:

@echo off
set INPUT_FILE=./ncm
set OUTPUT_FILE=./mp3
set VENV_NAME=class38

call conda activate %VENV_NAME% >nul
python convert_ncm_to_mp3_script.py "%INPUT_FILE%" "%OUTPUT_FILE%"

call conda deactivate >nul

Modify the suffix to .bat and then save and run.

Only one song is shown above but you can try multiple songs as follows:

At this point, it is almost over. For QQ Music, I haven’t started using it yet, so I haven’t recharged as a member. I’ll talk about it later.

When you want to use it, put the ncm file that needs to be converted into the ncm folder, run the batch file, then cut all the converted mp3 files and transfer them to the U disk, and then clear the ncm and mp3 folders. The main thing is A self-reliance.

Well, not much to write, the Lion General is waiting for me to get on the number! whee! 0-0!

When I have money, I must buy a cat that can laugh!

Guess you like

Origin blog.csdn.net/daxuanzi515/article/details/130770969