payload.cat

Accessing Unencrypted Content On Nintendo Music

Disclaimer

I do not condone piracy in any shape or form, specific API endpoints and how to access this content will not be shown and or discussed within this post. (tldr: nintendo ninjas please don't hurt me).

Anyways, now that I'm (hopefully) legally covered, let's continue.

Introduction

On 10/31/24, "Nintendo Music" was unveiled in an announcement by Nintendo. This app served to allow fans of Video Game Music, specifically from Nintendo, to listen to those tracks in a nice little convenient smart phone app that anyone could access as long as they coughed up the fee of Nintendo Switch Online, a subscription model which enables online play on Nintendo Switch games.

A mobile app was released for the platform exclusively on Android & iOS, with no hints or apparent plans to support web or even desktop (why?)

After watching a youtube video about the sound quality of the platform, where the video referenced a Nintendo Music support article that detailed what audio qualities are available. As detailed in the linked support article, the highest available quality would be 320kbps. The video I referenced & had peaked my interest in this said that the audio files were in AAC, which is popularly used in many videos as their audio channel. This is popularly used in many music streaming platforms, such as Spotify which serves lower quality music in AAC, and Apple Music that uses AAC alongside their lossless options in their ALAC format.

Investigation

After gaining this preliminary information, it's time to dig into the app itself.

Static analysis (an attempt)

After obtaining the APK and opening it in the popular and open-source Android decompiler jadx, we're greeted with...
JADX showing the Nintendo Music apk with randomly named class, meaning it is obfuscated.
Yea... I should of expected it, but as with any modern commercial android app, it is obfuscated with everything renamed so the purpose of the classes is much harder to decipher. At this point, I ignored the APK itself, as it wasn't going to give me any major clues.

Dynamic analysis

So, we aren't going to get anywhere trying to decompile the app. Let's make some assumptions, it's safe to assume this app makes some sort of API request to obtain this music (which music streaming app doesn't?). Let's try to analyze the requests this app makes.

After sacrificing my precious $4 to Nintendo to purchase a subscription to Nintendo Switch Online, we're able to use the app.
The setup I used here is as follows:

After having HTTP Toolkit running and playing a few tracks, I noticed a few requests to: https://api.m.nintendo.com/license/widevine/licenses and immediately recognize the media DRM component created by Google: Widevine.
Obviously, DRM systems such as Widevine are designed to prevent people like me from getting the audio tracks themselves. At this point, I looked back at the API requests being made and asked myself "How are they getting the track, albeit, encrypted?". Looking at the response of a specific request, I see:

"payloadList": [
  {
    "containsLoopableMedia": true,
    "durationMillis": 72629,
    "encryption": "CBCS",
    "keyIDs": [
      "<redacted-widevine-kID>"
    ],
    "loopableMedia": {
        "presentationURL": "<redacted url>/master.mpd",

We found it! A .mpd file details URLs to where all the files to the content are, specifically for content encoded in MPEG-DASH. We still have the major problem of that this content is encrypted, so our journey investigating this app ends here.

Or does it...? (queue dramatic music)
Looking back at the URL that showed the JSON payload above, I noticed an odd URL parameter: packageType=dash_cbcs. "dash" here refers to how the media is encoded, as referred to above, and "cbcs" (also present in the JSON payload) refers to the AES-CBC encryption scheme.

Inherently, this means we potentially have a choice of which type of encryption gets applied to our media.

The Fail: Unused package types

Let's revisit our initially failed static analysis approach.
Assuming this app, made in Java, has to send an API request with this package type, what if we tried to search it in the binary?
After inputting dash_cbcs into JADX, an enum called PackageType appears:

public enum PackageType {
    /* JADX INFO: Fake field, exist only in values array */
    hls_cbcs(0),
    /* JADX INFO: Fake field, exist only in values array */
    hls_clear(1),
    dash_cbcs(2),
    /* JADX INFO: Fake field, exist only in values array */
    dash_cenc(3),
    /* JADX INFO: Fake field, exist only in values array */
    dash_clear(4),
    unknown_default_open_api(5);
}

The comments provided by JADX indicates that the other fields in the enum are used nowhere else in this application, meaning they have no chance of being sent by this app.
Two fields of this enum stood out immediately to me, hls_clear and dash_clear. Why? This is because the "clear" it is referring to is referring to the ClearKey Content Protection format. Usually, content like this is still encrypted meaning we have no chance at getting the true, unencrypted content.
This usually requires having a key server setup (like Widevine, as you saw earlier) that can provide the key to the end user, but I did not see anything like that when looking for the key server dedicated towards ClearKey. This lead to me changing the packageType from dash_cbcs to dash_clear, and downloading the MPD file and parsing it to get the content as a whole.

After analyzing the files, something became very "clear" (pun intended):
It has no encryption.

Conclusion

Utilizing the unused package types, anyone technically has the ability to circumvent any DRM that may be enforced upon the app & the music files themselves.

In the end, the question I still have for myself is why would they leave these unused package types in here? The iOS app instead utilizes the hls_cbcs format, as DASH is not natively supported on iOS devices, which HLS (created by Apple) is natively supported. Both still utilize Widevine, so the purpose of having ClearKey (which we discussed here it isn't even clearkey, it's just not encrypted) makes no sense.

I do plan to utilize this flaw to hopefully bring some type of desktop app that allows you to stream from Nintendo Music given you have an account, but that's for some time in the future.

Anyways, thanks for reading. See you next time.