|
@ -5,11 +5,10 @@ Created on Sun Jul 15 01:05:58 2018 |
|
|
@author: Nzix |
|
|
@author: Nzix |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
import binascii |
|
|
import binascii, struct |
|
|
import struct |
|
|
import base64, json |
|
|
import base64 |
|
|
import os, traceback |
|
|
import json |
|
|
|
|
|
import os |
|
|
|
|
|
from Crypto.Cipher import AES |
|
|
from Crypto.Cipher import AES |
|
|
from Crypto.Util.strxor import strxor as XOR |
|
|
from Crypto.Util.strxor import strxor as XOR |
|
|
from mutagen import mp3, flac, id3 |
|
|
from mutagen import mp3, flac, id3 |
|
@ -17,6 +16,8 @@ from mutagen import mp3, flac, id3 |
|
|
def dump(input_path, output_path = None, skip = True): |
|
|
def dump(input_path, output_path = None, skip = True): |
|
|
|
|
|
|
|
|
output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta['format']) if not output_path else output_path |
|
|
output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta['format']) if not output_path else output_path |
|
|
|
|
|
output_path = (lambda path, meta: path) if not callable(output_path) else output_path |
|
|
|
|
|
|
|
|
core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') |
|
|
core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') |
|
|
meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') |
|
|
meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') |
|
|
unpad = lambda s : s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] |
|
|
unpad = lambda s : s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] |
|
@ -52,6 +53,7 @@ def dump(input_path, output_path = None, skip = True): |
|
|
meta_length = f.read(4) |
|
|
meta_length = f.read(4) |
|
|
meta_length = struct.unpack('<I', bytes(meta_length))[0] |
|
|
meta_length = struct.unpack('<I', bytes(meta_length))[0] |
|
|
|
|
|
|
|
|
|
|
|
if meta_length: |
|
|
meta_data = bytearray(f.read(meta_length)) |
|
|
meta_data = bytearray(f.read(meta_length)) |
|
|
meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) |
|
|
meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) |
|
|
meta_data = base64.b64decode(meta_data[22:]) |
|
|
meta_data = base64.b64decode(meta_data[22:]) |
|
@ -59,6 +61,8 @@ def dump(input_path, output_path = None, skip = True): |
|
|
cryptor = AES.new(meta_key, AES.MODE_ECB) |
|
|
cryptor = AES.new(meta_key, AES.MODE_ECB) |
|
|
meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] |
|
|
meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] |
|
|
meta_data = json.loads(meta_data) |
|
|
meta_data = json.loads(meta_data) |
|
|
|
|
|
else: |
|
|
|
|
|
meta_data = {'format': 'flac' if os.fstat(f.fileno()).st_size > 1024 ** 2 * 16 else 'mp3'} |
|
|
|
|
|
|
|
|
# crc32 |
|
|
# crc32 |
|
|
crc32 = f.read(4) |
|
|
crc32 = f.read(4) |
|
@ -68,7 +72,7 @@ def dump(input_path, output_path = None, skip = True): |
|
|
f.seek(5, 1) |
|
|
f.seek(5, 1) |
|
|
image_size = f.read(4) |
|
|
image_size = f.read(4) |
|
|
image_size = struct.unpack('<I', bytes(image_size))[0] |
|
|
image_size = struct.unpack('<I', bytes(image_size))[0] |
|
|
image_data = f.read(image_size) |
|
|
image_data = f.read(image_size) if image_size else None |
|
|
|
|
|
|
|
|
# media data |
|
|
# media data |
|
|
output_path = output_path(input_path, meta_data) |
|
|
output_path = output_path(input_path, meta_data) |
|
@ -78,15 +82,6 @@ def dump(input_path, output_path = None, skip = True): |
|
|
f.close() |
|
|
f.close() |
|
|
|
|
|
|
|
|
# stream cipher (modified RC4 Pseudo-random generation algorithm) |
|
|
# stream cipher (modified RC4 Pseudo-random generation algorithm) |
|
|
# data = bytearray(data) |
|
|
|
|
|
# i = 0 |
|
|
|
|
|
# j = 0 |
|
|
|
|
|
# for k, _ in enumerate(data): |
|
|
|
|
|
# i = (i + 1) % 256 |
|
|
|
|
|
# j = (i + S[i]) % 256 # in RC4, is j = (j + S[i]) % 256 |
|
|
|
|
|
# # S[i], S[j] = S[j], S[i] # no swapping |
|
|
|
|
|
# data[k] ^= S[(S[i] + S[j]) % 256] |
|
|
|
|
|
|
|
|
|
|
|
stream = [S[(S[i] + S[(i + S[i]) & 0xFF]) & 0xFF] for i in range(256)] |
|
|
stream = [S[(S[i] + S[(i + S[i]) & 0xFF]) & 0xFF] for i in range(256)] |
|
|
stream = bytes(bytearray(stream * (len(data) // 256 + 1))[1:1 + len(data)]) |
|
|
stream = bytes(bytearray(stream * (len(data) // 256 + 1))[1:1 + len(data)]) |
|
|
data = XOR(data, stream) |
|
|
data = XOR(data, stream) |
|
@ -96,28 +91,28 @@ def dump(input_path, output_path = None, skip = True): |
|
|
m.close() |
|
|
m.close() |
|
|
|
|
|
|
|
|
# media tag |
|
|
# media tag |
|
|
|
|
|
def embed(item, content): |
|
|
|
|
|
item.encoding = 0 |
|
|
|
|
|
item.type = 3 |
|
|
|
|
|
item.mime = 'image/png' if content[0:4] == binascii.a2b_hex('89504E47') else 'image/jpeg' |
|
|
|
|
|
item.data = content |
|
|
|
|
|
|
|
|
|
|
|
if image_data: |
|
|
if meta_data['format'] == 'flac': |
|
|
if meta_data['format'] == 'flac': |
|
|
audio = flac.FLAC(output_path) |
|
|
audio = flac.FLAC(output_path) |
|
|
# audio.delete() |
|
|
|
|
|
image = flac.Picture() |
|
|
image = flac.Picture() |
|
|
image.encoding = 0 |
|
|
embed(image, image_data) |
|
|
image.type = 3 |
|
|
|
|
|
image.mime = 'image/jpeg' |
|
|
|
|
|
image.data = image_data |
|
|
|
|
|
audio.clear_pictures() |
|
|
audio.clear_pictures() |
|
|
audio.add_picture(image) |
|
|
audio.add_picture(image) |
|
|
elif meta_data['format'] == 'mp3': |
|
|
elif meta_data['format'] == 'mp3': |
|
|
audio = mp3.MP3(output_path) |
|
|
audio = mp3.MP3(output_path) |
|
|
# audio.delete() |
|
|
|
|
|
image = id3.APIC() |
|
|
image = id3.APIC() |
|
|
image.encoding = 0 |
|
|
embed(image, image_data) |
|
|
image.type = 3 |
|
|
|
|
|
image.mime = 'image/jpeg' |
|
|
|
|
|
image.data = image_data |
|
|
|
|
|
audio.tags.add(image) |
|
|
audio.tags.add(image) |
|
|
audio.save() |
|
|
audio.save() |
|
|
audio = mp3.EasyMP3(output_path) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if meta_length: |
|
|
|
|
|
audio = flac.FLAC(output_path) if meta_data['format'] == 'flac' else mp3.EasyMP3(output_path) |
|
|
audio['title'] = meta_data['musicName'] |
|
|
audio['title'] = meta_data['musicName'] |
|
|
audio['album'] = meta_data['album'] |
|
|
audio['album'] = meta_data['album'] |
|
|
audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) |
|
|
audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) |
|
@ -143,5 +138,5 @@ if __name__ == '__main__': |
|
|
dump(path) |
|
|
dump(path) |
|
|
print(os.path.split(path)[-1]) |
|
|
print(os.path.split(path)[-1]) |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
print(e) |
|
|
print(traceback.format_exc()) |
|
|
pass |
|
|
pass |