Coral client attestation/f
parameter
#10
Replies: 6 comments 6 replies
-
Since 23/08/2022 Nintendo is validating the parameters used to generate the
What changed on 23/08/2022 is that Nintendo appears to be somehow checking the Just changing the client to get the timestamp in milliseconds before sending it to imink/flapg will allow authentication attempts to succeed, but only if the client's time (plus request latency) exactly matches the time on the Android device. So, the proper solution is to not send the timestamp to the API and instead have the API use and return the timestamp on the Android device with the resulting
imink and nxapi both have fully compatible APIs when used as documented, however nxapi's server will only return parameters that were not included in the request and were generated by the server, while imink will always return the |
Beta Was this translation helpful? Give feedback.
-
In v2.4.0 the format of
This broke most projects using the Coral API as it was still accepting If you are using the Nintendo Switch Online app API: you do not need to do anything if you are using the imink API (or my nxapi-znca-api test server) to generate If you are using a custom imink API server you need to update the server to v1.0.3. If you are using another API to generate ... |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Coral 2.7.0 changes the obfuscated names of some of the classes and methods that are called by the token generation functions in the native library. No additional data is used and no changes to clients are required. Coral authentication (
|
Previous method | New method | Description/purpose |
---|---|---|
com.nintendo.coral.core.entity.NAUser/c |
com.nintendo.coral.core.entity.NAUser/a |
Returns the user's Nintendo Account ID |
com.nintendo.nx.nasdk.m/d |
pb.k/c |
Returns the Nintendo Account id_token (the same token passed to gen_audio_h as the first argument) |
Web service authentication (gen_audio_h2
/hash method 2)
Previous method | New method | Description/purpose |
---|---|---|
com.nintendo.coral.core.network.e/b |
c9.l/b |
Returns the Coral token (the same token passed to gen_audio_h2 as the first argument) |
za.h/v |
ea.a/h |
Returns an instance of com.nintendo.coral.core.entity.CoralUser (not renamed), with the a field (not renamed) set to the Coral user ID (other fields are not used) (com.nintendo.coral.models.AccountModel ) |
com.nintendo.coral.core.entity.NAUser/c |
com.nintendo.coral.core.entity.NAUser/a |
Returns the user's Nintendo Account ID |
(Example of patching these using Frida: https://github.com/samuelthomas2774/nxapi-znca-api/blob/8cf62e95e705b64249321a965bb950281c923c5f/src/android-frida-server/frida-script.cts#L162)
Beta Was this translation helpful? Give feedback.
-
Coral 2.8.0 changes the obfuscated names of some of the classes and methods that are called by the token generation functions in the native library. No additional data is used and no changes to clients are required. Coral authentication (
|
Previous method | New method | Description/purpose |
---|---|---|
com.nintendo.coral.core.entity.NAUser/a |
com.nintendo.coral.core.entity.NAUser/h |
Returns the user's Nintendo Account ID |
pb.k/c |
bw.j/c |
Returns the Nintendo Account id_token (the same token passed to gen_audio_h as the first argument) |
Web service authentication (gen_audio_h2
/hash method 2)
Previous method | New method | Description/purpose |
---|---|---|
c9.l/b |
s4.l/b |
Returns the Coral token (the same token passed to gen_audio_h2 as the first argument) |
ea.a/h |
ty.a/i |
Returns an instance of com.nintendo.coral.core.entity.CoralUser (not renamed), with the p field (renamed from a ) set to the Coral user ID (other fields are not used) (com.nintendo.coral.models.AccountModel ) |
com.nintendo.coral.core.entity.NAUser/a |
com.nintendo.coral.core.entity.NAUser/h |
Returns the user's Nintendo Account ID |
Beta Was this translation helpful? Give feedback.
-
I have looked into this more, these are my findings: the JNI function Java_com_nintendo_coral_core_services_voip_LibvoipJni_genAudioH takes 5 arguments:
these char arrays are directly passed into the gen_audio_h native function, like so:
The issue with this is that gen_audio_h is 500k instructions long, and does multiple syscalls to fopen, fclose, and gettimeofday. So I think unless someone is able to find out what this giant gen_audio_h function does in the .so file, running it the way we currently do is probably the best we're gonna get. Note: There is a possibility that the x86 library and the arm64-v8a/armeabi-v7a libraries do something else, but that is hard to find out as I am not as good at debugging on android and tools like ghidra/binaryninja seem to handle those libraries worse, though the general gist of the JNI function seems to be the same. |
Beta Was this translation helpful? Give feedback.
-
Tracking issue for anything related to the
f
parameter required to authenticate to the Coral API and web services...If you can help reverse engineering this, leave a comment here or send a message on Discord (#12).
Related:
Currently nxapi, splatnet2statink, ikaWidget2, imink and anything else that uses the Coral (Nintendo Switch Online app) API or any web services rely on either the flapg or imink API to generate some data necessary for two (actually three) authentication-related API calls, which requires sending them some authentication data (!). The data doesn't seem to have any useful purpose other than to (somewhat unsuccessfully) prove the client is actually Nintendo's app.
Ideally this would just be done locally so we don't have to send any data anywhere...
From #9 (comment):
No idea how that would actually work (either reimplementing or somehow embedding
gen_audio_h
/gen_audio_h2
), but (if possible) it should be usable in anything that can compile WebAssembly modules (e.g. for Python pywasm or wasmer), then we could create a simple API that would be required by the module to prevent clients sending too many/any invalid requests to Nintendo.From https://www.reddit.com/r/NintendoSwitch/comments/tpzabb/comment/i2kk9ny/, re. possibly running Nintendo's app locally as flapg/my service do now (w/ added line breaks):
It is possible to run Coral on a Mac with an ARM/M1 processor but you need a jailbroken iOS device to dump a decrypted copy of the app. I can't get past the login screen though (where it should launch a Safari web view with the Nintendo Account login page it just doesn't do anything, I think it shows a message with the Safari icon but then immediately closes it). Attaching to the app with Frida (as root) works, and you can read the app's memory and Objective-C classes, but even just attempting to call anything causes the app to segfault. (Possibly due to SIP?)
It should be possible to inject a dylib when launching Coral (assuming it's signature has already been removed to get it to run at all). Then that could provide some API that could be used to call
genAudioH
/2
, without dynamic instrumentation.Is it possible to isolate the
gen_audio_h
/2
functions, and any other functions they call, and remove everything else any Android (/iOS?) specific dependencies from the binary? That would at least mean it would be possible to just call it on any Linux OS…So far I’ve managed to compile a binary that (would) call
gen_audio_h
, but it doesn’t work because it tries to load Android stuff.Or, would it be possible to just create stubs of anything
libvoip
imports but doesn’t actually need to callgen_audio_h
?If this works it could be run in a WebAssembly binary, using a minimal Linux environment with v86. (If this can restore a snapshot of graphical OS almost instantly it’s definitely fast enough to run a single function from a Linux binary. Possibly this could also run a custom minimal Android environment as well.)
Beta Was this translation helpful? Give feedback.
All reactions