NCM 파일을 MP3로 변환하는 방법 알아보기——네트워크를 충전하고 클라우드 구성원을 억제한 후 해야 할 중요한 작업은 무엇입니까?

뭐 말할것도 없고 VIP님 노래는 ncm형식이라 제 대파를 세게 잘랐어요!

저는 왕이윤으로 음악듣고 VIP로 충전했어요 묻지마요 인기없는 노래듣는거 좋아해서 그런거아니면 ​​옛날에 QQ뮤직을 썼겠죠?

검색하고 검색한 결과, 돌보는 사람들이 음악을 다양한 형식으로 변환하기 위한 웹사이트를 개발했음을 발견했습니다.

여기는

게으른 개는 이미 노를 젓고 나머지는 던질 수 있음을 알았습니다.

다만 사이트를 zip으로 압축하는건 정말 느립니다. 하나씩 다운받는게 알바같은 느낌입니다 . 무료로 성매매를 할 수 있지만 (죄송합니다. 정말 보상을 안받았습니다.) 그래도 사용하고 싶습니다. 좀 더 편리하게 하려고 github에서 남들이 남긴 코드 찾아보러 C#, PHP, python, java 등등 여러가지가 있는데 생각해보니 가상환경을 참 많이 설치했는데 안쓰는 것 같다. 그래픽 인터페이스(그래픽 인터페이스를 거의 사용하지 않음 ) , 그래서 일괄 처리에 파이썬 스크립트를 사용하고 마지막으로 bat 파일을 사용하여 자동 처리를 실현할 계획입니다. 아름답지 않습니까?

최근에 흥경철도를 하다가 현기증이 나서 공부를 안한게 아니라 음양사 느낌의 게임을 만나기 힘들었고, 처음에 모바일 게임만 하던 시절로 돌아간 것 같습니다. 중학교의 날. 모레 인턴십을 위해 지옥 훈련 공장에 갈 것입니다. 얼마나 행복 할 수 있을지 모르겠습니다.

나는 주로 두 사람의 코드를 참조합니다. 하나는 Java 사람이고 그래픽 세트는 설명과 함께 제공되며 다른 하나는 Python 사람의 기본 코드입니다. 필요에 따라 약간 수정했습니다.

자바 가이 파이썬 가이

처음에는 별거 못느꼈는데 ffmpeg 설치하고 바로 가보니 저한테 인코딩 오류가 직접 튕겨져 나와서 깨달았습니다. VIP 플레이??나중에 ncm이 여러 주류 암호의 암호화를 포함하여 분할 암호화라는 것을 알고 키는 사람이 해독해야 합니다.키와 알고리즘을 알고 나면 즐겁게 복호화할 수 있습니다!

예전에 암호학 공부해서 같은거 봤는데 모르는 친구들은 너무 걱정하지 않아도 되니까 논문을 안써서 암호를 설계하면 너무 알 필요가 없으니까 디테일, 원리만 알고 사용하세요.

여기에 첨부된 것은 Java 사용자의 분석입니다. 매우 잘 작성되었으며 변경하지 않겠습니다. 내가 게을러서. (빨아)

정보 크기 주목
매직 헤더 10바이트 뛰어 넘다
키 길이 4 바이트 AES128로 암호화된 RC4 키의 길이(리틀 엔디안 바이트 순서, 부호 없는 정수)
AES128 디코드의 키 키 길이(실제 128바이트) AES128로 암호화된 RC4 키(참고: 1. 바이트별 XOR 0x64 2. AES 암호 해독(PKCS5Padding 채우기 모드는 끝에 패딩을 제거합니다.) 3. 처음 17바이트를 제거합니다 neteasecloudmusic.
마타 길이 4 바이트 Mata 정보의 길이(little endian 바이트 순서, 부호 없는 정수)
헤드 데이터(JSON) 마타 길이 JSON 형식의 Mata 정보(참고: 1. 바이트별 XOR 0x63, 2. 처음 163 key(Don't modify):22바이트 제거, 3. Base64 디코딩, 4. AES 복호화, 5. music:처음 6바이트 JSON 제거 후 가져오기)
CRC 확인 코드 4 바이트 뛰어 넘다
5바이트 뛰어 넘다
이미지 크기 4 바이트 이미지 크기
영상 이미지 크기 이미지 데이터
음악 데이터 - RC4-KSA는 s-box 생성, RC4-PRGA 복호화

소프트웨어에 특별한 복호화 시스템을 설계한 다음 이를 일치시켜 복호화하고 플레이해야 하는데 왜 키가 고정되어 다른 사람이 크랙할 수 있는지 알고 싶습니다. ? ? 이렇게 하면 너무 많은 키를 저장할 필요가 없고 대부분의 사람들이 크랙하는 방법을 모르기 때문에 얼마나 게으른지... 하나는 너무 게을러서 알 수 없기 때문이고 다른 하나는 그들이 그것이라고 생각하기 때문입니다. 불필요하지만 어, 서비스를 구매했는데 여전히 깨끗하지 않습니다. 최소한 소스 데이터를 제공해주세요. 키를 직접 저장할 수 있습니까?

제목 속으로

이 암호 라이브러리를 설치하지 않은 사용자는 자신의 환경/가상 환경 에 설치해야 합니다 .

pip install pycryptodome

시나리오 1: 스크립트를 수동으로 실행

고정 폴더는 다음과 같습니다. 기본 파일 아래에 두 개의 폴더가 있습니다. 하나는 ncm 접미사 파일용이고 다른 하나는 mp3 접미사 파일용입니다.

코드를 실행하면 ncm 폴더에 있는 모든 노래가 mp3 형식으로 변환되어 mp3 폴더에 저장됩니다.

이름을 convert_ncm_to_mp3.py로 지정하고 convert_ncm_to_mp3 폴더 아래에 배치합니다.

문제가 있는 경우 여기에서 문제를 해결하십시오.

# 注意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)

해결 방법 2: 박쥐로 변신하여 자동으로 실행

나는 pycharm을 수동으로 열고 싶지 않습니다. 정말 게으르다! 이런 식으로 스크립트를 작성하는데 가상환경을 설치했기 때문에 가상환경 class38을 먼저 시작 하고 스크립트에 추가한 다음 새로운 스크립트 파일을 다시 작성하여 파이썬 파일을 고정된 형식으로 호출해야 합니다.

이름을 convert_ncm_to_mp3_script.py로 지정하고 convert_ncm_to_mp3 폴더에 넣습니다.

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)

새 convert_run.txt를 만들고 그 안에 다음을 작성합니다.

@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

접미사를 .bat로 수정한 다음 저장하고 실행합니다.

위에는 한 곡만 표시되지만 다음과 같이 여러 곡을 시도할 수 있습니다.

이쯤되면 거의 끝나가는데 QQ뮤직은 아직 사용을 안해서 멤버로 충전을 안해봤네요.. 나중에 얘기하겠습니다.

사용을 원하실때는 ncm폴더에 변환이 필요한 ncm파일을 넣고 배치파일을 실행하신 후 변환된 mp3파일을 모두 잘라서 U디스크로 옮기신 후 ncm, mp3 폴더를 지우시면 됩니다. 가장 중요한 것은 자립입니다.

글쎄요, 쓸 것이 많지 않습니다. 라이온 장군이 제가 번호를 얻기를 기다리고 있습니다! 큭! 0-0!

돈이 생기면 웃을 수 있는 고양이를 사야지!

추천

출처blog.csdn.net/daxuanzi515/article/details/130770969