Edit 2: Well I’ll be damned. An extremely knowledgeable and kind stranger just reverse-engineered the whole thing and poured it into a python script. And it’s only Monday. See comments for the script.


Edit: Oh wow, this community is already on fire. Thanks for your advice everybody, I didn’t even think of intercepting the downloads in transit! Brilliant.

I will try to see how far I can get there, but that does sound much easier than rummaging around in iOS. Thank you all :)


Hello,

I’m trying to get the downloaded audio out of an iOS app, but I struggle because the information I can find is mostly rather old, needs some additional software I need to pay for, etc. The content is downloaded post installing the app, so simply accessing the IPA doesn’t help.

I have this app called naturespace (see naturespace.org), it’s an app that has really good recordings of rain, thunderstorms, etc. In my opinion those recordings are far better than anything I’ve heard so far.

Now, I did pay for the content, but the app hasn’t been updated for years now, and there’s also been no new content for years as well. I wrote to the owners but didn’t get any response. I guess you could consider it abandoned at this point.

Since I fear that anytime soon the app stops working, I’d like to save that content.

I’m a bit tech savvy, I can work with CLI and such, but I’m not a professional coder or hacker, any help is appreciated.

You are viewing a single thread.
View all comments View context
2 points

Ah, thank you! See, it didn’t even occur to me to just intercept the audio in transit. That’s really helpful, I will try this, thank you very much :)

permalink
report
parent
reply
4 points

So I’ve reverse-engineered the naturespace Android APK and the files it downloads are definitely encrypted. They’re zip files (named as .nzp) that are XOR obfuscated with a rotating key every X amount of bytes. I haven’t quite worked out how the key rotates itself but I’m close. If I get it working I’ll put the details here and I can give you a Python script to grab whatever sounds you need.

permalink
report
parent
reply
3 points
*

Ha, I was just writing an update when your comment came.

I followed your advice and installed mitmproxy (basically fiddler2 but open source), which was easy enough, and managed to find that the app just posts GET requests the homepage, which result in a 302 Temporarily Moved, which ends on a public S3 folder.

The GET request includes some “ID”, which I’m not sure I should post publicly, maybe it might identify me? It’s like:

GET http://www.naturespace.com/ns5ios/?command=download&path=%2Fmedia%2Fmodules%2Fcom.HolographicAudioTheater.Naturespace.Aegir&lang=en&id=REDACTED&bvrs=5.15&sysv=16.5&model=iPhone&bid=com.HolographicAudioTheater.Naturespace&sys=iOS&loc=en_DE HTTP/1.1

But yes, it seems the files are encrypted. I couldn’t find anything to open them, and no file identifier knows what it is. If you manage to get somewhere, that’d be awesome, my tech knowledge definitely ends here lol.

I guess it’s not actually illegal to post this, since it really is just a public folder, so if anyone els wants to look at it, here’s a file.

permalink
report
parent
reply
6 points
*

Interesting, looks like they might be using a completely different file format for iOS versus Android. In any case, I’ve knocked up a script which will extract the track.ogg file from any pack of your choosing. Pasting directly here to see if it works (haven’t tried sharing code on Lemmy).

You can browse available packs using the below URL. If you want to find out a pack name, just copy the banner image URL for it and you’ll see the “com.whatever” name in the URL itself.

http://www.naturespace.com/android/v3/store/?live=true&udid=0

Code:

import sys
import requests
import hashlib
import io
import zipfile

ns_baseurl = "https://s3.amazonaws.com/naturespace/kindle_catalog/"

# Encryption key
key = b'DE2#We@(# sffsFSHfssfhsSFHSs_+&Gaa s,W.Z./lSFGSDF! NOWG!fjasdflasdkfjSADFKJASdflskgj fdkaG8HS42dncuFFSe=-56a'

def decryptNS(content):
	x = 1025
	y = 0
	dec = bytearray()
	for i in range(x,len(content)):
		if ((i+1024) % 1024) != 0:
			dec += bytes([content[i] ^ key[y % len(key)]])
			y = y+1

	return dec

if __name__ == '__main__':
	if len(sys.argv) < 2:
		print("Please provide a pack/module name (e.g. 'com.HolographicAudioTheater.Naturespace.TheImaginarium')")
		sys.exit(0)

	pack = sys.argv[1]
	json_url = ns_baseurl + pack + "/data.json"
	size = requests.get(json_url).json()["packageSize"]
	print(size)

	hashval = hashlib.sha1((pack + "8DvJx25sXwNwq2p" + size).encode()).hexdigest()
	dlurl = ns_baseurl + pack + "/" + hashval + "/" + pack + ".nzp"
	print(dlurl)

	content = decryptNS(requests.get(dlurl).content)
	"""
	with open(pack + ".zip", "wb") as f:
		f.write(content)
	"""
	zipf = io.BytesIO(content)
	zipfile = zipfile.ZipFile(zipf, 'r')
	track_nsp = zipfile.read('track.nsp')

	track_ogg = decryptNS(track_nsp)
	with open(pack + "_track.ogg", "wb") as f:
		f.write(track_ogg)
permalink
report
parent
reply

Piracy: ꜱᴀɪʟ ᴛʜᴇ ʜɪɢʜ ꜱᴇᴀꜱ

!piracy@lemmy.dbzer0.com

Create post
⚓ Dedicated to the discussion of digital piracy, including ethical problems and legal advancements.

Rules • Full Version

1. Posts must be related to the discussion of digital piracy

2. Don’t request invites, trade, sell, or self-promote

3. Don’t request or link to specific pirated titles, including DMs

4. Don’t submit low-quality posts, be entitled, or harass others


Loot, Pillage, & Plunder


💰 Please help cover server costs.


Community stats

  • 5.7K

    Monthly active users

  • 3.2K

    Posts

  • 84K

    Comments