Hi! emuiibo is one of my most well-known homebrew projects. It is actually my favorite Nintendo Switch homebrew project since I have really enjoyed working on it over the years. Would you like to know how it was made? Do you want some insight into how this kind of projects work? Then you will definitely enjoy this post.
- Amiibo spoofing
- Intercepting NFC
- Why amiibo dumps?
- Amiibo emulation
- Controlling the emulation
- Amiibo logic
- Are dumps really necessary?
- Bye C++, hello Rust
- Amiibo settings
- Crypto arrives
- Current state
Amiibo spoofing
The first known attempts at amiibo spoofing in the Nintendo Switch can be traced back to several forks/repositories of switch-nfp-mitm like this one. This homebrew consisted of a sysmodule intercepting the NFC service games use for anything amiibo related. A binary amiibo dump is read from the SD card, information is read and parsed from it, and all commands any games send to the mentioned service are intercepted and responded by emulating amiibo data.
This homebrew worked… to a certain point, just with a few games. Other developers forked and made their own improvements, but it still wasn’t the best. I happened to be one of them, since I wanted to play around with the project - getting amiibo spoofing to work sounded fun - and I got it to “work” properly. After deciding to take it as a serious project, and after speaking with the original dev for permission to effectively take over it, emuiibo was born back in april 2019.
Intercepting NFC
The core idea behind amiibo spoofing, as mentioned, is intercepting the console’s NFC services. The Nintendo Switch’s operating system is a microkernel; in other words, its kernel only takes care of basic operating system functionalities - managing processes, threads and other key system objects - while more high-level aspects - from filesystems to console users, battery, graphics, audio and so on - are managed by background processes, usually referred to as sysmodules.
The kernel provides a communication system named IPC or inter-process communication, so that a process - for example, taking care or system users - can provide information to other processes which need it - for instance, a game wanting to know the system user count, their names and icons, etc. This communication channels work through command interfaces, which kind of resemble object-oriented programming classes in that they consist of a collection of commands, with input and output arguments, which can be requested by other processes and responded by the host process - all this through rather complicated marshallings of said arguments and using kernel syscalls to receive and reply to the command. A command might be sent to request the current battery percentage of the console, to launch a game, to reboot/power off the console - yes, all these are real command examples, although served by different services/processes. Root interfaces are called services, each having a characteristic name, with other processes connecting to them in order to request their commands.
How does one intercept IPC? This can only be achieved via CFW, of course, with Atmosphere providing a special MitM API extension to the base service API. Some other well-known homebrew projects, such as ldn_mitm, also rely on MitM. For those unaware, MitM or man-in-the-middle consists on sitting in the middle of the server-client communication channel, so that requests from the client first reach us and we have the option to process and respond to them ourselves - the client will think the server responded, and the server doesn’t even know a request was sent since it never received it - or we can avoid intercepting requests we do not care about, forward them to the server and let the communication continue as if there was no interception whatsoever. Such intercepting is only possible since Atmosphere itself reimplements key components in services/IPC communication, hence MitM can be achieved without patching or other potential and more complicated approaches. IPC functionality, like other parts of the operating system, have a lot more details and subtleties… I might make a post exclusively dedicated to IPC in the future.
The nfc
process hosts NFC services which can be split into two kinds: pure NFC services, whose names start with nfc:
prefix and are used by any games with their own NFC specifications - Skylanders is a good example of this - and NFP services, providing simplified interfaces for anything amiibo related; Nintendo Figurines the internal name used by Nintendo for amiibos. Three NFP services exist: nfp:user
- used by games - nfp:sys
- used by system applets and processes - and nfp:dbg
, not really used by anything as far as I know - the name suggests its a debug service after all.
What do switch-nfp-mitm and emuiibo actually do then? They are just custom new sysmodules that Atmosphere launches at boot - along with the other sysmodules - that are constantly listening for communication in NFP services, intercepting those commands, hence lying to the game as if an amiibo were present, and providing fake amiibo data any moment games request it via commands to said services.
For switch-nfp-mitm and first emuiibo releases, only nfp:user
was intercepted since there was not really interest in intercepting the other services… but more on that later.
Why amiibo dumps?
I mentioned amiibo dumps are used to obtain amiibo information… But what information is exactly needed? Amiibo dumps contain everything an amiibo has, thus including NTAG manufacturer info - in other words, NFC-related info all devices have - its ID - more about this in a moment - its owner mii, its game-specific savedata… However, not all this information can be obtained: in fact, everything but the amiibo ID and NTAG info - and other less relevant fields, such as a counter incremented every time the amiibo is written - is encrypted. By this point neither switch-nfp-mitm nor emuiibo did any crypto whatsoever, since dumps were merely used to obtain the mentioned NTAG information and amiibo ID. In fact, decrypting those fields requires amiibo keys, which we still did not know how to dump from the Switch itself, and asking users to provide the key would be a bit annoying and confusing for many.
Amiibo emulation
The way emuiibo originally emulated amiibos in its first release has not really changed over the years. As mentioned, binary amiibo dumps are read, information is obtained from them, and then emuiibo generates a virtual amiibo, which is essentially a directory with a set of JSON files and other miscellaneous files containing all the amiibo information. All other needed amiibo fields which are encrypted in amiibo dumps can be effortlessly emulated: first and last dates the amiibo was written to, owner mii, amiibo name… In particular, simulating a mii is not that trivial. Luckily, the Switch’s mii services provide commands to generate data for a random mii - without even having to add it to the console mii list. In boot, emuiibo would convert all dumps it would find, generating default values of these mentioned fields. For example, the amiibo name is set to “emuiibo” and a random mii is generated for it. As an interesting note, these random amiibos generated by the system have “no name” as their default name. Nevertheless, users might want to set their own console miis as owner miis, which is why emuiibo also exports console miis to the SD card so users can replace the mii data file in the generated virtual amiibos with their console mii data file.
While in first releases emuiibo did not generate a virtual amiibo and would just simulate everything on-the-fly by reading from the dump, modern emuiibo releases dropped this in favor of only using the dump to create the virtual amiibo. This is still how emuiibo works, although as we will see later dumps are no longer needed to emulate amiibos.
Another key detail to discuss is per-game amiibo save-data emulation. Per-game save-data is saved by emuiibo as binary files inside the virtual amiibo directory. This inmediately supposes a big advantage of emulating amiibos: real amiibos can only save data for one game, while emuiibo has no reason to impose this limit… although this would end up causing minor trouble in future releases.
Controlling the emulation
While the original switch-nfp-mitm forks loaded the amiibo dump from a hardcoded path, emuiibo allows having several virtual amiibos and swapping between them. However, a sysmodule is a background process which cannot render anything on the screen - with a few notable or complex exceptions - so how can one switch between them? Like switch-nfp-mitm did for turning emulation on/off, emuiibo originally relied on button combinations - and shining the HOME button LED when the current virtual amiibo changed as some sort of success indicator - which was a bit clumsy but did its job.
Eventually a clean way to control the sysmodule was introduced thanks to WerWolv and others: overlays, a special kind of homebrew which is, as the name implies, overlaid over everything else on the screen. Overlays are opened with a button combination, and then are easily controlled by their UI. This is still the way emuiibo is controlled, and it is night and day compared with the old button combinations.
Amiibo logic
Over time, some issues arose from several games: these games - like ??? - simply wouldn’t work properly, hanging forever or complaining about nonsense amiibo connectivity problems. As it turns out, the underlying issue was the reason why first emuiibo releases “worked” or, in other words, they just appeared to work overall for the use cases it was tested with. In fact, amiibo logic is meticulous. So far, emuiibo only had the notion of having an amiibo selected or having nothing selected at all. In fact, the virtual amiibo was automatically unselected after the game requested certain commands which were expected after amiibo saving: most games wait until the user removes the amiibo from the NFC spot after having saved data, so this behavior was needed for them to not hang waiting for the removal.
Unfortunately, this tricky behavior was the cause for the unexpected hangs in other games. The solution to all of this was to properly mimic real amiibo behavior, by distinguishing three possible states: no amiibo selected, an amiibo selected but not connected - quite like having the amiibo figurine in your hand but not placing it on the NFC spot - and an amiibo selected and connected - like having the amiibo actually placed in the NFC spot. All these had to be controlled by the user via the overlay. Hence, when games request the amiibo be removed after saving, the user has to manually disconnect the amiibo from the overlay like they would physically remove the amiibo from the NFC spot, and they would have to connect it again to use it like a real amiibo would would be put back in the NFC spot when needed. This may sound more tedious than emuiibo doing it automatically for you, but there is no general satisfactory way of automating this logic without breaking other games.
Are dumps really necessary?
As it turns out, not only a small part of the contents of amiibo dumps was being used, but even less information is really needed. In fact, everything amiibo dumps have can be somehow emulated or randomly generated… but its amiibo ID.
Amiibo IDs are the field which actually identifies the amiibo. While the previously mentioned NTAG/NFC fields identify the unique figurine - and still can be made up without any issue - each amiibo has its unique ID… and these, of course, cannot be randomized. In other words, the only field needed to reliably create a virtual amiibo from scratch - aside from user-defined aspects like its name, mii and so on - is the amiibo ID.
Fortunately, soon after noticing this I found out there is an up-to-date online database compiling details about all released amiibos, featuring their name, series, description, even a picture of the figurine… and amiibo ID too: AmiiboAPI. This effectively opened the possibility of creating new virtual amiibos from scratch without the user having to provide anything but their desired amiibo model, name and so on. This is how emuGUIibo, later emutool - you might notice I suck at naming projects, the neat name of emuiibo was of course not my idea - was born: a PC tool simplifying amiibo creation, made in C# and WinForms:
This language choice would later prompt me to make a follow cross-platform approach; while WinForms programs can be run using Wine/Mono, this is far from perfect and they are still prone to compatibility issues. Following the same idea, CompSciOrBust made Amiigo, a Switch homebrew application essentially on the same virtual amiibo maker for emuiibo - also using AmiiboAPI - for the console itself.
Bye C++, hello Rust
Like almost all homebrew projects, emuiibo was made using C++ and Atmosphere’s libraries from the start. As I was devoting more and more time to trying to make Switch homebrew purely with Rust just for the sake of it, I noticed that emuiibo was the best choice of a project of mine to be ported to Rust, since the rest relied all on hardware-accelerated graphics, which would take an eternity to get working in Rust. Being able to port emuiibo to Rust “only” required to port IPC server functionality from Atmosphere, the only library properly implementing it - the code for sysmodules to create/host services, hence MitM them as well - which was way more feasible.
I had no particular goal with this other than getting better at Rust and making emuiibo the first popular homebrew made purely in Rust. The overlay was of course excluded from this migration - again, graphics was too much for me - but the sysmodule itself, the core part of emuiibo, was now purely made in Rust. Nevertheless, the rewrite turned out to be a great decision: the heap memory used by emuiibo could be now reduced to 10 times less, the resulting compiled binary was 5 times smaller, and emuiibo overall felt quite faster! While not completely clear, this probably has to do with reducing existing bloat in C++ and/or Atmosphere’s code, since my Rust homebrew libraries are more lightweight, with the pros and cons of that - supporting less features, being less accurate to reverse-engineered Nintendo code, etc.
I will eventually make a post in detail about how pure Rust homebrew is made, since it would be too long to cover here.
Amiibo settings
As you may know, amiibos can be edited in Switch system settings: changing their name, owner mii… but this just was a big headache regarding emuiibo.
As I mentioned, emuiibo essentially works by intercepting the nfp:user
service… while, nfp:dbg
is an unused debug service and nfp:sys
is the service used by the system: for instance, by the applet launched when editing an amiibo from a game, or straight by the amiibo menu in console settings.
Being able to edit emuiibo’s virtual amiibos straight from system settings that way would be great, but due to technical issues I was struggling to intercept the system service… until the problem was solved - which admittedly took a while - and such power was unleashed.
This, interestingly, is why eventually the multi save-data support emuiibo introduces started posing problems: system settings show the amiibo’s game save-data if present, so how would emuiibo simulate that if the selected virtual amiibo has multiple game save-data?
Since there is no fully satisfactory solution here, I decided that each virtual amiibo would keep track of the last game in which the amiibo was used, and that game would be displayed by system settings. This, of course, is not truly faithful to real amiibo logic, but without mimicking real amiibo save-data limits there aren’t really better options here.
Interestingly, back when I was having trouble successfully intercepting nfp:sys
services, system settings would show garbage data when reading a virtual amiibo, since emuiibo was mistakenly sending amiibo data in the wrong format. In fact, a blank amiibo name would be shown, along with blank icon mii named “Nick Name”.
Crypto arrives
As mentioned, a big part of amiibo dump data is encrypted. Since getting that data would be ideal in order to properly emulate real dumped amiibos, I eventually got around with porting hardware-accelerated Switch cryptography to Rust, since this functionality was already implemented in the widely used libnx libraries.
This, among other things, partially - and unexpectedly - revived interest in creating virtual amiibos from real amiibo dumps, but why? As discussed, amiibo dumps are not required to create “blank” virtual amiibos. However, some well known cases imply using existing amiibos with save-data from other games to benefit from certain unique in-game rewards, with the most notorious being Midna Wolf Link amiibo. If the amiibo contains Skyward Sword HD savedata and is used in Breath of the Wild, the companion wolf it spawns can have up to 20 hearts of health instead of the default 3. Thus, to get such 20-heart wolf companion, that special Wii U game save-data is needed, which requires either having the binary savedata and placing it inside the virtual amiibo directory, by finding it online or manually decrypting and extracting it on PC from an amiibo dump - both of these done by many users before emuiibo supported cryptography - or letting emuiibo do it automatically provided the amiibo dump.
Implementing amiibo dump decryption was not only a matter of implementing the corresponding algorithms. All the decrypted data has also to be parsed and understood, which took a while to get properly done… and some bits are not even properly understood nowadays. In particular, the owner mii is stored in the 3DS mii format, and guess what? It’s quite different from the Switch format. The NFC sysmodule - the real deal - contains code to convert between them, but both formats were barely documented. In the end, docs in [switchbrew] and reverse-engineering done in [Ryujinx] was the key to make a somewhat functional conversion code.
Current state
Since it is already quite stable, emuiibo has barely changed recently. The last major change was deprecating emutool in favor of the new tool emuiigen, the same concept but freshly made in JavaFX:
Do you have any ideas for emuiibo? Any quality-of-life improvement suggestions? Like with all my projects, feel free to post them as issues on emuiibo’s GitHub repository, or you can always reach me through Discord - both links can be found here on my blog. Hope you enjoyed this read!