This was done with version 8.0.6
. The methods detailed here may have been patched out since (but probably haven't).
Download the APK and open it as a ZIP file. Then go to /assets/flutter_assets/assets/key/
- and lo and behold, there it is.
It's stored as android.jpg
, and as you can see it is in fact a JPG image. There's also ios.jpg
, which is identical, and annex_poc.jpg
, which is slightly different. I don't know what annex means here, but I assume poc is short for Proof of Concept.
you can use this mitmproxy script to confirm that it's real:
from mitmproxy import http
import base64
class key_stealer:
def response(self, flow):
if "X-Radiko-KeyLength" in flow.response.headers:
# flow.response.headers["X-Radiko-KeyLength"] = "16000"
flow.response.headers["X-Radiko-KeyLength"] = "125779"
flow.response.headers["X-Radiko-KeyOffset"] = "0"
def request(self, flow):
if "X-Radiko-Partialkey" in flow.request.headers:
header_value = flow.request.headers["X-Radiko-Partialkey"]
print(header_value)
with open('fullkey', 'wb') as f:
f.write(base64.b64decode(header_value))
addons = [
key_stealer()
]
What that does, is it changes the headers sent by auth1 so that it requests the whole key - 125779 bytes, starting from byte 0.
Then, the app replies to that, it takes that whole key the app is sending, and writes it to disk.
run it like this: mitmweb --ignore-hosts connectivitycheck.gstatic.com -s mitmproxy-key-stealer.py
.
The ignore connectivitycheck bit is important, otherwise android will think there's no internet connection.
I also got the device info from mitmproxy:
X-Radiko-App: aSmartPhone8 X-Radiko-Device: android User-Agent: Mozilla/5.0 (Linux; Android 10; Pixel 4 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Mobile Safari/537.36my phone's not a pixel and it runs android 9 lol, it seems the user agent is hardcoded
I wanted the v8 key for resilience/to ensure the continued functionality of my plugin.
The v7 aSmartPhone7a
key is fairly widely distributed- every tool that impersonates the app, AFAIK does it as v7. If radiko decides to crack down and revoke the v7 key, we're fucked.
So I decided to try and get the key from the current version, which no one is impersonating. That way, if they do revoke v7, I can just switch over to v8 and keep going as normal.
I was looking around in the APK to see if there was anything interesting in there, and oh look, that's an interesting looking directory
I thought maybe it was obfuscated at first, or the app derived the real key from the image somehow - surely, they can't have just left it there?
I assumed the key had to be 16KB in size, as that's what the v7 key was. I didn't have any way to actually tell, as my phone was too old to run the new app lol
Conveniently(?) my phone finally died/stopped working as a telephone around that time, so I had to get a new one anyway.
I installed the radiko app, and with a bit of help from the chat gpt, I wrote the mitmproxy script above.
At time of writing (13th april 2024), the v7 key hasn't been revoked, so yt-dlp-rajiko continues to use that. But if/when it is revoked, I'll be ready.