From 3d9678bf9a38c013b0fbaf4b17a1cee44cec337f Mon Sep 17 00:00:00 2001 From: TroyHacks <5659019+troyhacks@users.noreply.github.com> Date: Tue, 24 Oct 2023 00:04:49 -0400 Subject: [PATCH 1/6] Decoding obfuscated PSSI data --- pyrekordbox/anlz/file.py | 12 ++++++++++++ pyrekordbox/anlz/structs.py | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pyrekordbox/anlz/file.py b/pyrekordbox/anlz/file.py index 2df531e..6b82429 100644 --- a/pyrekordbox/anlz/file.py +++ b/pyrekordbox/anlz/file.py @@ -8,6 +8,7 @@ from typing import Union from .tags import TAGS from . import structs +from construct import Int16ub logger = logging.getLogger(__name__) @@ -102,6 +103,17 @@ def _parse(self, data: bytes): tag_data = data[i:] # Get the four byte struct type tag_type = tag_data[:4].decode("ascii") + + if tag_type == 'PSSI': + # deobfuscate tag_data[18:] using xor with verysecretcode+len_entries + verysecretcode = bytearray.fromhex("CB E1 EE FA E5 EE AD EE E9 D2 E9 EB E1 E9 F3 E8 E9 F4 E1") + len_entries = Int16ub.parse(tag_data[16:]) + tag_data = bytearray(data[i:i+len(tag_data)]) + for x in range(len(tag_data[18:])): + decryptmask = verysecretcode[x%len(verysecretcode)]+len_entries + if decryptmask > 255 : + decryptmask -= 256 + tag_data[x+18] = tag_data[x+18] ^ decryptmask try: # Parse the struct diff --git a/pyrekordbox/anlz/structs.py b/pyrekordbox/anlz/structs.py index df54441..a6d398f 100644 --- a/pyrekordbox/anlz/structs.py +++ b/pyrekordbox/anlz/structs.py @@ -201,18 +201,18 @@ "index" / Int16ub, "beat" / Int16ub, "kind" / Int16ub, - "u1" / Int8ub, + Padding(1), "k1" / Int8ub, - "u2" / Int8ub, + Padding(1), "k2" / Int8ub, - "u3" / Int8ub, + Padding(1), "b" / Int8ub, "beat_2" / Int16ub, "beat_3" / Int16ub, "beat_4" / Int16ub, - "u4" / Int8ub, + Padding(1), "k3" / Int8ub, - "u5" / Int8ub, + Padding(1), "fill" / Int8ub, "beat_fill" / Int16ub, ) @@ -221,12 +221,12 @@ PSSI = Struct( "len_entry_bytes" / Const(24, Int32ub), "len_entries" / Int16ub, - "mood" / Bytes(2), - "u1" / Bytes(6), - "end_beat" / Bytes(2), - "u2" / Bytes(2), - "bank" / Bytes(1), - "u3" / Bytes(1), + "mood" / Int16ub, + Padding(6), + "end_beat" / Int16ub, + Padding(2), + "bank" / Int8ub, + Padding(1), "entries" / Array(this.len_entries, SongStructureEntry), ) From e927fca794d9545c4c88d24dec5707c493011b11 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:38:39 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyrekordbox/anlz/file.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pyrekordbox/anlz/file.py b/pyrekordbox/anlz/file.py index 6b82429..c3a7f4d 100644 --- a/pyrekordbox/anlz/file.py +++ b/pyrekordbox/anlz/file.py @@ -103,17 +103,19 @@ def _parse(self, data: bytes): tag_data = data[i:] # Get the four byte struct type tag_type = tag_data[:4].decode("ascii") - - if tag_type == 'PSSI': + + if tag_type == "PSSI": # deobfuscate tag_data[18:] using xor with verysecretcode+len_entries - verysecretcode = bytearray.fromhex("CB E1 EE FA E5 EE AD EE E9 D2 E9 EB E1 E9 F3 E8 E9 F4 E1") + verysecretcode = bytearray.fromhex( + "CB E1 EE FA E5 EE AD EE E9 D2 E9 EB E1 E9 F3 E8 E9 F4 E1" + ) len_entries = Int16ub.parse(tag_data[16:]) - tag_data = bytearray(data[i:i+len(tag_data)]) + tag_data = bytearray(data[i : i + len(tag_data)]) for x in range(len(tag_data[18:])): - decryptmask = verysecretcode[x%len(verysecretcode)]+len_entries - if decryptmask > 255 : + decryptmask = verysecretcode[x % len(verysecretcode)] + len_entries + if decryptmask > 255: decryptmask -= 256 - tag_data[x+18] = tag_data[x+18] ^ decryptmask + tag_data[x + 18] = tag_data[x + 18] ^ decryptmask try: # Parse the struct From bc4f06310be34047f4a346bc66be16d909e9c12a Mon Sep 17 00:00:00 2001 From: TroyHacks <5659019+troyhacks@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:42:41 -0400 Subject: [PATCH 3/6] Minor code simplification --- pyrekordbox/anlz/file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrekordbox/anlz/file.py b/pyrekordbox/anlz/file.py index 6b82429..bdc713c 100644 --- a/pyrekordbox/anlz/file.py +++ b/pyrekordbox/anlz/file.py @@ -113,7 +113,7 @@ def _parse(self, data: bytes): decryptmask = verysecretcode[x%len(verysecretcode)]+len_entries if decryptmask > 255 : decryptmask -= 256 - tag_data[x+18] = tag_data[x+18] ^ decryptmask + tag_data[x+18] ^= decryptmask try: # Parse the struct From b33b0a5191d286a33607b09278e728f646952f17 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:44:37 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyrekordbox/anlz/file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrekordbox/anlz/file.py b/pyrekordbox/anlz/file.py index dfe4d2b..495d57e 100644 --- a/pyrekordbox/anlz/file.py +++ b/pyrekordbox/anlz/file.py @@ -115,7 +115,7 @@ def _parse(self, data: bytes): decryptmask = verysecretcode[x % len(verysecretcode)] + len_entries if decryptmask > 255: decryptmask -= 256 - tag_data[x+18] ^= decryptmask + tag_data[x + 18] ^= decryptmask try: # Parse the struct From b6bf26fd2a2ad9f00cf9d89161a79e399e004ea2 Mon Sep 17 00:00:00 2001 From: TroyHacks <5659019+troyhacks@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:02:45 -0400 Subject: [PATCH 5/6] Remove the TODO :) --- pyrekordbox/anlz/structs.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyrekordbox/anlz/structs.py b/pyrekordbox/anlz/structs.py index a6d398f..c68ad85 100644 --- a/pyrekordbox/anlz/structs.py +++ b/pyrekordbox/anlz/structs.py @@ -195,8 +195,6 @@ # -- Song Structure Tag (PSSI) --------------------------------------------------------- -# FixMe: Implement reverse XOR mask to descramble values - SongStructureEntry = Struct( "index" / Int16ub, "beat" / Int16ub, From d3dc262f31894dc8e1e07947511587a051f8d3f6 Mon Sep 17 00:00:00 2001 From: TroyHacks <5659019+troyhacks@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:29:31 -0400 Subject: [PATCH 6/6] Decided unknown fields are present in structs --- pyrekordbox/anlz/structs.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyrekordbox/anlz/structs.py b/pyrekordbox/anlz/structs.py index c68ad85..ba995b8 100644 --- a/pyrekordbox/anlz/structs.py +++ b/pyrekordbox/anlz/structs.py @@ -199,18 +199,18 @@ "index" / Int16ub, "beat" / Int16ub, "kind" / Int16ub, - Padding(1), + "u1" / Int8ub, "k1" / Int8ub, - Padding(1), + "u2" / Int8ub, "k2" / Int8ub, - Padding(1), + "u3" / Int8ub, "b" / Int8ub, "beat_2" / Int16ub, "beat_3" / Int16ub, "beat_4" / Int16ub, - Padding(1), + "u4" / Int8ub, "k3" / Int8ub, - Padding(1), + "u5" / Int8ub, "fill" / Int8ub, "beat_fill" / Int16ub, ) @@ -220,11 +220,11 @@ "len_entry_bytes" / Const(24, Int32ub), "len_entries" / Int16ub, "mood" / Int16ub, - Padding(6), + "u1" / Bytes(6), "end_beat" / Int16ub, - Padding(2), + "u2" / Bytes(2), "bank" / Int8ub, - Padding(1), + "u3" / Bytes(1), "entries" / Array(this.len_entries, SongStructureEntry), )