Various MST implementations. Paper: https://inria.hal.science/hal-02303490/document
atproto docs: https://atproto.com/specs/repository
https://github.com/bluesky-social/atproto/tree/main/packages/repo/src/mst typescript "reference implementation"
Various MST implementations. Paper: https://inria.hal.science/hal-02303490/document
atproto docs: https://atproto.com/specs/repository
https://github.com/bluesky-social/atproto/tree/main/packages/repo/src/mst typescript "reference implementation"
I looked at a JAR file protected using JNIC, version jnic.dev v3.6.0
. I haven't written a full-auto deobfuscater yet, but these notes should be useful for anyone reversing it.
The first layer is a LZMA2 compressed .dat
file, from which a native library is extracted into a temp dir, and then loaded using System.load
.
The sample I looked at had 4 different library versions (for different platforms/architectures), and the script I wrote to extract them looks like this:
import lzma
# from JNICLoader.java
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes | |
KEY = bytes.fromhex("5c0e349a27dc46034c7b6744a378bd17") | |
IV = bytes.fromhex("a0b0924686447109f2d51dcddc93458a") | |
img = open("gz_a.bin", "rb") | |
img.seek(4) | |
length = int.from_bytes(img.read(4), "little") | |
img.seek(0x34) | |
offset = int.from_bytes(img.read(4), "little") |
The APK is stored in the firmware system
partition, and gets updated as a side-effect of OTA firmware updates. Thus, a certain OS version implies a particular APK version. The OS version numbers are more compact, so I'll use them to identify APK versions below.
v0.8.50
seems like a pre-prod version that accidentally got shipped on some early devices. Like all future versions, it sends the device's IMEI during account activation.
v0.8.67
is the "launch day" firmware. It sets the OS-Version
and App-Version
HTTP headers. It also sends the device's IMEI during authentication.
Newer versions of the Rabbit R1's APK are protected by https://www.zimperium.com/zshield/ (I don't know this for certain, somebody told me it is but I haven't really seen any identifying marks in the code yet)
Interesting assets within the APK:
lib/arm64-v8a/liboptipkawfn.so ~3MB packed/encrypted ELF
assets/optipkawfn/0.odex only 41 bytes (EDIT: I think this is part of an asset obfuscation scheme, the real file contents are likely elsewhere - inside the .szip maybe?)
assets/optipkawfn.szip ~8MB - I predict containing encrypted+compressed bytecode
import os | |
from cryptography.hazmat.primitives.ciphers.aead import AESGCM | |
from cryptography.hazmat.primitives.ciphers import algorithms | |
from cryptography.hazmat.primitives.kdf.kbkdf import ( | |
CounterLocation, KBKDFCMAC, Mode | |
) | |
# https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md | |
class XAES256GCM: | |
# sizes in bytes |
import base64 | |
import time | |
from cryptography.hazmat.primitives import serialization | |
from cryptography.hazmat.primitives import hashes | |
from cryptography.hazmat.primitives.asymmetric import padding | |
import ctypes | |
libc = ctypes.CDLL("libc.so.6") # glibc needed | |
OS_VERSION = "rabbit_OS_v0.8.99_20240606175556" |
The Rabbit R1 uses a few custom APIs to talk to The Cloud™. Almost nothing happens on-device, and all the AI magic happens on servers.
Consequently, you don't really need the physical device.
In lieu of an authentication scheme, Rabbit's servers attempt to verify device authenticity by checking the TLS client's JA3 fingerprint, presumably enforced by AWS WAF.
If your TLS client doesn't match an expected fingerprint, you'll get HTTP 403 errors. This fingerprint works:
The R1 checks for updates by querying https://ota.transactional.pub/qa/{Build.DISPLAY}.json
, where {Build.DISPLAY}
is the current build.
The JSON file returns metadata for a delta update package.
Known values of Build.DISPLAY
: