Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to the app.asar file in Rekordbox v6.6.5 breaks database unlocking #64

Closed
dylanljones opened this issue Oct 28, 2022 · 19 comments
Closed
Labels
enhancement New feature or request help wanted Extra attention is needed RBv6 database Related to the Rekordbox v6 database

Comments

@dylanljones
Copy link
Owner

dylanljones commented Oct 28, 2022

Pioneer changed the app.asar file contents in Rekordbox version 6.6.5.
The encryption password of the database key is no longer stored in plain text, which breaks the database unlocking.

Previously, the app.asar file contained JS files in plain text.
Since update 6.6.5 the JS files are now stored in a compiled format (.jsc).
The password should still be somewhere in the content of the file (jsc/controllers/auth_manager.jsc), but it can no longer be extracted easily.

Please feel free to join the discussion if you have any ideas!

Environment

  • Rekordbox version: >=6.6.5
@dylanljones dylanljones added bug Something isn't working help wanted Extra attention is needed labels Oct 28, 2022
@morenoh149
Copy link

can a copy of the .jsc be shared in this thread?

@dylanljones
Copy link
Owner Author

dylanljones commented Oct 29, 2022

I am not sure if it is a good idea to share parts of the source code of Pioneer here, but i can send you an Email if you want to have a look at the auth_manager.jsc file.
If you have Rekordbox 6.6.5 installed, it is also really easy to extract the file from the asar archive yourself. I made a little tool to print out or extract single files form an archive, if you are interested, it is here. The app.asar file is located in RBv6 program data directory in .../rekordbox 6.6.5/rekordboxAgent-win32-x64/resources

@cheung31
Copy link

cheung31 commented Dec 8, 2022

@dylanljones would asarlib allow one to inspect the auth_manager.jsc for the password?

@dylanljones
Copy link
Owner Author

The asarlib package only extracts the contents of the archive, so it is not possible to read the password. The auth_manager.jsc is not stored in plain text, but the password should still be stored in the file somewhere, although scrambled.

@niderhoff
Copy link

niderhoff commented Dec 8, 2022

Hey guys, just want to chime in and ask if I understand the problem correctly.

I am using pyrekordbox master installed from git, Rekordbox v 6.6.5 and I was trying to run the rekordbox 6 example code from the readme (https://github.com/dylanljones/pyrekordbox#rekordbox-6-database). I am directly using the example code, which I copied directly from the readme:

from pyrekordbox import Rekordbox6Database

db = Rekordbox6Database()

for content in db.content():
	print(content.Title, content.Artist.Name)

However, it would always give me the following error, which was a bit confusing to me at first glance: "WARNING:root:No Rekordbox 5 folder found in /Applications". Then it would crash.

Then I turned on the debugger and found that the problem must be inside the _get_rb6_config function which is invoked from config.py during import. It in turn invokes the _get_rb_config function, which I assume is for rekordbox 5, hence the confusing warning.

Apart from that, the function _get_rb6_config correctly identifies my master.db location.

The following procedures of said function include

# Read password from app.asar, see
# https://www.reddit.com/r/Rekordbox/comments/qou6nm/key_to_open_masterdb_file/

asar_data = read_rekordbox6_asar(conf["install_dir"])
match = re.search('pass: ".(.*?)"', asar_data).group(0)

It looks like something is read from the asar file but the regex does not match 'pass:' anywhere in the asar file. This results in a KeyError, because group(0) tries to index in an empty list and the error is not handled.

Question 1: Am I right in assuming that this line (i.e. the regex matching part) needs to be swapped out for some clever parsing of the asar_data which can read the obfuscated password?

You mention that

The asarlib package only extracts the contents of the archive, so it is not possible to read the password. The auth_manager.jsc is not stored in plain text, but the password should still be stored in the file somewhere, although scrambled.

After some googling I found that .jsc is most likely the nodejs equivalent of something like bytecode. So it would need to be de-compiled to be read properly, and according to my research that is quite a dead end, since there have been no public attempts to de-compile .jsc files generated with node > 8.4 in the past 2 years or so.

Question 2: You think this might be true or is it some other kind of obfuscation in place here? In general I am not very experienced in reverse engineering... any ideas how we could go about it?

I tried to extract the contents of the asar using asarlib but it failed because of some KeyError on (self.header["files"]) at some point in the extraction loop, so I could not verify or further analyze the structure or contents of the asar file.

@11ib
Copy link

11ib commented Jan 9, 2023

Does anyone have the path to the auth_manager.jsc file? I couldn't find it on a fresh install of Rekordbox (6.6.8) on Windows.

@dylanljones
Copy link
Owner Author

Hey everybody, sorry for the late response!

@niderhoff, regarding question 1, you are totally right. Before we could just do a regex search, but ever since update 6.6.5 all the relevant files in the app.asar archive are scrambled. I also looked for a clever way to hack the .jsc file, but with no result.
So I think it really is a "compiled" version of a JavaScript file, but I have no clue how one could de-compile it. This should also answer your second question... But I still have some hope left that it can be reverse engineered somehow, however I am also not too experienced in that field.
The warning due to the missing Rekordbox v5 installation was a bad design decision on my part. Didn't notice it since I still have v5 installed, but I will fix that. Thanks for letting me know:) Also sorry to hear that asarlib failed, to be honest I only tested it with the app.asar from my Rekordbox installation.

@11ib, the auth_manager.jsc is stored in the app.asar file, which is a kind of archive that contains files and directories. There are tools out there to extract the contents (like the one I wrote, which is pretty buggy). The path for the archive on Windows is something like

C:\Program Files\Pioneer\rekordbox 6.5.3\rekordboxAgent-win32-x64\resources\app.asar

Hope that answers a few question, I wish I knew more. And thank you for your interest!

@niderhoff
Copy link

Apparently .jsc is compiled v8 bytecode. We can disassemble v8 bytecode, but it will not bring back javascript, but instead human readable v8 instructions: https://github.com/noelex/v8dasm. Maybe then we can look through it look for something that might look like the password.

Another route would be if you knew the format of the password (assuming it has not changed since rekordbox 6.4, you could search in the hex dump for a string which has roughly the same length and type of characters.)

@DanielMS93
Copy link

Any progress on this guys? i'm hitting the same issue i believe

image

@dylanljones
Copy link
Owner Author

Hey, sorry for the inactivity, have a lot of other stuff going on right now.
Sadly no progress so far, but I am looking into a few things! The key is still the same as in earlier Rekordbox versions, but i would really like to avoid just hard-coding it for legal reasons (as discussed at the end of this blog of rekordcloud).

@niderhoff
Copy link

Hey Dylan I might have a idea, can I contact you somehow?

@dylanljones
Copy link
Owner Author

Sorry, just realized my Email wasn't showing up. It should be on my profile now. You can contact me there!

@DanielMS93
Copy link

DanielMS93 commented Jul 27, 2023 via email

@puhitaku
Copy link

puhitaku commented Aug 4, 2023

The disassembly of a simple hello world shows that the string "Hello World!" is stored in a "Constant pool" as-is, like other usual executables.

$ cat app.js
function foo() {
    console.log("Hello World!")
}

foo()

$ node --print-bytecode --print-bytecode-filter=foo app.js
[generated bytecode for function: foo (0x1f66e1498a39 <SharedFunctionInfo foo>)]
Bytecode length: 19
Parameter count 1
Register count 3
Frame size 24
OSR urgency: 0
Bytecode age: 0
   21 S> 0x1f66e1499ac0 @    0 : 21 00 00          LdaGlobal [0], [0]
         0x1f66e1499ac3 @    3 : c3                Star1
   29 E> 0x1f66e1499ac4 @    4 : 2d f9 01 02       GetNamedProperty r1, [1], [2]
         0x1f66e1499ac8 @    8 : c4                Star0
         0x1f66e1499ac9 @    9 : 13 02             LdaConstant [2]
         0x1f66e1499acb @   11 : c2                Star2
   29 E> 0x1f66e1499acc @   12 : 5e fa f9 f8 04    CallProperty1 r0, r1, r2, [4]
         0x1f66e1499ad1 @   17 : 0e                LdaUndefined
   49 S> 0x1f66e1499ad2 @   18 : a9                Return
Constant pool (size = 3)
0x1f66e1499a61: [FixedArray] in OldSpace
 - map: 0x12fa427812e1 <Map>
 - length: 3
           0: 0x12fa42784a01 <String[7]: #console>
           1: 0x32d47820c731 <String[3]: #log>
           2: 0x1f66e14999f9 <String[12]: #Hello World!>
Handler Table (size = 0)
Source Position Table (size = 10)
0x1f66e1499ad9 <ByteArray[10]>
Hello World!

I compiled the app.js into jsc and the constant is still intact in the binary.

$ npm install -g bytenode
$ bytenode -n -c app.js
$ grep "Hello World!" app.jsc
Binary file app.jsc matches

As @dylanljones pointed out, the key is the same as in the previous version, and the key may be stored in the jsc intact if it is not obfuscated in a way we don't expect.

Expecting that the key is a string literal, this gives us a way to "match" the key string that fulfills the known format with surrounding fingerprints of constants. Embedding the match condition (not the key itself) in this repository will not cause any legal concerns.

How about this idea?

@puhitaku
Copy link

puhitaku commented Aug 4, 2023

I wish I could get Rekordbox older than 6.6.5 ...

@dylanljones
Copy link
Owner Author

dylanljones commented Aug 5, 2023

Hi @puhitaku,

thanks for joining in on the discussion! Sadly, the key is not a string literal and is obfuscated in some way. I already tried to match the known key - without any success...
Do you know if there is an option for that when generating the .jsc? If so, there might be a way to reverse the obfuscation.

@DanielMS93, thank you for the hint! As far as i understand, blackbox just encrypts the 'shipped' keys, right? I did not spend a lot of time looking into it yet, but it seems we still would have to ship the (encrypted) key, right? But i will look a bit more into blackbox:)

@dylanljones
Copy link
Owner Author

dylanljones commented Aug 5, 2023

Maybe we should use some workaround until we have figured out how to de-obfuscate the .jsc files (as some other projects do, see issue #77)

@niderhoff
Copy link

niderhoff commented Aug 6, 2023

One could pass the key to the db handler. This is how it would look:

from pyrekordbox import Rekordbox6Database

db = Rekordbox6Database(key="<insert key here>")

for content in db.get_content():
    print(content.Title, content.Artist.Name)

playlist = db.get_playlist()[0]
for song in playlist.Songs:
    content = song.Content
    print(content.Title, content.Artist.Name)

if you had an old installation, rb.cache file, or the key noted down, you can just use it like thit.

If not one could go to #77 where someone linked to another repository where the developer(s) have embedded the key into the code.

dylanljones added a commit that referenced this issue Aug 15, 2023
If the extraction of the Rekordbox database key fails (>6.6.5), the user can now write the key manually to the cache file. After updating the cache the database can be opened without providing the key each time.
To make this work pyrekordbox now caches the decrypted key, not the password for decrypting the key. If an old cache file is found it is upgraded automatically.
dylanljones added a commit that referenced this issue Aug 15, 2023
…eb (#64)

Pyrekordbox tries to download the key from projects that have hard-coded the key (see issue #77). If the download was successful it writes it to the cache file.
@dylanljones
Copy link
Owner Author

dylanljones commented Aug 15, 2023

The key of the Rekordbox v6 database can now be downloaded and cached from external sources (mainly the projects in #77) using the command line interface:

python -m pyrekordbox download-key

This is still just a workaround, it still would be nice to find a way to extract the key from the .jsc-files, especially if Pioneer decides to change the key (maybe in Rekordbox v7?). In the mean time this fix should get the project running for everyone:)

If anyone finds some more sources for the key, feel free to add them to the CLI or post the links here in case the other projects remove the key!

@dylanljones dylanljones added enhancement New feature or request and removed bug Something isn't working labels Aug 25, 2023
@dylanljones dylanljones pinned this issue Sep 6, 2023
@dylanljones dylanljones added the RBv6 database Related to the Rekordbox v6 database label Sep 7, 2023
Repository owner locked and limited conversation to collaborators Oct 24, 2023
@dylanljones dylanljones converted this issue into discussion #97 Oct 24, 2023
@dylanljones dylanljones unpinned this issue Oct 24, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement New feature or request help wanted Extra attention is needed RBv6 database Related to the Rekordbox v6 database
Projects
None yet
Development

No branches or pull requests

7 participants